Open Form

open-form theme

List reference themes, check contrast, add a starter, and add Google Fonts.

Themes in your project's themes/ folder are references for new forms: a form starts from one's tokens with open-form create <id> --theme <theme>, and its own look lives in forms/<id>/theme/. See Themes. open-form theme has four subcommands.

theme list

npx open-form theme list

Lists the project's themes with the one-line description from each THEME.md, and how to start a form from one. Then it lists the starters: brutalist, classic, conversational, editorial and terminal.

theme check

npx open-form theme check <id>
npx open-form theme check <form> --form

Checks the WCAG contrast of every color pair forms actually use, in light and dark:

PairNeeds
foreground on surface, on background and on input4.5:1
muted help text on surface4.5:1
primaryForeground on primary (button text)4.5:1
error on surface4.5:1
control outlines on input3:1
primary focus and selection on surface3:1

A theme with dark: false is checked in light only, and one with colorScheme only in that scheme. When the theme has its own Layout, a failing foreground on background is shown as a hint (▲) instead of a failure: the layout decides whether any text sits straight on background. It also warns when a theme sets colors without dark, since dark mode would mix your light colors with the built-in dark defaults.

Colors can be hex, rgb(), hsl(), oklch() or oklab(). Values it can't resolve, such as var() or color-mix(), show as ? and count as failures. The command exits with code 1 when any pair fails, except a hint (▲); fix it by changing that token's lightness and keeping its hue.

FlagDefaultDescription
--formoff<id> is a form id: check that form's own theme in forms/<id>/theme/.
--jsonoffMachine-readable output.

theme add

npx open-form theme add editorial
npx open-form theme add editorial --as brand

Copies a starter's whole folder into themes/<name>/: its tokens, THEME.md, and any components and CSS it has. It's a reference to adapt into your own look; new forms start from its tokens with create --theme, and agents read the rest while writing a form's look. Editing it later never changes an existing form.

FlagDefaultDescription
--as <name>the starter's idSave it under a new kebab-case id. [data-of-theme="<starter>"] selectors and the name and heading in THEME.md are renamed to match; file names and class names stay as they are.
-f, --forceoffReplace an existing theme with that id.

theme font

npx open-form theme font brand Inter
npx open-form theme font brand Noto Sans TC
npx open-form theme font meetup Inter --form

Downloads a Google Fonts family into the fonts/ folder next to the theme's file — themes/<id>/fonts/, or forms/<id>/theme/fonts/ with --form — and imports it from the theme. A single-file theme, themes/<id>.ts, uses a shared themes/fonts/. Then it prints the value to use for font or headingFont. The form serves the files itself, so respondents never contact Google. Variable families get their whole weight range; static ones get weights 400 to 700. Adding the same family again replaces its files.

It needs to reach fonts.google.com, fonts.googleapis.com and fonts.gstatic.com. Behind a proxy set in HTTPS_PROXY, run it with NODE_USE_ENV_PROXY=1 (Node 22.21 or later) so Node's fetch goes through the proxy.

Chinese, Japanese and Korean families take a few MB in the project, split into small files. Respondents only download the ones holding the characters a page uses.

FlagDefaultDescription
--formoff<id> is a form id: add the font to that form's own theme in forms/<id>/theme/.

On this page