Skip to content

Getting started

@jsonresume/ui is a TypeScript React package. Styles are written with vanilla-extract and compiled to one static stylesheet, so there is no runtime styling cost and nothing to configure in your bundler.

Install

Inside this monorepo, add it as a workspace dependency.

terminal
pnpm add @jsonresume/ui --filter <your-app>

Set up the root

Import the stylesheet once and put the base class on <body>.

app/layout.tsx
// app/layout.tsx
import '@jsonresume/ui/fonts.css'; // optional: self-hosted Open Sans + Ubuntu
import '@jsonresume/ui/styles.css'; // tokens and component styles
import { base } from '@jsonresume/ui';

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body className={base}>{children}</body>
    </html>
  );
}

Why a base class?

The package never styles bare elements globally. base applies the brand type, color and element defaults only where you opt in, so it can sit alongside an app’s existing styles during a migration.

Use components

app/themes/page.tsx
import { Button, PageHeader } from '@jsonresume/ui';

export default function Page() {
  return (
    <PageHeader
      title="Themes"
      description="Browse the community gallery."
      actions={<Button variant="primary">Submit a theme</Button>}
    />
  );
}

Use tokens in your own styles

Every token is a CSS custom property with a stable --jr-* name, and a typed reference in TypeScript.

notice.module.css
/* Any stylesheet can use the tokens as CSS custom properties. */
.notice {
  padding: var(--jr-space-4);
  background: var(--jr-color-surface-brand);
  color: var(--jr-color-text-on-brand);
  border-radius: var(--jr-radius-sm);
}
notice.css.ts
import { style } from '@vanilla-extract/css';
import { vars } from '@jsonresume/ui/tokens';

export const notice = style({
  padding: vars.space[4],
  background: vars.color.surface.brand,
});

Writing your own .css.ts files in a Next.js app

Add @vanilla-extract/next-plugin to next.config and run Next with --webpack. The package itself ships compiled, so apps that only use its components need no plugin at all.

Dark mode

Pages are light by default. Set data-theme="dark" on any element to switch it and its children to the dark tokens, or data-theme="system" to follow the operating system.