Button
A button that does something, such as sending a form or saving a draft. It never sends a form by accident, and it can stay reachable by keyboard when it’s disabled.
Automated tests and an independent accessibility review pass. Manual testing with assistive technology is pending. Don't use it in a live service yet.
Example
Knappar som tar bort något behöver alltid ett bekräftelsesteg. De visas tillsammans här bara för att kunna jämföras.
Code
import { Button } from '@kvirn-ui/react'
import '@kvirn-ui/theme/theme.css'
<div className="kv-button-group">
<Button className="kv-button--primary">Send application</Button>
<Button>Save draft</Button>
<Button className="kv-button--danger">Delete draft</Button>
</div>When to use it
- Use a button when the user does something: sends, saves, deletes or opens.
- Write the label as a verb that says what will happen: “Send application”, not “OK”.
- Use one primary button per page, for the main next step.
- Deleting and other actions that can’t be undone need a confirmation step.
When not to use it
To go to another page, use a Link. Don’t make a link look like a button, or a button look like a link.
Installation
pnpm add @kvirn-ui/react @kvirn-ui/i18nFor the default look, also add @kvirn-ui/theme and import theme.css once, for example in your root layout. Every Button is then styled. Remove the import, and it’s unstyled again: KvirnUI never loads CSS for you.
pnpm add @kvirn-ui/theme
import '@kvirn-ui/theme/theme.css'Usage
A button that does something
type="button" is the default, so a Button never sends a form by accident.
<Button onClick={saveDraft}>Save draft</Button>Sending a form
Use type="submit" for the one button that sends the form.
<form onSubmit={sendApplication}>
{/* fields */}
<Button type="submit" className="kv-button--primary">
Send application
</Button>
</form>Disabled buttons
Try not to disable buttons. Let people press them and then explain what’s missing. If you must disable one, use focusableWhenDisabled so keyboard and screen reader users can still find it, and show the reason next to it.
Fyll i alla obligatoriska fält innan du skickar.
Code
<p id="send-reason">Fill in all required fields before you send.</p>
<Button
className="kv-button--primary"
disabled
focusableWhenDisabled
aria-describedby="send-reason"
>
Send application
</Button>Using your own button component
Use render to change the element. It must still render a <button>. To go somewhere, use Link.
<Button render={<MyStyledButton />}>Save draft</Button>The hook: useButton
Build your own button with the same behaviour. Pass your click handler to the hook, so it stays blocked while the button is disabled.
const button = useButton({ disabled: isSaving, focusableWhenDisabled: true, onClick: save })
<button {...button.buttonProps}>Save draft</button>Styling
Button renders class="kv-button", and its state as data-disabled and data-focus-visible. The default theme styles that class and those attributes. Choose how much of it you want.
1. Use the default theme
Import @kvirn-ui/theme/theme.css. A Button is secondary by default. Add className="kv-button--primary" for the one main action on the page, or className="kv-button--danger" for an action that deletes something. Put class="kv-compact" on a container for smaller buttons in staff tools.
<Button className="kv-button--primary">Send application</Button>2. Override variables
The theme is role scales (--kv-primary-500, --kv-neutral-50), named for what they do and not for their hue, and semantic tokens that point at them (--kv-color-primary). Set either in your own CSS. Everything in theme.css is in @layer kv, so your CSS always wins.
/* Rebrand: give the primary scale your brand's colours. All four themes follow. */
:root {
--kv-primary-50: #edfafa;
--kv-primary-100: #cdf0f0;
--kv-primary-200: #9be0e2;
--kv-primary-300: #5fc6cb;
--kv-primary-400: #1e9ca4;
--kv-primary-500: #007d86;
--kv-primary-600: #00707a;
--kv-primary-700: #005a62;
--kv-primary-800: #00474e;
--kv-primary-900: #003a40;
--kv-primary-950: #00262a;
}A secondary Button's edge uses the secondary scale, which is the neutral steps by default. Give --kv-secondary-* your own 11 steps to colour it.
Each theme uses different steps, so a swapped scale can break contrast. Check your colours with checkThemeCss() from @kvirn-ui/theme on your customised copy. It measures every text, control and focus pair in all four themes.
3. Replace it or skip it
theme.css is one readable file. Copy it from node_modules/@kvirn-ui/theme/theme.css into your project, edit it, and import your copy instead. Or skip it, and style the kv-button class and the state attributes with Tailwind or your own CSS.
<Button className="rounded-md border px-4 py-2 data-disabled:border-dashed data-focus-visible:outline-2">
Save draft
</Button>