Button
A Button is a interactive element which triggers an action.
Overview
When to use
- To communicate actions users can take in a page.
- To move into another step in a flow.
- To close modals.
- To submit forms.
When not to use
- To navigate the user into another URL or context. (Use Links instead)
- To open something in another browser tab.
When using buttons outside our products:
- Buttons may be used for navigating users into our products or institutional page.
- Externalization indicators (icons) may be customized to better suit the button's context.
Anatomy
- IconBefore: Icon complementing text label context.
- Text Label: Text indicating the action.
- IconAfter: Icon indicating the action type of the button (such as opening a dropdown or opening in a new tab).
Building Guidelines
- Its width may be set manually, otherwise it always extend 100% of parent width.
Variants
Primary button is the standard surface button, used for most actions across the interface. Its muted green tone (#739584) keeps it visually neutral while still clearly interactive. Use it as the default choice unless the action requires extra emphasis or caution.
Accent button is used to draw attention to key actions that need to stand out, such as confirming a flow or highlighting a promoted action. Its bright green (#37BB89) makes it immediately noticeable. Use sparingly — one per context to maintain effectiveness.
Negative button is used to provide caution when the user is about to make a destructive action (e.g. delete, remove). Its red tone (#ff4e4c) with matching red bevels signals danger clearly.
Button with Icon
Icon before text
Icons are placed before text to complement its context.
Icon after text
Icons are placed after text to indicate which action will be triggered (e.g.: using a chevron icon to indicate a dropdown, or external icon to indicate navigation patterns).
Two icons display
Buttons can support displaying two icons simultaneously—one before and one after the text.
Icon Button
Use size="icon" for square, icon-only buttons — e.g. close, settings, or edit actions. This variant renders a fixed 24×24 container with minimal padding, inheriting all variant bevels and states from the base Button.
- Always provide an
aria-labelfor accessibility. - Pass the icon as
children, not vialeftIcon/rightIcon. - Works with all color variants (primary, accent, negative).
Sizes
Medium (default) Is the most common use cases of a button, it's height aligns with input fields and other common UI elements, also provides an acceptable interactive area for mobile devices.
Large is the most common use case for mobile, providing the largest interactive area. It may also be used with big headings or text sections.
Small is used for compact UI situations, such as providing actions inside a table or inside a small card component. This size may not be used for mobile devices.
Icon is a square button for icon-only actions. See the Icon Button section above for usage guidelines.
States
Default
Default state is how the button is initially presented to the user, regardless of being interacted with or not.
Hover
On hover, a brightness(0.9) filter darkens the button surface. Triggered by :hover on non-disabled buttons.
Motion animation — cubic-bezier(0.3,0.02,0.7,0.02) 120ms
Pressed / Active
On press, the bevel inverts (raised → sunken) and the button shifts 1px diagonally to simulate physical depression. Triggered by :active.
Motion animation — cubic-bezier(0.3,0.02,0.7,0.02) 120ms
Disabled
Disabled state is for when users cannot perform an action due to another pendency on the same context. It should be clear why a button is disabled — clarify via a form or helper text nearby.
Interactions (Web Only)
Hover
Hover state of a primary button.
Motion animation — Color changes using the bezier and transition time below.
cubic-bezier(0.3,0.02,0.7,0.02) 120ms
Focus
Focus state indicates which button is focused on keyboard navigation.
Controls
Interactive controls are available in Storybook. Open Storybook
Props
Token mapping
| Variant | Property | Token |
|---|---|---|
| primary | background | --color-accent-primary |
| primary | active background | --bevel-highlight |
| accent | background | pending tokenization |
| accent | active background | pending tokenization |
| negative | background | pending tokenization |
| negative | active background | pending tokenization |
| all | text color | --color-text-on-accent |
| primary / accent | raised bevel | --sunken-outer-light, --sunken-outer-dark, --sunken-inner-light, --sunken-inner-dark |
| negative | raised bevel | pending tokenization |
Changelog
| Date | Change |
|---|---|
| 2026-03-22 | Added size="icon" variant for square icon-only buttons; children prop is now optional |
| 2026-03-22 | Variant rename: secondary → accent; per-variant bevel colors (green for primary/accent, red for negative); icons switched to custom pixelarticons wrappers; active state uses sunken bevel + translate for Win95 press effect |
| 2026-03-22 | Migrated to shadcn pattern (CVA + Tailwind); Win95 beveled borders |
| 2026-03-15 | Stories updated to use Phosphor Shapes icon matching Figma mockups; extra non-Figma content removed from MDX; markdown tables converted to HTML |
| 2026-03-15 | CSS: explicit height per size (sm:24px md:32px lg:40px); states via filter:brightness(); disabled opacity 0.4; transition cubic-bezier from Figma |
| 2026-03-15 | MDX copy updated to exact Figma text |
| 2026-03-15 | Full docs from Figma — anatomy, guidelines, all states and interactions |
| 2026-03-14 | Migrated to TypeScript; renamed disabled → isDisabled |
| 2026-03-14 | Initial component created |