alouette
Version:
A modern, customizable design system built on top of NativeWind v5 with configurable defaults
186 lines (131 loc) • 5.63 kB
Markdown
---
name: alouette-typography
description: >
Style alouette Text and Paragraph entirely via className: combined font
family+weight utilities (font-body, font-body-bold, font-body-extrabold,
font-heading*, font-mono*), Tailwind text-* sizes, and semantic color tokens
(text-sharp, text-muted, text-accent, text-on-accent). No variant props. Load
when rendering any text; avoids font-bold and raw color classes.
type: core
library: alouette
requires:
- alouette-theming
sources:
- "christophehurpeau/alouette:packages/alouette/src/ui/primitives/Text.tsx"
- "christophehurpeau/alouette:packages/alouette/src/ui/primitives/Text.stories.tsx"
- "christophehurpeau/alouette:CLAUDE.md"
---
This skill builds on alouette-theming. Read it first for the color token model.
# alouette — Typography
`Text` and `Paragraph` have no variant props — style them entirely with
`className`. `Text` defaults to `font-body` + `text-sharp`, so plain body text
needs no family or color class. `Paragraph` is `Text` with `role="paragraph"`
(renders a `<p>` on web) and selectable text — a block of prose, not a generic
text wrapper (see "Text vs Paragraph").
## Setup
```tsx
import { Text, Paragraph } from "alouette";
<Text className="font-heading-extrabold text-4xl">Title</Text>
<Paragraph className="text-base">Body copy.</Paragraph>
```
## Core Patterns
### Text vs Paragraph
`Paragraph` means "this is prose": one or more sentences, in a `<p>`, selectable
so the reader can copy them. Everything else is `Text` — a label, a heading, a
stat, a table cell, a single value — even when it stands alone on its own line.
A value with its own component keeps that component: a code fragment is `Code`,
a code listing `CodeBlock`, a link `ExternalLinkText` / `LinkText`, a quotation
`Blockquote` (which already wraps its text in a `Paragraph`).
A `<p>` takes no block content, so a `Paragraph`'s children are inline only —
`Text`, `Code`, `ExternalLinkText`. Nesting a `Paragraph`, a `View` or a
`Surface` inside one is invalid DOM on web.
```tsx
<Paragraph>
Point the client at <Code>{endpointUrl}</Code>, then{" "}
<ExternalLinkText size="sm" href={docsUrl} text="read the guide" />.
</Paragraph>
<Text className="text-sm text-muted">{endpointUrl}</Text>
```
### Family + weight (one combined utility)
Family and weight are a single utility — never a standalone `font-bold`:
- `font-body`, `font-body-bold`, `font-body-extrabold`
- `font-heading`, `font-heading-bold`, `font-heading-extrabold`
- `font-mono`, `font-mono-bold`, `font-mono-extrabold`
```tsx
<Text className="font-body-bold">Bold body</Text>
<Text className="font-heading-extrabold text-2xl">Heading</Text>
<Text className="font-mono text-sm text-muted">code()</Text>
```
### Size (standard Tailwind, font-size only)
`text-xs` 12 · `text-sm` 14 · `text-base` 16 · `text-lg` 18 · `text-xl` 24 ·
`text-2xl` 32 · `text-3xl` 40 · `text-4xl` 48 · `text-5xl` 64 · `text-6xl` 80.
Pair `font-heading*` with `text-xl` (24px) or larger — the heading family is
tuned for display sizes. For smaller emphasis, use `font-body-bold`.
### Color (semantic tokens)
`text-sharp` (default) · `text-muted` · `text-accent` · `text-on-accent`
(+ `-muted` variants). Accent color follows the nearest accent scope:
```tsx
<Text accent="brand" className="text-accent">
Brand-colored
</Text>
```
## Common Mistakes
### MEDIUM Using Paragraph as a generic text wrapper
A URL, a label, a stat or a heading is not prose: `role="paragraph"` announces a
paragraph to a screen reader and emits a `<p>` that cannot legally hold the
`View`/`Surface` such a value usually sits next to. Keep `Paragraph` for
sentences; a value with its own component (`Code`, `CodeBlock`,
`ExternalLinkText`) keeps that component.
Source: packages/alouette/src/ui/primitives/Text.tsx
### HIGH Using font-bold instead of font-body-bold
Wrong:
```tsx
<Text className="font-bold text-base">Title</Text>
```
Correct:
```tsx
<Text className="font-body-bold text-base">Title</Text>
```
On native, bold/extrabold are separate font files baked into the family utility.
A standalone `font-bold` / `font-extrabold` / `font-normal` has no effect and is
overridden — it only appears to work on web.
Source: CLAUDE.md (Text styling); src/ui/primitives/Text.stories.tsx (Invalid)
### HIGH Using react-native Text instead of alouette Text
Wrong:
```tsx
import { Text } from "react-native";
<Text className="text-muted">Hi</Text>;
```
Correct:
```tsx
import { Text } from "alouette";
<Text className="text-muted">Hi</Text>;
```
react-native's `Text` has no `font-body` default, no semantic color, and no
`accent` prop, so it doesn't participate in theming. alouette's `Text` applies
`font-body` + `text-sharp` and re-themes via `accent`.
Source: packages/alouette/src/ui/primitives/Text.tsx
### MEDIUM Using a heading font below text-xl
Wrong:
```tsx
<Text className="font-heading-bold text-base">Section</Text>
```
Correct:
```tsx
<Text className="font-heading-bold text-xl">Section</Text>
```
The heading family is tuned for display sizes (`text-xl` / 24px and up). Below
that it looks off — use `font-body-bold` for small emphasized text instead.
Source: scripts/build-css.ts (type scale); src/ui/primitives/Text.stories.tsx
### MEDIUM Coloring text with the raw Tailwind palette
Wrong:
```tsx
<Text className="text-black">Body</Text>
```
Correct:
```tsx
<Text className="text-sharp">Body</Text>
```
`text-black` / `text-gray-500` ignore the theme and break dark mode; semantic
tokens resolve per mode and accent.
Source: CLAUDE.md (Color tokens)