This is part of a series of posts about writing component API for great developer experience.
This post was originally posted on my newsletter a few weeks ago, just saying.
This is one of the easier ones:
We have a button here:
<Button>Click me</Button>
You probably also need a primary button to serve as your main action on a page. I used to like shaping the API just like you would say it - "Give me a primary button"
<Button>Click me</Button>
<Button primary>Click me</Button>
So pretty.
Now, as it goes with buttons, you probably need a few more. Here's what the props table ends up looking like:
name | description | type | default |
---|---|---|---|
primary |
used to indicate the main action | boolean |
false |
secondary |
used for actions which are less important | boolean |
false |
destructive |
indicate that the user should be cautious, example: delete | boolean |
false |
link |
used to style button similarly to a hyperlink | boolean |
false |
There are multiple props that can be used to change the appearance of the button. What is the expected outcome if someone uses them together?
<Button primary destructive>
Click me
</Button>
Will one of them win, which one? Is it dependent on the order?
I would always ask: Why would someone write that? Is this even a real use case - "Give me a primary destructive button"?
Most of the times, this would be by mistake. But, if the developers have to ask questions like the ones above, it's probably not a good API.
As someone who is deciding the API, it's your job to:
- minimise mistakes
- minimise confusions around the API
So here's tip #1 for you: Don't create conflicting props
We can fix our above code pretty easily by using one prop which allows a list of options: appearance
<Button appearance="default">Click me</Button>
<Button appearance="primary">Click me</Button>
<Button appearance="destructive">Click me</Button>
We can add a list of supported appearance
using prop-types.
Button.PropTypes = {
appearance: PropTypes.oneOf(['default', 'primary', 'secondary', 'link', 'destructive'])
}
Now, even if the developer makes a mistake, they will get a helpful warning on their developer tools.
<Button appearance="danger">Click me</Button>
Warning: Failed prop type:
Invalid prop `appearance` of value `danger` supplied to `Button`,
expected one of `["default","primary","secondary","link","destructive"]`
in Button
This tip is pretty easy to implement, but will make your API a lot easier to use (and maintain).
Hope this was helpful on your journey
Sid
Top comments (1)
Thanks, Sid.
The tradeoff was made (
appearance
a bit more verbose) but the outcome outweighs what's lost 👍.