Overview
Font pairings combine three fonts (heading, body, and mono) with complete CSS configurations for typography across all HTML elements. Each pairing includes metadata, dependencies, CSS variables, and styles.
Schema Structure
Root Fields
Unique identifier for the pairing, typically prefixed with pairing- Example : "pairing-minimal", "pairing-brutalist"
Registry type identifier. Always "registry:style" for pairings.
Base style to extend from. Use "none" for standalone pairings.
Human-readable title showing the pairing name and font combination Format : "{Name} — {Heading} + {Body} + {Mono}"Example : "Minimal — Geist + Geist + Geist Mono"
Descriptive text explaining the pairing’s aesthetic and design philosophy
Array of category tags for filtering and discovery Common categories : "sans-serif", "serif", "minimal", "modern", "brutalist", "display", "bold"
Dependencies
Array of URLs pointing to font configurations in the registry Each URL typically references 2-3 fonts:
Heading font
Body font
Monospace font
Format : "https://www.fonttrio.xyz/r/{font-name}.json"
CSS Variables
Defines CSS custom properties for theme integration Theme-level CSS variables CSS variable reference for heading font Example : "var(--font-geist)"
CSS variable reference for body font Example : "var(--font-inter)"
CSS variable reference for monospace font Example : "var(--font-geist-mono)"
CSS Styles
Complete typography styles for all HTML elements. Keys are CSS selectors, values are style objects. Styles for primary headings Font family, typically referencing var(--font-heading)
Font size in rem, em, or px Example : "2.25rem"
Unitless line height value Example : "1.15"
Letter spacing in em units Example : "-0.025em"
Font weight value (100-900) Example : "700"
Similar structure to h1, can target multiple selectors
Styles for body text and paragraphs Body font family, typically var(--font-body)
Line height for body text Example : "1.6"
Styles for code elements Monospace font family, typically var(--font-mono)
Additional metadata for preview and categorization Sample text for font preview Default : "The quick brown fox jumps over the lazy dog"
Array of mood descriptors Examples : ["modern", "minimal"], ["raw", "brutalist"]
Suggested use cases for the pairing Examples : ["SaaS", "developer tools"], ["portfolio", "art"]
Complete Examples
Minimal Pairing
A clean, modern single-font pairing using Geist:
{
"name" : "pairing-minimal" ,
"type" : "registry:style" ,
"extends" : "none" ,
"title" : "Minimal — Geist + Geist + Geist Mono" ,
"description" : "Ultra-minimal Vercel-style pairing. One font family for everything, clean and modern." ,
"categories" : [ "sans-serif" , "minimal" , "modern" ],
"registryDependencies" : [
"https://www.fonttrio.xyz/r/geist.json" ,
"https://www.fonttrio.xyz/r/geist-mono.json"
],
"cssVars" : {
"theme" : {
"--font-heading" : "var(--font-geist)" ,
"--font-body" : "var(--font-geist)" ,
"--font-mono" : "var(--font-geist-mono)"
}
},
"css" : {
"h1" : {
"font-family" : "var(--font-heading)" ,
"font-size" : "2.25rem" ,
"line-height" : "1.15" ,
"letter-spacing" : "-0.025em" ,
"font-weight" : "700"
},
"h2" : {
"font-family" : "var(--font-heading)" ,
"font-size" : "1.875rem" ,
"line-height" : "1.2" ,
"letter-spacing" : "-0.02em" ,
"font-weight" : "600"
},
"h3" : {
"font-family" : "var(--font-heading)" ,
"font-size" : "1.5rem" ,
"line-height" : "1.3" ,
"letter-spacing" : "-0.015em" ,
"font-weight" : "500"
},
"h4, h5, h6" : {
"font-family" : "var(--font-heading)" ,
"letter-spacing" : "-0.01em"
},
"body, p" : {
"font-family" : "var(--font-body)" ,
"line-height" : "1.6"
},
"code, pre" : {
"font-family" : "var(--font-mono)"
}
},
"meta" : {
"preview" : "The quick brown fox jumps over the lazy dog" ,
"mood" : [ "modern" , "minimal" , "Vercel-style" ],
"useCase" : [ "SaaS" , "developer tools" , "Vercel-style" ]
}
}
Brutalist Pairing
A bold, high-contrast pairing with Archivo Black:
{
"name" : "pairing-brutalist" ,
"type" : "registry:style" ,
"extends" : "none" ,
"title" : "Brutalist — Archivo Black + Archivo + Source Code Pro" ,
"description" : "Raw typographic power. Archivo Black's heavy weight fills every pixel of the headline, while regular Archivo maintains the same DNA in a readable body weight. No decoration, pure function." ,
"categories" : [ "display" , "brutalist" , "bold" ],
"registryDependencies" : [
"https://www.fonttrio.xyz/r/archivo-black.json" ,
"https://www.fonttrio.xyz/r/archivo.json" ,
"https://www.fonttrio.xyz/r/source-code-pro.json"
],
"cssVars" : {
"theme" : {
"--font-heading" : "var(--font-archivo-black)" ,
"--font-body" : "var(--font-archivo)" ,
"--font-mono" : "var(--font-source-code-pro)"
}
},
"css" : {
"h1" : {
"font-family" : "var(--font-heading)" ,
"font-size" : "2.75rem" ,
"line-height" : "1.05" ,
"letter-spacing" : "-0.035em" ,
"font-weight" : "800"
},
"h2" : {
"font-family" : "var(--font-heading)" ,
"font-size" : "2.25rem" ,
"line-height" : "1.1" ,
"letter-spacing" : "-0.025em" ,
"font-weight" : "700"
},
"h3" : {
"font-family" : "var(--font-heading)" ,
"font-size" : "1.75rem" ,
"line-height" : "1.2" ,
"letter-spacing" : "-0.02em" ,
"font-weight" : "700"
},
"h4, h5, h6" : {
"font-family" : "var(--font-heading)" ,
"letter-spacing" : "-0.01em"
},
"body, p" : {
"font-family" : "var(--font-body)" ,
"line-height" : "1.6"
},
"code, pre" : {
"font-family" : "var(--font-mono)"
}
},
"meta" : {
"preview" : "The quick brown fox jumps over the lazy dog" ,
"mood" : [ "raw" , "brutalist" ],
"useCase" : [ "portfolio" , "art" , "experimental" ]
}
}
CSS Override Behavior
When query parameters are provided to the API endpoint, the CSS properties are dynamically overridden:
Example Request
GET /api/r/minimal?h1-size=3rem&body-lh=1.8
Resulting CSS
The returned JSON will have modified CSS:
{
"css" : {
"h1" : {
"font-family" : "var(--font-heading)" ,
"font-size" : "3rem" , // ← Overridden from 2.25rem
"line-height" : "1.15" ,
"letter-spacing" : "-0.025em" ,
"font-weight" : "700"
},
"body, p" : {
"font-family" : "var(--font-body)" ,
"line-height" : "1.8" // ← Overridden from 1.6
}
}
}
Implementation : app/api/r/[name]/route.ts:47-85
Usage in Next.js
import { NextResponse } from 'next/server' ;
interface PairingConfig {
name : string ;
title : string ;
cssVars : {
theme : Record < string , string >;
};
css : Record < string , Record < string , string >>;
}
export async function loadPairing (
name : string ,
overrides ?: Record < string , string >
) : Promise < PairingConfig > {
const params = new URLSearchParams ( overrides );
const url = `https://www.fonttrio.xyz/api/r/ ${ name }${
params . toString () ? `? ${ params } ` : ''
} ` ;
const response = await fetch ( url );
if ( ! response . ok ) {
throw new Error ( `Failed to load pairing: ${ name } ` );
}
return response . json ();
}
// Usage
const pairing = await loadPairing ( 'minimal' );
const customPairing = await loadPairing ( 'brutalist' , {
'h1-size' : '3.5rem' ,
'body-lh' : '1.7'
});
See Also
Font Schema Schema for individual font configurations
API Endpoints Complete endpoint reference with examples