Components

DhButton

Action button family split by role — DhPrimaryButton / DhSecondaryButton / DhTertiaryButton / DhErrorButton — with filled / outlined / text surfaces, the M3 Expressive five-size scale, two shapes with size-scaled corners and a press morph, icon slots, and built-in loading + disabled states.

Basic

Reach for the role that matches the action. Primary is the highest-emphasis filled button.

Light dh-button primary, md (light theme)
Dark dh-button primary, md (dark theme)
DhPrimaryButton(
    text = "Save",
    onClick = { save() }
)

Roles

Four role composables; each picks its own colour from the Material 3 colour scheme.

Light dh-button secondary, md (light theme)
Dark dh-button secondary, md (dark theme)
// Pick the composable that matches the action's role.
DhPrimaryButton(text = "Save", onClick = { save() })
DhSecondaryButton(text = "Cancel", onClick = { cancel() })
DhTertiaryButton(text = "Highlight", onClick = { promote() })
DhErrorButton(text = "Delete", onClick = { delete() })

Surface

Every role accepts a surface override. Defaults are Filled (Primary, Tertiary, Error) and Outlined (Secondary).

Light dh-button primary, md, outlined (light theme)
Dark dh-button primary, md, outlined (dark theme)
// Override the per-role default surface to lower the emphasis.
DhPrimaryButton(
    text = "Save",
    onClick = { save() },
    surface = DhButton.Surface.Outlined,
)

// Ghost / text-button equivalent.
DhSecondaryButton(
    text = "Skip",
    onClick = { skip() },
    surface = DhButton.Surface.Text,
)

Ghost (Secondary + Text)

Pair DhSecondaryButton with the Text surface for a transparent, label-only affordance — the KMP equivalent of Svelte's ghost variant.

Light dh-button secondary, md, text (light theme)
Dark dh-button secondary, md, text (dark theme)
DhSecondaryButton(
    text = "Skip",
    onClick = { skip() },
    surface = DhButton.Surface.Text,
)

Sizes

The M3 Expressive five-size scale: XSmall (32 dp), Small (40 dp), Medium (56 dp), Large (96 dp), XLarge (136 dp).

Light dh-button primary, lg (light theme)
Dark dh-button primary, lg (dark theme)
DhPrimaryButton(text = "Dense", onClick = {}, size = DhButton.Size.XSmall)
DhPrimaryButton(text = "Compact", onClick = {}, size = DhButton.Size.Small)
DhPrimaryButton(text = "Default", onClick = {})
DhPrimaryButton(text = "Prominent", onClick = {}, size = DhButton.Size.Large)
DhPrimaryButton(text = "Hero", onClick = {}, size = DhButton.Size.XLarge)

Shape

Square corners scale with size (12 dp on XSmall/Small, 16 dp on Medium, 28 dp on Large/XLarge); Round renders a pill. Both shapes morph to a smaller radius while pressed.

Light dh-button primary, md, round (light theme)
Dark dh-button primary, md, round (dark theme)
DhPrimaryButton(
    text = "Pill",
    onClick = {},
    shape = DhButton.Shape.Round,
)

Icons

Pass a composable for the leading or trailing slot — the button enforces a consistent icon size per geometry tier.

Light dh-button primary, md, start, icon (light theme)
Dark dh-button primary, md, start, icon (dark theme)
DhPrimaryButton(
    text = "Add",
    onClick = { add() },
    startIcon = { DhIcon(DhIcons.Plus, null, decorative = true) },
)

Loading

Replaces the leading icon with a spinner, hides the trailing icon, and blocks clicks. Announces progress via Compose semantics.

Light dh-button primary, md, loading (light theme)
Dark dh-button primary, md, loading (dark theme)
DhPrimaryButton(
    text = "Submit",
    onClick = { submit() },
    loading = isSubmitting,
)