meowerse_
docs menu

Button

A native button in four variants and two sizes, with a loading state.

import { Button } from "@meowerse/ui"; · source packages/ui/src/components/Button.tsx

variants and states

primary — the one main action
secondary
ghost
danger
small — 36 px drawn, 44 px hit area
loading
disabled

props

proptypedefaultrequired
variant"primary" | "secondary" | "ghost" | "danger" the button's tone; use primary for the one main action per view."secondary"no
size"sm" | "md" the button's size; both keep a 44 px hit area."md"no
loadingboolean shows a spinner and disables the button.falseno

…plus all ButtonHTMLAttributes<HTMLButtonElement>.

css custom properties

variabledarklight
--c-accent-fill#00ff82same
--c-danger#ff6b63#b42318
--c-fg#ededeb#1a1a1c
--c-fg-muted#b3b3af#46464a
--c-fg-subtle#8c8c88#5e5e5b
--c-line#232326#cfcec8
--c-line-strong#404044#a9a8a2
--c-on-accent#06170dsame
--c-on-danger#1a0605#ffffff
--c-surface#151517#dfded9
--control-height44pxsame
--d-fast120mssame
--disabled-opacity0.5same
--easecubic-bezier(.16,1,.3,1)same
--font-mono"JetBrains Mono", "JetBrains Mono Fallback", ui-monospace, "SFMono-Regular", Menlo, monospacesame
--fs-20.8125remsame
--fs-30.875remsame
--r-m4pxsame
--sp-28pxsame
--sp-312pxsame
--sp-416pxsame

Classes: .mw-btn. Set any of these variables on an ancestor (or wrap a subtree in .mw-theme--dark / .mw-theme--light) to restyle just that part of a page.

usage

primary

tsx
import { Button } from "@meowerse/ui";

<Button variant="primary">save</Button>

html (needs @meowerse/ui/tokens.css)
<button class="mw-btn mw-btn--primary mw-btn--md"><span>save</span></button>

secondary

tsx
import { Button } from "@meowerse/ui";

<Button>cancel</Button>

html (needs @meowerse/ui/tokens.css)
<button class="mw-btn mw-btn--secondary mw-btn--md"><span>cancel</span></button>

ghost

tsx
import { Button } from "@meowerse/ui";

<Button variant="ghost">more options</Button>

html (needs @meowerse/ui/tokens.css)
<button class="mw-btn mw-btn--ghost mw-btn--md"><span>more options</span></button>

danger

tsx
import { Button } from "@meowerse/ui";

<Button variant="danger">delete account</Button>

html (needs @meowerse/ui/tokens.css)
<button class="mw-btn mw-btn--danger mw-btn--md"><span>delete account</span></button>

small

tsx
import { Button } from "@meowerse/ui";

<Button size="sm">copy all</Button>

html (needs @meowerse/ui/tokens.css)
<button class="mw-btn mw-btn--secondary mw-btn--sm"><span>copy all</span></button>

loading

tsx
import { Button } from "@meowerse/ui";

<Button variant="primary" loading>saving</Button>

disabled

tsx
import { Button } from "@meowerse/ui";

<Button variant="primary" disabled>save</Button>

html (needs @meowerse/ui/tokens.css)
<button disabled="" class="mw-btn mw-btn--primary mw-btn--md"><span>save</span></button>

accessibility

  • A native <button>: Enter and Space work, and focus shows the 2 px ring.
  • loading disables it and adds a spinner; keep the label saying what is happening.
  • It sets no default type (audit U-20): inside a form, set type="button" on buttons that must not submit.
keydoes
Tabfocuses the button
Enter or Spacepresses it

do and don't

do

  • Use one primary (green) button per view, for the main action.
  • Explain a disabled button next to it.

don't

  • Don't put two green buttons in one view.
  • Don't enable a button and then refuse the click with "not ready".