[HN Gopher] Just use a button
       ___________________________________________________________________
        
       Just use a button
        
       Author : moebrowne
       Score  : 212 points
       Date   : 2025-10-31 16:59 UTC (6 hours ago)
        
 (HTM) web link (gomakethings.com)
 (TXT) w3m dump (gomakethings.com)
        
       | giancarlostoro wrote:
       | Weird, I always use buttons when I can, unless what I need is not
       | actually a button, but something that performs and on-click sort
       | of like a button, like a hyperlink that navigates you through the
       | web app.
        
         | ervine wrote:
         | I guess if it doesn't update the url, it's a button.
         | 
         | If it changes the url, it should be a link. At least that's how
         | I've always done it.
        
           | cassepipe wrote:
           | Is is not okay to wrap a link inside a button ? I guess not
           | 
           | Which elements are allowed to wrap which is unclear to me
        
             | stevula wrote:
             | What is the use case? It's hard for me to think of a reason
             | you'd want to wrap a link in a button. If you want to
             | navigate, use an anchor. If you want to trigger JS logic,
             | use a button with onclick handler. If you want to navigate
             | while doing some side effect like an API call, use an
             | anchor with onclick handler (and don't prevent default).
        
             | cferdinandi wrote:
             | Literally absolutely never ever do this.
        
             | Shog9 wrote:
             | FWIW, you can generally figure out what's allowed fairly
             | quickly by checking the content model for a given
             | element[1]. Some browsers might be more or less
             | restrictive, but for normal usage this'll be more than
             | enough to avoid unexpected behavior.
             | 
             | [1]: https://html.spec.whatwg.org/#the-button-
             | element:concept-ele...
        
         | Zak wrote:
         | > _like a hyperlink that navigates you through the web app_
         | 
         | You mean an <a> tag?
        
       | bugsliker wrote:
       | - tabindex=0 doesn't affect ordering, does it?
       | 
       | - why do you need to listen for events at the document level?
       | 
       | not that i disagree with the article, but some arguments didn't
       | seem right.
        
         | thyristan wrote:
         | > - tabindex=0 doesn't affect ordering, does it?
         | 
         | Of course it does. tabindex=0 doesn't sort naturally into the
         | automatic tabindex order, it sorts AFTER everything. So you are
         | jumping through all the other tabindex elements, then you are
         | jumping back to all tabindex=0.
        
           | brandonhorst wrote:
           | This is incorrect. https://developer.mozilla.org/en-
           | US/docs/Web/HTML/Reference/...
        
             | thyristan wrote:
             | That is correct. From your link: "tabindex="0" means that
             | the element should be focusable in sequential keyboard
             | navigation, after any positive tabindex values. The focus
             | navigation order of these elements is defined by their
             | order in the document source. "
        
             | Ma8ee wrote:
             | Your link actually supports the comment you replied to.
        
           | pverheggen wrote:
           | That's the same behavior as a <button> without tabindex, like
           | the author is proposing.
           | 
           | It's generally advised not to set tabindex to anything but 0
           | or -1 and let the document order dictate tab order.
        
             | thyristan wrote:
             | > That's the same behavior as a <button> without tabindex,
             | like the author is proposing.
             | 
             | Yes, but often you have elements with taborder > 0.
             | 
             | > It's generally advised not to set tabindex to anything
             | but 0 or -1 and let the document order dictate tab order.
             | 
             | Only if document order is sane. Usually with modern
             | websites it isn't, document order is a broken notion if you
             | can position elements at will and e.g. put navigation at
             | the bottom of a document but move it to the top by CSS.
             | Which is actually a recommendation that some people make
             | for acessibility...
             | 
             | What you usually want to do is assign a sensible taborder >
             | 0 to the one form element that the user is probably
             | currently using. Otherwise, he will pointlessly tab through
             | search, menus, cookie bars and a ton of other pointless
             | stuff first.
        
               | pverheggen wrote:
               | > Yes, but often you have elements with taborder > 0.
               | 
               | You can just as easily apply the same tabindex to a div
               | though.
               | 
               | > Only if document order is sane. Usually with modern
               | websites it isn't...
               | 
               | Well that's the real problem, all your non-interactive
               | content (like text) is going to be out of order too.
               | You're just adding to the confusion if buttons and other
               | inputs are in a different order from the content they're
               | associated with.
               | 
               | > Otherwise, he will pointlessly tab through search,
               | menus, cookie bars and a ton of other pointless stuff
               | first.
               | 
               | The proper way of dealing with this is a "Skip to Main
               | Content" element:
               | 
               | https://webaim.org/techniques/skipnav/
        
               | thyristan wrote:
               | > The proper way of dealing with this is a "Skip to Main
               | Content" element: > >
               | https://webaim.org/techniques/skipnav/
               | 
               | No, it isn't the proper way. That only works if you can
               | see the skip link and know to press enter. Otherwise you
               | will tab straight into the navigation. So possibly useful
               | for screen readers, but completely useless for most
               | keyboard users. Yet another stupid webdev workaround for
               | a selfimposed problem.
               | 
               | What you should do is autofocus the first form element
               | (if there is a form), give it tabindex=1 and number the
               | other form elements in a sensible ascending tabindex
               | order. Otherwise, proper semantic markup is sufficient,
               | even for screen readers.
        
               | pverheggen wrote:
               | Usually you would have it appear when it's focused, like
               | this for example:
               | 
               | https://www.nytimes.com/
               | 
               | And yes, this is an acceptable solution according to the
               | W3C:
               | 
               | https://www.w3.org/WAI/WCAG21/Techniques/general/G1
               | 
               | Your solution of focusing the first form element is
               | pretty idiosyncratic. It's better to follow WAI patterns,
               | because patterns have predictable behavior. Otherwise,
               | keyboard users will have to learn how to interact with
               | your website from scratch, instead of just following the
               | same pattern they're used to from other sites.
        
               | thyristan wrote:
               | Any website implementing a form for data entry is
               | expected by any sane user to autofocus the first form
               | element.
        
               | pverheggen wrote:
               | Sorry, missed the part about "form for data entry". If
               | that's the main point of the given page, then sure, focus
               | on the first input is fine.
               | 
               | Your original comment was to use tabindex to skip search,
               | menu bars, breadcrumbs, etc. and for that there are
               | better options.
        
               | MrJohz wrote:
               | I would be very surprised if a website autofocused almost
               | anything on page load, except for very specific
               | applications where that makes sense. I just tried
               | clicking through some forms on gov.uk, which is a website
               | that has spent a _lot_ of time testing and improving the
               | UX of their forms, and none of them had autofocused
               | elements, not even on later pages after having already
               | filled in elements.
               | 
               | I can imagine screen readers would deal particularly
               | poorly with this behaviour, because the user would be
               | dropped in a field without any of the context of the
               | page, just the field label to work with. However, I've
               | not been able to test that out properly.
               | 
               | I don't think the behaviour you're describing is anywhere
               | near as common as you think it is, and I suspect it would
               | make a page less accessible for a number of kinds of
               | users.
        
               | MrJohz wrote:
               | You almost certainly don't want to assign tab order
               | manually. Theoretically, if your html is out-of-order for
               | some reason, then you can fix it with taborder, but there
               | are so many issues with out-of-order html that it's much
               | better to avoid that in the first place. Even on modern
               | websites, it is almost always easier to lay your html out
               | in the correct order rather than messing around with the
               | order via CSS. (I read an article recently by a web
               | accessibility expert that discussed the issue of
               | flexbox's order parameter and how the working group
               | designing it failed to accessibility into account when
               | adding it to the spec:
               | https://alice.boxhall.au/articles/a-threat-model-for-
               | accessi...)
               | 
               | You mention using it to skip a nav header or something
               | similar, but (1) you have autofocus for that if you need
               | it (and you don't usually need it), and (2) the pattern
               | where you provide a "jump to content" button is typically
               | a better approach, because it allows the user to decide
               | what they want to do when they arrive on your site,
               | rather than you deciding for them. If the "jump to
               | content" button behind visible when focused and is the
               | first element on the screen, then it works perfectly for
               | screen readers and other keyboard users, and you don't
               | need to handle taborder manually.
               | 
               | There are always exceptions to these sorts of rules, and
               | some times tabindex might be necessary, but I've not yet
               | come across a case where the problem couldn't be solved
               | better in a different way.
        
           | bugsliker wrote:
           | I'm saying tabindex=0 is naturally sorted wrt other naturally
           | focusable elements. That matches the behavior of the <button>
           | you're trying to emulate. I don't know what tabindex>0 has to
           | do with this.
           | 
           | See this fiddle https://jsfiddle.net/483uqjnp/
           | 
           | (again, I do not condone building your own <button>, just
           | pointing this out)
        
           | minitech wrote:
           | tabindex=0 _does_ sort naturally into the automatic tabindex
           | order.
           | 
           | > So you are jumping through all the other tabindex elements
           | 
           | This part is correct (for elements with an explicit positive
           | tabindex), which is why specifying an explicit positive
           | tabindex is considered a code smell. If you don't specify a
           | tabindex on an element that's focusable by default, it
           | behaves like tabindex=0.
           | 
           | Try it:                 data:text/html,<button>foo</button><i
           | tabindex=0>bar</i><button>baz</button>
        
         | cferdinandi wrote:
         | Hey, it's me, the original author!
         | 
         | The issue isn't with tabindex=0 specifically, but fucking with
         | tabindex in general. People go down that path, and start
         | putting that shit on everything, like it's Frank's Red Hot.
         | 
         | And in my experience, the same folks who use div's instead of
         | button's are the ones who don't know better and start throwing
         | tabindex around.
         | 
         | "why do you need to listen for events at the document level?"
         | 
         | Not events generally, keydown events specifically, which do not
         | fire on child elements of the document.
        
           | pverheggen wrote:
           | Not sure about that, MDN's example shows keydown being
           | attached to an element.
           | 
           | https://developer.mozilla.org/en-
           | US/docs/Web/API/Element/key...
        
           | susam wrote:
           | > Not events generally, keydown events specifically, which do
           | not fire on child elements of the document.
           | 
           | Are you sure? I have a 17 year old HTML tool written using
           | plain, vanilla JavaScript where keydown on a child element
           | seems to have been working as expected.
           | 
           | https://susam.net/quickqwerty.html
           | 
           | https://github.com/susam/quickqwerty/blob/1.2.0/quickqwerty..
           | ..
           | 
           | Nice article, by the way!
        
             | skrebbel wrote:
             | I think that's because it's an input and not a div, so it
             | can get focus. Im not sure whether tabindex is enough to
             | make a div do that too, article suggests no
        
           | kyle-rb wrote:
           | Hi, good premise overall, but there are just a lot of little
           | things that are off.
           | 
           | - It only counts as "fucking with tabindex" if you give it a
           | value that's not 0 or -1. You should give that specific
           | disclaimer, because there are uses for tabindex=0 other than
           | reimplementing <button>.
           | 
           | - Divs can definitely receive keydown events. If I go to an
           | arbitrary web page, pick a div and run `div.tabIndex = 0;` +
           | `div.addEventListener('keydown', console.log);`, I see those
           | events coming through when I have the div keyboard-focused.
           | 
           | - "Run your code, somehow..." I think just calling
           | `notRealBtn.click()` is the best option.
           | 
           | - Stupid but semi-interesting nitpick: 'keydown' is good for
           | enter, but you should be listening to 'keyup' for the space
           | bar. That's how real <button>s work anyway.
           | 
           | - The 'keyup' listener should call event.preventDefault() to
           | prevent the default behavior of the space bar scrolling the
           | page.
        
       | tarwich wrote:
       | 100%
       | 
       | Use elements as close to their original intention as possible
        
       | flemhans wrote:
       | Why is the <div> option proposed by anyone in the first place?
        
         | wrs wrote:
         | Based on what I see in the world, I suspect one reason is that
         | a <div> makes it easier to apply some bizarro appearance to the
         | button, so it not only doesn't act like a button, it doesn't
         | even _look_ like a button.
        
           | mcny wrote:
           | This comes from either business or the UX people who want
           | stuff to look pixel perfect to their stupid wireframe.
           | 
           | Why does a website that sells to a pretty much captive
           | audience who cares more about functionality than looks obsess
           | so much about every single button looking pixel perfect to
           | some arbitrary wireframe, I will never know.
        
         | Joker_vD wrote:
         | Well, have you been on, I don't know, TV Tropes? They have
         | those long lists, that are separated into "folders" on a single
         | page. You can click on those "folders" to expand/collapse them,
         | and it's implemented as a <div> with "onclick" property and
         | <ul> inside it (well, used to IIRC; nowadays this <ul> is a
         | child of a sibling <div>).
        
           | 1-more wrote:
           | what's annoying about that example is that all of those
           | <div>s could be buttons with no other changes. The only
           | content inside the button <div> is the title and folder icon,
           | not the list of examples associated with that title. That's
           | just fine for a button!
           | 
           | The other thing I'd do is add `aria-controls=folder0` to the
           | button that toggles visibility of the list with `id=folder0`
        
             | no_wizard wrote:
             | I'll do you one better and argue they could `<details>`
             | elements. This is a perfect use case for that.
        
               | 1-more wrote:
               | I use them EXTENSIVELY but some don't like them for being
               | annoying to control en-masse with the "toggle all
               | folders" button at the top. But yeah I 100% agree with
               | you. I've snuck them into a webapp where I just needed
               | that much local state rather than have the whole page's
               | state care about the collapse/open state of that one
               | thing.
        
         | cferdinandi wrote:
         | The most common reason I've seen is whining about having to
         | override default button styles.
        
           | no_wizard wrote:
           | I too have encountered this reasoning.
           | 
           | Then I write some basic CSS and show them they have nothing
           | to fear.
           | 
           | Yet, I still remain irritated beyond belief that its such a
           | common thing. In 2025. Hell, in 2017!
           | 
           | I don't know what to do about it, other than constantly
           | remind people about things, but it gets tiring.
           | 
           | Though, its a great interview question. Its a quick way to
           | understand if someone knows the fundamentals or not.
           | 
           | Kinda like how people got ".bind" wrong on functions for
           | years.
        
       | 827a wrote:
       | > This element does not announce itself as an interactive element
       | to screen reader users.
       | 
       | Is this actually true nowadays? Given that advice like this is
       | often parrotted by people who don't actually use screen-reading
       | software, I sometimes wonder if this is a situation where we've
       | just been saying this and repeating this advice; meanwhile,
       | screen readers have _obviously_ become sophisticated enough to
       | recognize that a div with an onclick handler on it is probably,
       | you know, clickable and interactive.
        
         | mnhnthrow34 wrote:
         | Have you tested this? Often click handlers are on some non-
         | interactive ancestor element, it is not a good heuristic for
         | something being interactive itself or what name it should have.
         | Sometimes the listener is on the body element and we just parse
         | out the triggering element and do something.
        
           | 827a wrote:
           | No I haven't tested it, that's what I'm asking.
           | 
           | This piece of advice, to me, just feels like a piece of
           | advice constantly repeated by a bunch of people, none of whom
           | actually use the software for which the piece of advice is
           | meant to benefit. That scares me; like we've all lost touch
           | with the ground truth on this one; I'd love to re-sync with
           | it, that's what I'm trying to do, I just don't have the first
           | clue how to do it.
        
         | SoftTalker wrote:
         | Screen reading software seems like it would have a very small
         | market and I would expect it lags rather than keeps up with the
         | ever changing ways people invent to build web pages.
        
         | isleyaardvark wrote:
         | Screen readers have and continue to lag in implementing
         | standards designed specifically for accessibility, so I would
         | say they are obviously not sophisticated enough.
         | 
         | (One example: https://heydonworks.com/article/aria-controls-is-
         | poop)
        
         | pverheggen wrote:
         | There are well-defined standards for how the role of every
         | element is determined, and according to those standards, adding
         | an onclick handler does not change the role.
         | 
         | Screen readers also don't access the DOM directly, there's an
         | extra abstraction layer. Browsers expose accessibility data to
         | the appropriate OS API, and screen readers use the data exposed
         | by the OS. There's too much variation as-is between different
         | screen readers to be piling browser-specific behavior on top.
        
       | Joker_vD wrote:
       | > 1. This element does not announce itself as an interactive
       | element to screen reader users.
       | 
       | It has the "onclick" property set though. The other two points
       | are pretty valid, however. It's a shame we don't have a proper
       | "onsubmit" property or something like that. "Oninteract"?
        
       | pverheggen wrote:
       | A good addition to this article is that most buttons should have
       | type="button" on them. By default, buttons are type="submit",
       | which if contained inside a form will submit that form.
       | 
       | I'm sure there are some devs who reach for a div because they're
       | unaware of the proper way to disable submit behavior.
        
         | rado wrote:
         | Right. I learned it the hard way lol
        
         | galaxyLogic wrote:
         | > they're unaware of the proper way to disable submit behavior.
         | 
         | That is an issue in favor of DIV, you don't accidentally set
         | type="submit" because you don't know about that. There are many
         | things many people don't know.
         | 
         | Using a DIV means you start from empty plate and explicitly add
         | the features you want to add, which makes it easy to later
         | remove or change those features when you want to.
         | 
         | Of course if your knowledge of HTML standards is great and
         | Button exactly fits your current use-case you probably will use
         | it, but designs and requirements change all the time.
         | 
         | Using DIV makes your design more transparent, you see there are
         | certain features you have set to it by adding the attributes.
         | 
         | Using a Button means you (and other people reading your code)
         | probably want to consult documentation to understand what it
         | exactly does. With a DIV + attributes that is explicitly
         | "spelled out".
         | 
         | Just some pros and cons.
        
           | thyristan wrote:
           | DIV isn't a button with features disabled. DIV is something
           | else entirely, and you have to emulate most of the features
           | in Javascript, badly. As the original article explains...
        
           | marcosdumay wrote:
           | Every input should have a type. It's a good thing to put in a
           | linter and run before you consider your code complete.
           | 
           | Yes, the default is bad, but you should be overriding every
           | one of those anyway.
        
           | MrJohz wrote:
           | You always want all the accessibility features. If your
           | button is a button, then you want the whole lot: the correct
           | role, tabability, keyboards shortcuts, everything. There is
           | no situation where you only want some of those features.
           | 
           | So if you use a div, you _always_ need to add _all_ of the
           | features. Whereas if you use a button, you usually need to
           | remember to add the correct "type" attribute (although if
           | you're building a form, you might not even need that).
           | 
           | You also mention transparency. A button makes your design
           | transparent: it is a standard element, and web developers
           | should know what it does. A div is not transparent - firstly,
           | if I'm a developer reading that code, I need to look at
           | context clues to understand what the authors' intent was (a
           | tabbable element with a keydown handler and a click handler
           | could be all sorts of elements, not just a button, so now I
           | need to inspect event handlers and see what they do), and
           | secondly, many people do not implement this stuff correctly,
           | so what you're usually looking at is something that looks
           | like it might have been intended as a button, but is missing
           | a bunch of features. Was that intentional or did the author
           | just forget some stuff?
           | 
           | This isn't really a "pros and cons" type of thing. Just use a
           | button. It's doing all the work that you'd have to do
           | manually, but automatically. Just use it.
        
           | znort_ wrote:
           | > Of course if your knowledge of HTML standards is great and
           | Button exactly fits your current use-case you probably will
           | use it
           | 
           | i would have imagined that coding html should be done by
           | people with basic understanding of it, at the bare minumum to
           | know what a button is. but maybe that's just me being old and
           | not going on with the vibes ... maybe i'm just going to
           | facepalm a bit and get some fresh air.
        
           | jmull wrote:
           | How is it harder to learn "want normal button" => <button
           | type="button"...> than "want normal button" => <div
           | role="button" tabindex="0"...>, plus the javascript for
           | keyboard access (plus css for at least the cursor), etc.?
        
             | culi wrote:
             | Agreed. It's not hard and it's definitely not unreasonable
             | to expect front-end developers to know the very basics of
             | semantic HTML and accessibility standards. It's literally
             | their jobs
        
           | Sohcahtoa82 wrote:
           | > Using a DIV means you start from empty plate
           | 
           | When comparing to a Button, that's a bug, not a feature.
        
           | cferdinandi wrote:
           | No. Objectively no.
           | 
           | It is INFINITELY easier to add type="button" than all of the
           | other shit I mentioned in my article.
        
           | serial_dev wrote:
           | So some developers cannot be trusted to figure out that they,
           | in some cases, need to add a single attribute to the button,
           | but they can reimplement a button with all its behavior,
           | feel, look, and accessibility settings starting with a div?
        
             | brazukadev wrote:
             | React in a nutshell
        
             | Levitz wrote:
             | No, but they can reimplement it in a good enough state for
             | the vast majority of users without getting bothered by
             | default behaviour or styling that might vary per browser.
             | 
             | Which, don't get me wrong, is still a problem,
             | accessibility matters, but if there's a reason as to why
             | something happens, the way to fix it is to actually look at
             | that reason.
        
           | Mawr wrote:
           | > Using a DIV means you start from empty plate and explicitly
           | add the features you want to add,
           | 
           | Yep, which guarantees you will not add everything that's
           | required for e.g. accessibility. It's not realistic for every
           | single dev to be aware of every single important property of
           | a button. This approach just doesn't scale.
        
         | mixmastamyk wrote:
         | Believe that default is for <input type="submit">, not
         | <button>.
        
           | pverheggen wrote:
           | Nope, it's the default:
           | 
           | https://developer.mozilla.org/en-
           | US/docs/Web/HTML/Reference/...
           | 
           | Maybe you're thinking of <input type="button">, which doesn't
           | submit?
        
           | cferdinandi wrote:
           | It's the default for buttons inside forms, but it's SO
           | trivial to add type="button" than any argument that div's are
           | a better choice because of this should be dismissed as
           | unserious trolling out-of-hand.
        
           | tomkarho wrote:
           | I seem to recall that once upon a time the default type for a
           | button was in fact "button" but at some point (somewhere in
           | the region of html 5 / es6) it was switched into "submit".
        
         | sam_lowry_ wrote:
         | Indeed this long rant by OP misses the critical info.
         | 
         | A button of default type will do weird things, IIRC it will
         | skip the JS handler onCick, for instance.
        
           | efilife wrote:
           | I don't think it skips the handler behavior on default but
           | can't check now
        
             | Shog9 wrote:
             | It does not. What it _does_ do is submit the form, so if
             | you trigger some fast change to the page or async behavior
             | from the click event, you may never see it because the
             | submission happens and the page reloads (or a different
             | page loads if form action is set to a different URL). If
             | you 're relying on event bubbling, the click handler may
             | run _after_ the form is submitted, which is even less
             | likely to do what you intend.
             | 
             | If you aren't expecting this (and don't know how to
             | discover it e.g. by examining browser dev tools, server
             | logs, etc.) then you'll assume the button is broken and...
             | probably try something else.
             | 
             | Even if you _do_ discover it, you may try something that
             | won 't quite have the same reliability - at one point it
             | was common to see folks putting preventDefault() or return
             | false in their click handlers to squelch the (correct)
             | behavior, rather than changing the type of button.
        
               | sam_lowry_ wrote:
               | Yes, you are right. Thanks for the lengthy explanation.
        
       | lyricaljoke wrote:
       | My very similar pet peeve is about websites that use `onclick`
       | handlers and similar to implement navigation. Just use a damn
       | anchor tag, which gets you correct link behavior for free:
       | 
       | * works with middle click for new tab
       | 
       | * integrates with accessibility devices
       | 
       | * works with right click + open in new window or similar options
       | 
       | * etc. etc. etc.
       | 
       | If it's notionally navigation, don't use javascript soup: use a
       | link.
        
         | Zak wrote:
         | I've seen an increase in people doing this sort of thing over
         | the past few years. I imagine it has something to do with
         | frameworks and ignorance or apathy, but the old fashioned way
         | almost always provides the best UX.
         | 
         | To anyone reading who has tried to get fancy with a substitute
         | for the <a> tag, I wish you mild discomfort and inconvenience.
        
           | philistine wrote:
           | Could it be that the devs who write that code are not allowed
           | to touch the CSS so they implement the visual functionality
           | they want in their framework instead of telling the design
           | team their intent?
        
             | Zak wrote:
             | There could be any number of weird constraints that would
             | lead a developer who knows better to do such a thing in a
             | specific situation, but someone designed (or failed to
             | intentionally design) the system in question.
             | 
             | That person should sit alone in a room with no distractions
             | and think about what they did.
        
         | weaksauce wrote:
         | when i was doing .net programming way back in the day asp.net
         | handled each navigation with a javascript event and it broke
         | all that stuff. this was right before ruby on rails existed so
         | maybe it's better now.
        
         | tln wrote:
         | Yes! If it's clickable, it should either be a button or a link.
        
           | culi wrote:
           | there are plenty of other vanilla html elements that are
           | clickable. <details>, <input
           | type=[button|checkbox|radio|file|etc]>, <label>, <select>,
           | etc
        
         | epidemian wrote:
         | oh, 100% yes! The job project i joined somewhat recently is a
         | moderately-complex React web app, and _none_ of the navigation
         | elements are actual links. Everything is done by onClick
         | handling, even thought many things are, conceptually, just
         | links. I have no idea why this kind of thing is so widespread
         | on the web front-end world.
        
         | derefr wrote:
         | I wonder why browsers don't intercept JS-triggered navigation
         | (or history.push) events that happen with a click handler on
         | the stack -- where it can be determined from the event data of
         | that click handler that the user additionally used the middle
         | mouse button or was holding cmd/ctrl at the time -- and rewrite
         | them into navigation-in-new-tab. (Ideally, without making the
         | caller aware that anything different happened than what it was
         | expecting.)
         | 
         | It might not be what the developer of the site/app intended;
         | but it's exactly the semantics the user is _expressing their
         | desire_ to trigger. So why not do what the user wants? Browsers
         | are user agents, not developer agents, after all.
         | 
         | (Before you say "that sounds like a layering violation" --
         | well, yes it is, but that particular layering violation already
         | exists to support most browsers' JS engines' "suppress popup-
         | window / new-tab navigation if the stack of the navigating call
         | _doesn 't_ contain a click event" logic. The code ugliness was
         | already bought and paid for; we may as well reap as much
         | benefit from it as we can!)
        
           | yakshaving_jgt wrote:
           | > it's exactly the semantics the user is expressing their
           | desire to trigger.
           | 
           | That's not necessarily true. You could imagine writing
           | perhaps a video game or something where this control is
           | intended to have a different meaning. For this reason, I
           | don't think this is a liberty that browser developers can
           | take.
        
             | derefr wrote:
             | Keep in mind that this check+logic would only come into
             | play _within_ the call to `history.push` or the
             | `window.location.href` setter.
             | 
             | It's not "add a browser-default click event listener that
             | shims in special behavior" (which wouldn't be able to catch
             | the JS navigation in the first place, since that would be
             | occurring in its _own, separate_ click event listener.)
             | 
             | It's instead "when I-the-browser have been called by page
             | JS to do something navigation-like through the native
             | `location` or `history` APIs, first check if the current
             | call stack has a event-listener call triggered by a
             | browser-delivered click event in its ancestry. If it does,
             | check further whether the click was a "special" [middle-
             | mouse-button / shift / ctrl-or-cmd / alt] click. If it was,
             | then cause some other side-effect depending on the
             | "special" modifier [i.e. open the target URL in a new tab,
             | or new window, or download it] while silently failing to
             | actually navigate _this_ tab. Otherwise, proceed with the
             | original semantics of the native `location`  / `history`
             | API call that was made."
             | 
             | If your game isn't specifically trying to have middle-
             | clicking / ctrl/cmd-clicking _navigate the tab_ , then this
             | check+logic would never fire.
             | 
             | ---
             | 
             | That being said, _in theory_ , if you bound a listener to
             | `auxclick` and told it to `e.preventDefault()`, that should
             | maybe tell the browser you're doing something special and
             | different where the middle-mouse button isn't just "the
             | left mouse button with extra flags set", and therefore that
             | navigation triggered via the middle mouse button shouldn't
             | be seen as "navigation triggered via the left mouse button
             | with extra flags set."
             | 
             | I say _in theory_ because web developers would probably use
             | that to prevent people from opening their site /app in
             | multiple tabs at once. And the whole point here is that
             | people should be able to do this whether web developers
             | like it or not.
             | 
             | --
             | 
             | Also, a tangent:
             | 
             | Web developers may have what are, to them, _good reasons_
             | for preventing the user from opening their page /app in
             | multiple tabs.
             | 
             | For instance, each instance of a page/app on their site
             | might open its own persistent websocket connection to their
             | backend, and so having O(N) tabs open to their site means
             | O(N) websocket connections. And if many users do that,
             | their backend falls over.
             | 
             | Or each instance of the page/app thinks it has exclusive
             | ownership of a local IndexedDB, and so might try to migrate
             | the data in a non-atomic way at any time; where if other
             | instances of the page/app are also running and accessing
             | the same DB, they might blow up, or do the same thing and
             | corrupt the DB.
             | 
             | (I've seen both of these in practice. In fact, I believe
             | _Reddit_ [in its new design] does the former; at around
             | ~100 open Reddit tabs, they all crash! [I think it has
             | something to do with their chat system.])
             | 
             | IMHO, any webpage that can't stand being open multiple
             | times simultaneously is badly architected. Such pages have
             | been "coddled" too long by browser vendors, by allowing
             | devs to _mostly_ disable the user 's ability to easily open
             | links as tabs. We should stop coddling these pages.
             | 
             | If we give users back the ability to easily open tabs on
             | modern websites, we'll see the owners of these sites
             | finally [probably begrudgingly] fix the problems that cause
             | them to want to disable opening things in tabs in the first
             | place.
        
         | psygn89 wrote:
         | Yup. I think a lot of the devs that started with React jumped
         | straight into the "fun" stuff without learning some of the
         | "boring" fundamentals.
         | 
         | And those devs set the wrong patterns and standards for others
         | following hot behind them. The only time I can remember needing
         | to dress a div up like a button was when an accordion trigger
         | was just a giant button and anything passed in would be
         | rendered inside, but I needed an action to the right of the
         | trigger title. But those happen super rarely. You can't just
         | pass in a button as it was invalid html to have nested buttons
         | obviously. Yes, I know I could probably use css to absolutely
         | position it or something but that takes it out of the flow and
         | starts hacking about it in another way.
        
         | Akronymus wrote:
         | Also, get rid of JS based scrolling. I scroll a lot with
         | pressing the middle mouse button. Too many sites break that.
        
         | OptionOfT wrote:
         | This reminds me of Microsoft's website checker in Office 365.
         | 
         | Click a link with left-mouse, and it'll intercept the page with
         | their safety checker (that doesn't work half of the time)
         | before forwarding you.
         | 
         | But middle click? No safety for you.
        
       | croisillon wrote:
       | <3 the top-border
        
       | randyrand wrote:
       | > This element does not announce itself as an interactive element
       | to screen reader users
       | 
       | Are you sure? Screen readers should be able to detect a div with
       | a onclick as interactable, no? And if they can't, that seems like
       | an exceedingly simple fix. I'd be shocked if they can't already
       | detect onclick.
        
         | rictic wrote:
         | A click handler can be doing a lot of things that aren't much
         | like a button, like letting you close a modal if you click
         | outside of it, capturing mouse events for a game, or passively
         | recording events for analytics. All that a click handler tells
         | you is that there's some code that sometimes cares about some
         | clicks somewhere inside that element.
        
           | knute wrote:
           | Also a click handler on a div isn't going to do much for
           | someone who isn't using a mouse, which would include a lot of
           | screen reader users.
        
           | randyrand wrote:
           | All of those seem like examples of things you'd want your
           | screen reader to tell you about.
        
         | 1-more wrote:
         | I can confirm. I got decent with VoiceOver as the "guy on the
         | team who gives a shit about this" (unofficial title) and yeah,
         | it stinks. Also, you don't necessarily move through the page
         | linearly with a screen reader; the rotor lets you jump between
         | links, or jump to forms, or jump to navs. The more semantic
         | your markup, the better it will be populated.
        
           | cferdinandi wrote:
           | It's worth noting that VoiceOver is well-known for being a
           | lot more lax than most other screen readers. Other options
           | tend to be a lot more strict around standards and what
           | they'll announce.
        
       | stack_framer wrote:
       | I wonder if the "React Ry-thought-leader-guy" crowd (I love this
       | not-so-subtle reference to Ryan Florence) preferred div over
       | button because of the built-in styles that browsers used to apply
       | to button elements.
        
         | 1-more wrote:
         | This I've never gotten. It takes very little CSS to unstyle
         | them!!
        
           | exogen wrote:
           | In today's world, yes. But as with a LOT of complaints about
           | "web developers!!!!" the answer is usually "because of the
           | way the web WAS."
           | 
           | Before IE became Edge (and maybe even in the earliest
           | versions of Edge), there were certain styles and descendants
           | that simply did not work on a <button> element, like Flexbox
           | and Grid positioning. So, if your button had content like an
           | icon, and you were trying to align it a certain way with the
           | label, you simply couldn't use some features of CSS like you
           | could with a <div>. It was a pain in the ass.
           | 
           | In the same vein, do you remember the period where some
           | browsers wouldn't allow you to make a button look like a link
           | using CSS, because they thought it might deceive people and
           | thus be a security issue? I do.
           | 
           | And similarly when people complain about the complexities of
           | webpack and bundlers in general, do you remember including
           | the jQuery <script> tag on the page and then almost always
           | needing to call `jQuery.noConflict()`? And how in those days,
           | most people got even THAT wrong, because atomic <script async
           | onload> behavior didn't work correctly in all browsers yet,
           | so other code could actually run in between a <script> and
           | its onload callback, meaning the jQuery.noConflict call was
           | ineffective and something else could steal it? I remember.
           | webpack fixed that by automatically scoping everything.
           | 
           | Nowadays, a lot of those workarounds are unnecessary (depends
           | what browsers you're supporting). But it's not like there was
           | never a reason for them.
        
             | 1-more wrote:
             | A cool thing about a lot of the agency work I did early in
             | my career is our audience was not actually the stated
             | audience, it was the staff at the company that hired us.
             | And one of the companies was on IE7. So yeah, I've nine-
             | sliced a gif or two and done a few clearfixes in my time,
             | haha. Never ran into a lot of these, but these weren't apps
             | so much as brochures that happened to be online. Luckily
             | enough we could control the environment pretty well to
             | avoid actually needing noConflict() on jQuery.
             | 
             | But that was in 2011-'13 and things have gotten a bit
             | easier since then and it's up to us to stay abreast of
             | what's possible on the platform.
        
         | cferdinandi wrote:
         | That was a big part of "thought leader guy"'s argument in favor
         | of divs, but not the only one.
        
       | donatj wrote:
       | I would love to see this expanded into "Just use the HTML element
       | that was built for that explicit purpose". I feel like your
       | average SPA developer doesn't understand what even a quarter of
       | the HTML elements are meant for and just reinvent the wheel every
       | time.
        
         | culi wrote:
         | Yes it's called "just use the platform" and it's become a
         | common refrain in the front-end world at least since HTML5 came
         | out around 2014. Unfortunately it hasn't caught on in all parts
         | of web dev but it's definitely seen as the "correct" way to do
         | things
        
           | serial_dev wrote:
           | I heard it almost a decade ago in Polymer and Web components
           | circles https://www.polymer-
           | project.org/blog/2016-05-26-IO-2016-Reca...
           | 
           | It's strange to look back and see that most spa projects
           | still just bundle it all up into a gigantic js file...
        
         | christophilus wrote:
         | I wish the elements were just stylable, then. For example, the
         | date picker sucks. I'd love to use it and eschew a JS based
         | one, but my clients complain that it's ugly.
        
         | jay_kyburz wrote:
         | I vaguely remember, back in 2010, when I wrote my app, you
         | couldn't style a button consistently across all browsers. They
         | were grey boxes in firebox, or used other OS standard styling.
         | 
         | We had to invent our own buttons if we wanted it to look the
         | same everywhere. I could be wrong though.
        
           | tomwheeler wrote:
           | > I vaguely remember, back in 2010, when I wrote my app, you
           | couldn't style a button consistently across all browsers.
           | They were grey boxes in firebox, or used other OS standard
           | styling.
           | 
           | I'm sure I'll trigger a lot of designers by saying this, but
           | I'm probably not alone in valuing basic usability FAR above
           | styling. I much rather have an ugly button that looks like
           | 90's era Tcl/TK than something pretty that doesn't behave
           | like I expect it to.
        
       | SmartHypercube wrote:
       | I got bitten by this: user agent stylesheet contains "button
       | {align-items: flex-start}" (at least in Chrome). The default
       | behavior is "stretch". Spent an hour debugging why my flexboxs'
       | sizes are wrong. I still want to use correct HTML elements as
       | much as possible, but I do think using <div>s everywhere makes my
       | small side projects so much easier, since I don't have to
       | remember all the non-default behaviors.
        
         | cferdinandi wrote:
         | I probably should have included "if you're building for the
         | frontend you should probably know CSS". Good follow-up piece.
         | Thanks for mentioning it!
        
         | crisnoble wrote:
         | `appearance: none` goes a long way to resetting button styles.
         | I usually make a .unbuttonify class to use or extend for things
         | I want to behave like buttons (free focus, accessibility, and
         | interactivity) but look like, say, a hamburger menu toggle.
        
           | culi wrote:
           | are css resets not in vogue any more? I still use them for
           | all my side projects. As well as a normalize.css[0] that
           | smooths over any additional browser inconsistencies. The
           | original Meyer reset is definitely overkill, but there are a
           | couple newer more minimal ones out there[2][3]
           | 
           | [0] https://necolas.github.io/normalize.css/
           | 
           | [1] https://meyerweb.com/eric/tools/css/reset/
           | 
           | [2] https://www.joshwcomeau.com/css/custom-css-reset/
           | 
           | [3] https://piccalil.li/blog/a-more-modern-css-reset/
        
       | xnx wrote:
       | Page makes no mention of <input type="button">. Are there any
       | situations where that should be used?
        
         | adam_beck wrote:
         | From MDN:
         | 
         | > Note: While <input> elements of type button are still
         | perfectly valid HTML, the newer <button> element is now the
         | favored way to create buttons. Given that a <button>'s label
         | text is inserted between the opening and closing tags, you can
         | include HTML in the label, even images.
        
         | jarek83 wrote:
         | It's a thing from the times when <button> did not exist. Other
         | use cases were for supporting IE. Today just use button.
        
         | cferdinandi wrote:
         | I would literally never use <input type="submit|button"> for
         | anything when the <button> element is an option, personally.
        
       | Brendinooo wrote:
       | Related, because I don't always get to talk about buttons:
       | 
       | In my day job's shared library, we made a Clickable component
       | that basically exists to abstract away the decision to use a
       | button or an anchor tag, and resets the styles so both elements
       | act the same way (both by default and when we apply styles to
       | each).
       | 
       | We'd have a lot of confusion on the design side about button-as-
       | design vs button-as-function and now we don't have to deal with
       | that at all anymore.
       | 
       | And since the styling's been reset in a predictable way, it takes
       | away one of the bigger reasons why people go to divs in the first
       | place.
        
         | Sharlin wrote:
         | How does style reset make the elements work the same way? Links
         | have vastly more features built into browsers than buttons
        
       | jarek83 wrote:
       | The type of developers that would go with <div> in such cases are
       | also those that know very, extremely little about semantic HTML
       | and its purpose. Then if one is challenged about using React or
       | other heavy-JS framework when you don't really have to, the
       | discussion will be met with utter even surprise that someone out
       | there is actually not using React.
       | 
       | The web is darn simple, but we are the place where it is made
       | extremely over engineered and expensive for both companies
       | (salaries and 2-3x more staff needed than necessary because of
       | the bloat) and users of their products (in terms of payloads).
       | 
       | And yet JS-heavy frameworks seems to have the best job market.
       | 
       | Everything seems to be upside down.
        
       | steve_adams_86 wrote:
       | This is a good example of cases where LLMs can tend to write
       | 'bad' code, because these patterns (i.e. reinventing wheels in
       | the browser) are quite common in the wild, and LLMs tend to
       | choose them over just using native features (such as buttons). I
       | find myself telling Claude to revisit implementations and
       | simplify them in these kinds of ways.
       | 
       | Another good example is bizarre error handling conventions when
       | working in TypeScript. Claude will come up with tons of weird
       | ways of doing this, using different approaches all over the
       | place, but rarely consider simple patterns like 'return an
       | expected value or an error'.
        
         | turtletontine wrote:
         | These are great examples of how LLMs are great at _writing
         | code_ , but pretty bad at _software engineering_
        
           | serial_dev wrote:
           | Search engines were also only good at looking up things, not
           | software engineering. I find it a blessing that a human is
           | still valuable in this process we call software engineering.
           | And meanwhile you can use search engines just like LLMs to
           | learn and discover much faster than without them.
        
             | boothby wrote:
             | Only nowadays LLMs are embedded in search engines so if
             | you're looking for something that doesn't exist the top of
             | the page is liable to hallucinate its existence.
        
       | Sohcahtoa82 wrote:
       | tbh, I've started to grow a disdain for front-end developers. It
       | seems their favorite pastime is re-inventing the wheel, and every
       | single time, they destroy something while gaining _absolutely
       | nothing_.
       | 
       | Stop implementing date pickers when <input type="date"> exists.
       | 
       | Stop implementing smooth scrolling. _Browsers already do it on
       | their own_ , and your implementation _will not work_. Really,
       | just don 't mess with scrolling in general. Don't make scrolling
       | have "momentum". Don't change scroll speed. One site I've been to
       | goes out of its way to change how much a scroll wheel click
       | scrolls the page. For fuck's sake, can someone explain to me why
       | that would be a feature!? Why go out of your way to override a
       | specific user preference!?
       | 
       | All this bullshit changes expected behaviors, reduces
       | accessibility, reduces the performance of your web page (and
       | therefore increases CPU and battery usage)... _for no reason
       | whatsoever_.
        
         | al_borland wrote:
         | > Stop implementing date pickers when <input type="date">
         | exists.
         | 
         | This still has issues in some browsers. With sites already
         | having other methods from before this existed, there isn't a
         | good reason to move to it, when they'll need the custom version
         | for browsers that lack full support.
         | 
         | This is the issue with a lot of newer features.
        
           | Sohcahtoa82 wrote:
           | > This still has issues in some browsers.
           | 
           | Your knowledge is out of date. <input type="date"> been
           | implemented in _nearly every_ browser since 2018, with the
           | exception of Safari which was slow and didn 't put it in
           | until 2021, and Opera Mini which still doesn't have it at
           | all, but who the hell uses Opera Mini?
           | 
           | https://caniuse.com/input-datetime
        
         | Zak wrote:
         | This is enough of an issue that someone made
         | https://dontfuckwithscroll.com/
        
       | HocusLocus wrote:
       | A whole generation of people who click all over to find places
       | that do something. People have this problem where they feel
       | 'proudly vested' in learning things that just weren't designed
       | well.
       | 
       | 10 years ago someone decided that _dragging links_ is so much
       | more important than selecting text, selecting text is scarcely
       | possible. I 'm going to have to fork a browser to give link-
       | dragging the demotion it deserves. It was probably those DIV
       | guys.
        
         | culi wrote:
         | This is a great point that I don't see brought up enough. I
         | don't know if I've ever purposely wanted to drag a link but I
         | struggle to highlight/select some in a link every other day
        
         | ForLoveOfCats wrote:
         | I might be a weirdo but I drag links all the time as it's how I
         | open links as background tabs even though there is a right-
         | click context menu entry for it
         | 
         | Unless the site is _really_ messing with events, holding alt on
         | PC (Windows/Linux/ect) or Option on macOS lets you select text
         | in links without triggering the link to navigate.
        
           | ivanche wrote:
           | Holy fsck! 30 years on the web and today I learn about this
           | Alt/Option trick. Thank you!
        
         | ajmurmann wrote:
         | Almost as bad as copying a phone number on iOS instead of
         | calling it (no idea if this is better on Android). The
         | eagerness of iOS to call phone numbers which almost never is
         | the thing I want to happen, is a source of much anxiety.
        
           | Shog9 wrote:
           | Android works great - lets you select the # and then gives
           | you a context menu with the option to call (or copy, or
           | search).
           | 
           | ...unless someone made the phone # a tel: protocol link, in
           | which case it has the selection behavior of any other link.
           | Which is mostly fine, since "copy" is a context menu option
           | for tel: links... unless some jerk put a tel: URL in that
           | isn't the same number as what is shown in the text of the
           | link, in which case it's time for some crazy hoop-jumping to
           | either copy OR call the number.
        
         | ratijas wrote:
         | There are browser extensions for selecting links. It used to be
         | called Select Like A Boss, now it's Drag-Select Link Text.
         | tl;dr: drag horizontally to select text, drag vertically to
         | drag-and-drop as usual, press and hold to select the whole link
         | text.
        
         | tomwheeler wrote:
         | > selecting text is scarcely possible
         | 
         | I find non-selectable text maddening, but I recently found an
         | macOS app called TextSniper that restores my control. It lets
         | you select an area with the mouse (as you would when taking a
         | screenshot) and it then OCRs the text and puts it into your
         | clipboard. It almost makes Google Analytics usable again.
        
       | shreddit wrote:
       | > You shouldn't, though! Seriously, just don't fuck with focus
       | order.
       | 
       | And here i am, wishing some would do just this. Especially
       | creators of log in forms which make the "reveal password" button
       | the next focus point instead of the "submit" button
        
         | culi wrote:
         | is pressing tab twice instead of a single time really that big
         | of an issue? Messing with focus order is definitely a bad idea,
         | but they could also use less semantic html to skip the reveal
         | password "button". For people who can _only_ use keyboards,
         | this would make it impossible to access that feature however
        
       | throwaway106382 wrote:
       | For the love of god why can't people just use standard elements
       | for their intended purpose.
       | 
       | Here's a tip for weirdo front-end devs that do this: You are not
       | smarter than the people that created the spec.
        
         | culi wrote:
         | it's not about being smarter. It's about being lazy. They don't
         | wanna reset the default button css in order to perfectly match
         | the figma they're being contracted to draw up. They simply
         | don't care and the people contracting them don't have the
         | knowledge to check if shortcuts were taken
        
           | throwaway106382 wrote:
           | Yeah I don't want to work with lazy people either. Shame.
        
       | spkm wrote:
       | Just don't use animated gifs inbetween text.
        
       | fullstackchris wrote:
       | div onclick is an abomination that should be eliminated
        
       ___________________________________________________________________
       (page generated 2025-10-31 23:01 UTC)