Installation
Keyline is a shadcn registry. The shadcn CLI copies each component's source into your project, with the components, styles and packages it needs, so the code is yours to read and change. Nothing to clone, build or host: you map the @keyline-ui registry once, then add components by name.
New project
Create a Next.js or Vite app set up for shadcn (pick either):
In the new app's folder, map the Keyline registry. This writes one line to components.json:
Add a component and use it:
Existing shadcn project
In the folder that holds components.json, map the registry once, then add what you need. Each component page shows its command.
The first command adds this to components.json, which you can also write by hand:
Requirements
- React 19 and TypeScript.
- Tailwind CSS 4. Keyline's theme uses
@theme inline, which Tailwind 3 does not have. - A shadcn project: a
components.jsonwith any style and base, and thecn()helper at itsutilsalias.shadcn initsets both up. - Network access to npm and to this site while you run the CLI. Nothing is fetched from this site at runtime.
What installing does
- Files go to
components/keyline/(ui,lib, andblocksfor a block), undersrc/when your project uses it, following yourcomponentsalias. Import them as@/components/keyline/ui/button, with your own alias in place of@. - Dependencies come along: the Keyline components a component is built from, Base UI, the fonts, and any library it wraps (for example
rechartsfor Chart), at the version Keyline is tested with. - CSS is merged into the stylesheet named in
components.json: the theme's--kl-*tokens and each component's ownkl-rules. Adding a component again updates its rules in place; it does not add a second copy. - Fonts (Atkinson Hyperlegible Next and Mono) are npm packages imported from that stylesheet, so they are bundled with your app.
Your app and Keyline
Keyline's CSS only styles Keyline's own names (--kl-* tokens, kl- classes, data-kl-*attributes). Your shadcn components, body, fonts and tokens look the same as before, and Keyline's Button and shadcn's Button can sit on the same page. Dark mode follows a .dark class on an ancestor, as shadcn's own setups already set it.
To give the whole app Keyline's look, stock shadcn components included, add the opt-in theme:
Next.js and Vite
Interactive components start with "use client";, so a Next.js App Router server page can import and render them. Vite and other bundlers without React Server Components ignore the directive. Other frameworks the shadcn CLI supports work the same way when they meet the requirements above.
Updating
Installed components are your code: nothing changes until you add them again. To take a newer version, re-add it with --overwrite. It replaces the component's files, so commit or keep your own edits first and compare afterwards.
Without --overwrite, the CLI skips files that are unchanged and asks before replacing one you edited. CSS rules that changed are updated in place; a rule Keyline removed or renamed stays in your stylesheet until you delete it.
Removing
Delete the component's files from components/keyline/. The CLI does not remove CSS, so delete that component's kl- rules from your stylesheet as well, and any packages you no longer use. For configuration, theming and the composition rules, start with Theming and Composition.
Troubleshooting
Each of these was reproduced with shadcn 4.23.
“Unknown registry "@keyline-ui"”
The project has no @keyline-ui mapping, and the CLI does not know the name on its own. Map the namespace first with the registry command under Existing shadcn project, then add the item again.
The registry command says “already configured”
registry add never replaces a mapping. If @keyline-ui already points somewhere else, the old address stays and items keep coming from it. Open components.json and set registries["@keyline-ui"] to the address shown under Existing shadcn project.
Keyline's items refer to each other as @keyline-ui/<name>, so the mapping needs that exact name.
“Couldn't find tsconfig.json”, or the mapping lands in package.json
The command ran outside a shadcn project. Run it in the folder that holds components.json, or create the project first with shadcn init (see New project). Run outside one, registry add writes the mapping to package.json instead.
The CLI asks to overwrite utils.ts
Keyline's items depend on shadcn's cn() helper, and the CLI asks before replacing a utils.ts that differs from its copy. Answer No to keep yours; Keyline only needs it to export cn().