Typography
Two families, one scale of sizes and one of weights, all of them custom properties. The kit ships the faces, and repointing two variables replaces them everywhere at once.
API
Tokens
Two families, named by the job they do rather than by the typeface that happens to fill them: primary is what you read, secondary is what you glance at. No component names a font — they all read one of these two variables, which is what makes a substitution reach the whole kit at once.
| token | |
|---|---|
--margo-font-family-primary | Nunito, the reading typeface |
--margo-font-family-secondary | Bebas Neue, the display typeface |
--margo-font-size-* | mc, xs, sm, base, md, lg, 2lg, xl, 2xl … 9xl |
--margo-font-weight-* | thin through black, mapped to the numeric weights |
The faces
Nunito and Bebas Neue ship with the kit, self-hosted as woff2, and are imported separately from the rest of the CSS. That separation is deliberate: fonts are the one part of a kit a project usually already has — a brand typeface, a licence, a provider — so they stay opt-in, one family at a time.
@import "margo-ui/fonts/nunito.css";
@import "margo-ui/fonts/bebas.css";Examples
Using your own typefaces
Skip the imports entirely and repoint the two variables. Declare the faces however your project already does — @font-face of your own, a provider, a framework loader — then name them here.
/* your own @font-face declarations, or a provider of your choice */
:root {
--margo-font-family-primary: "Inter", helvetica, sans-serif;
--margo-font-family-secondary: "Anton", impact, sans-serif;
}Keep in mind what the secondary family is used for: it is a display face, set in capitals by design. Swapping in a typeface with lowercase letterforms changes how every title of the kit reads, which is a decision worth making deliberately rather than discovering.
Reaching the files
The two stylesheets are the whole setup: they declare the faces and point at the woff2 files themselves, so nothing else is required. The files are exported alongside them for the cases where you need the URL rather than the declaration — a preload, an asset pipeline, a framework that would rather own the @font-face itself. They follow the family name and the weight name, as they are declared in the stylesheets.
margo-ui/fonts/nunito/nunito-medium.woff2
margo-ui/fonts/bebas-neue/bebas-neue-regular.woff2Details
Self-hosted, and painted immediately
The faces are served from your own origin rather than a CDN, which removes a third-party request from the critical path and a privacy question from your legal page. Each one declares font-display: swap, so text paints in the fallback straight away and reflows once the file lands.
Preloading, if you preload
The exported paths are import specifiers resolved by the package, not paths you can serve as they are: how you turn one into a URL, and where you then declare the link, is your bundler's business. What holds everywhere is the rest — preload only the weights that appear above the fold, since preloading everything competes with the page for bandwidth; keep the preloaded URL identical to the one the stylesheet requests; and set crossorigin even when the file is same-origin. Miss either of the last two and the font is fetched twice instead of once.