Buttons considered harmful when used on a web page
TL;DR Just use Links
Specifically an event handler on click is a bad thing.
This arose because I was doing an admin page which kicked off long running actions, three to four days, and it kept tripping security timeouts. I would have liked to have the luxury of a back end but this is a Single Page Application (SPA) that runs entirely in the browser. I made the mistake of just embedding the code directly into the pack and using an onclick event to trigger it.
- If the code ran more than forty minutes I got security errors.
- The code was impossible to access except for clicking on the button so this could not be automated.
The fix was quick enough, as its an SPA I have access to the routing so I just added to the routes to allow the code to be called directly by specifying an entity and an action.
https://site/application#admin/entity/action
Simple enough now I can just invoke the code from a browser.
Then all the buttons had to do was call the URL above, so that meant they could now be links. I still style them as buttons as its a visual clue to the end users that they invoke an action rather than do navigation.
This got me thinking about how buttons basically break the stateless nature of the web. In fact its not just buttons its really any of the ‘on’ events they lose your place in the transaction history and it means you cannot easily roll forward to an equivalent state if anything happens.
The question is can we write web applications that encapsulate their state within their URI? If we can then this gives a very powerful facility for use and testing, no longer do you need to explain to users how to get to something just send them the URI, similarly help documentation doesn’t need screen shots, just give the URI and by clicking on it someone will see exactly how the system is in its current version.
Buttons are considered harmful because…
They can only mean that the ‘state of the page’ is wrong based on its only unique identifier it’s URI.
If we replace buttons with links then the URI and the page state must match.
Note this doesn’t mean the page’s contents will be identical just their state so if I use the following URI
https://site/application#ordercollection/unfulfilled
Then a page showing the currently unfulfilled orders is guaranteed, could be none, one or many depends on other systems. However I am guaranteed that I am seeing the currently unfulfilled orders.
If I decide to sort by oldest first in response to an onclick event on a button then I rerunning the URI, by say using F5,will now give me a different state, or if I send that link to another party they will see a the data in a different order from me. If instead I add the sort order to the URI and navigate to it (possibly via button)
https://site/application#ordercollection/unfulfilled?sort=placeddate:ascending
Then a refresh or sharing of the URI at least guaratees that the state remains the same, even if the manifestation may have been affected by other events, e.g. orders being fulfilled.
Similarly if I fulfil an order as a result of an ‘oncheck’ action on a check box then the state is changing in a way that is not recorded, instead I need a URI say
https://site/application#order/235/fulfil
Now I can fulfil that order without having to go through a display screen.
As I gear up for the next project I’m going to see if this will really work on an industrial scale.