Stop choosing DX over UX.
By no means I want to dunk on Devon. This is just an example of sentiment flowing around the internet. So you, reader, would understand where I coming from.
DX - developer experience. UX - user experience, usability.
Let’s talk about button
Using <button>
instead of <div>
for a clickable elements is a good for UX (and accessibility). Yet a lot of front-end developers keep using divs or spans or something else. Why is that?
My guess is that because it is much easier to work with div then button, because div doesn’t have built in styles. Developers taking short cut here, and probably unconsciously, selecting better DX.
If using button would be as easy as using div, I guess a lot of people would use it. Maybe if we would thought about DX in the first place, UX would be better, because developers would have more time to spend on solving actual user’s problems instead of fighting with tooling and lack of standard libraries?
The code
If you wonder how hard it can be to use button <button>
instead of <div>
. Here is the snippet with “CSS reset”, which removes all quirks from the button:
import styled from "styled-components";
if (typeof document !== "undefined") {
// https://alxgbsn.co.uk/2011/10/17/enable-css-active-pseudo-styles-in-mobile-safari/
document.addEventListener("touchstart", function () {}, false);
}
export const focusRing = (color: string = "blue", inset?: boolean) => ({
/* Remove excess padding and border in Firefox 4+ */
"::-moz-focus-inner": {
border: 0,
padding: 0,
},
":focus": {
outline: "none",
},
":focus-visible": {
// https://css-tricks.com/platform-news-rounded-outlines-gpu-accelerated-svg-animations-how-css-variables-are-resolved/#rounded-outlines-are-coming-to-firefox
"box-shadow": inset
? `inset 0 0 0 3px ${color}`
: `0 0 0 2px #fff, 0 0 0 5px ${color}`,
},
transition: `box-shadow 100ms ease-in-out`,
});
/**
* reset built-in styles of a button https://css-tricks.com/overriding-default-button-styles/
*
* Don't forget to provide styles for:
*
* - default state
* - `:hover`
* - `:active` (See also https://bugzilla.mozilla.org/show_bug.cgi?id=68851)
* - `:disabled`
* - `:focus-visible`
*
*/
export const BaseButton = styled.button`
${focusRing()}
display: inline-block;
border: none;
margin: 0;
padding: 0;
width: auto;
overflow: visible;
background: transparent;
/* inherit font & color from ancestor */
color: inherit;
font: inherit;
text-align: inherit;
text-transform: inherit;
/* Corrects font smoothing for webkit */
-webkit-font-smoothing: inherit;
-moz-osx-font-smoothing: inherit;
cursor: pointer;
:disabled {
cursor: default;
}
/* Corrects inability to style clickable input types in iOS */
-webkit-appearance: none;
user-select: none;
touch-action: manipulation;
-webkit-tap-highlight-color: transparent;
`;
BaseButton.defaultProps = {
type: "button",
// @ts-ignore https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#attr-autocomplete
autocomplete: "off",
};
Source code on the Github. My previous post about button.
Links in the code:
- Enable CSS active pseudo styles in Mobile Safari
- Rounded outlines are coming to Firefox
- Overriding Default Button Styles
- Bug 68851: HTML buttons should go :active on keydown (spacebar) (opened 21 year ago)
- button autocomplete
What to do?
If you have components library in your company, add BaseButton
to it. And your team can follow the best practice easily:
- const MyButton = styled.div` ... `
+ const MyButton = styled(BaseButton)` ... `
- <div onClick={...} />
+ <BaseButton onClick={...} />
A bit of DX may improve life for developers and users.
Top comments (10)
I'm not sure I agree with your axioms.
If I want something to act like a button, I'll use a
button
.I'm not sure that people think it's more difficult than using a
div
.Using a
div
means you have to replicate all the features that button already provides. You have to reinvent the wheel. You can't have it act like a nativebutton
widget, with all the familiarity that invokes.I don't think people use
div
because it's technically easier to implement - it's not - I think they use it because they haven't learned aboutbutton
.Cynically, if someone made a library called "newTrendyButton" and released it to the world and all it was was actually, you know, a straight-up HTML button, then I think people would use it, and when you listed its features they'd all be very impressed and write tweets about it.
Devices and browsers have their own systems - for example if you made your own select replacement and someone used it on iOS, they'd get a different experience to the one they get in native apps or on other websites. If you have a good reason for that, you can override the select element, but I honestly think the case for this is small.
Users see something that looks like a button and it behaves like a button. Developers see a button and it behaves like a button.
My argument is a pure speculation. We would never know the truth, unless we're gonna do big poll asking "Hey, do you know HTML supports buttons natively? If yes, why don't you use it?"
But from my experience, when I was less experienced, I tried to use semantic HTML and resorted to divs as soon as it didn't work as I would expect (because I know divs are working at least CSS-vice)
But this isn't really working. You are making some look the way you want, but by using a div you are:
I'm not really sure why anyone would reach for a div when form elements in HTML are so well known and have been in use for decades. As for styling, there are literally thousands of guides online to show how to do it, and plenty of ready-made solutions that even the laziest developer can copy/paste into their own websites.
apparently it is not so wide knowledge, if you take a look around, there are plenty webiste using divs instead of button
There are even dedicated articles about it, for example web.dev/use-semantic-html/#use-but...
But even in your example in this post, you're not showing the full picture, despite already using Javascript to modify the CSS of a button. What you're doing by removing the "quirks" is you're removing the very features of a button that people rely on to actually use the button.
Not sure what you're talking about
You've removed the hover and focus styles, and left in a comment from the original React example that warns about making sure they get set correctly, but you don't do that. Focus styles are absolutely essential for those users who rely on keyboard for navigation. Try it yourself, visit a website and move around without a mouse. Notice how the visual focus indicator moves to each interactive element as you tab to it? Now imagine how difficult that navigation would be if there were no focus rings or borders on elements.
Never remove focus styles. You can change them if you feel you need something more in keeping with your design, but never remove them.
(Safari and IE require polyfill)
That is how CSS reset works - everything is removed, developer suppose to provide their own style
There is even a comment
The problem exists because someone "started".
Before we value User(paying money to the business) and Business needs(paying us) over our own "developer happiness". There were a lot of solutions a little harder for developers, but providing amazing results and value to the end users.
Those solutions of the past, and their analogs of today are generally ignored by the developers due to many reasons.
And the "Bad DX" is one of them.
So, that's a classical Chicken/Egg problem. What do you think?
Discussion went to abstract realm. I'm not sure I understand what you trying to say.
Classical example of "choosing DX over UX" is CSS-in-JS. It provides much better DX, than plain CSS, but worse UX, because any CSS-in-JS (with runtime) is slower than plain CSS.
And stop choosing DX over UX in this case would be to use CSS-in-JS without runtime, like vanilla-extract.