Button
The action: a button in five looks (primary, secondary, outline, ghost, danger), three sizes and two shapes.
Web and mobile — the same component for React and React Native. Stable: its API only changes in a major version.
When to use
- To run an action: submit a form, open a dialog, start an upload, save a draft.
- One
primarybutton for the main action of a view;secondary,outlineorghostfor the others. IconButtonfor a compact action shown by its icon alone (close, add, more), with alabelfor its name.
When not to use
- To go to another page: use a link (
asChildwith your router's<Link>keeps the button look). - To turn a setting on or off, with an immediate effect.Use instead: Switch
- For a destructive action that needs a second press to confirm, in place.Use instead: Confirm button
- To choose one option among several, or filter a list.Use instead: Chip
Installation
Install
npm install @krizaka/ui@beta @krizaka/tailwind@beta @krizaka/tokens@beta tailwindcssStyles
@import "tailwindcss";
@import "@krizaka/tailwind";
@import "@krizaka/ui/tailwind.css";Import
import { Button, IconButton } from "@krizaka/ui/button";Examples
Primary
The main action of a view: the accent.
import { Button } from "@krizaka/ui/button";
export default function ButtonPrimary() {
return <Button variant="primary">Continue</Button>;
}Secondary
The default: a raised surface, for the other actions.
import { Button } from "@krizaka/ui/button";
// `secondary` is the default variant: a raised surface.
export default function ButtonSecondary() {
return <Button>Continue</Button>;
}Outline
A lighter action next to a primary one.
import { Button } from "@krizaka/ui/button";
export default function ButtonOutline() {
return <Button variant="outline">Continue</Button>;
}Ghost
In toolbars and dense lists: no frame until hovered.
import { Button } from "@krizaka/ui/button";
export default function ButtonGhost() {
return <Button variant="ghost">Continue</Button>;
}Danger
A destructive action: the border and the tint carry the danger, the label stays legible in both themes.
import { Button } from "@krizaka/ui/button";
export default function ButtonDanger() {
return <Button variant="danger">Delete</Button>;
}Sizes
sm, md (default) and lg.
import { Button } from "@krizaka/ui/button";
export default function ButtonSizes() {
return (
<div className="flex items-center gap-3">
<Button variant="primary" size="sm">
Continue
</Button>
<Button variant="primary" size="md">
Continue
</Button>
<Button variant="primary" size="lg">
Continue
</Button>
</div>
);
}Pill
shape="pill": fully rounded.
import { Button } from "@krizaka/ui/button";
export default function ButtonPill() {
return (
<Button variant="primary" shape="pill">
Continue
</Button>
);
}Disabled
Not available yet: out of the tab order.
import { Button } from "@krizaka/ui/button";
export default function ButtonDisabled() {
return (
<Button variant="primary" disabled>
Continue
</Button>
);
}Loading
While the action runs: disabled, aria-busy, data-loading.
import { Button } from "@krizaka/ui/button";
// Disabled, `aria-busy` and `data-loading`: add your own spinner if you want one.
export default function ButtonLoading() {
return (
<Button variant="primary" loading>
Saving…
</Button>
);
}As a link
asChild renders your <a> (or router link) with the button's look.
import { Button } from "@krizaka/ui/button";
// `asChild`: the `<a>` is rendered, with the button's classes and props merged into it.
export default function ButtonAsChildLink() {
return (
<Button variant="outline" asChild>
<a href="#docs">Read the docs</a>
</Button>
);
}Icon button
IconButton: a square button holding an icon; label is its accessible name.
import { IconButton } from "@krizaka/ui/button";
export default function ButtonIcon() {
return (
<div className="flex items-center gap-3">
<IconButton label="Close" variant="ghost">
<svg viewBox="0 0 24 24" className="h-4 w-4" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" aria-hidden>
<path d="M18 6 6 18M6 6l12 12" />
</svg>
</IconButton>
<IconButton label="Add" variant="primary" shape="pill">
<svg viewBox="0 0 24 24" className="h-4 w-4" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" aria-hidden>
<path d="M12 5v14M5 12h14" />
</svg>
</IconButton>
</div>
);
}Props
Button
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | — | Renders the child (e.g. a <Link>) instead of the <button>, with props, classes and ref merged. |
loading | boolean | — | Disables and signals the wait (aria-busy, data-loading) — the product adds a spinner if it wants one. |
shape | "rounded" | "pill" | rounded | rounded · pill. |
size | "icon" | "sm" | "md" | "lg" | md | sm · md · lg, or icon (a square). |
variant | "danger" | "primary" | "secondary" | "outline" | "ghost" | secondary | The look: primary (the accent), secondary (a raised surface), outline, ghost, danger. |
IconButton
An icon-only button: label is required, it is its accessible name.
| Prop | Type | Default | Description |
|---|---|---|---|
labelrequired | string | — | The accessible name (and tooltip) of the button — required, passed translated. |
asChild | boolean | — | Renders the child (e.g. a <Link>) instead of the <button>, with props, classes and ref merged. |
loading | boolean | — | Disables and signals the wait (aria-busy, data-loading) — the product adds a spinner if it wants one. |
shape | "rounded" | "pill" | rounded | rounded · pill. |
size | "icon" | "sm" | "md" | "lg" | icon | sm · md · lg, or icon (a square). |
variant | "danger" | "primary" | "secondary" | "outline" | "ghost" | secondary | The look: primary (the accent), secondary (a raised surface), outline, ghost, danger. |
Accessibility
- A native
<button type="button">: the role, the focus and the keyboard come from the platform. IconButtonrequireslabel: it becomes thearia-labelof a button that shows no text.loadingsetsaria-busyand disables the button;disabledkeeps it out of the tab order.
Keyboard
| Keys | Action |
|---|---|
| Enter / Space | Runs the action. |
| Tab | Moves the focus to the next control; the focus ring uses --kz-ring. |
Best practices
- Name the action with a verb: “Save”, “Send the invitation” — not “OK” or “Yes”.
- One primary per view; the danger variant only for what destroys or cannot be undone.
loadingwhile the action runs: the button is disabled and says it is busy; keep its width by keeping its words short.- Style a link without the component with
buttonVariants({ variant, size }).
Related components
Generated from the code of @krizaka/ui 2.0.0-beta.6: its meta.ts, its examples and its types.Edit this documentation on GitHub