Primary and supporting actions
This is the default pattern for forms, drawers, and dialogs.
<CwButton variant="primary">Save changes</CwButton>
<CwButton variant="secondary">Preview</CwButton>
<CwButton variant="ghost">Cancel</CwButton>All variant × size × state combinations.
<CwButton variant="primary">Save Changes</CwButton><script lang="ts">
import moreVertIcon from '$lib/icons/more_vert.svg';
</script>
<CwButton variant="secondary" aria-label="Refresh data">
<svg viewBox="0 0 16 16" fill="none" aria-hidden="true">
<path
d="M12.8 7.9A4.8 4.8 0 118 3.2c1.3 0 2.5.5 3.4 1.4"
stroke="currentColor"
stroke-width="1.4"
stroke-linecap="round"
/>
<path
d="M11.7 3.2h2.4v2.4"
stroke="currentColor"
stroke-width="1.4"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</CwButton>
<CwButton variant="primary" aria-label="More actions" icon={moreVertIcon} />
<CwButton variant="primary" icon={moreVertIcon}>More</CwButton>CwButton is the standard action component. Use it for labeled actions, icon-and-text buttons, and icon-only controls that still need a proper accessible name.
The docs table lists the CWUI-specific API. Native button attributes still pass through.
| API | Type | Details |
|---|---|---|
variant Default: | 'primary' | 'secondary' | 'ghost' | 'danger' | 'info' | Visual treatment for the action. |
size Default: | 'sm' | 'md' | 'lg' | Padding and font scale. |
loading Default: | boolean | Shows the built-in spinner and disables the button. |
disabled Default: | boolean | Prevents interaction without showing a loading spinner. |
fullWidth Default: | boolean | Expands the button to the width of its container. |
icon | string | { src: string } | { default: string } | Snippet | Optional leading icon asset or snippet. For icon-only buttons, pair it with `aria-label`. |
children | Snippet | Button content. This can be text, icon-only markup, or mixed inline content. |
...native button attrs | HTMLButtonAttributes | Pass `type`, `name`, `value`, `aria-*`, `onclick`, and standard button attributes directly to the underlying `<button>`. |
These snippets intentionally show the full public API surface the live demo relies on.
This is the default pattern for forms, drawers, and dialogs.
<CwButton variant="primary">Save changes</CwButton>
<CwButton variant="secondary">Preview</CwButton>
<CwButton variant="ghost">Cancel</CwButton>Use `loading` instead of manually wiring your own spinner.
<script lang="ts">
let saving = $state(false);
async function submitForm() {
saving = true;
await new Promise((resolve) => setTimeout(resolve, 900));
saving = false;
}
</script>
<CwButton
variant="primary"
size="lg"
fullWidth
type="submit"
loading={saving}
onclick={submitForm}
>
Save irrigation plan
</CwButton>Use inline markup when you want full control, or `icon={...}` when you already have an asset import.
<script lang="ts">
import moreVertIcon from '$lib/icons/more_vert.svg';
</script>
<CwButton variant="secondary" aria-label="Refresh data">
<svg viewBox="0 0 16 16" fill="none" aria-hidden="true">
<path
d="M12.8 7.9A4.8 4.8 0 118 3.2c1.3 0 2.5.5 3.4 1.4"
stroke="currentColor"
stroke-width="1.4"
stroke-linecap="round"
/>
<path
d="M11.7 3.2h2.4v2.4"
stroke="currentColor"
stroke-width="1.4"
stroke-linecap="round"
stroke-linejoin="round"
/>
</svg>
</CwButton>
<CwButton variant="primary" aria-label="More actions" icon={moreVertIcon} />