[HN Gopher] Don't disable buttons
___________________________________________________________________
Don't disable buttons
Author : damethos
Score : 152 points
Date : 2023-11-08 09:07 UTC (13 hours ago)
(HTM) web link (gomakethings.com)
(TXT) w3m dump (gomakethings.com)
| anon23432343 wrote:
| Can we add an "AD" tag in HN?
|
| Don't get me wrong but this really does not explain the full
| story and the post ends with basically: "If you really want to
| know pay for it".
|
| I don't have anything about paying for this information but at
| least say it is an AD for your agency.
| Leimi wrote:
| Kinda harsh to see it that way. You could remove the last four
| 4 sentences of the post and don't see it as an ad at all. The
| post does actually explain the most important part and the guy
| just tells us we can hire him if we need help.
| thih9 wrote:
| What information exactly are you missing? The post lists why
| developers do it, why it's bad, and what you can do instead -
| as promised.
|
| I don't think we should have an "ad" tag. Most "show hn" posts
| are basically ads for new products, and still very useful and
| very welcome. If you think a submission is inappropriate or
| dishonest, you can flag it and write your reasons in comments.
| g-b-r wrote:
| It for sure makes you aware of a problem; I personally never
| thought about it, I imagine many other people didn't either
| agos wrote:
| I was under the impression that a disabled submit button would
| also prevent the form by submitting on enter/return, is this not
| the case?
| anon23432343 wrote:
| No you can submit by pressing enter. for example if you have an
| login form and your focus is on the PW and you press enter then
| it still will be sent.
| dbrgn wrote:
| That depends on whether it's actually a classic HTML <form>,
| or whether it's just a collection of input fields submitted
| through JavaScript.
|
| And of course, if you disable the button, you could prevent
| duplicate form submission as well through the onsubmit event.
| recursive wrote:
| This is missing a detail. This only works if there is not a
| disabled `type=submit` element inside the form.
| chrismorgan wrote:
| You are correct, and the original article is incorrect in this
| point (a pity, since the rest seems sound).
|
| Spec reference: https://html.spec.whatwg.org/multipage/form-
| control-infrastr...
|
| (It's not written in the most obvious way as regards this
| detail, but it's clearly there: if there _is_ a default button,
| click on it, _if you can_ --implied is: if you can't, just do
| nothing; and if there _isn't_ a default button, try to just
| submit the form.)
| huijzer wrote:
| Wouldn't this cause problems if the first submit attempt fails?
| Then, the form won't send again because it tried already?
| anon23432343 wrote:
| Its your job to remove that state if it fails and inform the
| user. This is just not written down in this post. Thats the
| part were you have to contact the writer.
| alpaca128 wrote:
| > Thats the part were you have to contact the writer.
|
| Why? It's basic error handling. And the author linked to
| another explanation about the aria-live attribute for the
| user informing part.
| chrismorgan wrote:
| "Basic error handling" is distressingly rarely present, and
| when present, regularly broken.
|
| In general I do think it's _mildly_ irresponsible to not
| mention error handling at all and (taking what this article
| does) to show reenablement only via linear code flow that
| assumes success. But when it's in an article about _the
| problems of disabling submit buttons_ , then it's even more
| perplexing.
| magicalhippo wrote:
| We've been following that policy in our desktop application for a
| long time. It's almost always much better for the users that they
| get an error message saying why it's not possible to do X when
| they press the button, than not knowing why the button is
| disabled.
| wizofaus wrote:
| "almost always" - agreed, but the specific case where your
| application has clearly gone into a temporary mode where no
| user interaction is permitted (other than perhaps "cancel") I
| would think was the exception. But simply adding the disabled
| attribute to the existing input controls probably isn't the
| best way to do it if it's an issue with screenreaders etc.
| Though it's not clear why such tools couldn't deal with it in a
| better fashion.
|
| I'd also say I'd have no issue with a button showing as
| disabled provided when you attempt to click it or hover over
| it, it tells you why it's not yet a permitted action. But
| again, might be an issue for accessibility etc.
| eviks wrote:
| It's much better adding information to the UI explaining why
| the button is disabled rather than confusing the user to the
| point he's done an unnecessary action and got an error
| pavlov wrote:
| The article is right, but it's also an indictment of just how
| poorly designed HTML is for dynamic applications.
|
| Preventing double submission of data is a thoroughly basic
| feature for any UI library. It should be easy and obvious. But
| for HTML forms, the properly accessible solution shown here
| involves a non-intuitive combination of JavaScript, CSS and
| custom data attributes on an element.
| mattlondon wrote:
| HTML wasn't designed for writing applications.
| kypro wrote:
| HTML is just the language for describing the page content. It's
| not designed to be dynamic. A modern JS component library could
| have support for something like this.
|
| The author's suggestion of using a data attribute instead of
| adding a disabled class to the element and the styling of it is
| more of preference thing.
|
| That said, I don't really understand why there isn't something
| like a "singleSubmit" attribute you can add to a HTML form to
| automatically disable duplicate submissions. Handling double
| form submits is a frequent problem - you almost never want a
| form to be immediately resubmitable which HTML forms are.
| pavlov wrote:
| Your comment is a good example of the peculiar cognitive
| dissonance that surrounds HTML.
|
| The first reaction is always defensive, "HTML isn't designed
| for this!" -- and two paragraphs later it's: "HTML should
| really do this though".
| wzdd wrote:
| I didn't see this as cognitive dissonance. It is "HTML and
| CSS are declarative. It would be good if there were a way
| to specify this requirement declaratively."
| kypro wrote:
| To clarify, I don't think HTML should be expected to be
| responsible for button styling - that is a CSS concern. But
| I was really more responding to the "why can't I do this
| with a HTML library" comment, which you can but with a JS
| library instead. And while it's true HTML has some dynamic
| elements the assertion that you should be able to build
| advanced dynamic behaviour like this in HTML alone I think
| misunderstands the purpose of HTML. JS was built for more
| advanced dynamic behaviour, and you can absolutely do what
| the parent commenter is asking for with a JS library.
|
| To defend my suggestion of a "singleSubmit" attribute - I
| think the form element itself which already has the ability
| to do some basic dynamic stuff like submit a form in
| various ways could reasonably include the basic requirement
| of not allowing said form to be submitted twice. Personally
| this isn't something I think is a huge issue because most
| of the time when we'd want to do this we're looking to
| build fancy dynamic form behaviour anyway and in those
| cases JS is going to be what you need to use for that. But
| there are some simple webpages out there which don't care
| about any of that fancy stuff and literally just want a
| form on a page which POSTs data to another page, and in
| those cases it would be nice to have the "singleSubmit"
| attribute I suggested.
| wongarsu wrote:
| Forms are one of the rare instances where "dynamic" content
| was actually designed into HTML. Sure, the original intention
| was to have a page transition on form submission, but for the
| user that might be indistuinishable from what JavaScript is
| doing today.
|
| A much better behavior would be to have the form handle the
| button state automatically: once you submit the form, all
| submit buttons of the form are disabled until the completion
| the button's onclick handler, the form's onsubmit handler,
| and any request triggered by the form action. Once all of
| these are done, all submit buttons belonging to this form are
| automatically enabled again.
|
| If you want to get fancy, HTML could have introduced a fifth
| button state for this to make it distinct from a "normal"
| disabled button, and maybe allowed the form to change the
| button content for that state (you might want the button to
| say "please wait" or "loading"). But really, just simple sane
| handling of the disabled state would have been so much better
| than the barebones forms we have. Make it overridable by an
| attribute if you really want to support the edge case of a
| form having intentional concurrent submissions.
| thaumasiotes wrote:
| > That said, I don't really understand why there isn't
| something like a "singleSubmit" attribute you can add to a
| HTML form to automatically disable duplicate submissions.
| Handling double form submits is a frequent problem - you
| almost never want a form to be immediately resubmit[t]able
| which HTML forms are.
|
| I assume because submitting a form takes you to a different
| page, where the form no longer exists.
| foobarchu wrote:
| This problem is bigger than JavaScript and dynamic
| applications. Even decades ago you'd see warnings to "please
| only click submit once", because most users don't look at the
| browser activity state to see if it is actually doing
| something (regardless of it being an spa or classic pages).
|
| There needs to be two kinds of forms, one that asks if you
| really want to re-submit, and another that allows infinite
| submission. The backend should handle the problem too, but
| this would go a long way toward a better default UX.
| akira2501 wrote:
| > I don't really understand why there isn't something like a
| "singleSubmit" attribute
|
| addEventListener has a 'once' option that will only fire the
| event once. If you're willing to handle all the error cases,
| it seems like the easiest option.
| contravariant wrote:
| That's probably because HTML wasn't intended to be the part
| where you prevent against double submission. The backend should
| probably handle that.
| merb wrote:
| Http Post was not designed to be Idempotent so, basically you
| either fix double submission or your post starts to be
| Idempotent, which is basically against the spec (it's not
| directly against it, but put would be preferred in that
| case). Of course you can always add an uuid hidden field and
| do upsert instead of insert/update. But such things are way
| harder to do.
| wongarsu wrote:
| Maybe pedantic, but OPs advise is actually "disable the button,
| but don't use the disable attribute to do it". Instead they store
| the disabled state in the form and set a CSS style to make the
| button look like a disabled button. Which makes that information
| unavailable to screen readers, but avoids screen readers jumping
| around the page because button loses focus when disabled.
|
| Also a useful note that disabling the button with the disabled
| attribute isn't enough to prevent people from submitting a form.
| Which is useful to remember, but not actually a justification for
| any of this (you can just check the disabled state of the button
| in your submit method)
| sshine wrote:
| Another comment about what the author intends to fix:
|
| What if you submit the form, but the request never arrives?
|
| Then either a disabled or an unresponsive submit button are
| both jinxed:
|
| You may need to reload the page, possibly losing form data, in
| order to reset the ability to submit.
|
| Preventing fast double submits opens up a (small) can of worms
| wrt. managing state.
|
| You want to allow double submit in case of connection failure.
| You may even want to automate them, or add exponential back-
| off.
| rendall wrote:
| > What if you submit the form, but the request never arrives?
|
| I think the proper way is to disable the button, then set the
| subsequent state of the button depending on the response from
| the server if any. submit => check button
| state and if enabled then => disable button => server
| response (or not, then timeout) => update button state (along
| with error message if any)
| feoren wrote:
| That flow is exactly what this article is telling you _not_
| to do. Basically the article said "don't do X, do Y
| instead", and GP said "ok, but if I don't do X, what if Z
| happens?" and your response is "the proper way to do it is
| X". If that's true, can you address the reasons the article
| says to _not_ do X?
| sshine wrote:
| The article seems to discourage disabled buttons for
| accessibility reasons also.
|
| The article uses the wording "re-enable the button after
| the API responds", but doesn't elaborate on
| failure/timeout.
|
| There's other stuff you may want to do, like persist form
| data. Or if you go with the article's recommendation of
| preserving the button, but make it inert, perhaps add
| some indication to what the request is doing.
|
| There is nothing as a "sufficiently smart" website that
| altered the browser's visual language of page loading
| progress. Meetup.com is doing this to me lately; some
| links I just don't know if they're broken, or my net is
| being slow, and I'm being impatient.
| jwestbury wrote:
| OP's advice is also incredibly frustrating if you've ever
| encountered a form where the Submit button seems to just do
| nothing. (Yes, you could pop a dialog which tells the user why
| it's doing nothing. In practice, that doesn't always occur.)
| firejake308 wrote:
| I'm thinking a loading spinner would be the best compromise?
| Notifies the user that their input has been registered, and
| also explains why clicking again won't have any effect?
| kspacewalk2 wrote:
| You may have missed this, towards the end of the post:
|
| >You can also style form elements to "appear" disabled using
| the [data-submitting] CSS selector...
| karmakaze wrote:
| So really all this whole post is saying is that the browser
| behaviour of an attribute-disabled button isn't optimal and
| that we can do better for accessibility, etc. Way to bury
| the lede.
| danShumway wrote:
| Frustratingly, there is also an aria attribute for this, aria-
| disabled, that does not remove focus, and it should absolutely
| be added to any button implementing this strategy.
|
| If you're going to follow this article's advice, don't add a
| [data-submitting] attribute; use the aria-disabled as your
| selector. A custom data attribute does nothing for
| screenreaders or blind users who have no idea now whether a
| given button is disabled or not.
| dbrgn wrote:
| If accessibility tools remove the focus from the disabled button
| and focus the document instead when a button is disabled,
| wouldn't this be a problem of the accessibility tool in the first
| place?
|
| Even just focussing the parent element would be a much much
| better idea than focusing the document.
|
| Making a button _look_ disabled without actuall disabling it
| sounds like a semantically bad idea.
| alpaca128 wrote:
| As written in the article the "disabled" attribute doesn't
| disable submissions either, so it's mostly an appearance thing
| either way.
| dbrgn wrote:
| Of course the submission needs to be handled separately (
| _if_ a <form> tag is being used). But that's not the point.
| The semantics for a disabled button are much clearer: You
| indicate that the button cannot be pressed (because it
| wouldn't actually do anything). Having a button that can be
| clicked, but that doesn't do anything, sounds like a wrong
| choice. Even worse is "making it look like it cannot be
| pressed by adding CSS rules".
|
| From what I know about accessibility, semantics are key. If
| the semantics are clear, then accessibility tools can
| optimize their flows accordingly. Using styling to convey
| semantics is a bad idea.
|
| If accessibility tools cannot deal well with certain
| situations, then those tools should be improved instead of
| making semantics worse.
| creshal wrote:
| There's two levels here:
|
| 1. The screenreader transforms the visual structure into
| something understandable for the human behind it
|
| 2. The human tries to make sense of it and maintain a
| mental model of what the screenreader is presenting to them
|
| Semantics are key for #1, but #2 can still lose track of
| what's happening on a complex form. For that, it helps if
| the human can keep trying, and fix whatever they missed on
| the next pass.
| lyu07282 wrote:
| I agree that is a strange article, setting disabled on the
| submit button is absolutely the correct semantic solution,
| the CSS presented as a workaround is also not enough,
| you'll need to set CSS for pointer-events, hover, active,
| and focus at least to re-create (badly) what the browser
| actually does when a button is disabled. That feels like
| such a hack. Of course you need to block the onSubmit event
| on the form element too but that is a separate issue
| entirely.
|
| Do we really now have to work around broken screen readers
| too? Fuck that.
| hombre_fatal wrote:
| Well, the article is right, though. The disabled
| attribute resets focus to the document which is really
| bad UX.
|
| It might seem like a trivial detail, but it's not for
| people who depend on keyboard navigation nor is it for
| any form where users might want to keep the button
| focused after submit. You don't have to use a screen
| reader to be inconvenienced here.
|
| I've had to handle the latter case in game-related apps,
| but another example off the top of my head would be the
| obvious ability to resubmit the Reddit reply form by
| hitting Enter again when it responds with its "Error, try
| again" message. I don't see the argument for settling for
| the poor UX of using the disabled attribute here if you
| knew better and had the time/energy to polish it.
|
| There is a level of polish where it makes sense to
| replace the disabled attribute with a disabled (e.g.
| "submitting") class which implements all the things you
| expect, like pointer-event changes, but is even more
| powerful, like being able to use it on a wider variety of
| elements and even container elements like `form`.
|
| Finally, as the article points out, you still to write JS
| to prevent double submits even when using the disabled
| attribute. It's used as a quick hack rather than any sort
| of "submitting" semantics, so there's nothing lost
| recreating it with CSS.
| function_seven wrote:
| Would it be a good idea to first move the focus to an
| adjacent item before disabling the submit button? Like,
| have something that says "Submitting...", move the focus
| to that, disable the [Submit] button, and _also_ tag the
| form element with an attribute that marks it as already
| sent.
| danShumway wrote:
| > Finally, as the article points out, you still to write
| JS to prevent double submits even when using the disabled
| attribute. It's used as a quick hack rather than any sort
| of "submitting" semantics, so there's nothing lost
| recreating it with CSS.
|
| Eh, disabling an entire form submit is easy.
|
| Developers who manually replicate built-in browser
| features though and manually duplicate those features
| through CSS have far more opportunities to make mistakes
| and make inaccessible forms that don't account for
| keyboard focus vs click focus, different input methods,
| etc...
|
| The article is correct in the sense that it doesn't
| matter what the correct behavior is, if you want to build
| an accessible site for browsers as they exist today then
| you have to care about this. But it's still the fault of
| the browsers if developers are working around browser
| quirks because the built-in semantics that the browser
| exposes provide a bad UX. Ideally, over time, those
| quirks should be fixed within browsers, although of
| course doing so on the web is very complicated.
| SebastianKra wrote:
| Yes it does. You can't submit a form by pressing enter unless
| it contains a non-disabled <button type="submit" />
|
| It's a shame that screen-reader support sucks, but it's
| semantically correct.
| lopis wrote:
| It virtually always better to allow the button to be pressed
| and present a reason why the click action failed. "this field
| is required" or "this field is not valid" or "do this action
| first". A disabled button is just confusing even for people
| that can see.
| lloeki wrote:
| Isn't it instead that the browser changes the focus target upon
| disablement, and the accessibility tool merely follows? That's
| what I understood but I may be wrong.
| hunter2_ wrote:
| Indeed, the outcome of a focused thing becoming unfocusable
| affects typical keyboard usage (tab order), not just
| accessibility tools.
| moritzwarhier wrote:
| Basically the whole "disable submit button after submit" thing
| is a lazy hack.
|
| Double submit should be prevented by other means and "disabled"
| is semantically different from "this action is in progress".
|
| This problem can basically only occur for async form submits,
| so one can easily just alter the button and replace it with a
| dummy like ("submitting") in any way it seems fit, using JS.
|
| One can also set a "submitting" CSS class for the UI state and
| change text accordingly (or aria-label).
|
| For old-fashioned plain HTML form submits, the browser handles
| the client side of the double-submit problem already, no?
| Spivak wrote:
| > Basically the whole "disable submit button after submit"
| thing is a lazy hack.
|
| It is and there is a ready-made solution to handle it
| https://developer.mozilla.org/en-
| US/docs/Web/HTTP/Headers/ET... Your HTTP library likely
| already has support for it.
| hombre_fatal wrote:
| How would etags help you avoid multiple inflight requests
| from users double submitting a form?
| mgkimsal wrote:
| Potentially snarky answer: they don't/can't.
|
| A double click is something people do within a split
| second. Within a few ms, your application is now trying
| let's say, to store a comment and send a notification.
| Even with some sort of one-time token, process A will
| check the token, mark it 'used', but process B may be
| doing the same thing, and when process B started, the
| token was valid then too. If stored in SQL, you can try
| to do something with locking the table or row, and a
| second process might not get to update (or you can look
| in to optimistic locking/versioning/etc) but it's a
| thorny problem to deal with when people 'double click'
| and two processes start within a few ms of each other.
|
| tldr: disabling a submit button to prevent a double click
| scenario is by far the easiest and most pragmatic
| approach that stops the problem from entering "much more
| complex/difficult" territory. Ideally, the 'disabled'
| state might auto-undisable after a couple seconds, but
| the original request handler should be able to reset the
| state after processing the response.
|
| Would be so much nicer if this was a standard attribute
| to add in to forms to prevent this (2 single clicks
| registered back to back within X ms... ignore second).
|
| edit: finished the article, and the 'data-submitting'
| approach is something I also have implemented some times,
| and works decently well as an alternative. You're still
| having to prevent double submission. etags won't really
| help there.
| Nextgrid wrote:
| Redis should be able to handle tens of thousands of
| reads/writes without much issue on contemporary hardware.
|
| Every request that comes in contains a random
| "idempotency token" (can be in a hidden form field) and
| upon reception the server checks the previous value &
| sets the key if it's not there (GETSET command on Redis
| should do it?)
|
| The presence of the previous value indicates whether this
| token was handled already (if so it means duplicate
| request and return an error/etc), and setting the value
| will ensure any subsequent duplicate request will get
| rejected.
| SebRollen wrote:
| EDIT: My reply below is wrong - you _can_ deal with in-
| flight requests with E-Tags as well using the if-match
| header. I had only seen them used with if-none-match. TIL.
|
| E-Tags would probably not help here, because the client
| won't have a tag to send along with its request until after
| the original response returns. But the thing we're trying
| to prevent in the first place is multiple concurrent
| requests being processed.
|
| The Idempotency-Key header[1] is probably a better fit, but
| that relies on the server implementing the spec, including
| properly dealing with multiple in-flight requests with the
| same header. I found this blog post[2] pretty good for
| exploring some of the implementation challenges.
|
| [1]: https://www.ietf.org/archive/id/draft-ietf-httpapi-
| idempoten....
|
| [2]: http://live.julik.nl/2021/12/actually-creating-a-gem-
| for-ide...
| hombre_fatal wrote:
| > For old-fashioned plain HTML form submits, the browser
| handles the client side of the double-submit problem already,
| no?
|
| No, users can still double-click the submit button to create
| multiple requests. I don't see how you can solve it without
| JS.
| 542458 wrote:
| I believe it is solvable without JS - you can't prevent the
| request from being created, but you can prevent the second
| submission for having any effect.
|
| You could add a hidden UUID to the form server side and
| only process any submission with a given UUID once. I
| believe something similar is commonly done for anti-CSRF
| purposes.
|
| Alternatively, just rate limit users. A user making
| multiple comments within a few seconds of each other is
| probably either accidentally double-submitting or spamming.
| I think this is what HN does.
| feoren wrote:
| > You could add a hidden UUID to the form server side and
| only process any submission with a given UUID once.
|
| Not if you have a load balancer that might send the two
| requests to different servers. If all of your requests
| are idempotent (difficult to pull off, but often worth
| it), you might be able to just let both servers handle
| it. But you still have your users inadvertently hogging
| resources they don't need. And if your request is taking
| a long time, a pissed-off user could be spamming the
| submit button in frustration (I'm sure I've done this
| before).
|
| You should absolutely prevent the 2nd submit in
| JavaScript, but I'll accept that disabling the button is
| not the best approach for that.
|
| > I believe something similar is commonly done for anti-
| CSRF purposes.
|
| That's a crypto-signed token you can use to verify you've
| pre-authorized the submission, not just some UUID. (You
| could do it with UUIDs if you keep a list, but ... don't)
| 542458 wrote:
| > That's a crypto-signed token you can use to verify
| you've pre-authorized the submission, not just some UUID.
| (You could do it with UUIDs if you keep a list, but ...
| don't)
|
| I'm struggling to remember the exact details here, but I
| believe Drupal 7 does what I described and just keeps a
| big list (expiry on entries set to 6 hours) in their
| database. I remember having issues with it getting very
| large when we had issues with bad scrapers hammering our
| site. Part of the issue though is that Drupal tracks the
| entire form (in order to prevent form tampering issues)
| and not just the UUID, which makes the table much larger
| than necessary for the use case of preventing CSRF and
| double-submits.
|
| https://drupal.stackexchange.com/questions/69803/cache-
| form-...
| eviks wrote:
| it's not a lazy hack, but a useful indication to the user
| that his action has an effect. Besides double submit there is
| also an issue of a single sumbit - have I actually clicked on
| the button or somewhere nearby or never properly clicked or
| has something else, pardon the pun, not clicked?
| withinboredom wrote:
| Worse is when the request fails but the JS written doesn't
| know how to handle that and now I can't try again.
| moritzwarhier wrote:
| You imply that this is the only possibility to provide user
| indication for a form submit - why?
|
| What about some stupid text below the button: "Your data is
| being submitted..."?
|
| Seems the meat of the argument is the disabling behavior,
| which is really trivial to implement in JS.
|
| When I want to submit a form and the button changes to a
| regular grayed-out disabled button on click, on top of that
| without a page reload, I'd assume something went wrong.
|
| You need to distinguish "disabled" from "action in
| progress" any way, by using a bit of special casing and CSS
| polish for the "submitting disabled" button... in which
| case, why use the disabled attribute at all, instead of
| preventing submit in JS?
|
| It's not harder compared to toggling attribute in JS.
| iteratethis wrote:
| The problem occurs for any type of form submit, not just
| async.
|
| Replacing a submit button with a dummy is wrong, it does not
| solve the accessibility issue where focus is lost or moves.
| moritzwarhier wrote:
| Re replacing the element and losing focus:
|
| Yeah that's true, I was writing this from my lunch break in
| a hurry and this was sloppy/wrong.
|
| What I have actually opted for so far in SPAs and other JS
| form submits is to show a loading indicator inside the
| button tag, and ignoring the function call as long as a
| request is pending.
|
| Sibling comments and the article suggest equivalent
| solutions.
|
| Re sync form submit:
|
| OK, it is still possible to trigger double submits, youre
| right.
|
| I'd argue that 99% of the users notice their browser's
| native loading indicator though. Also I have personally
| experienced the "do you want to submit this POST request
| again?" popup for spamming form submit buttons without
| manually reloading the page, but I'm not sure how reliable
| that is or what the preconditions are.
|
| This being possible is directly caused by browser trying to
| appear faster by not replacing the current page until they
| can start rendering the next one. Like with bfcache,
| vendors do their best to make full page reloads feel like
| an SPA if the site performance allows.
|
| Which brings us to the only sane answer: if you need to
| reliably prevent double submits against malicious or
| clueless users, you need to act on the server.
|
| You can't de-duplicate HTTP requests with client code.
| gpvos wrote:
| It's not the accessibility tools that do that, it's the default
| browser behaviour.
| feoren wrote:
| Screen readers are browsers. They could just ... not do that.
| jay_kyburz wrote:
| Browsers can't change their behavior.
| danShumway wrote:
| It is extremely complicated for browsers to change their
| existing behavior, and we should be cautious about them
| doing so.
|
| We could however introduce another attribute that has the
| correct behavior, deprecate `disabled`, and throw
| warnings during ARIA validation/linting for pages that
| continue to use it. Call it `blocked` or `unsusable` or
| have if you want to be fancy, make a `status` or
| something with attribute with multiple values that it
| accepts. Whatever seems most reasonable.
|
| But my point is we're not trapped in the world of
| developers needing to poorly replicate browser
| functionality for every single form they make; we could
| still have an attribute that makes it easy for developers
| to by-default program forms with the correct behavior.
|
| In Javascript, adding `let` and `const` didn't require us
| to get rid of `var`. We didn't have to change `var`
| behavior to make `let` throw errors on redeclarations.
| There are options here for providing tools within
| browsers that work correctly.
| Lornedon wrote:
| Why not?
| danShumway wrote:
| Agreed that this is a user-agent problem.
|
| People here are arguing about whether a form being submitted
| counts as actually disabled or not, but that's missing the
| broader point: even clearly disabled buttons should be
| selectable, because they might focus tooltips showing why
| they're disabled, or because users using a keyboard cycling
| through the interface shouldn't have their muscle memory
| interrupted by having the number of tabs required to reach a
| button change unexpectedly depending on the context, or to
| prevent errors during automation and scripting, and on and on.
|
| Even if you believe that an "in-progress" indicator should be
| treated differently from "disabled", it's still bad UX that
| disabled buttons aren't focusable and it's still bad semantics
| to avoid a browser attribute just to fix that problem.
|
| Now, you might have to avoid it anyway, because good luck
| getting browsers and screenreaders to all change their
| behavior; that would be fairly difficult to do. But... it is
| their fault regardless of what the rest of us on the web have
| to do to cover for their mistake and to make our applications
| accessible to people who are using these tools with their
| broken behaviors.
|
| ----
|
| Mozilla writes about this exact scenario
| (https://developer.mozilla.org/en-
| US/docs/Web/Accessibility/A...):
|
| > When needing to disable native HTML form controls, developers
| will need to specify the disabled attribute, as it provides all
| of the generally expected features of disabling a control by
| default. However, there can be instances where elements need to
| be exposed as disabled, but are still available for users to
| find when navigating via the Tab key. Doing so can improve
| their discoverability as they will not be removed from the
| focus order of the web page, as aria-disabled does not change
| the focusability of such elements, nor will the elements be
| dimmed by default browser styling, making them easier to read.
| Some examples of where this may be useful include:
|
| > The header button element associated with non-collapsible
| accordion panel,
|
| > A button which is important to keep in the page's focus
| order, but its action is presently unavailable - such as
| submitting a form,
|
| I would argue that if you are calling an aria-attribute and
| ignoring the real attribute specifically because the actual
| attribute is stricter than the aria-attribute and has
| unintended side-effects, then maybe the actual attribute is not
| accurately representing its semantic value or its expected
| semantic behavior.
|
| If screenreaders and browsers aren't using aria-disabled as an
| indicator to skip focus, then the clear indication from that is
| that disabled elements should not necessarily skip focus. If
| disabled elements were meant to universally be unfocusable,
| then aria-disabled would block focus.
| bradley13 wrote:
| For me, the more common use case is to prevent users from making
| unnecessary mistakes. Only enable elements (like buttons) when
| all prerequisites are fulfilled. Simple example: if you require a
| user-name and password to login, then only enable the login
| button when that information is present.
|
| This improves the experience for the vast majority of users; it
| prevents them from overlooking something, and having to go back
| later and fix it. If this makes life difficult for a very few?
| That's probably a worthwhile tradeoff.
|
| Anyway, if you actually care about the people using screen
| readers, you should be offering them a separate experience
| anyway. One that doesn't involve JavaScript. Bet: the author of
| the article hasn't ever tried to use his fancy web-forms in Lynx.
| infotainment wrote:
| _> For me, the more common use case is to prevent users from
| making unnecessary mistakes. Only enable elements (like
| buttons) when all prerequisites are fulfilled._
|
| I'd argue this is actually worse UX, because in some cases
| (like a login form), it's obvious, but in other cases, it might
| not be immediately clear to a user _why_ the button is
| disabled. IMO it's better UX to always enable the button, but
| provide clear messaging explaining 1) why the user couldn't do
| the thing and 2) what needs to be fixed in order to do the
| thing
| xigoi wrote:
| Disable the button and give it a tooltip or some text above
| it saying why it's disabled. I've seen this pattern and liked
| it.
| ghusbands wrote:
| > Anyway, if you actually care about the people using screen
| readers, you should be offering them a separate experience
| anyway.
|
| That's a very odd claim. Pretty much nobody does that, and
| segregating people is not generally a good idea. You need to
| bake accessibility into everything you do. Screen readers and
| javascript work well enough together.
| FabHK wrote:
| Stupid question - couldn't (shouldn't) form submission be sort of
| idempotent? That is, if the same thing gets submitted again, drop
| it on the server side, rather than doing all sorts of fancy stuff
| on the client?
| Toutouxc wrote:
| Should I not be able to send money to the same person twice in
| a row? Unless you add a single-use token to the form, your
| server doesn't know whether it was a misclick or a legitimate
| action. The client more or less knows.
| Waterluvian wrote:
| Yes it should be. But belt and suspenders. It's crummy UX for
| it to happen in the first place. And an easy way to
| accidentally spam calls if someone's cat sits on the enter key.
| SoftTalker wrote:
| Thank you, I was scanning the replies looking for this. If
| preventing duplicate submissions is a concern, you _must_
| prevent it on the server side. You should also _try_ to prevent
| it on the client for a better UX.
| recursive wrote:
| Only sometimes. Whether it is in your case depends on the
| business rules of your application.
| vasdae wrote:
| Allow me to hijack this thread to say something that is related:
|
| Do not disable buttons or checkboxes or whatever unless it's very
| obvious how to enable them! I have seen software applications
| that showed disabled form controls or menu entries depending on
| settings that were in other screens or even compile-time settings
| - that is unacceptable!
| jspash wrote:
| Does anyone remember the "reset" button? I assume it still
| exists, but to be honest I have never found the need for it.
| But I do remember it being on many forms that you would
| encounter pre-2000.
| lakomen wrote:
| Reset buttons are for edit forms.
| city41 wrote:
| I was going to post this. Many times I've sat there trying to
| guess what the developer was thinking "maybe this will enable
| it? no... how about this?..." I can't even imagine what non-
| techy people do in these situations.
| Robdel12 wrote:
| No, I 100% disagree. You just need to manage the focus yourself
| when you do disable the button.
| crazygringo wrote:
| Yup. That seems like the easiest, most straightforward
| workaround for the bad browser behavior than anything the
| article suggests.
| flappyeagle wrote:
| It's weird to see so many UX articles on the front page of HN
| that are just wrong.
|
| Disabling buttons that are functionally no-ops is the
| semantically correct thing to do.
| nosefurhairdo wrote:
| It's not a UX article, it's an accessibility article. Disabling
| the button can be confusing for users relying on screen
| readers, and if it's the only way the "submission pending"
| state is communicated to the user then it's plainly non-
| conforming with WCAG.
| agloe_dreams wrote:
| Seeing as most forms work this way...shouldn't the screen
| reader understand this? You are in a form, the button is the
| submit button. It went to disabled after form submit. Save
| that ref, fake the tab index so tabbing takes you to the next
| item, if the button becomes enabled again, highlight it. This
| feels like an easy win.
| rickstanley wrote:
| If the problem is shifting focus to the document, is it not
| better to: before disabling the button, with the attribute,
| create an element that contains information about the action in
| progress and focus on this element via `element.focus();`, and
| then add the "disabled" attribute?
| g-b-r wrote:
| I agree, you're avoiding disabling the button to cater for
| screen readers, at that point go one step further and move to
| an (invisible?) "Form sent" element ..
| viggity wrote:
| furthermore, on any app, don't disable a button when an action
| isn't available. you can still mark it as disabled via color, but
| if someone clicks on it, you should show them a message _WHY_
| that action isn 't available. "Sorry, you haven't filled in your
| phone number", etc.
| thesuitonym wrote:
| Similarly, don't disable submit buttons so you can wait for me to
| type something. Especially for login forms, many password
| managers don't type usernames and passwords, but some login forms
| wait for you to type something before they'll allow you to
| submit.
| pimlottc wrote:
| Furthermore, these forms often don't notice when your password
| manager has filled in the fields for you, so you have to go
| back and make a meaningless edit (e.g. add and then remove a
| character) in order to enable to the submit button.
| Semaphor wrote:
| Like ebay
| sefrost wrote:
| Every time I have to do something like that I wonder how
| people like my parents manage to use computers.
| extraduder_ire wrote:
| I assume they're in the group of users these sorts of
| interfaces are designed for. Hunt and peck typing, will
| dutifully following the flow chart of interaction across
| multiple pages and assume they are wrong when they are made
| to start again when they click a _wrong button_ , and not
| being annoyed when the "you are being logged out in 30
| seconds. Cancel?" message pops up.
|
| Or, they are used to finding someone who's "good with
| computers" to assist. That alone probably hides so much
| garbage UX from being known to developers.
| beambot wrote:
| My parents used punch cards and DIP switches to control
| their first computers. They think modern computers are
| basically magic by comparison...
| dpkirchner wrote:
| I've watched my parents use phones. The main things that
| throw them off are borderless buttons, long-press actions,
| and swiping/dragging table rows. If we could all agree to
| stop implementing these that's be great.
| Baguette5242 wrote:
| I think it is the case for PayPal.
| Semaphor wrote:
| Nope, never had that issue with them, only ebay
| graftak wrote:
| That's an implementation error and not inherent to a disabled
| button.
| zamadatix wrote:
| I think it's better to let the user click the button and then
| have it tell them why the submission didn't work instead of
| just disabling the ability to submit. Put all the onus on
| figuring out what's specifically missing/invalid on the
| validation code, not the user.
| SilasX wrote:
| Sufficiently advanced "inability to implement it right" is
| indistinguishable from bad design.
| abdullahkhalids wrote:
| Yes. But secure password managers should be registering a
| virtual keyboard and typing into the fields with it, instead of
| using the clipboard which can very easily lead to exposing your
| password.
| danShumway wrote:
| Neither is necessary. Secure password managers should
| directly set the value attribute on the text fields (the
| password manager has direct access to the page's DOM), and
| then they should use a DispatchEvent to notify the page that
| the field has changed.
|
| Websites, applications, and login forms should handle those
| generic events rather than listening specifically to keydown
| events.
|
| There's really no need to simulate typing or to touch the
| clipboard if you're using a browser extension; and while I
| haven't checked, I'd honestly be kind of surprised if any of
| the major password manager extensions are doing so.
|
| Of course, if for some reason the _user_ decides to copy and
| paste their password, then a change event should also be
| handled, not just a keydown event.
| abdullahkhalids wrote:
| Keepassxc has an auto-type command that does type in the
| username/password into your "last viewed window". This is
| for cases when you don't have a browser extension or want
| to put in a password into the terminal, or some electron
| app.
| danShumway wrote:
| That's a good point, although I would argue that's not
| what most users are going to run into, and I would note
| that properly handling a `DispatchEvent` and listening
| for changes will also properly handle KeepassXC's
| situation.
|
| My main point is that it's not a security issue that
| browser extensions don't simulate a keyboard. I'll grant
| that some applications need to simulate a keyboard
| because they don't have any access to the page or
| application, and yeah, they have a good reason for what
| they're doing, but it's a rare situation.
|
| And it is technically generally not ideal for a password
| manager to be doing that for websites; it does tend to
| make the user more vulnerable to phishing attacks. But
| it's fine, I see the use-case, I don't think KeepassXC is
| wrong to include that feature or that users are wrong to
| use it.
|
| It just shouldn't be impacting how login forms are
| designed or what events they listen to. The users who are
| complaining above about login forms not listening to the
| correct events are most likely not being insecure and are
| most likely not using a clipboard when they fill in their
| passwords, and if the password managers they're using
| within their browser swapped from DOM manipulation over
| to simulating a keyboard, that would make those password
| managers _less_ secure. Simulating a keyboard is
| something a secure password manager should mostly avoid
| unless for some reason it doesn 't have access to the
| DOM.
| hk1337 wrote:
| It's an excellent point but perhaps the solution still doesn't
| solve the problems. Like, it fixes the problem for accessibility
| but then creates or leaves problems for user experience.
| nosefurhairdo wrote:
| For sighted users, show indeterminate progress element while
| form is submitting. For sight-impaired users, use aria live
| region for accessible status messages (as noted in article).
|
| For more info on status messages:
| https://www.w3.org/WAI/WCAG22/Understanding/status-messages....
|
| Were there any other UX concerns you had with this pattern?
| hk1337 wrote:
| I don't know of any. I liked that OP pointed it out also the
| glaring hole that sighted users (or really any user) could
| still move up to a form element and hit enter to resubmit,
| thus bypassing that the submit button is disabled.
| seanwilson wrote:
| Will browsers ever catch up here so that the right way to do it
| is the default way? Or at least one of the easiest ways?
|
| It's clearly difficult if there's so many options and this
| generates so much discussion. It shouldn't be this hard to get a
| basic UI pattern right (submitting a form once with progress
| updates).
|
| If it's even a little hard, it's inevitable 90% of sites will get
| it wrong. There's just too much stuff for devs to realistically
| stay on top of to blame them.
|
| Related: the `inert` attribute has good support now for
| preventing users from editing/interacting with forms that are
| currently being submitted so you don't have to mess with
| overriding input events (https://developer.mozilla.org/en-
| US/docs/Web/HTML/Global_att...). You'll have to add it manually
| when the form is submitted though, remove it if the submission
| fails, and use something like aria-live to give progress updates
| (https://developer.mozilla.org/en-
| US/docs/Web/Accessibility/A...). You'll also need to manually
| test all your custom forms like this work on actual screen
| readers (they have inconsistent behaviour, similar to cross-
| browser bugs), as well as edge cases like resubmitting after a
| failure, when the network request fails with error feedback, and
| when the network request fails from a time out. Not easy.
| ASalazarMX wrote:
| > Will browsers ever catch up here so that the right way to do
| it is the default way? Or at least one of the easiest ways?
|
| My pet peevee is how browsers; and later smartphones;
| normalized that interactive elements can reflow/reorganize all
| the time. Now, things like joining a specific WiFi, or
| mirropring to a specific TV, can become a game of chance if you
| don't let the UI settle a bit. We had this problem more or less
| solved before.
| jbverschoor wrote:
| HTML is a document, as in hyperlinked rich text, format /
| "language".
|
| People abused HTTP/HTML as an application delivery platform.
|
| Now we finally have some better positioning / sizing for
| applications.
|
| It's the same as QWERTY... Not the best way, but got popular,
| and now we're stuck with it, trying to patch everything for
| the last 25 years.
| danShumway wrote:
| `inert` has the exact same problem, and is arguably even worse
| since it removes content from the accessibility tree entirely:
|
| > Specifically, inert does the following:
|
| > Prevents the click event from being fired when the user
| clicks on the element.
|
| > Prevents the focus event from being raised by preventing the
| element from gaining focus.
|
| > Hides the element and its content from assistive technologies
| by excluding them from the accessibility tree.
|
| An `inert` attribute is basically invisible to screenreaders,
| and if you have mitigations in place for that, you might as
| well just use `disabled`. So I advise against using `inert`,
| I'm not going to say it's completely useless, but I don't think
| there are ton of instances where it makes sense and it's easy
| to get wrong.
|
| ----
|
| The real solution here is pretty obvious: `disabled` shouldn't
| block focus. It's not what users want in most situations, and
| there are easy ways to block focus from an element if it needs
| focus blocked. The problem is that it would probably be
| extremely complicated to change browser specs to implement the
| better behavior. Introducing another attribute that has the
| correct behavior would likely be easier, but it's still not
| going to be trivial to get that through standardization
| process.
|
| But it's no great difficulty to block a button from being
| focusable in HTML, that's easy. We're only in this position
| because `disabled` blocks focus by default and offers no way to
| get focus back. Even manually setting a `tabindex` does
| nothing. And that's just bad design, clearly there are
| situations where disabled buttons should be able to receive
| focus. If not the default behavior, it should at least be
| possible to allow focus as an override.
| seanwilson wrote:
| To clarify, I only meant `inert` is another (fairly new) tool
| that can be useful, not a complete solution. For example, you
| can use it to prevent the user editing the fields of the form
| while the current field values are being submitted. You don't
| need to use it on the submit button.
|
| As far as I remember, for similar behaviour you either have
| to add `disabled` to all the fields (then remember to revert
| only the `disabled` attributes you added if the form submit
| fails...) or wrap all the fields in a `disabled` `fieldset`
| tag (now you have to research if there's any quirks when you
| nest `fieldset`s).
|
| Saying that, why keep the focus on the submit button? Are
| there no better alternatives?
| no_wizard wrote:
| `inert` is intended primarily to help with overlay focusing
| (think dialogs, drawers etc) or offscreen elements that
| should be hidden. While yes, it can be added to any element
| (and therefore make it and its subtree inert) which could
| enable some kind of novel use case, I think the standard case
| are primarily dialogs / overlays and offscreen elements that
| need to be hidden
| danShumway wrote:
| I'm open to a use-case here that isn't obvious to me, I'm
| not saying you're wrong. But I don't understand why I
| wouldn't use `display: none` for an offscreen element or a
| hidden dialog/overlay? Screenreaders do skip over `display:
| none`, right?
|
| If I'm moving an element offscreen but not full-on hiding
| it, in my experience 99% of the time it's because I want it
| to be visually hidden but still show up for a screenreader.
| `inert` gives me the opposite behavior by default. I'm
| trying to think when I've ever wanted an element to be
| visually hidden from both sighted users and a screenreader,
| but also couldn't do that via normal CSS.
|
| Again, open to learning more, but this still seems to me
| like an attribute that should be generally avoided. I can
| think of some use-cases; maybe I have something like a
| chart where there are a lot of focusable elements but where
| the experience is awful for keyboard or screenreaders and I
| want to basically declare bankruptcy and say, "no, I don't
| want it to work with those controls at all, it might as
| well not exist for those people."
|
| But those situations seem very rare to me.
| progmetaldev wrote:
| Seems like the best option may be to add the disabled
| attribute to the button, as well as provide an aria-live
| section with a message stating that the form is in the
| process of submittal. Of course then you'll have to handle
| removing the disabled attribute, as well as providing a
| message either stating the submittal was successful, or that
| an error occurred.
|
| I get that HTML wasn't supposed to be an application
| platform, but it's what we've got for now, and all we can do
| is work with what we have and keep pushing forwards for
| better standards or a better application delivery method
| (which is tough, since deployment as HTML is just so easy as
| compared to updating a rich client application).
| danbruc wrote:
| Disagree. If it is currently invalid to click the button, disable
| it, that is what it is for. Disabled buttons should be focusable,
| that resolves the issue with disabling the focused button in
| response to a click. How you achieve this in any given
| environment is a different issue, if the out of the box disabled
| functionality does not work properly, you will have to find
| workarounds.
| some1else wrote:
| Do disable buttons. You can keep an isSubmitting value around for
| tracking form state. This does not forbid using the disabled
| property.
| extraduder_ire wrote:
| Is there a blogpost out there like "X things programmers don't
| understand about HTML forms"? In the same vain as the ones for
| names, character encoding, etc...
|
| I'm sure there'd be a few humdingers in there.
| jolt42 wrote:
| Can we also talk about aggressively deleting form fields? Forgot
| password? Let me forget the email you just typed in when trying
| to login. Guessed the wrong password? I'll erase that field for
| you.
| danShumway wrote:
| The article doesn't mention this, but if you are going to build
| your own disabled state, at the very least include an aria-
| disabled attribute on your button. See Mozilla docs on the
| subject, which mention this exact same scenario:
| https://developer.mozilla.org/en-US/docs/Web/Accessibility/A...
|
| Using pure-CSS and data-attributes without additional indicators
| doesn't help low-vision users; the only thing they'll be able to
| tell is that click doesn't work on some of your buttons, they
| won't be able to see the CSS or non-semantic attributes that say
| the button is disabled. If you're getting rid of browser
| semantics, you need to include the relevant aria semantics to
| compensate.
| al_be_back wrote:
| For me the disabled button on a partially-valid Form say, is a
| metaphor-overload.
|
| Whilst a physical button may be disabled to indicate being
| functional-but-not-ready, in software one doesn't have to
| show/display them until they are ready for action. If the Form is
| partially valid, show a Message instead of a Button, then when it
| is valid, pop the Action button clearly on display.
|
| Personally I like to leave the button enabled, check the Action
| can be performed (form valid etc), and notify the User of errors,
| progress etc. It's better to communicate with the User exactly,
| than imply messages - it's a form, not a puzzle or an opportunity
| to play physical jokes on the User (gotcha, can't press this!).
| beders wrote:
| The crux with a disabled button is discoverability:
|
| What is the user supposed to do to enable it?
| Night_Thastus wrote:
| Title is a bit broad for what the post actually talks about.
| There's plenty of good reasons to disable buttons, just not in
| this _particular_ case.
| notfed wrote:
| Also this sounds like an implementation detail with browsers.
| amelius wrote:
| With this approach, an exception thrown while submitting may
| break the submit button. This is worse than what we started with!
| andrewmcwatters wrote:
| Amazon, of all places, had this defect in their login flow for
| the longest time which was only recently fixed.
|
| It was so bad that when you were waiting for an SMS code, after
| you received it and autofilled it in iOS, their website and app
| would automatically submit the input, and so hitting submit on
| your keyboard would cause the backend to reprocess the code a
| second time, invalidating your login.
|
| It was obvious someone slapped the implementation together and it
| was so embarrassing.
|
| Yet, I'm still nonplussed that we keep screwing up forms.
| yuters wrote:
| It would be weird to avoid the only reason I have to use this
| button attribute. I thought the disabled state only existed to
| fix this problem. I can't find any other use that wouldn't end up
| being a complete UX mistake.
| lakomen wrote:
| BS I say.
|
| In a JS framework frontend I will disable the button on submit,
| so the form can't be submitted twice, because accidental double
| clicks happen. I will enable it after at most 6 seconds or if the
| response is an error response.
| iteratethis wrote:
| So you have focus on a button, which then becomes disabled, this
| throws focus back at the document level.
|
| That sounds like a browser bug to me. It's absurd behavior. The
| focus change is as unhelpful as is humanly possible. It's not
| what the developer intended, it's not what anyone possibly would
| intend, so why is it the default behavior?
|
| Same for "implementing an ARIA live region"
|
| How about no? Developers are supposed to piece together hundreds
| of obscure articles to figure out the right way to build an
| accessible form. Most won't, but if they do, they're still not
| confident about its implementation.
|
| How about after 30 years the web platform provides some elements
| that actually do something, with sane defaults instead of
| millions of developers being puzzled what to do for even the most
| basic of tasks?
___________________________________________________________________
(page generated 2023-11-08 23:01 UTC)