Skip to content

Installation

The packages are private to the zitdevs organisation on GitHub Packages. An app needs a token to install them, React 19 for the components, and Tailwind 4 to style them.

1. Point the @zitdevs scope at GitHub Packages

Section titled “1. Point the @zitdevs scope at GitHub Packages”

Create a personal access token (classic) with the read:packages scope, and export it as GITHUB_TOKEN in your shell. Never commit the token itself: the files below only name the variable.

For npm, pnpm and Bun, an .npmrc at the root of the app:

.npmrc
@zitdevs:registry=https://npm.pkg.github.com
//npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}

Bun reads .npmrc too. If the app configures Bun through bunfig.toml instead:

bunfig.toml
[install.scopes]
"@zitdevs" = { url = "https://npm.pkg.github.com/", token = "$GITHUB_TOKEN" }

In GitHub Actions, the workflow’s own GITHUB_TOKEN can install the packages: give the job permissions: packages: read, and grant the app’s repository read access in each package’s settings on GitHub (Package settings → Manage Actions access).

Terminal window
bun add @zitdevs/ui @zitdevs/tokens

@zitdevs/ui expects these in the app, as peer dependencies:

Package Version Why
react ^19 The components are React 19 function components.
@zitdevs/tokens ^0.1 The theme the components’ classes compile against.
tailwindcss ^4 Generates the classes; not imported by the components.

@zitdevs/tokens alone needs nothing: an app that only wants the tokens, such as a Svelte or Expo app, installs just that.

Tailwind 4 is configured in CSS. In the app’s stylesheet, import Tailwind, then the kit’s theme, then tell Tailwind to scan the kit’s build: Tailwind skips node_modules, so without @source none of the components’ classes would be generated.

app/globals.css
@import 'tailwindcss';
@import '@zitdevs/tokens/theme.css';
/* Proxima Nova and JetBrains Mono, self-hosted. Leave out if the app loads the fonts itself. */
@import '@zitdevs/tokens/fonts.css';
/* Optional: the brand's element defaults (body type, links, focus ring, reduced motion). */
@import '@zitdevs/tokens/base.css';
/* Relative to this file: adjust the depth to reach the app's node_modules. */
@source '../node_modules/@zitdevs/ui/dist';

theme.css replaces Tailwind’s default theme: its palette, type scale, radii and shadows compile to nothing, so every value comes from the tokens. Breakpoints stay Tailwind’s own. The URLs inside the token stylesheets (fonts, patterns, the chevron motif) are relative to the package, and Tailwind rebases them when it inlines the import, so they resolve from the app.

The components assume Tailwind’s preflight, which @import 'tailwindcss' includes: its box-sizing: border-box, and its rule that keeps a [hidden] element hidden whatever display utility it carries — a tab panel, a searchable select’s parts and a sending button are switched with hidden. Another reset has to provide both.

Load the stylesheet the way the framework expects:

  • Vite + React and Astro: add @tailwindcss/vite to the Vite plugins, and import the stylesheet from the entry module or the layout.
  • Next.js: add @tailwindcss/postcss to postcss.config.mjs, and import globals.css in the root layout.
app/page.tsx
import { Button, SectionHead } from '@zitdevs/ui';
export default function Page() {
return (
<section aria-labelledby="start">
<SectionHead
headingId="start"
eyebrow="Start here"
title="Tell us what you need to launch."
/>
<Button label="Contact us" href="/contact" icon="arrow-right" />
</section>
);
}
  • Next.js: the components work in Server Components as they are. A component that needs the browser (Tabs) keeps that part in a small client module of its own, and its page says so. Route links through next/link with asChild or linkAs: see Router links.
  • Astro: render them with no client:* directive. They need no hydration: Astro ships their HTML and no JavaScript. A component that needs the browser comes with an enhancer to run in a page script, such as enhanceTabs(document) from @zitdevs/ui/enhance: see Interactive components.
  • Vite + React: import and render.

cn() is exported too, for the app’s own components: it joins classes and resolves conflicts with the kit’s theme in mind.

import { cn } from '@zitdevs/ui';
cn('text-label text-muted', isActive && 'text-ink'); // 'text-label text-ink' when active
  • Svelte, or any CSS: use @zitdevs/tokens alone. theme.css gives Tailwind the utilities; tokens.css gives plain CSS the variables (var(--ui-primary)).
  • Expo and React Native: the components are DOM components and do not run there. Import the values instead: import { semantic, fontSize, space } from '@zitdevs/tokens'. See Tokens.