Button

 is used to trigger interactions.

variant
solid | soft | ghost | outline
size
micro | tiny | small | medium | large
color
accent | blue | red | amber | black
shape
square | round
loading
boolean
disabled
boolean

Component design

Most  Button components limit you to two appearance props: variant and size.
You might use variant="primary" for a button like this:

Great! But what if it just feels too strong on the page, yet you still want a primary button? This is where the variant prop breaks down because it couples color and appearance.

Alas, your next best option is a variant="secondary" button which might give you something more muted like this:

DD Button works with three props: variant, color, and size.

Variant does not impose color, only appearance. Which allows you to have not just one Primary button, but 4 unique ones for different interfaces.

The amount of combinations compounds because there are 5 colors: accent, red, blue, amber, and black.


Feature showcase

Smooth transitions between loading states

Animating margin-left on an inner element also animates the parent width, without ResizeObserver

Prefix, suffix, and tight interation with components like  Kbd and  Tooltip

Control the rendered element with the render prop

<Button render={<Link href="/" />}>
Home
</Button>

On light mode,  Button becomes darker on press, and lighter on inverted variants or on dark mode.

Each variant responds with an unique sound. Disabled on mobile because most operating systems will actually pause any playing music to play the sound which is very jarring.


Force press

Using the non-standard Safari-only webkitmouseforcedown event, we can detect when a user is pressing down on a button with enough pressure to trigger a force press.

If so, the button gets scaled down even further from 0.97 to 0.94.

Force press is available on macOS Safari

Naturally, this will only work on devices with a pressure-sensitive, proprietary Apple trackpad.


Dynamic spinner

Loading states are represented by a loader that re-calculates its arc length and motion config after each cycle, resulting in a more varied and natural response.


Disabled states

Most buttons have two commonly used states: loading and disabled. And generally they both get applied when the button is loading.

becomes gray when loading

My opinionated take is that these two states are discrete. Meaning, buttons do not need to become visually disabled when loading, only functionally.

This approach reduces cognitive load because the button no longer jarringly transitions from an accent color to gray. Only the not-allowed cursor gets applied.

retains color when loading

Perhaps we need an exception for non-pointer devices. But my hot take is that communicating disabled state is unimportant as long as the button provides some feedback with a pressed and loading state.

People are smart enough to figure out what's happening if a button is loading, I think.