ButtonVariant is the visual emphasis setting for Button. It answers a simple design question: how loudly should this action speak? In a real app, not every button should look equally important. The variant lets you express primary, secondary, and low-emphasis actions without changing the underlying action flow.
Example
use fission::prelude::*;
let primary = Button {
variant: ButtonVariant::Primary,
child: Some(Text::new("Save").into()),
on_press: Some(save_action),
..Default::default()
};
let secondary = Button {
variant: ButtonVariant::SecondaryGray,
child: Some(Text::new("Preview").into()),
on_press: Some(preview_action),
..Default::default()
};
let destructive = Button {
variant: ButtonVariant::Destructive,
child: Some(Text::new("Delete").into()),
on_press: Some(delete_action),
..Default::default()
};
All three buttons use the same runtime action path. The variant changes visual
hierarchy, not how the action is dispatched.
Choice table
| | | |
|---|
| | Primary action hierarchy. | Filled is the default compatibility name; both resolve the design system's primary recipe. |
| | Neutral secondary hierarchy. | Use for an alternative that should remain clearly actionable without competing with the primary action. |
| | Neutral tertiary hierarchy. | Use for toolbars and low-emphasis utility actions. |
| | Brand-colored secondary hierarchy. | Keeps brand emphasis while remaining subordinate to Primary. |
| | Brand-colored tertiary hierarchy. | Appropriate for a quiet action that still benefits from brand color. |
| | Brand-colored link hierarchy. | Use only when an action should visually read as a link-like control. |
| | | Quietest link-like action treatment. |
| | Destructive action hierarchy. | Reserve for actions with harmful or difficult-to-reverse consequences. |
How to choose
Use Primary for the action you most want the user to notice right now. Use a
secondary hierarchy when the action is important but not dominant. Use a
tertiary hierarchy when the action should stay available without pulling focus
away from the main task. The Filled, Outline, and Ghost names remain useful
shorthands for the primary, neutral-secondary, and neutral-tertiary choices.
Do not treat variants as random styling choices. If every action on a screen is filled, nothing feels primary. If every action is ghost, important flows can disappear into the interface.
Specific advice
Keep the meaning of each variant stable across your product. If Filled means "commit the main action" on one screen but "tiny utility action" on another, users have to relearn the hierarchy every time.
Production checklist
For ButtonVariant, review the action hierarchy and consequence before treating the control as finished. The goal is to make importance visible without turning every action into the loudest action on the screen.
If this widget appears inside an interactive flow, keep the surrounding action binding in the parent component and test that the flow still has one clear reducer path.
Check the semantics tree for the user-facing label or role that makes this widget understandable without relying only on pixels.
Add at least one component or harness test that confirms the visible text, semantic role, action dispatch, and layout constraint that matter for this widget in context.
If a screen starts repeating the same ButtonVariant setup, extract a named component around this widget. That keeps the reference API small while making product code easier to read and safer for generated code to copy.