Skip to content
Site volume
Colourway

Components

Button

Every action is the comic hit key: a flat face, a 3 px ink rule and a hard offset that a press closes.

  • Beta
  • Reading layer
  • Server component
  • Since 0.1.0
  • Press check
Import from@maxgrits/overprint-react/button
On this page

Example#

Look of this example
Live render of examples/button/basic.tsx

Usage#

Use a button for an action that happens on this page: send a form, open a dialog, start something. Going to another page is a link; use href on a button only when the destination is the page's main action, such as "Get a quote".

  • One action key per view. action prints in the yellow key ink, the only yellow on the page (D-C1). Everything else is secondary (the default), primary for a firm second choice, quiet beside a stronger key, or link for an action that reads as text.
  • Line keys. variant="line" with line fills the face with a line's plate, for actions that belong to one line of work, such as "See the websites".
  • Destructive actions use primary with a glyph and an explicit verb ("Delete the draft"). There is no red button: every Process ink already means a line of work (D-C2).
  • Pending and toggles. loading keeps the key focusable, blocks a second submit and draws a bar under the label. pressed makes a toggle key that holds at half travel.
  • Sizes. sm 40 px, md 48 px (default), lg 56 px; on touch screens nothing goes under 44 px. block="phone" stretches the key below the md width.

Anatomy#

The parts of examples/button/anatomy.tsx, numbered:
  1. Key faceThe face, the 3 px ink rule and the hard offset, which a press closes..mk-button
  2. Start glyphOptional, from the shape alphabet; hidden from assistive tech..mk-button-start
  3. LabelA literal verb in the control role..mk-button-label
  4. End glyphOptional; an arrow when the key goes somewhere..mk-button-end

Volume#

The key is reading layer, so it prints the same at every volume and in every comic register (D-B2, D-N9): the face, the rule and the offset never change. The art around it is what gets louder.

  • Quiet

    Docs, forms, legal and long reads. Flat inks, no art in motion.

  • Studio

    The site default. Art on its own plates, one display moment per view.

  • Press

    Hero moments, covers and campaigns. Halftone fields and the second ink.

  • Rave

    Launches, posters and the 404. Every ink, and the words still win.

Content#

  • Start with a verb and say what happens: "Send", "Get a quote", "Email it instead". The joke goes next to the key, never on it (D-I2).
  • Sentence case, one to four words. Labels never wrap mid-word; a full-width key balances its lines.
  • The same action keeps the same label everywhere it appears, so "Get a quote" is never also "Request pricing".
  • No "Click here", "Submit" or "OK": a reader who lands on the key alone should know what it does.

Do and don't#

Do

One action key, one secondary.

Don't

Two yellow keys compete.

The yellow key is the page's one main action. Two of them make the reader choose, so the second action steps down to secondary or primary.

Do

A firm key with an explicit verb.

Don't

A label that says nothing.

A destructive action names what it destroys. With no red in the system, the verb and the firm primary face carry the weight.

Accessibility#

  • A native button (type="button" by default) or, with href, a link; labels are literal verbs.
  • Pending (loading) keeps the key focusable with aria-busy and aria-disabled, blocks a second submit and draws a bar under the label; under reduced motion the bar becomes a static ellipsis.
  • A toggle key (pressed) exposes aria-pressed and sits at half travel, so its state does not depend on colour.
  • Keys are 40, 48 and 56 px tall and never under 44 px on touch screens; the focus ring is 2 px in --mk-focus with a 2 px gap.
KeysWhat happens
TabMoves focus to the key; a pending key stays focusable
EnterActivates the key (a link-rendered key follows its link)
SpaceActivates a button key; a toggle key flips aria-pressed

The colour pairs it prints, with their contrast on both papers:

TextSurfaceRoleBoneNight
--mk-ink-disabled--mk-paperui 3.27:1 · Lc 56.5, passes 6.53:1 · Lc 46.1, passes
--mk-ink-disabled--mk-paper-sunkenui 3.01:1 · Lc 51.2, passes 6.25:1 · Lc 45.7, passes
--mk-ink-disabled--mk-paper-plateui 3.65:1 · Lc 64.1, passes 6.05:1 · Lc 45.4, passes
--mk-on-m--mk-ink-m-solidcontrol-sm 5.31:1 · Lc 79.9, passes 4.53:1 · Lc 67.8, passes
--mk-on-m--mk-ink-m-hovercontrol-sm 6.06:1 · Lc 83.1, passes 5.10:1 · Lc 71.2, passes
--mk-on-a--mk-ink-a-solidcontrol-sm 8.36:1 · Lc 60.1, passes 10.43:1 · Lc 70.0, passes
--mk-on-a--mk-ink-a-hovercontrol-sm 9.30:1 · Lc 65.2, passes 11.51:1 · Lc 75.1, passes
--mk-on-r--mk-ink-r-solidcontrol-sm 4.51:1 · Lc 75.7, passes 8.53:1 · Lc 60.1, passes
--mk-on-r--mk-ink-r-hovercontrol-sm 5.10:1 · Lc 79.6, passes 9.56:1 · Lc 65.4, passes
--mk-on-k--mk-ink-k-solidcontrol-sm 18.42:1 · Lc 107.1, passes 16.21:1 · Lc 95.1, passes
--mk-on-k--mk-ink-k-hovercontrol-sm 19.43:1 · Lc 107.6, passes 17.71:1 · Lc 101.1, passes
--mk-on-y--mk-ink-y-solidcontrol-sm 14.44:1 · Lc 89.2, passes 14.76:1 · Lc 89.4, passes
--mk-on-y--mk-ink-y-hovercontrol-sm 15.85:1 · Lc 94.9, passes 16.20:1 · Lc 95.2, passes
--mk-on-wood--mk-ink-wood-solidcontrol-sm 9.31:1 · Lc 64.8, passes 4.54:1 · Lc 70.2, passes
--mk-on-wood--mk-ink-wood-hovercontrol-sm 10.35:1 · Lc 70.1, passes 5.18:1 · Lc 73.9, passes
--mk-on-go--mk-ink-go-solidcontrol-sm 4.54:1 · Lc 76.3, passes 10.08:1 · Lc 68.6, passes
--mk-on-go--mk-ink-go-hovercontrol-sm 5.15:1 · Lc 80.3, passes 11.15:1 · Lc 73.7, passes
--mk-on-lead--mk-ink-lead-solidcontrol-sm 5.31:1 · Lc 79.9, passes 4.53:1 · Lc 67.8, passes
--mk-on-lead--mk-ink-lead-hovercontrol-sm 6.06:1 · Lc 83.1, passes 5.10:1 · Lc 71.2, passes
--mk-on-support--mk-ink-support-solidcontrol-sm 8.36:1 · Lc 60.1, passes 10.43:1 · Lc 70.0, passes
--mk-on-support--mk-ink-support-hovercontrol-sm 9.30:1 · Lc 65.2, passes 11.51:1 · Lc 75.1, passes
--mk-on-spot--mk-ink-spot-solidcontrol-sm 14.44:1 · Lc 89.2, passes 14.76:1 · Lc 89.4, passes
--mk-on-spot--mk-ink-spot-hovercontrol-sm 15.85:1 · Lc 94.9, passes 16.20:1 · Lc 95.2, passes
--mk-on-action--mk-actioncontrol-sm 14.44:1 · Lc 89.2, passes 14.76:1 · Lc 89.4, passes
--mk-on-action--mk-action-hovercontrol-sm 15.85:1 · Lc 94.9, passes 16.20:1 · Lc 95.2, passes

Process at Studio, normal contrast. Every look: the press check.

Props#

PropTypeDefaultDescription
variantButtonVariantnone
sizeSizenone
line"custom-apps" | "growth" | "maxos" | "software" | "websites"noneThe line a `variant="line"` key prints in (D-C2).
block"phone" | booleannoneFull width always, or below the md width (48rem).
loadingbooleannone`aria-busy` and `aria-disabled`; stays focusable; the label stays.
pressedbooleannoneA toggle key (`aria-pressed`).
hrefstringnoneRenders `<a>`; Next.js routing uses `render`.
renderRenderPropnone
iconStartReactNodenone
iconEndReactNodenone
children requiredReactNodenoneA literal verb (D-I2 floor). Icon-only actions use `IconButton`.

Plus 289 React and DOM attributes passed through to the root element (className, ref, aria-*, event handlers and the rest). Generated from ButtonProps in packages/overprint-react/src/reading/button/button.tsx.

Tokens#

Changelog#

Arrived in 0.1.0.

0.1.024 October 2026

  • MinorreactThe reading layer's controls, overlays, forms and visitor prefs (P2-T1 to P2-T5): every Button is the comic hit key, with IconButton, Link and Tooltip; Input, Textarea, Select, Checkbox and CheckboxGroup, Radio and RadioGroup, Switch, Slider with the ruler, RulerReadout and SegmentedControl; Dialog, Drawer, NavSheet, Tabs, Disclosure, Faq and faqJsonLd on Base UI 1.9 where the platform falls short; Field, Fieldset, Form with the site's inline validation, ErrorSummary, Callout, Honeypot, FormTimestamp and QuoteForm; PrefsScript under 1 KB, usePref and setPref with cross-tab sync, ThemeToggle and the visitor VolumeDial; VisuallyHidden.