# Typography (/docs/typography)



42UI rests on two type families:

* **Lato** — sans-serif. Drives `--font-sans` and runs everywhere prose lives — body copy, descriptions, form input.
* **Kode Mono** — monospaced. Drives `--font-mono`, which `Button`, `Badge`, and `ActionIcon` reach for in their labels, and which any heading-class surface should pick up to land the kit's slightly-technical voice.

The kit ships the tokens; it never bundles font files. Loading the families is your bundler's job — every framework wants to optimize fonts a little differently, and forcing one strategy into a UI package would only get in your way.

## Tokens [#tokens]

`theme.css` declares two CSS variables:

```css
--font-sans: "Lato",      sans-serif;
--font-mono: "Kode Mono", monospace;
```

Tailwind v4 generates `font-sans` and `font-mono` utilities directly from these. Override either variable in your own stylesheet to retheme without touching components.

```tsx
<h1 className="font-mono text-4xl">Heading</h1>
<p  className="font-sans">Body copy</p>
<Button>Mono label by default</Button>
```

## Loading the fonts [#loading-the-fonts]

Pick the path that fits your stack. As long as the family is registered under its canonical name (`"Lato"`, `"Kode Mono"`), the kit's tokens resolve with no extra wiring. `next/font` is the exception — it hashes family names — so that path needs a small override.

### Next.js — `next/font/google` [#nextjs--nextfontgoogle]

```tsx
// app/layout.tsx
import { Kode_Mono, Lato } from 'next/font/google';

const lato = Lato({
  subsets: ['latin'],
  weight: ['400', '700'],
  variable: '--font-lato',
});

const kodeMono = Kode_Mono({
  subsets: ['latin'],
  weight: ['400', '500', '600', '700'],
  variable: '--font-kode-mono',
});

export default function RootLayout({ children }) {
  return (
    <html lang="en" className={`${lato.variable} ${kodeMono.variable}`}>
      <body>{children}</body>
    </html>
  );
}
```

Then in your global stylesheet, after `@import "@42-central/ui-react/theme.css"`:

```css
:root {
  --font-sans: var(--font-lato),      sans-serif;
  --font-mono: var(--font-kode-mono), monospace;
}
```

Lato ships canonical weights at `100 / 300 / 400 / 700 / 900`; intermediate `font-weight` values fall back to the nearest available weight at the browser layer.

### Vite, Remix, plain React — Fontsource [#vite-remix-plain-react--fontsource]

```sh
pnpm add @fontsource/lato @fontsource/kode-mono
```

```ts
// app entry — pick the weights you actually use
import '@fontsource/lato/400.css';
import '@fontsource/lato/700.css';
import '@fontsource/kode-mono/400.css';
import '@fontsource/kode-mono/500.css';
import '@fontsource/kode-mono/600.css';
import '@fontsource/kode-mono/700.css';
```

No token override needed — Fontsource registers the families under their canonical names.

### CDN — Google Fonts `<link>` [#cdn--google-fonts-link]

For prototypes, demos, or anywhere a bundler isn't in the loop:

```html
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link
  href="https://fonts.googleapis.com/css2?family=Lato:wght@400;700&family=Kode+Mono:wght@400..700&display=swap"
  rel="stylesheet"
/>
```

### Self-hosted — `@font-face` [#self-hosted--font-face]

Drop the woff2 files in your asset directory and declare them once:

```css
@font-face {
  font-family: "Lato";
  src: url("/fonts/lato-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Lato";
  src: url("/fonts/lato-700.woff2") format("woff2");
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: "Kode Mono";
  src: url("/fonts/kode-mono-400.woff2") format("woff2");
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
/* …repeat for 500 / 600 / 700 */
```

Grab the woff2 files from [Google Fonts](https://fonts.google.com/specimen/Lato) and [Kode Mono](https://fonts.google.com/specimen/Kode+Mono), or any self-hosting service you trust.

## Why two families [#why-two-families]

Lato carries the prose — readable at small sizes, generous at large. Kode Mono is the kit's *second voice*: monospaced, slightly technical. It's what `Button`, `Badge`, and `ActionIcon` use for their labels, and what to reach for whenever a piece of UI should read as code-adjacent — data values, IDs, hot keys, chip labels, page titles that want a deliberately technical tone.
