Button
A button is a form: pressed, it acts. The button is the most basic interactive element in Malevich.
When to use
Use a button when the action happens on the current page (submitting
a form, opening a dialog, toggling a state). Use an anchor (<a>)
when the action navigates to a new page or scrolls to a section.
Variants
| Variant | Class | Use for |
|---|---|---|
| Primary | .button.-primary |
Primary CTA, hero conversions |
| Secondary | .button.-secondary |
Secondary actions, "Cancel" |
| Ghost | .button.-ghost |
Tertiary actions, low emphasis |
| Danger | .button.-danger |
Destructive actions |
| Success | .button.-success |
Positive confirmation actions |
v0.1.0 compatibility:
.button.-accentand.button.-neutralare retained as aliases for.button.-primaryand.button.-secondaryrespectively. They will be removed during the v0.2.0 codemod migration. New code should use the v1.0 names.
States
States are expressed via pseudo-classes and the disabled attribute.
The component handles them automatically — no manual class management.
| State | Trigger |
|---|---|
| Default | (initial render) |
| Hover | :hover |
| Active | :active or [data-active="true"] |
| Disabled | disabled attribute |
| Focused | :focus-visible |
[data-active="true"] is set by the runtime while keyboard activation
(Space/Enter) is held, giving keyboard users the same pressed visual
as mouse users.
Sizes
| Size | Class | Typography token | Use for |
|---|---|---|---|
| Small | .button.-s |
caption | Inline tools, table actions |
| Medium | (default) | body-support | Most cases |
| Large | .button.-l |
body-regular | Hero CTAs |
Anatomy
The author writes:
<button class="button -accent">Save</button>
After initButton runs, the DOM is:
<button class="button -accent" data-malevich-ready="true">
<span class="button__bg" data-tweak-layer="background" hidden></span>
<span class="button__glow" data-tweak-layer="glow" hidden></span>
<span class="button__content">
<span class="button__label">Save</span>
</span>
<span class="button__fx" data-tweak-layer="effects" hidden></span>
</button>
Tweak layers are hidden by default and have zero paint cost. A tweak
(e.g. t-glow-hover) unhides the layer it needs.
Tokens used
color.accent,color.accent-strong,color.ink-strong,color.ink-inverse,color.danger,color.border-strongfont.caption,font.body-support,font.body-regularradius.buttonspace.inset-element-s,space.inset-element-m,space.inset-element-lspace.gap-elements-smotion.fast,motion.easing-default
Tier 3 (component-specific):
button.background-disabled,button.text-disabled,button.border-disabledbutton.background-accent-active,button.background-danger-active,button.background-ghost-hover
Accessibility
- Use
<button>element, never<div role="button">. - Provide visible text label OR
aria-labelfor icon-only buttons.initButtonwarns on the console if a button has neither. disabledattribute prevents focus and interaction.- Focus visible via
:focus-visible— 2px outline usingcolor.accentwith 2px offset. - Pressed state on keyboard activation (Enter, Space) handled by the
browser; visual feedback comes from
:activeand the runtime's[data-active="true"]mirror.
Edge cases
- Icon-only buttons MUST set
aria-label. The runtime warns on console if it detects a button with no accessible label. - Loading state is not a built-in variant; compose with a tweak
(
t-loading) or replace the label content with a spinner element while disabling the button. - Within forms —
type="submit"is the default; usetype="button"for non-submit actions.
Do
- Use the variant that matches action priority — one accent button per region.
- Keep button labels short (1–3 words ideal, 5 maximum).
- Use icon + label for clarity; avoid icon-only unless space-constrained.
Don't
- Don't use multiple accent buttons next to each other.
- Don't style buttons with raw CSS values; use the variant system.
- Don't replace
<button>with<a>for actions that don't navigate. - Don't disable buttons silently; consider a tooltip explaining why.
Related
Input— for text entryDialog— buttons commonly appear in dialog actionsCard— buttons commonly appear as card actions- Tweak
t-glow-hover— adds subtle glow on hover for accent buttons - Tweak
t-loading— placeholder for loading-state spinner