• Using POST with a regular link

    Nov 22 2006

    Here's the problem: According to the principals of Representational State Transfer (REST), GET requests shouldn't change anything on the web server. Only POST requests should. For example, you really shouldn't have an <a> link that deletes an item. When you click a link, it sends a GET request to another page, and deleting an item is definitely a change. You should have a delete button that submits a form using POST instead.

    Why? Well for one, Google Accelerator speeds up your web surfing by downloading all the pages that it knows about through the links on a page. So if there are links that delete items or other horrible things, Google Accelerator will go and delete everything for you. This actually happened to some users of 37 signals.

    So the real solution is to just use a submit button for all the actions that actually do something (delete, save, etc.). And this is totally fine from a technical point of view, but not so great from an asthetic point of view. Buttons can be pretty ugly, right? (I actually like how they look, but then again, I'm not a designer.)

    There is also another solution. You can use JavaScript to make a hidden form, then add an onclick event to a link that submits the form when you click the link. This solution is okay, except for those who don't have JavaScript (like search engine spiders).

    I came up with a solution that tackles the problem from the asthetic angle. We can style the buttons so they look like links! Seriously!

    Okay, it's not so easy. And it's not perfect. But it's pretty close. Here's the code:

    .link-button {
        border: 0;
        padding: 0;
        background: inherit;
        font: inherit;
    
        cursor: pointer;
        text-decoration: underline;
        color: blue;
    
        overflow: visible;
    }
    
    <input type="submit" class="link-button" value="Delete"/>
    <button type="submit" class="link-button">Delete</button>
    

    It's a bit long because buttons have a lot of default styling to them. First, we remove the border, padding, background and font. Next, we change the mouse cursor and colour, and add an underline so that it looks and acts like a link. Last, we add this overflow: visible to force Internet Explorer to get rid of that weird spacing it adds inside buttons.

    You might also have to set the actual font and size of the button to make it match the text around. I don't know why, but font: inherit just doesn't always do the job like it should. If you specifically set font: 12px Arial, it will look fine.

    In Safari, it won't do anything if you're using an <input type="submit"> because you can't style these. However, you can style a <button type="submit"> though. You will just have to set the background colour directly and not use inherit. So as long as you don't have some trippy background image, it will be fine.

    Another thing: it's not perfect in Firefox or Safari. It will still have some weird spacing around it. Have a look at what Firefox does:

    Buttons have some spacing around them in Firefox

    The top is a regular link, the bottom is a button. You can see it's pretty close, but not perfect. Safari has a similar effect with spacing on the bottom.

    Well we can take it to the next level and use JavaScript so that it's perfect for the 90% of people who use JavaScript. The other 10% can see the extra spacing, but that's no big deal (they probably won't even notice). We can use the following function to accomplish this:

    function replaceButtonWithLink(button) {
    	var link = document.createElement('a');
    	link.href = '#';
    
    	// find link text either as value of input or innerHTML of button
    	link.innerHTML = button.value || button.innerHTML;
    
    	link.onclick = function() {
    		button.form.submit();
    		return false;
    	};
    	button.parentNode.insertBefore(link, button);
    	button.parentNode.removeChild(button);
    }
    
    // here's what you do for an <input type="submit"/> or <button type="submit"/>
    var button = document.getElementById("my_button");
    replaceButtonWithLink(button);
    

    Now we have a nearly perfect solution. If the spacing in Firefox isn't a problem for you, you don't even need the JavaScript portion. But it's there just in case you have some pixel-paranoid designers on your team that insist it should look perfect in their browsers (just hope they have JavaScript turned on!)

  • Comments

    1. Julian Reschke at 4:14am on November 23, 2006

    I think you missed something important. GET being "safe" is not only for things like the Google Accelerator, but also for users. They should be able to rely that something that looks like a plain link actually is one.

    Bad idea!

    2. Jesse Skinner at 10:29am on November 23, 2006

    Interesting point. I'd have to agree with you. I hadn't considered the principals of REST from a usability point of view. I've always thought in terms of clients and servers. I guess, too often I've seen this as a solution:

    <a href="#" onclick="document.forms['delete'].submit()">Delete</a>

    I also think designers often care more about how things look, and some just don't want buttons (or underlined links for that matter). And often as developers, we're stuck doing what we're told. So at least for this scenario, there is a way to remain RESTful and still match the design.

    3. MikeD at 9:07pm on November 24, 2006

    While I sympathize with a page designer trying for a spartan look and feel, it is important to realize that a link is not a widget. This breaks the explore-ability of Web applications and exposes destructive operations to utilities and tools that pre-fetch data - links should cause no harm.
    Designers /should/ care about how things look, and it is their job to make sure that destructive operations /look/ destructive.

    See also: http://korrespondence.blogspot.com/2005/11/link-is-not-widget.html

    4. Emil Stenström at 7:19am on November 25, 2006

    A minor problem in your HTML, you seem to end your button before the containing text, perhaps that's the reason for the strange space?

    5. Jesse Skinner at 10:31am on November 25, 2006

    Oops, no that's just a typo. It wasn't in my test code..

    Thanks, Emil.

    6. Morgan Roderick at 5:07am on November 30, 2006

    Just like the server expects the POST to be used for modifying data, the user expects buttons to modify data ... not links.

    By making links instead of buttons, you're putting a lot of effort into confusing your users.

    By no means affiliated, but do read Steve Krug's book - Don't Make Me Think!

    7. Jesse Skinner at 4:10pm on November 30, 2006

    I fully agree that web sites should make things clear to the user, and that the best way to do this is to use common conventions (like buttons) so that things are predictable. And honestly, I would never use a link to submit a form, nor would I ever choose to style a button to look like a link.

    However, I think there are some scenarios where someone might want to do this, and it might not be a totally evil idea. Consider a less severe example than 'Delete', like 'Add a row'. Adding a blank row isn't destructive, yet it does alter the data. This is an action that should be done with POST, however I'd expect no usability problems with clicking a link to perform the action. This is so common in web interfaces that I'd almost consider it a common convention of it's own.

    If someone really wants to use a link in their interface, even if it's not the greatest usability idea, at least there is a way they can do so and still use POST (without JavaScript).

    8. Nate See at 4:32pm on December 11, 2006

    I think it's a great idea.  I'm actually going to use it in a report drill down.  The report looks stupid if I have a bunch of buttons the user clicks on to see what data produces the numbers, but with links, it maintains readability.

    And for you hard core geeks out there, I think you are confusing yourselves with users.  Users don't really know the difference between links and buttons, to them, they both change what they're looking at.

    9. Strafverteidiger München at 3:48pm on April 19, 2007

    hey, thanks for the long long button. great.

    10. Haymaker84 at 8:59am on February 13, 2008

    Hi, i think it is a great idea! (even if this article might be a little old) way better than using JavaScript or alikes for this kind of Work. I will definately use this for my Web Application. I am planning to implement a site navigation which calls a Servlet (which needs to process POST-Data).
    Since I am not allowed to use JavaScript by our guidelines - it's the perfect solution!
    I don't see why users could get confused cause they don't see the button... HTML forms are by default able to display a functional graphic instead of a button. I heard nobody complain about that so far!

    11. Jared at 12:00am on February 20, 2009

    Come on guys don't over simplify. This isn't a tool for all scenarios. There ARE times when submitting a form with a link causes no harm at all. Awesome work, not the solution for me but still cool.

    12. Jules Manson at 11:59am on July 23, 2010

    Please allow me to illustrate the absolutely perfect solution for such a button. I am building a PHP framework, now with all the fine choices out there why I am building it as another story, and one of its components will be a PHP stylesheet switcher. Styles can be selected from buttons that appear to be anchor links and I could hide the query string inside a POST instead of GET polluting my already populated query string. Because the settings will be stored inside cookies/sessions it should be relatively safe to use. Please correct me if I may possibly be wrong as I am definitely new to web applications design.

    In addition although I definitely appreciate the free technical advice and tutorials out there it still erks me, just a little bit, when authors post instructional material yet do not provide a working demonstration. One would think that providing such a demo is tutorial 101.

    Just call me an ungreatful bass turd.  o_~

    Commenting is now closed. Come find me on Twitter.