At the core, a UI component library is about building an abstraction for developers. Instead of constructing our page with
<a> and allowing arbitrary CSS and properties, we want to work in a nice semantic API using components like
<Button> offering only the variants we need. But there’s lots of questions to ask when designing these abstractions. Should the components wrap basic HTML elements like headings? Should the components automatically optimize for accessibility? Is custom CSS allowed to be passed into components?
A quick aside on the "science" of this all. The above is just a sample of questions with non-obvious answers. And different UI component libraries may answer these questions in (sometimes subtly) different ways, with good reason for each approach. It would be great if there was a universal science to this all. If we could create a type of A/B test, measure some kind of output, and ultimately arrive at a conclusion for the perfectly optimal UI component library. But this stuff is largely about trying to minimize cognitive load of developers, allow the codebase to scale with a growing team, change with an evolving product, and much more. There’s a lot of variables, and many are hard or impossible to measure. So! There we have it - it’s not a science at all.
But science of not, let’s look at this question about accessibility. Should the components automatically optimize for accessibility? A tangible example:
Say we want a button component and link component. From a visual perspective, we usually think of buttons as looking like this:
And links like this:
But from an accessibility perspective, there’s a more discrete difference. A
<a> should always contain a valid “href” pointing somewhere, whereas a
<button> is used for triggering an action on the page and cannot container an “href”. With this in mind, there a few ways to design components for buttons and links.
#Option A: visual-centric API approach
<ui_link>. Give each component an optional “href” property. If passed a valid value as the “href”, the component will render into a
<a> tag because this is consistent with accessibility standards. If there is not “href” property passed, render into a
Pro: in a big codebase, a link
<a> might sometimes be styled to look like buttons. This API makes this easy because the “href” can simply be passed to the
Con: It’s a bit awkward and strange to accept a property “href” into a component called
#Option B: markup-centric API approach
<ui_link> to pass something valid in the “url” property, but disallow the "url" property in buttons. The
<ui_button> component will always render into a
<button> tag, and
<ui_link> will always render into a
Pro: more intuitive API where
<ui_link> will always render
<link> tags, respectively.
Con: in our big codebase with links
<a> that want to look like buttons, this won’t be possible unless we allow custom CSS styles in
<ui_link> or extend the API to include all the button styles.
There is probably also an option C and D, or a way to tweak and improve option A, etc, etc. The point is, as far as I can tell, there isn’t an obviously correct way to design UI component APIs, especially when considering added factors like accessibility. Maybe someday when the overlord AI has conquered this field and makes a science out of it, we’ll have some concrete recommendations on this stuff. But until then, keep criticizing those UI components and striving to improve.