vite-plugin-capsize-radix 0.1.4 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +44 -2
- package/SKILL.md +952 -0
- package/dist/index.js +36 -3
- package/dist/index.mjs +36 -3
- package/package.json +15 -13
package/README.md
CHANGED
|
@@ -56,6 +56,31 @@ export default defineConfig({
|
|
|
56
56
|
})
|
|
57
57
|
```
|
|
58
58
|
|
|
59
|
+
### Install Fonts via Fontsource
|
|
60
|
+
|
|
61
|
+
For open source fonts, use [@fontsource](https://fontsource.org/):
|
|
62
|
+
|
|
63
|
+
```bash
|
|
64
|
+
pnpm add @fontsource/merriweather @fontsource/merriweather-sans @fontsource/source-code-pro
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### Import CSS in Correct Order
|
|
68
|
+
|
|
69
|
+
In your entry file (e.g., `main.tsx`), the import order matters:
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
// 1. Radix base styles FIRST
|
|
73
|
+
import "@radix-ui/themes/styles.css"
|
|
74
|
+
|
|
75
|
+
// 2. Your font CSS from Fontsource
|
|
76
|
+
import "@fontsource/merriweather/latin.css"
|
|
77
|
+
|
|
78
|
+
// 3. Generated typography CSS LAST (overrides Radix variables)
|
|
79
|
+
import "/merriweather.css"
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Critical**: The generated typography CSS must come AFTER `@radix-ui/themes/styles.css` to properly override the CSS variables.
|
|
83
|
+
|
|
59
84
|
### Using with Radix UI
|
|
60
85
|
|
|
61
86
|
This plugin overrides all typography related CSS for Radix so you can simply
|
|
@@ -72,8 +97,25 @@ They all share a `size` prop from "1" to "10". This corresponds to the optional
|
|
|
72
97
|
the array, etc. `<Text>` defaults to `size="2"` and `<Heading>` defaults to
|
|
73
98
|
`size="6"`.
|
|
74
99
|
|
|
75
|
-
|
|
76
|
-
|
|
100
|
+
### Spacing with Capsize
|
|
101
|
+
|
|
102
|
+
Because Capsize trims the invisible whitespace above and below text, **adjacent text elements will sit directly against each other** without any natural spacing. This is by design—it gives you precise control over layout.
|
|
103
|
+
|
|
104
|
+
You must explicitly add spacing between text elements using `<Flex gap>`:
|
|
105
|
+
|
|
106
|
+
```tsx
|
|
107
|
+
// Without gap - heading and text will touch
|
|
108
|
+
<Flex direction="column">
|
|
109
|
+
<Heading>Title</Heading>
|
|
110
|
+
<Text>Body text...</Text>
|
|
111
|
+
</Flex>
|
|
112
|
+
|
|
113
|
+
// With gap - natural spacing between elements
|
|
114
|
+
<Flex direction="column" gap="2">
|
|
115
|
+
<Heading>Title</Heading>
|
|
116
|
+
<Text>Body text...</Text>
|
|
117
|
+
</Flex>
|
|
118
|
+
```
|
|
77
119
|
|
|
78
120
|
<img width="669" alt="Screenshot 2024-03-28 at 10 44 10 AM" src="https://github.com/KyleAMathews/vite-plugin-capsize-radix-ui/assets/71047/b8552d58-4e2d-42d6-9b7b-a595466c2725">
|
|
79
121
|
|
package/SKILL.md
ADDED
|
@@ -0,0 +1,952 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: radix-typography
|
|
3
|
+
description: Set up pixel-perfect typography for Radix UI using vite-plugin-capsize-radix. Helps configure fonts, choose pairings, and integrate with your project.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Radix Typography with Capsize
|
|
7
|
+
|
|
8
|
+
This skill helps you set up bulletproof typography for Radix UI applications using `vite-plugin-capsize-radix`. It generates CSS that trims the invisible whitespace above and below text (caused by font metrics), enabling pixel-perfect alignment.
|
|
9
|
+
|
|
10
|
+
## What This Plugin Does
|
|
11
|
+
|
|
12
|
+
Traditional CSS font rendering includes invisible space above and below text based on the font's ascender/descender metrics. This makes precise layouts difficult. Capsize calculates these metrics and applies CSS pseudo-elements to trim the excess, so your text sits exactly where you specify.
|
|
13
|
+
|
|
14
|
+
This plugin:
|
|
15
|
+
- Generates CSS that overrides Radix UI's typography variables
|
|
16
|
+
- Creates font stacks with metric-aware fallbacks
|
|
17
|
+
- Supports separate fonts for body text, headings, and code
|
|
18
|
+
- Handles responsive sizing (mobile vs desktop)
|
|
19
|
+
|
|
20
|
+
## Important: Spacing with Capsize
|
|
21
|
+
|
|
22
|
+
Because Capsize trims the invisible whitespace above and below text, **adjacent text elements will sit directly against each other** without any natural spacing. This is by design - it gives you precise control over layout.
|
|
23
|
+
|
|
24
|
+
You must explicitly add spacing between text elements using:
|
|
25
|
+
- **Flex with gap** (recommended): `<Flex direction="column" gap="2">`
|
|
26
|
+
- **margin/padding**: Apply to individual elements
|
|
27
|
+
- **Radix spacing props**: `mt`, `mb`, `my`, etc.
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
// Without gap - heading and text will touch
|
|
31
|
+
<Flex direction="column">
|
|
32
|
+
<Heading>Recipes</Heading>
|
|
33
|
+
<Text>Define your chocolate recipes...</Text>
|
|
34
|
+
</Flex>
|
|
35
|
+
|
|
36
|
+
// With gap - natural spacing between elements
|
|
37
|
+
<Flex direction="column" gap="2">
|
|
38
|
+
<Heading>Recipes</Heading>
|
|
39
|
+
<Text>Define your chocolate recipes...</Text>
|
|
40
|
+
</Flex>
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
This explicit spacing model is more predictable than relying on font metrics and gives you pixel-perfect control over your layouts.
|
|
44
|
+
|
|
45
|
+
## Installation
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
pnpm add vite-plugin-capsize-radix @capsizecss/metrics
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Quick Start
|
|
52
|
+
|
|
53
|
+
### 1. Configure the Plugin
|
|
54
|
+
|
|
55
|
+
In `vite.config.ts`:
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import { defineConfig } from "vite"
|
|
59
|
+
import react from "@vitejs/plugin-react"
|
|
60
|
+
import { capsizeRadixPlugin } from "vite-plugin-capsize-radix"
|
|
61
|
+
|
|
62
|
+
// Import metrics for your chosen fonts
|
|
63
|
+
import inter from "@capsizecss/metrics/inter"
|
|
64
|
+
import arial from "@capsizecss/metrics/arial"
|
|
65
|
+
|
|
66
|
+
export default defineConfig({
|
|
67
|
+
plugins: [
|
|
68
|
+
react(),
|
|
69
|
+
capsizeRadixPlugin({
|
|
70
|
+
outputPath: `./public/typography.css`,
|
|
71
|
+
defaultFontStack: [inter, arial],
|
|
72
|
+
}),
|
|
73
|
+
],
|
|
74
|
+
})
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 2. Install Fonts via Fontsource
|
|
78
|
+
|
|
79
|
+
For open source fonts, use [@fontsource](https://fontsource.org/):
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
pnpm add @fontsource/inter
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### 3. Import CSS in Correct Order
|
|
86
|
+
|
|
87
|
+
In your entry file (e.g., `main.tsx`), the import order matters:
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
// 1. Radix base styles FIRST
|
|
91
|
+
import "@radix-ui/themes/styles.css"
|
|
92
|
+
|
|
93
|
+
// 2. Your font CSS from Fontsource
|
|
94
|
+
import "@fontsource/inter/latin.css"
|
|
95
|
+
|
|
96
|
+
// 3. Generated typography CSS LAST (overrides Radix variables)
|
|
97
|
+
import "/typography.css"
|
|
98
|
+
|
|
99
|
+
// 4. Your app styles
|
|
100
|
+
import "./App.css"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**Critical**: The generated typography CSS must come AFTER `@radix-ui/themes/styles.css` to properly override the CSS variables.
|
|
104
|
+
|
|
105
|
+
## Using Fontsource Fonts
|
|
106
|
+
|
|
107
|
+
Fontsource provides npm packages for Google Fonts and other open source fonts. Each package includes the font files and CSS.
|
|
108
|
+
|
|
109
|
+
### Installation Pattern
|
|
110
|
+
|
|
111
|
+
```bash
|
|
112
|
+
# Install the font package
|
|
113
|
+
pnpm add @fontsource/[font-name]
|
|
114
|
+
|
|
115
|
+
# Install the metrics (usually same name, check @capsizecss/metrics)
|
|
116
|
+
# Metrics are included in @capsizecss/metrics
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
### Import Patterns
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
// Full font (all weights, styles, subsets)
|
|
123
|
+
import "@fontsource/inter"
|
|
124
|
+
|
|
125
|
+
// Specific subset (recommended for performance)
|
|
126
|
+
import "@fontsource/inter/latin.css"
|
|
127
|
+
|
|
128
|
+
// Specific weight
|
|
129
|
+
import "@fontsource/inter/400.css"
|
|
130
|
+
import "@fontsource/inter/700.css"
|
|
131
|
+
|
|
132
|
+
// Variable font (if available)
|
|
133
|
+
import "@fontsource-variable/inter"
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Common Fontsource Packages
|
|
137
|
+
|
|
138
|
+
| Font | Package | Metrics Import |
|
|
139
|
+
|------|---------|----------------|
|
|
140
|
+
| Albert Sans | `@fontsource/albert-sans` | `@capsizecss/metrics/albertSans` |
|
|
141
|
+
| Alegreya | `@fontsource/alegreya` | `@capsizecss/metrics/alegreya` |
|
|
142
|
+
| Alegreya Sans | `@fontsource/alegreya-sans` | `@capsizecss/metrics/alegreyaSans` |
|
|
143
|
+
| Archivo | `@fontsource/archivo` | `@capsizecss/metrics/archivo` |
|
|
144
|
+
| Arvo | `@fontsource/arvo` | `@capsizecss/metrics/arvo` |
|
|
145
|
+
| Atkinson Hyperlegible | `@fontsource/atkinson-hyperlegible` | `@capsizecss/metrics/atkinsonHyperlegible` |
|
|
146
|
+
| Be Vietnam Pro | `@fontsource/be-vietnam-pro` | `@capsizecss/metrics/beVietnamPro` |
|
|
147
|
+
| Bodoni Moda | `@fontsource/bodoni-moda` | `@capsizecss/metrics/bodoniModa` |
|
|
148
|
+
| Bricolage Grotesque | `@fontsource/bricolage-grotesque` | `@capsizecss/metrics/bricolageGrotesque` |
|
|
149
|
+
| Cabin | `@fontsource/cabin` | `@capsizecss/metrics/cabin` |
|
|
150
|
+
| Cabin Condensed | `@fontsource/cabin-condensed` | `@capsizecss/metrics/cabinCondensed` |
|
|
151
|
+
| Commissioner | `@fontsource/commissioner` | `@capsizecss/metrics/commissioner` |
|
|
152
|
+
| Crimson Text | `@fontsource/crimson-text` | `@capsizecss/metrics/crimsonText` |
|
|
153
|
+
| DM Sans | `@fontsource/dm-sans` | `@capsizecss/metrics/dmSans` |
|
|
154
|
+
| DM Serif Display | `@fontsource/dm-serif-display` | `@capsizecss/metrics/dmSerifDisplay` |
|
|
155
|
+
| DM Serif Text | `@fontsource/dm-serif-text` | `@capsizecss/metrics/dmSerifText` |
|
|
156
|
+
| Domine | `@fontsource/domine` | `@capsizecss/metrics/domine` |
|
|
157
|
+
| Epilogue | `@fontsource/epilogue` | `@capsizecss/metrics/epilogue` |
|
|
158
|
+
| Exo | `@fontsource/exo` | `@capsizecss/metrics/exo` |
|
|
159
|
+
| Figtree | `@fontsource/figtree` | `@capsizecss/metrics/figtree` |
|
|
160
|
+
| Fira Sans | `@fontsource/fira-sans` | `@capsizecss/metrics/firaSans` |
|
|
161
|
+
| Fraunces | `@fontsource/fraunces` | `@capsizecss/metrics/fraunces` |
|
|
162
|
+
| Geist | `@fontsource/geist-sans` | `@capsizecss/metrics/geist` |
|
|
163
|
+
| Instrument Sans | `@fontsource/instrument-sans` | `@capsizecss/metrics/instrumentSans` |
|
|
164
|
+
| Instrument Serif | `@fontsource/instrument-serif` | `@capsizecss/metrics/instrumentSerif` |
|
|
165
|
+
| Inter | `@fontsource/inter` | `@capsizecss/metrics/inter` |
|
|
166
|
+
| Josefin Sans | `@fontsource/josefin-sans` | `@capsizecss/metrics/josefinSans` |
|
|
167
|
+
| Lato | `@fontsource/lato` | `@capsizecss/metrics/lato` |
|
|
168
|
+
| Lexend | `@fontsource/lexend` | `@capsizecss/metrics/lexend` |
|
|
169
|
+
| Libre Baskerville | `@fontsource/libre-baskerville` | `@capsizecss/metrics/libreBaskerville` |
|
|
170
|
+
| Literata | `@fontsource/literata` | `@capsizecss/metrics/literata` |
|
|
171
|
+
| Lora | `@fontsource/lora` | `@capsizecss/metrics/lora` |
|
|
172
|
+
| Manrope | `@fontsource/manrope` | `@capsizecss/metrics/manrope` |
|
|
173
|
+
| Merriweather | `@fontsource/merriweather` | `@capsizecss/metrics/merriweather` |
|
|
174
|
+
| Merriweather Sans | `@fontsource/merriweather-sans` | `@capsizecss/metrics/merriweatherSans` |
|
|
175
|
+
| Montserrat | `@fontsource/montserrat` | `@capsizecss/metrics/montserrat` |
|
|
176
|
+
| Neuton | `@fontsource/neuton` | `@capsizecss/metrics/neuton` |
|
|
177
|
+
| Newsreader | `@fontsource/newsreader` | `@capsizecss/metrics/newsreader` |
|
|
178
|
+
| Open Sans | `@fontsource/open-sans` | `@capsizecss/metrics/openSans` |
|
|
179
|
+
| Oswald | `@fontsource/oswald` | `@capsizecss/metrics/oswald` |
|
|
180
|
+
| Outfit | `@fontsource/outfit` | `@capsizecss/metrics/outfit` |
|
|
181
|
+
| Patua One | `@fontsource/patua-one` | `@capsizecss/metrics/patuaOne` |
|
|
182
|
+
| Playfair Display | `@fontsource/playfair-display` | `@capsizecss/metrics/playfairDisplay` |
|
|
183
|
+
| Plus Jakarta Sans | `@fontsource/plus-jakarta-sans` | `@capsizecss/metrics/plusJakartaSans` |
|
|
184
|
+
| PT Sans | `@fontsource/pt-sans` | `@capsizecss/metrics/pTSans` |
|
|
185
|
+
| Quattrocento Sans | `@fontsource/quattrocento-sans` | `@capsizecss/metrics/quattrocentoSans` |
|
|
186
|
+
| Raleway | `@fontsource/raleway` | `@capsizecss/metrics/raleway` |
|
|
187
|
+
| Roboto | `@fontsource/roboto` | `@capsizecss/metrics/roboto` |
|
|
188
|
+
| Roboto Condensed | `@fontsource/roboto-condensed` | `@capsizecss/metrics/robotoCondensed` |
|
|
189
|
+
| Roboto Slab | `@fontsource/roboto-slab` | `@capsizecss/metrics/robotoSlab` |
|
|
190
|
+
| Rosario | `@fontsource/rosario` | `@capsizecss/metrics/rosario` |
|
|
191
|
+
| Sora | `@fontsource/sora` | `@capsizecss/metrics/sora` |
|
|
192
|
+
| Source Sans 3 | `@fontsource/source-sans-3` | `@capsizecss/metrics/sourceSans3` |
|
|
193
|
+
| Source Serif 4 | `@fontsource/source-serif-4` | `@capsizecss/metrics/sourceSerif4` |
|
|
194
|
+
| Space Grotesk | `@fontsource/space-grotesk` | `@capsizecss/metrics/spaceGrotesk` |
|
|
195
|
+
| Varela Round | `@fontsource/varela-round` | `@capsizecss/metrics/varelaRound` |
|
|
196
|
+
| Vollkorn | `@fontsource/vollkorn` | `@capsizecss/metrics/vollkorn` |
|
|
197
|
+
| Work Sans | `@fontsource/work-sans` | `@capsizecss/metrics/workSans` |
|
|
198
|
+
| Yrsa | `@fontsource/yrsa` | `@capsizecss/metrics/yrsa` |
|
|
199
|
+
|
|
200
|
+
## Plugin Configuration Options
|
|
201
|
+
|
|
202
|
+
```typescript
|
|
203
|
+
capsizeRadixPlugin({
|
|
204
|
+
// Required: where to write the generated CSS
|
|
205
|
+
outputPath: `./public/typography.css`,
|
|
206
|
+
|
|
207
|
+
// Body text font stack (first font = primary, rest = fallbacks)
|
|
208
|
+
defaultFontStack: [inter, arial],
|
|
209
|
+
|
|
210
|
+
// Heading font stack (defaults to defaultFontStack if not specified)
|
|
211
|
+
headingFontStack: [playfairDisplay, arial],
|
|
212
|
+
|
|
213
|
+
// Code/monospace font stack
|
|
214
|
+
codingFontStack: [sourceCodePro],
|
|
215
|
+
|
|
216
|
+
// Custom text sizes (fontSize = cap-height, lineHeight = total)
|
|
217
|
+
textStyles: [
|
|
218
|
+
{ fontSize: 9, lineHeight: 19 }, // size 1
|
|
219
|
+
{ fontSize: 11, lineHeight: 23 }, // size 2
|
|
220
|
+
{ fontSize: 12, lineHeight: 25 }, // size 3 (mobile default)
|
|
221
|
+
{ fontSize: 14, lineHeight: 28 }, // size 4 (desktop default)
|
|
222
|
+
{ fontSize: 18, lineHeight: 30 }, // size 5
|
|
223
|
+
{ fontSize: 24, lineHeight: 36 }, // size 6
|
|
224
|
+
{ fontSize: 36, lineHeight: 44 }, // size 7
|
|
225
|
+
{ fontSize: 48, lineHeight: 52 }, // size 8
|
|
226
|
+
{ fontSize: 64, lineHeight: 64 }, // size 9
|
|
227
|
+
],
|
|
228
|
+
})
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Font Pairing Recommendations
|
|
232
|
+
|
|
233
|
+
These pairings are drawn from [typography.js themes](https://github.com/KyleAMathews/typography.js), a collection of carefully designed typographic systems. Choose based on your app's personality.
|
|
234
|
+
|
|
235
|
+
### Quick Reference Table
|
|
236
|
+
|
|
237
|
+
| Theme | Body | Heading | Vibe |
|
|
238
|
+
|-------|------|---------|------|
|
|
239
|
+
| Alton | Open Sans | Domine | Professional, authoritative |
|
|
240
|
+
| De Young | Alegreya | Alegreya Sans | Literary, sophisticated |
|
|
241
|
+
| Doelger | Cabin | Arvo | Friendly, sturdy |
|
|
242
|
+
| Elk Glen | PT Sans | Oswald | Bold, industrial |
|
|
243
|
+
| Fairy Gates | Quattrocento Sans | Work Sans | Warm, inviting |
|
|
244
|
+
| Funston | Cabin Condensed | Patua One | Playful, distinctive |
|
|
245
|
+
| Grand View | Arvo | Montserrat | Modern slab, geometric |
|
|
246
|
+
| Irving | Yrsa | Exo | Editorial, futuristic |
|
|
247
|
+
| Judah | Vollkorn | Roboto Condensed | Classic, efficient |
|
|
248
|
+
| Kirkham | Fira Sans | Playfair Display | Elegant contrast |
|
|
249
|
+
| Lawton | Libre Baskerville | Raleway | Traditional meets modern |
|
|
250
|
+
| Legible | Fira Sans | Merriweather | Highly readable |
|
|
251
|
+
| Lincoln | Lora | Varela Round | Bookish, friendly |
|
|
252
|
+
| Moraga | Source Sans Pro | Source Sans Pro | Clean, unified |
|
|
253
|
+
| Noriega | Lato | Lato | Simple, warm |
|
|
254
|
+
| Ocean Beach | Roboto | Roboto Slab | Technical, solid |
|
|
255
|
+
| Parnassus | Merriweather | Merriweather Sans | Literary, premium |
|
|
256
|
+
| St. Annes | Source Sans 3 | Source Serif 4 | Adobe superfamily |
|
|
257
|
+
| Stardust | Merriweather | Josefin Sans | Dreamy, vintage |
|
|
258
|
+
| Stern Grove | Georgia | Montserrat | Classic body, modern heads |
|
|
259
|
+
| Stow Lake | Lato | Neuton | Contemporary, refined |
|
|
260
|
+
| Sutro | Merriweather | Open Sans | Readable, friendly |
|
|
261
|
+
| Twin Peaks | Crimson Text | Rosario | Book typography |
|
|
262
|
+
| US Web Design | Source Sans 3 | Merriweather | Government standard |
|
|
263
|
+
|
|
264
|
+
---
|
|
265
|
+
|
|
266
|
+
### Clean & Modern (SaaS, Dashboards, Tools)
|
|
267
|
+
|
|
268
|
+
**Inter** - The gold standard for UI typography
|
|
269
|
+
```typescript
|
|
270
|
+
import inter from "@capsizecss/metrics/inter"
|
|
271
|
+
import arial from "@capsizecss/metrics/arial"
|
|
272
|
+
capsizeRadixPlugin({
|
|
273
|
+
outputPath: `./public/typography.css`,
|
|
274
|
+
defaultFontStack: [inter, arial],
|
|
275
|
+
})
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
**Lato** *(Noriega theme)* - Warm, humanist sans-serif
|
|
279
|
+
```typescript
|
|
280
|
+
import lato from "@capsizecss/metrics/lato"
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**Roboto + Roboto Slab** *(Ocean Beach theme)* - Material Design inspired
|
|
284
|
+
```typescript
|
|
285
|
+
import roboto from "@capsizecss/metrics/roboto"
|
|
286
|
+
import robotoSlab from "@capsizecss/metrics/robotoSlab"
|
|
287
|
+
capsizeRadixPlugin({
|
|
288
|
+
outputPath: `./public/typography.css`,
|
|
289
|
+
defaultFontStack: [roboto, arial],
|
|
290
|
+
headingFontStack: [robotoSlab, georgia],
|
|
291
|
+
})
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
### Editorial & Content-Heavy (Blogs, Documentation)
|
|
297
|
+
|
|
298
|
+
**Source Serif 4 + Source Sans 3** *(St. Annes theme)* - Adobe's superfamily
|
|
299
|
+
```typescript
|
|
300
|
+
import sourceSerif from "@capsizecss/metrics/sourceSerif4"
|
|
301
|
+
import sourceSans from "@capsizecss/metrics/sourceSans3"
|
|
302
|
+
capsizeRadixPlugin({
|
|
303
|
+
outputPath: `./public/typography.css`,
|
|
304
|
+
headingFontStack: [sourceSerif, georgia],
|
|
305
|
+
defaultFontStack: [sourceSans, arial],
|
|
306
|
+
})
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
**Merriweather + Merriweather Sans** *(Parnassus theme)* - Screen-optimized serif
|
|
310
|
+
```typescript
|
|
311
|
+
import merriweather from "@capsizecss/metrics/merriweather"
|
|
312
|
+
import merriweatherSans from "@capsizecss/metrics/merriweatherSans"
|
|
313
|
+
capsizeRadixPlugin({
|
|
314
|
+
outputPath: `./public/typography.css`,
|
|
315
|
+
defaultFontStack: [merriweather, georgia],
|
|
316
|
+
headingFontStack: [merriweatherSans, arial],
|
|
317
|
+
})
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
**Merriweather + Open Sans** *(Sutro theme)* - Readable body, friendly headings
|
|
321
|
+
```typescript
|
|
322
|
+
import merriweather from "@capsizecss/metrics/merriweather"
|
|
323
|
+
import openSans from "@capsizecss/metrics/openSans"
|
|
324
|
+
capsizeRadixPlugin({
|
|
325
|
+
outputPath: `./public/typography.css`,
|
|
326
|
+
defaultFontStack: [merriweather, georgia],
|
|
327
|
+
headingFontStack: [openSans, arial],
|
|
328
|
+
})
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
**Source Sans 3 + Merriweather** *(US Web Design Standards)* - Government-grade clarity
|
|
332
|
+
```typescript
|
|
333
|
+
import sourceSans from "@capsizecss/metrics/sourceSans3"
|
|
334
|
+
import merriweather from "@capsizecss/metrics/merriweather"
|
|
335
|
+
capsizeRadixPlugin({
|
|
336
|
+
outputPath: `./public/typography.css`,
|
|
337
|
+
defaultFontStack: [sourceSans, arial],
|
|
338
|
+
headingFontStack: [merriweather, georgia],
|
|
339
|
+
})
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
**Fira Sans + Merriweather** *(Legible theme)* - Maximum readability
|
|
343
|
+
```typescript
|
|
344
|
+
import firaSans from "@capsizecss/metrics/firaSans"
|
|
345
|
+
import merriweather from "@capsizecss/metrics/merriweather"
|
|
346
|
+
capsizeRadixPlugin({
|
|
347
|
+
outputPath: `./public/typography.css`,
|
|
348
|
+
defaultFontStack: [firaSans, arial],
|
|
349
|
+
headingFontStack: [merriweather, georgia],
|
|
350
|
+
})
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
### Bold & Distinctive (Marketing, Landing Pages)
|
|
356
|
+
|
|
357
|
+
**Fira Sans + Playfair Display** *(Kirkham theme)* - Elegant contrast
|
|
358
|
+
```typescript
|
|
359
|
+
import firaSans from "@capsizecss/metrics/firaSans"
|
|
360
|
+
import playfairDisplay from "@capsizecss/metrics/playfairDisplay"
|
|
361
|
+
capsizeRadixPlugin({
|
|
362
|
+
outputPath: `./public/typography.css`,
|
|
363
|
+
defaultFontStack: [firaSans, arial],
|
|
364
|
+
headingFontStack: [playfairDisplay, georgia],
|
|
365
|
+
})
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
**Arvo + Montserrat** *(Grand View theme)* - Slab serif meets geometric
|
|
369
|
+
```typescript
|
|
370
|
+
import arvo from "@capsizecss/metrics/arvo"
|
|
371
|
+
import montserrat from "@capsizecss/metrics/montserrat"
|
|
372
|
+
capsizeRadixPlugin({
|
|
373
|
+
outputPath: `./public/typography.css`,
|
|
374
|
+
defaultFontStack: [arvo, georgia],
|
|
375
|
+
headingFontStack: [montserrat, arial],
|
|
376
|
+
})
|
|
377
|
+
```
|
|
378
|
+
|
|
379
|
+
**Libre Baskerville + Raleway** *(Lawton theme)* - Classic meets modern
|
|
380
|
+
```typescript
|
|
381
|
+
import libreBaskerville from "@capsizecss/metrics/libreBaskerville"
|
|
382
|
+
import raleway from "@capsizecss/metrics/raleway"
|
|
383
|
+
capsizeRadixPlugin({
|
|
384
|
+
outputPath: `./public/typography.css`,
|
|
385
|
+
defaultFontStack: [libreBaskerville, georgia],
|
|
386
|
+
headingFontStack: [raleway, arial],
|
|
387
|
+
})
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
**Open Sans + Domine** *(Alton theme)* - Professional authority
|
|
391
|
+
```typescript
|
|
392
|
+
import openSans from "@capsizecss/metrics/openSans"
|
|
393
|
+
import domine from "@capsizecss/metrics/domine"
|
|
394
|
+
capsizeRadixPlugin({
|
|
395
|
+
outputPath: `./public/typography.css`,
|
|
396
|
+
defaultFontStack: [openSans, arial],
|
|
397
|
+
headingFontStack: [domine, georgia],
|
|
398
|
+
})
|
|
399
|
+
```
|
|
400
|
+
|
|
401
|
+
---
|
|
402
|
+
|
|
403
|
+
### Literary & Sophisticated (Publishing, Portfolios)
|
|
404
|
+
|
|
405
|
+
**Alegreya + Alegreya Sans** *(De Young theme)* - Designed for literature
|
|
406
|
+
```typescript
|
|
407
|
+
import alegreya from "@capsizecss/metrics/alegreya"
|
|
408
|
+
import alegreyaSans from "@capsizecss/metrics/alegreyaSans"
|
|
409
|
+
capsizeRadixPlugin({
|
|
410
|
+
outputPath: `./public/typography.css`,
|
|
411
|
+
defaultFontStack: [alegreya, georgia],
|
|
412
|
+
headingFontStack: [alegreyaSans, arial],
|
|
413
|
+
})
|
|
414
|
+
```
|
|
415
|
+
|
|
416
|
+
**Crimson Text + Rosario** *(Twin Peaks theme)* - Classic book typography
|
|
417
|
+
```typescript
|
|
418
|
+
import crimsonText from "@capsizecss/metrics/crimsonText"
|
|
419
|
+
import rosario from "@capsizecss/metrics/rosario"
|
|
420
|
+
capsizeRadixPlugin({
|
|
421
|
+
outputPath: `./public/typography.css`,
|
|
422
|
+
defaultFontStack: [crimsonText, georgia],
|
|
423
|
+
headingFontStack: [rosario, arial],
|
|
424
|
+
})
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
**Vollkorn + Roboto Condensed** *(Judah theme)* - Old-style meets modern
|
|
428
|
+
```typescript
|
|
429
|
+
import vollkorn from "@capsizecss/metrics/vollkorn"
|
|
430
|
+
import robotoCondensed from "@capsizecss/metrics/robotoCondensed"
|
|
431
|
+
capsizeRadixPlugin({
|
|
432
|
+
outputPath: `./public/typography.css`,
|
|
433
|
+
defaultFontStack: [vollkorn, georgia],
|
|
434
|
+
headingFontStack: [robotoCondensed, arial],
|
|
435
|
+
})
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
**Lora + Varela Round** *(Lincoln theme)* - Bookish warmth
|
|
439
|
+
```typescript
|
|
440
|
+
import lora from "@capsizecss/metrics/lora"
|
|
441
|
+
import varelaRound from "@capsizecss/metrics/varelaRound"
|
|
442
|
+
capsizeRadixPlugin({
|
|
443
|
+
outputPath: `./public/typography.css`,
|
|
444
|
+
defaultFontStack: [lora, georgia],
|
|
445
|
+
headingFontStack: [varelaRound, arial],
|
|
446
|
+
})
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
**Merriweather + Josefin Sans** *(Stardust theme)* - Dreamy, vintage feel
|
|
450
|
+
```typescript
|
|
451
|
+
import merriweather from "@capsizecss/metrics/merriweather"
|
|
452
|
+
import josefinSans from "@capsizecss/metrics/josefinSans"
|
|
453
|
+
capsizeRadixPlugin({
|
|
454
|
+
outputPath: `./public/typography.css`,
|
|
455
|
+
defaultFontStack: [merriweather, georgia],
|
|
456
|
+
headingFontStack: [josefinSans, arial],
|
|
457
|
+
})
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
**Yrsa + Exo** *(Irving theme)* - Editorial meets sci-fi
|
|
461
|
+
```typescript
|
|
462
|
+
import yrsa from "@capsizecss/metrics/yrsa"
|
|
463
|
+
import exo from "@capsizecss/metrics/exo"
|
|
464
|
+
capsizeRadixPlugin({
|
|
465
|
+
outputPath: `./public/typography.css`,
|
|
466
|
+
defaultFontStack: [yrsa, georgia],
|
|
467
|
+
headingFontStack: [exo, arial],
|
|
468
|
+
})
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
---
|
|
472
|
+
|
|
473
|
+
### Technical & Industrial
|
|
474
|
+
|
|
475
|
+
**PT Sans + Oswald** *(Elk Glen theme)* - Bold, industrial feel
|
|
476
|
+
```typescript
|
|
477
|
+
import pTSans from "@capsizecss/metrics/pTSans"
|
|
478
|
+
import oswald from "@capsizecss/metrics/oswald"
|
|
479
|
+
capsizeRadixPlugin({
|
|
480
|
+
outputPath: `./public/typography.css`,
|
|
481
|
+
defaultFontStack: [pTSans, arial],
|
|
482
|
+
headingFontStack: [oswald, arial],
|
|
483
|
+
})
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
**Lato + Neuton** *(Stow Lake theme)* - Contemporary refinement
|
|
487
|
+
```typescript
|
|
488
|
+
import lato from "@capsizecss/metrics/lato"
|
|
489
|
+
import neuton from "@capsizecss/metrics/neuton"
|
|
490
|
+
capsizeRadixPlugin({
|
|
491
|
+
outputPath: `./public/typography.css`,
|
|
492
|
+
defaultFontStack: [lato, arial],
|
|
493
|
+
headingFontStack: [neuton, georgia],
|
|
494
|
+
})
|
|
495
|
+
```
|
|
496
|
+
|
|
497
|
+
---
|
|
498
|
+
|
|
499
|
+
### Approachable & Friendly (Consumer Apps)
|
|
500
|
+
|
|
501
|
+
**Quattrocento Sans + Work Sans** *(Fairy Gates theme)* - Warm and inviting
|
|
502
|
+
```typescript
|
|
503
|
+
import quattrocentoSans from "@capsizecss/metrics/quattrocentoSans"
|
|
504
|
+
import workSans from "@capsizecss/metrics/workSans"
|
|
505
|
+
capsizeRadixPlugin({
|
|
506
|
+
outputPath: `./public/typography.css`,
|
|
507
|
+
defaultFontStack: [quattrocentoSans, arial],
|
|
508
|
+
headingFontStack: [workSans, arial],
|
|
509
|
+
})
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
**Cabin + Arvo** *(Doelger theme)* - Friendly humanist with sturdy slab
|
|
513
|
+
```typescript
|
|
514
|
+
import cabin from "@capsizecss/metrics/cabin"
|
|
515
|
+
import arvo from "@capsizecss/metrics/arvo"
|
|
516
|
+
capsizeRadixPlugin({
|
|
517
|
+
outputPath: `./public/typography.css`,
|
|
518
|
+
defaultFontStack: [cabin, arial],
|
|
519
|
+
headingFontStack: [arvo, georgia],
|
|
520
|
+
})
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
**Cabin Condensed + Patua One** *(Funston theme)* - Playful, distinctive
|
|
524
|
+
```typescript
|
|
525
|
+
import cabinCondensed from "@capsizecss/metrics/cabinCondensed"
|
|
526
|
+
import patuaOne from "@capsizecss/metrics/patuaOne"
|
|
527
|
+
capsizeRadixPlugin({
|
|
528
|
+
outputPath: `./public/typography.css`,
|
|
529
|
+
defaultFontStack: [cabinCondensed, arial],
|
|
530
|
+
headingFontStack: [patuaOne, georgia],
|
|
531
|
+
})
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
**Josefin Sans** - Geometric elegance with vintage charm
|
|
535
|
+
```typescript
|
|
536
|
+
import josefinSans from "@capsizecss/metrics/josefinSans"
|
|
537
|
+
capsizeRadixPlugin({
|
|
538
|
+
outputPath: `./public/typography.css`,
|
|
539
|
+
defaultFontStack: [josefinSans, arial],
|
|
540
|
+
})
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
---
|
|
544
|
+
|
|
545
|
+
## Modern Fonts (2015-2025)
|
|
546
|
+
|
|
547
|
+
These fonts represent the best typography additions from the last decade, featuring variable font support and modern design sensibilities.
|
|
548
|
+
|
|
549
|
+
### Modern Sans-Serifs
|
|
550
|
+
|
|
551
|
+
**Plus Jakarta Sans** - Geometric warmth, variable font
|
|
552
|
+
```typescript
|
|
553
|
+
import plusJakartaSans from "@capsizecss/metrics/plusJakartaSans"
|
|
554
|
+
capsizeRadixPlugin({
|
|
555
|
+
outputPath: `./public/typography.css`,
|
|
556
|
+
defaultFontStack: [plusJakartaSans, arial],
|
|
557
|
+
})
|
|
558
|
+
```
|
|
559
|
+
|
|
560
|
+
**Outfit** - Clean geometric, perfect for design systems
|
|
561
|
+
```typescript
|
|
562
|
+
import outfit from "@capsizecss/metrics/outfit"
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
**Manrope** - Humanist geometric, friendly and modern
|
|
566
|
+
```typescript
|
|
567
|
+
import manrope from "@capsizecss/metrics/manrope"
|
|
568
|
+
```
|
|
569
|
+
|
|
570
|
+
**Sora** - Futuristic, UI-optimized
|
|
571
|
+
```typescript
|
|
572
|
+
import sora from "@capsizecss/metrics/sora"
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
**Figtree** - Clean yet friendly, great for UI
|
|
576
|
+
```typescript
|
|
577
|
+
import figtree from "@capsizecss/metrics/figtree"
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
**Space Grotesk** - Tech-forward, futuristic
|
|
581
|
+
```typescript
|
|
582
|
+
import spaceGrotesk from "@capsizecss/metrics/spaceGrotesk"
|
|
583
|
+
```
|
|
584
|
+
|
|
585
|
+
**Geist** - Vercel's font, optimized for code/web apps
|
|
586
|
+
```typescript
|
|
587
|
+
import geist from "@capsizecss/metrics/geist"
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
---
|
|
591
|
+
|
|
592
|
+
### Modern Serifs
|
|
593
|
+
|
|
594
|
+
**Instrument Serif + Instrument Sans** - Rising star, editorial elegance
|
|
595
|
+
```typescript
|
|
596
|
+
import instrumentSerif from "@capsizecss/metrics/instrumentSerif"
|
|
597
|
+
import instrumentSans from "@capsizecss/metrics/instrumentSans"
|
|
598
|
+
capsizeRadixPlugin({
|
|
599
|
+
outputPath: `./public/typography.css`,
|
|
600
|
+
headingFontStack: [instrumentSerif, georgia],
|
|
601
|
+
defaultFontStack: [instrumentSans, arial],
|
|
602
|
+
})
|
|
603
|
+
```
|
|
604
|
+
|
|
605
|
+
**DM Serif Display + DM Sans** - Google/DeepMind family, cohesive
|
|
606
|
+
```typescript
|
|
607
|
+
import dmSerifDisplay from "@capsizecss/metrics/dmSerifDisplay"
|
|
608
|
+
import dmSans from "@capsizecss/metrics/dmSans"
|
|
609
|
+
capsizeRadixPlugin({
|
|
610
|
+
outputPath: `./public/typography.css`,
|
|
611
|
+
headingFontStack: [dmSerifDisplay, georgia],
|
|
612
|
+
defaultFontStack: [dmSans, arial],
|
|
613
|
+
})
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
**Newsreader + Figtree** - Designed for long-form reading
|
|
617
|
+
```typescript
|
|
618
|
+
import newsreader from "@capsizecss/metrics/newsreader"
|
|
619
|
+
import figtree from "@capsizecss/metrics/figtree"
|
|
620
|
+
capsizeRadixPlugin({
|
|
621
|
+
outputPath: `./public/typography.css`,
|
|
622
|
+
defaultFontStack: [newsreader, georgia],
|
|
623
|
+
headingFontStack: [figtree, arial],
|
|
624
|
+
})
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
**Literata** - Google Play Books default, exceptional for reading
|
|
628
|
+
```typescript
|
|
629
|
+
import literata from "@capsizecss/metrics/literata"
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
**Fraunces + Epilogue** - Expressive soft-serif with unique "wonk" axis
|
|
633
|
+
```typescript
|
|
634
|
+
import fraunces from "@capsizecss/metrics/fraunces"
|
|
635
|
+
import epilogue from "@capsizecss/metrics/epilogue"
|
|
636
|
+
capsizeRadixPlugin({
|
|
637
|
+
outputPath: `./public/typography.css`,
|
|
638
|
+
headingFontStack: [fraunces, georgia],
|
|
639
|
+
defaultFontStack: [epilogue, arial],
|
|
640
|
+
})
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
**Bodoni Moda + Outfit** - High-fashion luxury
|
|
644
|
+
```typescript
|
|
645
|
+
import bodoniModa from "@capsizecss/metrics/bodoniModa"
|
|
646
|
+
import outfit from "@capsizecss/metrics/outfit"
|
|
647
|
+
capsizeRadixPlugin({
|
|
648
|
+
outputPath: `./public/typography.css`,
|
|
649
|
+
headingFontStack: [bodoniModa, georgia],
|
|
650
|
+
defaultFontStack: [outfit, arial],
|
|
651
|
+
})
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
---
|
|
655
|
+
|
|
656
|
+
### Tech & Developer
|
|
657
|
+
|
|
658
|
+
**Space Grotesk + Space Mono** - Cohesive tech aesthetic
|
|
659
|
+
```typescript
|
|
660
|
+
import spaceGrotesk from "@capsizecss/metrics/spaceGrotesk"
|
|
661
|
+
import spaceMono from "@capsizecss/metrics/spaceMono"
|
|
662
|
+
capsizeRadixPlugin({
|
|
663
|
+
outputPath: `./public/typography.css`,
|
|
664
|
+
defaultFontStack: [spaceGrotesk, arial],
|
|
665
|
+
codingFontStack: [spaceMono],
|
|
666
|
+
})
|
|
667
|
+
```
|
|
668
|
+
|
|
669
|
+
**Geist + Geist Mono** - Vercel's Next.js default
|
|
670
|
+
```typescript
|
|
671
|
+
import geist from "@capsizecss/metrics/geist"
|
|
672
|
+
import geistMono from "@capsizecss/metrics/geistMono"
|
|
673
|
+
capsizeRadixPlugin({
|
|
674
|
+
outputPath: `./public/typography.css`,
|
|
675
|
+
defaultFontStack: [geist, arial],
|
|
676
|
+
codingFontStack: [geistMono],
|
|
677
|
+
})
|
|
678
|
+
```
|
|
679
|
+
|
|
680
|
+
**Be Vietnam Pro** - Neo-grotesque for tech companies
|
|
681
|
+
```typescript
|
|
682
|
+
import beVietnamPro from "@capsizecss/metrics/beVietnamPro"
|
|
683
|
+
```
|
|
684
|
+
|
|
685
|
+
**Bricolage Grotesque** - Editorial tech, variable width
|
|
686
|
+
```typescript
|
|
687
|
+
import bricolageGrotesque from "@capsizecss/metrics/bricolageGrotesque"
|
|
688
|
+
```
|
|
689
|
+
|
|
690
|
+
---
|
|
691
|
+
|
|
692
|
+
### Accessibility-Focused
|
|
693
|
+
|
|
694
|
+
**Atkinson Hyperlegible** - Braille Institute, maximizes character recognition
|
|
695
|
+
```typescript
|
|
696
|
+
import atkinsonHyperlegible from "@capsizecss/metrics/atkinsonHyperlegible"
|
|
697
|
+
capsizeRadixPlugin({
|
|
698
|
+
outputPath: `./public/typography.css`,
|
|
699
|
+
defaultFontStack: [atkinsonHyperlegible, arial],
|
|
700
|
+
})
|
|
701
|
+
```
|
|
702
|
+
|
|
703
|
+
**Lexend** - Reduces visual stress, improves reading performance
|
|
704
|
+
```typescript
|
|
705
|
+
import lexend from "@capsizecss/metrics/lexend"
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
---
|
|
709
|
+
|
|
710
|
+
### Versatile Modern Choices
|
|
711
|
+
|
|
712
|
+
**Commissioner** - Humanist with unique "flair" axis
|
|
713
|
+
```typescript
|
|
714
|
+
import commissioner from "@capsizecss/metrics/commissioner"
|
|
715
|
+
```
|
|
716
|
+
|
|
717
|
+
**Epilogue** - Clean variable sans, works at all sizes
|
|
718
|
+
```typescript
|
|
719
|
+
import epilogue from "@capsizecss/metrics/epilogue"
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
**Albert Sans** - Contemporary humanist warmth
|
|
723
|
+
```typescript
|
|
724
|
+
import albertSans from "@capsizecss/metrics/albertSans"
|
|
725
|
+
```
|
|
726
|
+
|
|
727
|
+
**Archivo** - Neo-grotesque superfamily (normal, condensed, black)
|
|
728
|
+
```typescript
|
|
729
|
+
import archivo from "@capsizecss/metrics/archivo"
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
---
|
|
733
|
+
|
|
734
|
+
### Modern Quick Reference
|
|
735
|
+
|
|
736
|
+
| Font | Type | Year | Best For | Variable |
|
|
737
|
+
|------|------|------|----------|----------|
|
|
738
|
+
| Plus Jakarta Sans | Sans | 2020 | Body/UI | Yes |
|
|
739
|
+
| Outfit | Sans | 2021 | Branding | Yes |
|
|
740
|
+
| Manrope | Sans | 2019 | UI/Body | Yes |
|
|
741
|
+
| Sora | Sans | 2020 | Apps/UI | Yes |
|
|
742
|
+
| Figtree | Sans | 2022 | UI/Body | Yes |
|
|
743
|
+
| Space Grotesk | Sans | 2018 | Tech/Display | No |
|
|
744
|
+
| Geist | Sans | 2024 | Web Apps | Yes |
|
|
745
|
+
| DM Sans | Sans | 2019 | Small Text | Yes |
|
|
746
|
+
| Instrument Sans | Sans | 2023 | Branding | Yes |
|
|
747
|
+
| Be Vietnam Pro | Sans | 2021 | Tech | Yes |
|
|
748
|
+
| Bricolage Grotesque | Sans | 2023 | Editorial | Yes |
|
|
749
|
+
| Instrument Serif | Serif | 2023 | Display | No |
|
|
750
|
+
| Newsreader | Serif | 2020 | Long-form | Yes |
|
|
751
|
+
| Literata | Serif | 2015 | Reading | Yes |
|
|
752
|
+
| DM Serif Display | Serif | 2019 | Headlines | No |
|
|
753
|
+
| Bodoni Moda | Serif | 2020 | Luxury | Yes |
|
|
754
|
+
| Fraunces | Serif | 2020 | Expressive | Yes |
|
|
755
|
+
| Atkinson Hyperlegible | Sans | 2021 | Accessibility | Yes |
|
|
756
|
+
| Lexend | Sans | 2019 | Readability | Yes |
|
|
757
|
+
| Commissioner | Sans | 2020 | Multilingual | Yes |
|
|
758
|
+
| Epilogue | Sans | 2018 | Versatile | Yes |
|
|
759
|
+
| Albert Sans | Sans | 2022 | Body/Heads | Yes |
|
|
760
|
+
| Archivo | Sans | 2017 | Headlines | Yes |
|
|
761
|
+
|
|
762
|
+
---
|
|
763
|
+
|
|
764
|
+
### System Fonts (Zero Network Requests)
|
|
765
|
+
|
|
766
|
+
For maximum performance, use system fonts. The plugin defaults to a carefully ordered system font stack:
|
|
767
|
+
|
|
768
|
+
```typescript
|
|
769
|
+
// No font imports needed - plugin uses built-in system font metrics
|
|
770
|
+
capsizeRadixPlugin({
|
|
771
|
+
outputPath: `./public/typography.css`,
|
|
772
|
+
// omit defaultFontStack to use system fonts:
|
|
773
|
+
// Apple System, Segoe UI, Roboto, Ubuntu, Noto Sans
|
|
774
|
+
})
|
|
775
|
+
```
|
|
776
|
+
|
|
777
|
+
## Adding Custom Fonts
|
|
778
|
+
|
|
779
|
+
For fonts not in Fontsource or proprietary fonts:
|
|
780
|
+
|
|
781
|
+
### 1. Get Font Metrics
|
|
782
|
+
|
|
783
|
+
Use `@capsizecss/unpack` to extract metrics from a font file:
|
|
784
|
+
|
|
785
|
+
```bash
|
|
786
|
+
pnpm add -D @capsizecss/unpack
|
|
787
|
+
```
|
|
788
|
+
|
|
789
|
+
```typescript
|
|
790
|
+
// scripts/extract-metrics.ts
|
|
791
|
+
import { fromFile } from "@capsizecss/unpack"
|
|
792
|
+
|
|
793
|
+
const metrics = await fromFile("./fonts/MyCustomFont.woff2")
|
|
794
|
+
console.log(JSON.stringify(metrics, null, 2))
|
|
795
|
+
```
|
|
796
|
+
|
|
797
|
+
### 2. Create a Metrics File
|
|
798
|
+
|
|
799
|
+
Save the output as a TypeScript file:
|
|
800
|
+
|
|
801
|
+
```typescript
|
|
802
|
+
// src/fonts/my-custom-font-metrics.ts
|
|
803
|
+
import type { FontMetrics } from "@capsizecss/core"
|
|
804
|
+
|
|
805
|
+
const myCustomFont: FontMetrics = {
|
|
806
|
+
familyName: "My Custom Font",
|
|
807
|
+
category: "sans-serif",
|
|
808
|
+
capHeight: 700,
|
|
809
|
+
ascent: 935,
|
|
810
|
+
descent: -265,
|
|
811
|
+
lineGap: 0,
|
|
812
|
+
unitsPerEm: 1000,
|
|
813
|
+
xHeight: 520,
|
|
814
|
+
xWidthAvg: 500,
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
export default myCustomFont
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
### 3. Add Font-Face CSS
|
|
821
|
+
|
|
822
|
+
```css
|
|
823
|
+
/* src/fonts/my-custom-font.css */
|
|
824
|
+
@font-face {
|
|
825
|
+
font-family: "My Custom Font";
|
|
826
|
+
src: url("/fonts/MyCustomFont.woff2") format("woff2");
|
|
827
|
+
font-weight: 400;
|
|
828
|
+
font-style: normal;
|
|
829
|
+
font-display: swap;
|
|
830
|
+
}
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
### 4. Configure the Plugin
|
|
834
|
+
|
|
835
|
+
```typescript
|
|
836
|
+
import myCustomFont from "./src/fonts/my-custom-font-metrics"
|
|
837
|
+
import arial from "@capsizecss/metrics/arial"
|
|
838
|
+
|
|
839
|
+
capsizeRadixPlugin({
|
|
840
|
+
outputPath: `./public/typography.css`,
|
|
841
|
+
defaultFontStack: [myCustomFont, arial],
|
|
842
|
+
})
|
|
843
|
+
```
|
|
844
|
+
|
|
845
|
+
### 5. Import the Font CSS
|
|
846
|
+
|
|
847
|
+
```typescript
|
|
848
|
+
// main.tsx
|
|
849
|
+
import "@radix-ui/themes/styles.css"
|
|
850
|
+
import "./src/fonts/my-custom-font.css" // Your @font-face rules
|
|
851
|
+
import "/typography.css" // Generated capsize CSS
|
|
852
|
+
```
|
|
853
|
+
|
|
854
|
+
## Validating Your Setup
|
|
855
|
+
|
|
856
|
+
After configuration, verify:
|
|
857
|
+
|
|
858
|
+
1. **Build succeeds**: `pnpm build` generates the CSS file
|
|
859
|
+
2. **CSS file exists**: Check `outputPath` location
|
|
860
|
+
3. **Variables are overridden**: Inspect `.radix-themes` in browser DevTools
|
|
861
|
+
4. **Text is trimmed**: Text should align precisely to grid lines
|
|
862
|
+
|
|
863
|
+
### Common Issues
|
|
864
|
+
|
|
865
|
+
**CSS not applying**: Check import order - typography CSS must come after Radix styles
|
|
866
|
+
|
|
867
|
+
**Font not loading**: Verify Fontsource import path and that font files are bundled
|
|
868
|
+
|
|
869
|
+
**Metrics mismatch**: Ensure the metrics package matches your font version
|
|
870
|
+
|
|
871
|
+
**Missing fallback**: Always include a fallback font (arial, georgia) for consistent rendering
|
|
872
|
+
|
|
873
|
+
## Code Font Configuration
|
|
874
|
+
|
|
875
|
+
For code blocks and inline code, choose a monospace font:
|
|
876
|
+
|
|
877
|
+
| Font | Package | Metrics Import | Notes |
|
|
878
|
+
|------|---------|----------------|-------|
|
|
879
|
+
| Source Code Pro | `@fontsource/source-code-pro` | `@capsizecss/metrics/sourceCodePro` | Adobe, clean |
|
|
880
|
+
| Fira Code | `@fontsource/fira-code` | `@capsizecss/metrics/firaCode` | Ligatures |
|
|
881
|
+
| JetBrains Mono | `@fontsource/jetbrains-mono` | `@capsizecss/metrics/jetBrainsMono` | IDE-optimized |
|
|
882
|
+
| Geist Mono | `@fontsource/geist-mono` | `@capsizecss/metrics/geistMono` | Vercel/Next.js |
|
|
883
|
+
| Space Mono | `@fontsource/space-mono` | `@capsizecss/metrics/spaceMono` | Retro-tech |
|
|
884
|
+
| DM Mono | `@fontsource/dm-mono` | `@capsizecss/metrics/dmMono` | DeepMind family |
|
|
885
|
+
| IBM Plex Mono | `@fontsource/ibm-plex-mono` | `@capsizecss/metrics/ibmPlexMono` | Corporate |
|
|
886
|
+
| Inconsolata | `@fontsource/inconsolata` | `@capsizecss/metrics/inconsolata` | Compact |
|
|
887
|
+
| Roboto Mono | `@fontsource/roboto-mono` | `@capsizecss/metrics/robotoMono` | Material Design |
|
|
888
|
+
|
|
889
|
+
```typescript
|
|
890
|
+
import sourceCodePro from "@capsizecss/metrics/sourceCodePro"
|
|
891
|
+
|
|
892
|
+
capsizeRadixPlugin({
|
|
893
|
+
outputPath: `./public/typography.css`,
|
|
894
|
+
defaultFontStack: [inter, arial],
|
|
895
|
+
codingFontStack: [sourceCodePro],
|
|
896
|
+
})
|
|
897
|
+
```
|
|
898
|
+
|
|
899
|
+
Don't forget to import the font CSS:
|
|
900
|
+
```typescript
|
|
901
|
+
import "@fontsource/source-code-pro/latin.css"
|
|
902
|
+
```
|
|
903
|
+
|
|
904
|
+
## Full Example
|
|
905
|
+
|
|
906
|
+
```typescript
|
|
907
|
+
// vite.config.ts
|
|
908
|
+
import { defineConfig } from "vite"
|
|
909
|
+
import react from "@vitejs/plugin-react"
|
|
910
|
+
import { capsizeRadixPlugin } from "vite-plugin-capsize-radix"
|
|
911
|
+
import playfairDisplay from "@capsizecss/metrics/playfairDisplay"
|
|
912
|
+
import firaSans from "@capsizecss/metrics/firaSans"
|
|
913
|
+
import sourceCodePro from "@capsizecss/metrics/sourceCodePro"
|
|
914
|
+
import georgia from "@capsizecss/metrics/georgia"
|
|
915
|
+
import arial from "@capsizecss/metrics/arial"
|
|
916
|
+
|
|
917
|
+
export default defineConfig({
|
|
918
|
+
plugins: [
|
|
919
|
+
react(),
|
|
920
|
+
capsizeRadixPlugin({
|
|
921
|
+
outputPath: `./public/typography.css`,
|
|
922
|
+
headingFontStack: [playfairDisplay, georgia],
|
|
923
|
+
defaultFontStack: [firaSans, arial],
|
|
924
|
+
codingFontStack: [sourceCodePro],
|
|
925
|
+
}),
|
|
926
|
+
],
|
|
927
|
+
})
|
|
928
|
+
```
|
|
929
|
+
|
|
930
|
+
```typescript
|
|
931
|
+
// main.tsx
|
|
932
|
+
import React from "react"
|
|
933
|
+
import ReactDOM from "react-dom/client"
|
|
934
|
+
import { Theme } from "@radix-ui/themes"
|
|
935
|
+
import App from "./App"
|
|
936
|
+
|
|
937
|
+
// CSS imports in correct order
|
|
938
|
+
import "@radix-ui/themes/styles.css"
|
|
939
|
+
import "@fontsource/playfair-display/latin.css"
|
|
940
|
+
import "@fontsource/fira-sans/latin.css"
|
|
941
|
+
import "@fontsource/source-code-pro/latin.css"
|
|
942
|
+
import "/typography.css"
|
|
943
|
+
import "./App.css"
|
|
944
|
+
|
|
945
|
+
ReactDOM.createRoot(document.getElementById("root")!).render(
|
|
946
|
+
<React.StrictMode>
|
|
947
|
+
<Theme accentColor="indigo">
|
|
948
|
+
<App />
|
|
949
|
+
</Theme>
|
|
950
|
+
</React.StrictMode>
|
|
951
|
+
)
|
|
952
|
+
```
|
package/dist/index.js
CHANGED
|
@@ -64,6 +64,7 @@ var template = `/* Auto-generated by vite-plugin-capsize-radix */
|
|
|
64
64
|
{{#mobileFontData}}
|
|
65
65
|
--font-size-{{{i}}}: {{{fontSize}}};
|
|
66
66
|
--line-height-{{{i}}}: {{{lineHeight}}};
|
|
67
|
+
--heading-line-height-{{{i}}}: {{{lineHeight}}};
|
|
67
68
|
{{/mobileFontData}}
|
|
68
69
|
|
|
69
70
|
/* Larger devices */
|
|
@@ -71,6 +72,7 @@ var template = `/* Auto-generated by vite-plugin-capsize-radix */
|
|
|
71
72
|
{{#fontData}}
|
|
72
73
|
--font-size-{{{i}}}: {{{fontSize}}};
|
|
73
74
|
--line-height-{{{i}}}: {{{lineHeight}}};
|
|
75
|
+
--heading-line-height-{{{i}}}: {{{lineHeight}}};
|
|
74
76
|
{{/fontData}}
|
|
75
77
|
}
|
|
76
78
|
}
|
|
@@ -127,6 +129,37 @@ var template = `/* Auto-generated by vite-plugin-capsize-radix */
|
|
|
127
129
|
{{{style}}}
|
|
128
130
|
{{/fontData}}
|
|
129
131
|
}
|
|
132
|
+
|
|
133
|
+
/* Native text-box-trim for browsers that support it (Chrome 133+, Safari 18.2+) */
|
|
134
|
+
@supports (text-box-trim: both) {
|
|
135
|
+
.rt-Text,
|
|
136
|
+
.rt-Heading,
|
|
137
|
+
.rt-Em,
|
|
138
|
+
.rt-Quote,
|
|
139
|
+
.rt-Link,
|
|
140
|
+
.rt-Code {
|
|
141
|
+
text-box-trim: both;
|
|
142
|
+
text-box-edge: cap text;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* Disable capsize pseudo-elements when native trim is supported */
|
|
146
|
+
.rt-Text::before,
|
|
147
|
+
.rt-Text::after,
|
|
148
|
+
.rt-Heading::before,
|
|
149
|
+
.rt-Heading::after,
|
|
150
|
+
.rt-Em::before,
|
|
151
|
+
.rt-Em::after,
|
|
152
|
+
.rt-Quote::before,
|
|
153
|
+
.rt-Quote::after,
|
|
154
|
+
.rt-Link::before,
|
|
155
|
+
.rt-Link::after,
|
|
156
|
+
.rt-Code::before,
|
|
157
|
+
.rt-Code::after,
|
|
158
|
+
:where(.rt-Text, .rt-Heading, .rt-Em, .rt-Quote, .rt-Link)::before,
|
|
159
|
+
:where(.rt-Text, .rt-Heading, .rt-Em, .rt-Quote, .rt-Link)::after {
|
|
160
|
+
display: none !important;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
130
163
|
`;
|
|
131
164
|
function validateOptions(options) {
|
|
132
165
|
if (!options.outputPath) {
|
|
@@ -347,9 +380,9 @@ function capsizeRadixPlugin({
|
|
|
347
380
|
{ fontSize: 14, lineHeight: 28 },
|
|
348
381
|
{ fontSize: 18, lineHeight: 30 },
|
|
349
382
|
{ fontSize: 24, lineHeight: 36 },
|
|
350
|
-
{ fontSize: 36, lineHeight:
|
|
351
|
-
{ fontSize: 48, lineHeight:
|
|
352
|
-
{ fontSize: 64, lineHeight:
|
|
383
|
+
{ fontSize: 36, lineHeight: 48 },
|
|
384
|
+
{ fontSize: 48, lineHeight: 60 },
|
|
385
|
+
{ fontSize: 64, lineHeight: 80 }
|
|
353
386
|
],
|
|
354
387
|
defaultFontStack,
|
|
355
388
|
headingFontStack,
|
package/dist/index.mjs
CHANGED
|
@@ -34,6 +34,7 @@ var template = `/* Auto-generated by vite-plugin-capsize-radix */
|
|
|
34
34
|
{{#mobileFontData}}
|
|
35
35
|
--font-size-{{{i}}}: {{{fontSize}}};
|
|
36
36
|
--line-height-{{{i}}}: {{{lineHeight}}};
|
|
37
|
+
--heading-line-height-{{{i}}}: {{{lineHeight}}};
|
|
37
38
|
{{/mobileFontData}}
|
|
38
39
|
|
|
39
40
|
/* Larger devices */
|
|
@@ -41,6 +42,7 @@ var template = `/* Auto-generated by vite-plugin-capsize-radix */
|
|
|
41
42
|
{{#fontData}}
|
|
42
43
|
--font-size-{{{i}}}: {{{fontSize}}};
|
|
43
44
|
--line-height-{{{i}}}: {{{lineHeight}}};
|
|
45
|
+
--heading-line-height-{{{i}}}: {{{lineHeight}}};
|
|
44
46
|
{{/fontData}}
|
|
45
47
|
}
|
|
46
48
|
}
|
|
@@ -97,6 +99,37 @@ var template = `/* Auto-generated by vite-plugin-capsize-radix */
|
|
|
97
99
|
{{{style}}}
|
|
98
100
|
{{/fontData}}
|
|
99
101
|
}
|
|
102
|
+
|
|
103
|
+
/* Native text-box-trim for browsers that support it (Chrome 133+, Safari 18.2+) */
|
|
104
|
+
@supports (text-box-trim: both) {
|
|
105
|
+
.rt-Text,
|
|
106
|
+
.rt-Heading,
|
|
107
|
+
.rt-Em,
|
|
108
|
+
.rt-Quote,
|
|
109
|
+
.rt-Link,
|
|
110
|
+
.rt-Code {
|
|
111
|
+
text-box-trim: both;
|
|
112
|
+
text-box-edge: cap text;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* Disable capsize pseudo-elements when native trim is supported */
|
|
116
|
+
.rt-Text::before,
|
|
117
|
+
.rt-Text::after,
|
|
118
|
+
.rt-Heading::before,
|
|
119
|
+
.rt-Heading::after,
|
|
120
|
+
.rt-Em::before,
|
|
121
|
+
.rt-Em::after,
|
|
122
|
+
.rt-Quote::before,
|
|
123
|
+
.rt-Quote::after,
|
|
124
|
+
.rt-Link::before,
|
|
125
|
+
.rt-Link::after,
|
|
126
|
+
.rt-Code::before,
|
|
127
|
+
.rt-Code::after,
|
|
128
|
+
:where(.rt-Text, .rt-Heading, .rt-Em, .rt-Quote, .rt-Link)::before,
|
|
129
|
+
:where(.rt-Text, .rt-Heading, .rt-Em, .rt-Quote, .rt-Link)::after {
|
|
130
|
+
display: none !important;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
100
133
|
`;
|
|
101
134
|
function validateOptions(options) {
|
|
102
135
|
if (!options.outputPath) {
|
|
@@ -317,9 +350,9 @@ function capsizeRadixPlugin({
|
|
|
317
350
|
{ fontSize: 14, lineHeight: 28 },
|
|
318
351
|
{ fontSize: 18, lineHeight: 30 },
|
|
319
352
|
{ fontSize: 24, lineHeight: 36 },
|
|
320
|
-
{ fontSize: 36, lineHeight:
|
|
321
|
-
{ fontSize: 48, lineHeight:
|
|
322
|
-
{ fontSize: 64, lineHeight:
|
|
353
|
+
{ fontSize: 36, lineHeight: 48 },
|
|
354
|
+
{ fontSize: 48, lineHeight: 60 },
|
|
355
|
+
{ fontSize: 64, lineHeight: 80 }
|
|
323
356
|
],
|
|
324
357
|
defaultFontStack,
|
|
325
358
|
headingFontStack,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-capsize-radix",
|
|
3
3
|
"description": "Great Typography with Radix & Capsize",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.2.0",
|
|
5
5
|
"author": "Kyle Mathews <mathews.kyle@gmail.com>",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@capsizecss/core": "^4.1.3",
|
|
@@ -43,7 +43,8 @@
|
|
|
43
43
|
"./package.json": "./package.json"
|
|
44
44
|
},
|
|
45
45
|
"files": [
|
|
46
|
-
"dist"
|
|
46
|
+
"dist",
|
|
47
|
+
"SKILL.md"
|
|
47
48
|
],
|
|
48
49
|
"keywords": [
|
|
49
50
|
"capsizecss",
|
|
@@ -54,6 +55,16 @@
|
|
|
54
55
|
"license": "MIT",
|
|
55
56
|
"main": "./dist/index.js",
|
|
56
57
|
"module": "./dist/index.mjs",
|
|
58
|
+
"scripts": {
|
|
59
|
+
"build": "pnpm run clean && tsup --external @capsizecss/core --external mustache --external @capsizecss/metrics",
|
|
60
|
+
"check": "tsc",
|
|
61
|
+
"clean": "shx rm -rf dist *.d.ts",
|
|
62
|
+
"lint": "eslint src tests --ext .ts,.tsx",
|
|
63
|
+
"format": "prettier --write .",
|
|
64
|
+
"format:check": "prettier --check .",
|
|
65
|
+
"prepublishOnly": "pnpm run build",
|
|
66
|
+
"test": "vitest run"
|
|
67
|
+
},
|
|
57
68
|
"tsup": {
|
|
58
69
|
"entry": [
|
|
59
70
|
"src/index.ts"
|
|
@@ -64,14 +75,5 @@
|
|
|
64
75
|
],
|
|
65
76
|
"dts": true
|
|
66
77
|
},
|
|
67
|
-
"types": "./dist/index.d.ts"
|
|
68
|
-
|
|
69
|
-
"build": "pnpm run clean && tsup --external @capsizecss/core --external mustache --external @capsizecss/metrics",
|
|
70
|
-
"check": "tsc",
|
|
71
|
-
"clean": "shx rm -rf dist *.d.ts",
|
|
72
|
-
"lint": "eslint src tests --ext .ts,.tsx",
|
|
73
|
-
"format": "prettier --write .",
|
|
74
|
-
"format:check": "prettier --check .",
|
|
75
|
-
"test": "vitest run"
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
+
"types": "./dist/index.d.ts"
|
|
79
|
+
}
|