Skip to content

Buttons

Buttons are the primary call-to-action elements. Naluma uses two variants — primary (filled) and secondary (outlined) — kept deliberately simple. The brand personality leans 65% toward Companion, which means CTAs should suggest rather than demand. Button copy should be specific and forward-looking (“Start tonight’s session” not “Get started”).

Token source: tokens/component/button.json

Default
Hover
Active
Disabled
Focus
Default
Hover
Active
Disabled
Focus
Large (16px / 16px 32px)
Medium (14px / 12px 24px)
Small (13px / 8px 16px)
Primary — icon left
Primary — icon right
Secondary — icon left
Large
Medium
Small
Primary — Large
Primary — Medium
Primary — Small
Secondary — Large
Secondary — Medium
Secondary — Small

The primary button is the main action on any screen. It uses the burnt-sienna-deep color family — the warm earth tone that carries forward-motion energy within the calm palette.

PropertyTokenResolved value
Backgroundsemantic.color.action.primary
#A55838
Background (hover)semantic.color.action.primary-hover
#914D31
Background (active)semantic.color.action.primary-active
#80442B
Textprimitive.color.white#FFFFFF
Border radiusprimitive.radius.md8px
Font weightprimitive.font-weight.semibold600
Transitionprimitive.transition.fast150ms ease

The secondary button is for supporting actions. It is transparent with a 2px border and uses the dark-burgundy color family in light mode.

PropertyTokenResolved value
Backgroundtransparent
Background (hover)rgba(134, 59, 61, 0.08)
Background (active)rgba(134, 59, 61, 0.15)
Textsemantic.color.action.secondary
#863B3D
Border colorsemantic.color.action.secondary#863B3D
Border width2px
Border radiusprimitive.radius.md8px
Font weightprimitive.font-weight.semibold600
Transitionprimitive.transition.fast150ms ease

In dark mode, the secondary button flips its color reference for contrast:

PropertyDark mode tokenResolved value
Textsemantic.color-dark.action.secondary
#F9DFAE (pale-wheat)
Border colorsemantic.color-dark.action.secondary#F9DFAE
Text (hover)semantic.color-dark.action.secondary-hover
#F2C087 (warm-gold)

Buttons have three sizes, each with separate specs for app (Flutter) and web (WordPress). App sizes enforce a 44px minimum touch target per accessibility requirements.

PropertyAppWeb
Padding Y12px (spacing.12)16px (spacing.16)
Padding X24px (spacing.24)32px (spacing.32)
Font size16px (font-size.16)16px (font-size.16)
Min height44px
PropertyAppWeb
Padding Y8px (spacing.8)12px (spacing.12)
Padding X16px (spacing.16)24px (spacing.24)
Font size14px (font-size.14)14px (font-size.14)
Min height44px
PropertyAppWeb
Padding Y6px (spacing.6)8px (spacing.8)
Padding X12px (spacing.12)16px (spacing.16)
Font size12px (font-size.12)13px (font-size.13)
Min height44px

Note that even the small app button maintains a 44px minimum height. The smaller padding and font size provide visual hierarchy without sacrificing touch target size.


Disabled buttons reduce opacity to primitive.opacity.disabled (0.4) and suppress all interaction feedback. They should be used sparingly — the companion personality favors guiding users away from unavailable actions rather than showing greyed-out options.

On press, the button scales to 0.98 (the active-scale token). This is a subtle physical feedback that reinforces the “settling” motion language — a gentle compression rather than a bounce.

Focus is indicated by a ring around the button:

PropertyValue
Ring colorsemantic.color.focus.ring (#A55838)
Ring width2px
Ring offset2px

The focus ring uses the primary action color to maintain warmth. In dark mode, it shifts to semantic.color-dark.focus.ring (#F2C087, warm-gold).


Buttons can include icons from the Lucide icon system for visual reinforcement. Two patterns are supported: icon + text and icon only.

Pair an icon with a text label to reinforce the action. Place the icon on the leading side (left in LTR) for action reinforcement (“Start session” with a play icon), or on the trailing side (right) for directional cues (“Continue” with an arrow).

Use icon-only buttons when the icon is universally understood (plus, close, share, edit) and space is constrained. Icon-only buttons use square padding for a balanced shape.

PropertyTokenResolved value
Icon-text gapcomponent.button.icon.gap8px (spacing.8)
Icon size (lg)component.button.icon.size-lg20px (spacing.20)
Icon size (md)component.button.icon.size-md16px (spacing.16)
Icon size (sm)component.button.icon.size-sm16px (spacing.16)
Icon-only padding (lg)component.button.icon.only-padding-lg12px (spacing.12)
Icon-only padding (md)component.button.icon.only-padding-md8px (spacing.8)
Icon-only padding (sm)component.button.icon.only-padding-sm6px (spacing.6)

Icon color inherits from currentColor, matching the button text color automatically in both variants and both light/dark modes.


  • One primary button per screen. Multiple primary buttons create competing urgency, which conflicts with the Still personality position.
  • Button copy should be specific. “Begin sleep session” not “Continue.” “Learn what’s happening” not “Read more.”
  • Avoid disabled buttons where possible. Guide the user toward available actions instead.
  • Never use buttons for navigation-only actions. Use text links or navigation patterns instead — buttons imply that something will happen, not that you will go somewhere.
  • Icon-only buttons must have aria-label. The visual icon alone is not sufficient for screen readers.
  • Prefer icon + text over icon-only for actions that aren’t universally recognizable. When in doubt, add a label.
  • Icon color is automatic. Icons use currentColor — no manual color management needed across variants or dark mode.