Basics

Buttons

Action hierarchy, sizing, and states for common WAfM workflows.

Button playground

Explore variants and states. Drag the right edge to resize the frame.

Preview size

Properties

Buttons fit their label by default. Fill frame stretches text buttons to the available width. Icon buttons stay square; long labels stay on one line and may overflow a narrow frame.

Button hierarchy

Use one primary action per decision area and quieter variants for supporting actions.

Button sizes

Compact 24–40px controls use consistent typography and 16px icon slots.

Buttons with text and icons

Use Phosphor icons from @phosphor-icons/react. A leading icon reinforces an action, and a trailing icon indicates direction. The visible text names the action; decorative icons are hidden from assistive technology.

Button groups

Group related actions with a shared accessible label. Each action remains independently reachable with Tab.

Bookmark toggle

Keep the accessible label stable: pressed means bookmarked. Supports controlled or uncontrolled state; the application owns persistence.

Not bookmarked
Select an action to preview its feedback.

Usage and props

Import shared components from @wafm/ui. Keep workflow state and data fetching in the application.

Button
import { Button } from '@wafm/ui/components/button'

<Button variant="outline" size="sm" disabled={isSaving}>Save changes</Button>
variant
default (primary), secondary, outline, ghost, destructive, or link.
size
default, xs, sm, lg, icon, icon-xs, icon-sm, or icon-lg.
disabled
Prevents activation. Explain the reason when it is not obvious.
render / nativeButton
Use render={<Link to="/" />} and nativeButton={false} role="link" for a router link. Icon-only buttons require an accessible label.
IconButton
import { PencilSimpleIcon } from '@phosphor-icons/react'
import { IconButton } from '@wafm/ui/components/icon-button'

<IconButton aria-label="Edit profile" variant="outline" onClick={onEdit}><PencilSimpleIcon aria-hidden="true" /></IconButton>
aria-label
Required action name for assistive technology; label the action, not the icon.
size / variant
Uses Button variants and icon, icon-xs, icon-sm, or icon-lg sizes. Defaults to type="button".
Link
import { Link } from '@wafm/ui/components/link'

<Link href="/help">Read the guide</Link>
href / render
Use a real href for navigation. render composes with your router link.
target
For a new tab, add rel="noreferrer" and announce that it opens a new tab. Links have no disabled state; omit unavailable destinations.
ButtonGroup
import { ButtonGroup } from '@wafm/ui/components/button-group'
import { Button } from '@wafm/ui/components/button'

<ButtonGroup aria-label="Editing actions">
  <Button variant="outline">Edit</Button>
  <Button variant="outline">Duplicate</Button>
</ButtonGroup>
aria-label
Required description of the related actions. Each control remains in the normal Tab order.
orientation
horizontal (default) or vertical. This groups actions; it does not manage selection.
BookmarkToggle
import { BookmarkToggle } from '@wafm/ui/components/bookmark-toggle'

<BookmarkToggle aria-label="Bookmark participant" pressed={bookmarked} onPressedChange={setBookmarked} />
pressed / onPressedChange
Controlled toggle state. Use defaultPressed for uncontrolled state. Persistence belongs to the application.
aria-label / disabled
Keep the required label stable; aria-pressed announces selection. disabled prevents pointer and keyboard activation.
DropdownMenu
import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from '@wafm/ui/components/dropdown-menu'
import { Button } from '@wafm/ui/components/button'

<DropdownMenu>
  <DropdownMenuTrigger render={<Button />}>Actions</DropdownMenuTrigger>
  <DropdownMenuContent>
    <DropdownMenuItem onClick={onRename}>Rename</DropdownMenuItem>
  </DropdownMenuContent>
</DropdownMenu>
open / onOpenChange
Optional controlled open state on the root. The menu supports keyboard navigation, typeahead, Escape, outside dismissal, and focus restoration.
DropdownMenuItem
onClick supports pointer and keyboard activation. disabled prevents activation while keeping the action discoverable with arrow keys. variant="destructive" marks a destructive action; the app owns confirmation.
DropdownMenuCheckboxItem
Use checked and onCheckedChange for a menu preference; the menu closes after selection by default.
DropdownMenuContent
Portalled content supports align and side, with viewport collision handling. Group, Label, and Separator organise related actions.
AccountMenu
import { AccountMenu } from '@wafm/ui/components/account-menu'

<AccountMenu name="Eva Muster" initials="EM" triggerLabel="Open account menu" profileLabel="Profile and settings" signOutLabel="Sign out" onProfileSelect={onProfile} onSignOutSelect={onSignOut} />
name / email / initials / imageSrc
Identity display with optional email and image. Initials are the fallback for a missing or failed image.
triggerLabel / profileLabel / signOutLabel
Caller-provided labels support the application language.
onProfileSelect / onSignOutSelect
Required callbacks. Routing and authentication remain in the application; this component performs neither itself.