Buttons
Buttons are the clearest invitations to act—submitting a form, confirming a dialog, or advancing a workflow. Their affordances must be unmistakable, from color and weight to the way icons sit beside copy, so people can identify primary actions without rereading the entire interface vocabulary.
The patterns below cover base styling, color systems (including the expressive Catppuccin palette), and variations like loading states, icon labels, sizes, and button groups. Use them to keep interaction density predictable while still telling a cohesive story across modules, so every call-to-action feels like part of a single design language.
Regular buttons
Default buttons provide the baseline chrome for actions that sit outside special contexts like toolbars or cards. Use the neutral version for secondary flows, pair it with helper icons when space is tight, and lean on the predefined hover, focus, and active states so the button communicates interactivity even without motion.
Always set an explicit type (type="button" vs. submit) to avoid surprising form submissions, and ensure every button text or icon has a clear, localized label so screen readers can announce the action.
<button>...</button>
<button class="hover">...</button>
<button class="focus">...</button>
<button class="active">...</button>
<button disabled>...</button>
<button><svg class="icon">...</svg></button>
States from ARIA. A state that screen readers need to hear can be set with an ARIA attribute instead of a class, and the button looks the same: aria-pressed="true" for a toggle that is on, aria-expanded="true" for a button whose menu is open, aria-disabled="true" for a button that is unavailable but can still be reached with the keyboard, and aria-busy="true" for a button that is loading. The look and the announcement then come from one attribute and can’t disagree.
<button type="button" aria-pressed="true">Bold</button>
<button type="button" aria-expanded="false">Menu</button>
<button aria-disabled="true">Save</button>
<button aria-busy="true">Saving</button>
Colors
Color-coded buttons establish hierarchy at a glance: Primary commands drive the main flow, Secondary buttons support alternative paths, while Positive and Negative treatments reinforce the intent of confirmation or caution. Reuse these roles consistently so returning readers can predict what will happen before they press the control.
<button class="primary">Primary</button>
<button class="secondary">Secondary</button>
<button class="positive">Positive</button>
<button class="negative">Negative</button>
<button class="radiant">Radiant</button>
Catppuccin hues add a more expressive layer while staying balanced. Reference the Catppuccin palette when theming knobs, menu chips, or contextual actions so the broader system retains cohesion, especially when pairing icons with warm gradients and dark surfaces.
<button class="rosewater">...</button>
<button class="flamingo">...</button>
<button class="pink">...</button>
<button class="mauve">...</button>
<button class="red">...</button>
<button class="maroon">...</button>
<button class="peach">...</button>
<button class="yellow">...</button>
<button class="green">...</button>
<button class="teal">...</button>
<button class="sky">...</button>
<button class="sapphire">...</button>
<button class="blue">...</button>
<button class="lavender">...</button>
E-ink: in the e-ink theme a button has one of three looks. A regular button is outlined; radiant and the palette colors are light grey; primary, secondary, positive, negative and midnight are black with white letters. A positive and a negative button then look the same, so let the words on the button say what it does.
Loading / Success states
Stateful buttons keep users oriented during async work. Swap in the loading variant the moment a submission begins, then transition to success when the operation completes so the button itself narrates progress without forcing someone to hunt for a detached status message.
Preserve button width when swapping labels or spinners to prevent layout shift, and expose the same status via aria-live regions so assistive tech can announce completion. aria-busy="true" on the button gives the same look as the class loading. When the visitor has asked for less motion, the icon keeps turning, slowly.
<button class="loading">...</button>
<button class="loading success">...</button>
E-ink: in the e-ink theme nothing moves, so the icon of a loading button stands still. The button still looks different from a button at rest, but give a wait of more than a moment a text as well.
Labels
Button labels pair supporting text or icons with the main caption to clarify meaning. Use the .label span for prepended glyphs, counters, or statuses so spacing and alignment stay consistent whether the label contains an SVG or short word like “New”.
<button>
<span class="label">
<svg class="icon"></svg>
</span>
...
</button>
<button>
<span class="label">Label</span>
...
</button>
Sizes
Size variants adapt buttons to the scale of their surroundings: Mini works well inside dense tables, while Massive anchors hero zones or confirmation modals. Mix sizes sparingly on a single screen so users can infer importance from weight without relearning padding math.
Keep targets large enough: WCAG 2.2 asks for at least 24 by 24 pixels, or enough space around a smaller target, and 44 by 44 pixels is better for touch. The smallest sizes here are for dense tables and toolbars on large screens; keep icon buttons square so that people can predict the tap target.
<button class="mini">...</button>
<button class="small">...</button>
<button class="medium">...</button>
<button>...</button>
<button class="large">...</button>
<button class="big">...</button>
<button class="huge">...</button>
<button class="massive">...</button>
Groups
Button groups bundle related actions so people can compare options side by side—ideal for pagination, segmented controls, or contextual toolbars. Wrap them in .group to keep borders merged and spacing uniform across different color schemes.
Manage focus order so each grouped button remains reachable via tabbing, and add aria-pressed or role="group" metadata when the collection acts like a toggle set. Doing so lets assistive tech describe the relationship and prevents navigation traps.
<div class="group">
<button>...</button>
<button>...</button>
<button>...</button>
<button disabled>...</button>
</div>