Components

DhButton

Role-colour button (primary / secondary / tertiary / error / ghost) with a boolean outlined surface modifier, the M3 Expressive five-size scale, size-scaled corner radii, a subtle press scale, icon slots, and loading.

Variants

`variant` picks the role colour. Surface defaults to filled — except `secondary`, which outlines by default (the conditional default for the most common Cancel/Skip button).

<DhButton>Secondary</DhButton>                  <!-- bare default -->
<DhButton variant="primary">Primary</DhButton>
<DhButton variant="tertiary">Tertiary</DhButton>
<DhButton variant="error">Error</DhButton>
<DhButton variant="ghost">Ghost</DhButton>

Surface modifier

`outlined` is a boolean modifier; default is filled. It defaults to `true` for `secondary` and `false` for everything else; pass it explicitly to override.

<DhButton variant="primary">Filled (default)</DhButton>
<DhButton variant="primary" outlined>Outlined</DhButton>

<!-- Secondary's outlined default is true; pass outlined={false} to fill it. -->
<DhButton>Secondary outlined</DhButton>
<DhButton outlined={false}>Secondary filled</DhButton>

Sizes

The M3 Expressive five-size scale: `xs` (2rem), `sm` (2.5rem, default), `md` (3.5rem), `lg` (6rem), `xl` (8.5rem). Square corner radius scales with the size.

<DhButton variant="primary" size="xs">XSmall</DhButton>
<DhButton variant="primary" size="sm">Small (default)</DhButton>
<DhButton variant="primary" size="md">Medium</DhButton>
<DhButton variant="primary" size="lg">Large</DhButton>
<DhButton variant="primary" size="xl">XLarge</DhButton>

Shape

`square` (default) scales its corner radius with the size (`0.75rem` on xs/sm up to `1.75rem` on lg/xl). `round` sets the radius to half the height for a full pill.

<DhButton variant="primary">Square (default)</DhButton>
<DhButton variant="primary" shape="round">Round (pill)</DhButton>

With icons

<DhButton variant="primary"  startIcon="plus"    text="Create" />
<DhButton                    endIcon="arrow-right" text="Next" />
<DhButton variant="ghost"    startIcon="copy" endIcon="chevron-down" text="Copy" />
<DhButton variant="error"    startIcon="trash-2" text="Delete" />

States

Loading replaces the leading icon with a spinner; the label dims to `0.6` opacity, `aria-busy` is set, and clicks are blocked.

<DhButton variant="primary" text="Default" />
<DhButton variant="primary" text="Disabled" disabled />
<DhButton variant="primary" text="Loading"  loading={isLoading} onclick={simulateLoad} />

As submit in a form

`type='submit'` fires the surrounding form; `type='reset'` clears it. Type defaults to `'button'`.

Clicked 0 times
<form onsubmit={(e) => e.preventDefault()}>
  <DhButton type="submit" variant="primary" text="Submit" />
  <DhButton type="reset" text="Reset" />
</form>