Buttons
Use the koala-btn tag helper
on <button> and
<a> elements.
Supports colours, variants, and composition with koala-loading.
Colours
Four colours, each tied to a clear role. Primary is filled --color-primary (sage green) — the page-level CTA (Submit, Save, Invite).
Secondary is filled --color-secondary (dark navy) — branded but lower-emphasis than Primary, for actions that aren't the main page CTA but still want brand weight.
Outline is white surface + neutral border — Cancel, Back, Close, in-section CTAs, persistent global CTAs.
Danger is filled red — destructive confirmation.
<button koala-btn="Primary">Primary</button> <button koala-btn="Secondary">Secondary</button> <button koala-btn="Outline">Outline</button> <button koala-btn="Danger">Danger</button>
Outlined variant
Use koala-btn-variant="Outlined"
for destructive triggers like "Cancel quote" or "Disable partner".
<button koala-btn="Danger" koala-btn-variant="Outlined">Outlined</button>
Example — destructive flow
Pairing in practice: an outlined trigger that opens a confirmation, with a filled variant inside the modal as the final commit.
<!-- Trigger (on the page) --> <button koala-btn="Danger" koala-btn-variant="Outlined">Cancel quote</button> <!-- Confirm (inside the modal) --> <button koala-btn="Danger">Yes, delete</button>
Links as buttons
The tag helper works on <a> elements too.
Use for navigation actions like "New quote" in page headers.
<a href="/partner/quotes/create" koala-btn="Primary">Primary</a> <a href="/partner/partners/create" koala-btn="Outline">Outline</a>
Loading state
Add koala-loading to submit buttons.
The tag helper auto-adds a spinner SVG, click guard, and disabled styling to prevent double-submits.
On click, the button shows a spinner and becomes disabled until the form response completes.
Click a button to see the loading state. The button enters the loading state until the form response arrives; here there's no form, so click again to reset by reloading the page.
<!-- Add koala-loading on a submit button. The tag helper auto-injects
x-data, a click guard, disabled styling, and a spinner SVG that
replaces the label on click. Loading state lasts until the form
response arrives. -->
<form method="post">
<button type="submit" koala-loading koala-btn="Primary">Primary</button>
</form>
The koala-loading tag helper automatically injects Alpine.js
x-data, a click guard to prevent double-submits,
opacity and disabled styling while loading, and a spinner SVG that replaces the button text. It also disables every other
<button> and
<a> inside the same
<form> (e.g. Back/Cancel) so users can't double-submit or
navigate away mid-submit. State resets when the form response arrives.
Exceptions: search buttons, sign out buttons, and instant-action buttons do not need spinners.
With icons
Place a <koala-icon> inside the button as child content.
Add gap-2 to the button's class to space the icon from the text.
<a href="/partner/quotes/create" koala-btn="Primary" class="gap-2">
<koala-icon name="Plus" size="Small" />
New quote
</a>
<button koala-btn="Outline" class="gap-2">
<koala-icon name="Plus" size="Small" />
New partner
</button>
<button koala-btn="Danger" koala-btn-variant="Outlined" class="gap-2">
<koala-icon name="X" size="Small" />
Cancel quote
</button>
Responsive sizing
Use w-full sm:w-auto for buttons that go full-width on mobile
and auto-width on larger screens. Wrap in flex flex-col sm:flex-row gap-3.
<div class="flex flex-col sm:flex-row gap-3">
<button koala-btn="Primary" class="w-full sm:w-auto">Save</button>
<a href="/cancel" koala-btn="Outline" class="w-full sm:w-auto">Cancel</a>
</div>
Icon buttons
Use koala-icon-btn on <button> or <a> elements that contain only a single <koala-icon> (e.g. inline edit, delete, close). Muted icon with a subtle rounded background on hover (GitHub-style), giving visual separation between adjacent icons.
<button koala-icon-btn="Neutral" title="Edit">
<koala-icon name="Pencil" />
</button>
<button koala-icon-btn="Danger" title="Delete">
<koala-icon name="Trash" />
</button>
Use Neutral for edit/close, Danger for delete. The helper adds padding, a rounded hover background, and colour transitions — don't re-apply those yourself. Extra classes (e.g. absolute top-4 right-4, opacity-reveal) merge onto the output.
Colour reference
When to use each colour and variant combination.
| Colour | Variant | Used for |
|---|---|---|
| Primary | Filled | Page-primary actions: Submit, Save, Invite, Accept; page-header CTAs (New partner, Add branch, Add team member, Invite team member) |
| Secondary | Filled | Branded actions a step below Primary in emphasis: Save draft alongside Publish, branded confirms that aren't a page CTA. Filled --color-secondary (dark navy) with white text. |
| Outline | Filled (white surface, neutral border) | Cancel, No, Back, Close; in-section CTAs (Add note, New revision); persistent global CTAs (top-nav "Get a quote") |
| Danger | Filled | Destructive confirm (Yes in delete/disable modals) |
| Danger | Outlined | Destructive trigger (Cancel quote, Disable partner) |
Copy + open link
Pairs a visible URL (or label) with two icon affordances: a Copy button on the left and an Open-in-new-tab link on the right. The Copy icon briefly swaps to a Check tick (~1.5s) on success. Used on pages that surface a shareable URL alongside a QR code (referral codes, discount quick-create links).
<koala-copy-open-link href="@quickCreateUrl" /> <!-- With a custom label instead of the URL --> <koala-copy-open-link href="@quote.PublicUrl" label="Open quote @quote.Reference" />