Showcase Icons Layout v0.3.0-rc.6

Button

Triggers an action. The most-used primitive in the system. Available in 5 sizes and 4 variants, with brand-specific hover/press personality coming from tokens.css.

Stable Introduced: v0.1.0 Class: .fam-btn Source: tokens.css

Anatomy

Five parts. Padding and gap come from spacing tokens; radius from --radius-lg2 (12px); height from --control-h-*.

padding Place trade label icon radius · 12px

When to use

  • Triggering a primary action ("Place trade", "Confirm withdrawal", "Send")
  • Triggering a destructive action ("Cancel order", "Delete account") — always with the --danger variant
  • Submitting a form

When NOT to use

  • For navigation — use a link (<a>) styled like a button if it changes the URL. Buttons are for actions, not navigation.
  • For toggling state — use a switch or checkbox instead.
  • As a tab trigger — use the .fam-tab primitive inside a .fam-tablist.

Variants

Four variants, each rendered identically across all 3 brands but tinted with that brand's primary color.

Perpetuals
Barriers
UpsideOnly
VariantClassUse case
Primary.fam-btn--primaryThe most important action on a surface. One per surface, ideally.
Secondary.fam-btn--secondaryAlternative action — same row as primary, different weight.
Ghost.fam-btn--ghostTertiary or de-emphasized. Common for "Cancel" next to a destructive primary.
Danger.fam-btn--dangerDestructive primary. "Delete account", "Cancel order". Use sparingly.

Sizes

5 sizes mapping to --control-h-* tokens.

SizeHeightPaddingRadiusUse
--sm32px4px / 12px10px (lg)Toolbars, table-row actions, compact UI
--md38px6px / 12px12px (lg2)Default. Forms, inline actions
--lg42px10px / 16px12px (lg2)Card CTAs, modal footer
--xl48px14px / 16px12px (lg2)Hero CTA, "Submit Trade", primary form action
--icon38×3809999px (pill)Icon-only. Always include aria-label.

States

Hover/active states are brand-specific via the motion vocabulary. Hover the buttons below to feel the difference.

Perpetuals · −2px lift
Barriers · no transform
UpsideOnly · −3px + 1.045 scale

Code

Pick your framework. HTML works today; React/Angular wrappers ship in v0.5.

<!-- Wrap any subtree in [data-brand] to set brand colors -->
<div data-brand="upsideonly">
  <button class="fam-btn fam-btn--primary fam-btn--xl">
    Submit Trade
  </button>

  <button class="fam-btn fam-btn--ghost fam-btn--md">
    Cancel
  </button>

  <!-- Icon-only: always include aria-label -->
  <button class="fam-btn fam-btn--primary fam-btn--icon"
          aria-label="Settings">
    <svg.../>
  </button>
</div>

Props / API (v0.5)

Available once the framework wrappers ship in v0.5. Until then, use the CSS classes directly — the modifier classes are 1:1 with these props.

PropTypeDefaultDescription
variant'primary' | 'secondary' | 'ghost' | 'danger''primary'Visual treatment
size'sm' | 'md' | 'lg' | 'xl' | 'icon''md'Height + padding scale
disabledbooleanfalseGreys out + cursor:not-allowed
loadingbooleanfalseShows inline spinner, disables clicks. Coming in v0.5.
iconLeftReactNodeIcon before label
iconRightReactNodeIcon after label
onClick(e) => voidClick handler
type'button' | 'submit' | 'reset''button'Native button type

Accessibility

Keyboard

  • Tab — moves focus to the button (in document order)
  • Enter or Space — activates the button (when focused)
  • Focus-visible outline uses --brand-primary with a 2px outline + 2px offset

Screen reader

  • Native <button> element is announced as "button"
  • For icon-only buttons, aria-label is required (the visible icon doesn't read as text)
  • For toggle-state buttons, use aria-pressed instead of styling alone
  • For loading state, set aria-busy="true" while async work runs

Compliance

  • Touch target — All sizes md and above (38px+) meet the 44×44 minimum when padding is included. SM (32h) is below — use only in dense desktop UI, never primary mobile actions.
  • Color contrast — Primary variants meet 4.5:1 on their backgrounds (verified in /layout audit)
  • Reduced motion — Hover transforms are killed when prefers-reduced-motion: reduce

Do's and Don'ts

Use a verb that matches the action. Be specific.
Use generic verbs that could mean anything.
One primary per surface. The primary is the most likely next step.
Two primaries. The user can't tell which one to pick.
Use danger variant for destructive actions, paired with a ghost cancel.
Use danger variant for non-destructive actions just for emphasis.

Changelog

v0.3.0-rc.6First per-component documentation page (this one). Sets the template for v0.4.
v0.2.0Renamed UpSideOnlyUpsideOnly.
v0.1.0Initial release. 5 sizes × 4 variants × 3 brands. Brand-specific motion personality (warm / minimal / springy).