When going somewhere does a thing: on links and buttons
kilianvalkhof.com
kilianvalkhof.com
If you're using Gmail, you get both types of behavior on the same page!
If your mouse has a scroll-wheel, then it's probably clickable as a middle-click. If you have a trackpad without a 3rd button then there is usually a gesture that will send a middle click.
Please, for the love of god, let open up anything on your site in a new tab.
I also think in the modern world that as long as your assets are all properly versioned with good cache control headers using actually web requests for navigation instead of a self-contained SPA makes a lot less sense. Once upon a time an SPA was a solution to shifty internet, limited bandwidth and rich web experiences - those arguments have become a lot less valid in the modern world.
(this is a topic extremely near and dear to my heart as a (eh-sorta) full stack developer that needs to suffer through many poorly built applications as a user)
So I reverted my changes and worked on features instead of stack
I was just responding to it being a criticism of 'designers', maybe I misread that, but my initial reaction was as above, that it's not completely trivial to allow, or like it necessarily comes for free and has been 'turned off' by design.
One thing that I noticed is that more than half the time "open in new tab" is broken, I can click the link, copy the URL, open a new tab, paste the url and get what I wanted. It's so maddening.
This is of course maddening if the site should not be a SPA but was developed that way because when you are running a company and need to build things quickly it is easier if you just have one toolbox labelled SPA-building tools and pull that out and get going.
I'd argue that each individual view in your app should have a routable URL, otherwise sharing links to anything is basically impossible, as is bookmarking certain pages, or even reloading them.
> With SPAs, that's often not true for entire 'pages', never mind modals and views you might not be expected to want in a new tab but do.
Some claim that modals are bad design and I wholeheartedly agree, though for a variety of reasons they still keep showing up across numerous systems. I guess a compromise could be giving the modal open state its own URL so the app would know what to do if the page is refreshed (the modal would still be open), but somehow that doesn't get much attention either.
An especially clever option (for niche cases) would be being able to open a modal in a tab/window of its own, without the surrounding UI, when opened directly through the URL/new tab/new window, but show it inline in the app during normal navigation. Then again, many dislike pop-ups either because that's not really the direction in which web development went, though I can see why in certain sites they could be useful (e.g. CRUD apps with lots of boring tables and element selection). Oh well.
nothing is more painful when, after scrolling through an control-clicking some things that might be what you're looking for, seeing 5 or more tabs open, and then realising that they're all just the default homepage.
It is extra work for sure, but usability improvements usually are, and if you know what you are doing, this will not cost that much extra in maintenance.
In particular it shouldn't change the original page at all, that's the whole point!
Now, if the original page is the kind that updates in real time (due to accesses from other tabs or even from other machines), just use a web socket!
You also have to disconnect styling from HTML tags for your headings to get the h1>h2>h3 order semantically correct for accessibility and SEO.
Regardless, I think designers making links appear as buttons is bad practice, but you usually don't have much influence over design as a developer.
Meanwhile, I've seen plenty of enterprise software and even banking sites, that:
* try to prevent you from having more than one tab open
* try to prevent you from having more than one session open
I get that sometimes server side state can throw a spanner into the works otherwise, when you can't write a proper stateless app/API, or write any kind of an app well enough either, but it's very annoying when you run into one of those systems.More so, sometimes the explanation for this is "security", which just feels like the people behind the system design wanted to be lazy in regards to various lifecycles in the application. If I have my internet banking site open, pay for some goods in an e-commerce store in another tab through the banking integration and then refresh the banking site, me being signed out of it feels like a design flaw, not a "security" feature.
But oh well, you don't really get a say in these things, your bank is going to do whatever they feel like in regards to their UI/UX, as will those behind whatever piece of enterprise software that you have to use, or that you'll have to write in accordance with the requirements.
It's up there in regards to annoyance, much like ctrl clicking some element, just to discover that it doesn't let you open up new tabs, or maybe even right clicking something or trying to select text, just to realize that neither works and you have to copy whatever you need out of the source of the page.
The statement I made is not a genuine expression of the most important reasons - it is a tool to persuade management using cherry picked boogiemen to scare foklks into the right decision... aka a bad faith argument made for the best of reasons.
I just want everything to always open in a new tab (or sometimes a new window). gmail yep, music sites yep, youtube yep.
It's absurd their engineers haven't fixed something so simple.
A poor implementation of a generally sensible approach is not justification to embrace a more complex and error-prone approach.
…But there is a network in between. I'm not sure why pretending there isn't can somehow make a system less complex.
Furthermore, how do you write automated tests for your modals and slide-out panels? Your test suite needs to essentially run a browser. This is absolutely more complex than having an application on the server compute the document that the client expects.
That's exactly my argument...? Seems to be a misunderstanding.
> I'm not sure why pretending there isn't can somehow make a system less complex.
Yes, that is exactly why pre-SPA web programming was more complex.
> Furthermore, how do you write automated tests for your modals and slide-out panels? Your test suite needs to essentially run a browser. This is absolutely more complex than having an application on the server compute the document that the client expects.
How do you test that the HTML/JS generated by the server actually show a modal? At least with libraries like React you can test everything up to the actual CSS engine. And no, you don't need a browser for that.
> How do you test that the HTML/JS generated by the server actually show a modal?
You can test for the existence of markup on page load. You can't test that some JavaScript for displaying a modal has run without running a JavaScript runtime, i.e., a [headless] browser.
In most cases, just loading a page which displays the appropriate information for the user is cheaper to test and implement, and usually is a better experience for the user also. It depends of course — this would not be true of an application like Google Maps. Most web applications aren't Google Maps though.
To make it worse ctrl/cmd click for opening it in a new tab doesn’t always work. Sometimes it open the repo you clicked on in a new tab, sometimes it opens a new tab but with your most recent repo, and sometimes it just opens the repo in the current tab. It is infuriating…
Azure DevOps is still utterly shit though.
I think there are plenty of reasons to choose Azure Cloud. Maybe Azure Devops flows from that. But it is far from my favourite tool.
https://twitter.com/gramofdata/status/1268661032890896387
One of the most annoying examples I encounter on a regular basis is in Twitter's trends sidebar, where they don't use links, but instead have manually added event listeners for ctrl-click and middle-click.
Why do only assistive technology users get treated with that level of respect?
Because let's be clear - for sighted users interacting with this person's webpage, whether the markup is a link or a button, they evidently plan that visually it's just going to be a paint roller icon, inside an area of the screen of indeterminate size which is going to be somehow interactable.
Apparently it's not important to consider whether I, a user not currently employing assistive tech, might need to know before I click it whether that control will cause a page navigation, carry out an operation, or what.
It might be a link; it might be a button; it might just be a decorative picture of a paint roller. It might interact on hover, on click, or on double click. Who knows!
This definition of accessibility as something distinct from usability, where frontend devs will torture themselves over the semantic markup that they use to ensure clarity of purpose for accessibility purposes, has somehow become completely divorced from the world of UX design, where visual indications of affordances are no longer seen as valuable.
Also sighted users get this information as well. If you hover over a link, it displays the target href in the lower corner or your window.
And there’s no hover-link-pop up on a mobile phone touchscreen.
You shouldn't rely on that: it won't work on mobile nor for users who don't want or can't use a mouse (e.g. people with a motoric disability).
If in his link example I click the "Open Theme Controler" link, then click the "Close" link, and do that a couple times, when I then click the back button to come back to Hacker News, I'm instead cycled through the number of times I clicked those links. I doubt any user would expect that to happen.
And now that I think of that phrasing, I think that probably the unifies the rules of thumb: if it changes local state, it’s a button. If it changes local scope, it’s a link.
It might still be valid to use a link for an on-page modal, for instance when it needs to be navigationable or should persist on a refresh.
I mean, that's pretty much my whole point. Forget javascript (as the example in the article does), but links by default append to the state, because that is pretty much how browsers always worked before they even exposed the history API to javascript.
If it makes sense to "open in new tab" then it should be a link. Otherwise it's a button.
Corollary: If it's a link then middle-clicking on it better open it in a new tab! There are way too many times that this was broken by JS with the href just being set to "#" or something, but clicking the link, copying the new URL, opening a new tab, pasting the url, going back to the original page and hitting "back" did exactly what I wanted. Don't do this!
Also related: if it is a GET request, don't mutate state or perform an action on the server (except perhaps logging). But that is basic security too.
There are exceptions, but know why you are doing the exception. For example a landing page will typically have button-like links for call to actions, because people expect that.
The problem is that apparently, an infuriating number of Front end devs seem to think that nothing in their shouldn’t-have-been-an-SPA page should ever be a link and go somewhere, preferring instead to waste an equivalent amount of time popping up some modal or changing page anyway.
Consider the possibility that some web applications might actually benefit from acting more like that.
Have you actually tried doing that on this very website you are now reading?
Click on my profile. Then click back. Where are you?
When I tested this just now, I was returned to exactly the point in the page where I left it.
Things become more iffy with client-side rendering, because the browser has no clear signal to decide when page-loading has progressed far enough that it can try to restore the previous scroll position.
- all the extra styling complexity
- the history API
- memory management (sometimes)
Etc.
I actually have been a proponent of replacing a bunch of buttons with links at a previous workplace, using the middle click as an argument in favor.
Sibling comments seem to misunderstand a frontend development a little. I’ve replaced quite a few dialog modals with pages (in a single page app), and it is usually because a backend developer (or a well meaning intern) thought they could implement the feature on their own (or more likely a project manager told them to), and simply didn’t known about the usability issues with this. Most front end developers I know deal with the same stuff in their workplace.
It’s disappointing how developers are so lazy to not even know the basic concept of a link. It’s completely ridiculous yet super common to see click handlers on DIV elements that set the value of location.href
As for A/BUTTON, we really need an attribute that clears the button’s style entirely, safely and forever. Nobody knows how to properly and full drop all useragent styles from a button, try googling it.
- right-clicking defaults - scrolling defaults - Back/forward browser buttons to traverse _state_ as the user expects - tabbing (and leave the damn default outline!)
If it's not a video game, please don't F with my keyboard and mouse's default behaviors. Thank you.
What I was really trying to go for with "state" in this context was something more like "business state". Things on the server that you change and can see with a refresh on a different client.
You'd need to do this for practical reasons too, considering links in e-mails might get automatically fetched whether for malware scanning, caching or generating a link preview, and it would erroneously trigger your verification workflow.
However, as the article points out, this analogy breaks down once you go beyond basic HTML and into complex UI layouts.
There are some use cases where a <button> won't work (eg if you want to use flexbox), but even then I'd first re-evaluate how important that use case is, then reach for a properly tested library to turn another element effectively into a button [1], and only then try to implement it myself and probably forget some built-im functionality, breaking things for users and costing me lots of time.
[1] https://react-spectrum.adobe.com/react-aria/useButton.html#c...
Er sorry, I meant type="button" for both. Neither submit a form or do anything other than show the default interactive styles without JS.
> There are some use cases where a <button> won't work (eg if you want to use flexbox)
I’m not sure what you mean, and having a hard time imagining what you might mean. Can you elaborate?
I think there was a bug in Chrome a couple of years ago where they incorrectly denied some element the ability to be flex containers (<fieldset> was a really annoying case of this) but I think that is fixed now.
The only case that I can think of where you can’t use a <button> is if you have nested interactive elements (a button within a link/button). There are sometimes ways around that (absolute positioning of the outer link/button) but sometimes there aren’t and then you need to re-implement a fake button from a <div>.
I actually do think that use cases are rare, and when you need a fake button, there are probably better solutions (in the SO question, the question author probably just wanted <details> and <summary>) but—though rare—these cases do exist.
And this rule of thumb is also incorrect (albeit by technicality). A form submit button goes somewhere (to the action response) and is a button.
I agree with the sentiment though, in general:
- If you are navigating through the page, use a link,
- if you are performing an action, use a button, (and in addition)
- if you are reveling some information, use a <details> <summary>
Another semantically-reasonable possibility which allows separation of source and destination would be using a button with appropriate aria-controls and aria-expanded to link it to the picker body; and probably giving that body the dialog role.
But I think the dismiss button, inside the dialog warrants it being a <dialog>. Dialogs usually open with a <button> (so that answers that question), and you would open this by calling dialog.show()—as opposed to the usual dialog.showModal()—since you don’t want to capture the focus. The Benefit of using the <dialog> element is that you can put it anywhere you want inside your DOM structure and allow it to interact with the page however you want to.
The OP widget is non of these, I would say it is an open question whether <details> <summary> is the right choice here.
There are countless of times that middle click to open new tab didn't work because page author use <button onclick="location.href='xxx'> as link. It's such an awful experience.
Has anyone used it? Thoughts?
I definitely recommend trying it out.
I'm pretty familiar with responsive design so I'm honestly not using the multi-viewport size set up that much. But it can also show dark/bright view next to each other, set up viewports with different networks speeds, and toggle various media preferences which is just super handy as these settings aren't that easy to toggle in default dev tools.
A nice extra is the page info pane which makes it super easy to validate all the metadata + check how the social cards show on popular networks.
It's been awesome using it. It's not just responsive design, it has fantastic features around accessibility and performance, I can set different viewports to different speeds and colour contrasts all at the same time. It is bonkers how powerful it is as a tool. I always recommend it to people to try out.
From purely technical point of view, the question would be rather irrelevant as the distinction between a button and link is mostly how a human perceives it, it does not matter for the program.
This is likely an explanation for the awkwardness that the author mentions feeling of this implementation, and is supported by it not making sense to open this kind of a "link" in a new tab (because it does not go anywhere).
And, you know, if you think about this from an assistive technology point of view, does a screenreader user actually need to worry about interacting with a control to make something visible? Isn't it better from their point of view to skip the interaction entirely and just put the list of theme options semantically under a navigable page heading?
A #menu href coupled with :target style is technically more accessible because the focus naturally shifts to it. Then the exit button should point to #menu-toggle so that closing the menu brings the focus back to the origin.
Login and land on the Home page. You want to look at transfers to your bank account (Balance > Account). Here you see big blue link box taking your to Balance: https://postimg.cc/yD97T8yT
Sometimes this blue box is a button to initiate an early transfer, which triggers an additional early transfer fee: https://postimg.cc/t1jpvGrG
Once you get to the Balance page, you still need to find the link taking you to the Account page (View All Transfers) to actually see your transfers. Square takes a second stab at getting that fee with a big blue button in the middle of the page: https://postimg.cc/bG98KVMD
Now perform this same action several times a week, all year round, and you will make the mistake and press the transfer button.
It only takes once for you to have a never ending enmity towards Square for filching $25 from your income.
I was caught the once in October of 2021. I *recall* the transfer was initiated immediately (and the extra fee of 1.5%). Since then I've revisited the button when the transfer was low, and I was willing to risk $5 to get a screen shot of the next page. That time I did find a confirmation screen (I can't find the screen shot now).
I call support, but they would not refund the transfer, despite having pressed it by accident, despite having never used the feature before, and having over five year relationship with about 200k/yr in sales going through their platform. "But you're getting the service" was their reply.
There’s more ways than a button or a link. Some people have suggested in the comments using details and summary.
It works without javascript, represents the states open and closed without requiring any aria attributes and some other usability features people might find interesting.
https://endtimes.dev/html-and-css-only-multiple-color-scheme...
Even if the button only does some action on the page, it could still be represented with a url. Sometimes it doesn't make sense. Then that's the time to use something other than an a tag.
If this were the default, most of this problem wouldn't exist.
Is it good practice to use links, then intercept then with preventDefault when it should go somewhere AND do something?