← Blog
20 Aug 2026typography systemdesign tokenstype scaleaccessible UIDOM Studio

Typography System Guide for Modern UI Builders

Learn how to design and ship a typography system that scales, with practical principles, accessibility rules, tokens and component integration tips.

Typography System Guide for Modern UI Builders

You’ve inherited a front-end codebase that has been alive long enough to accumulate typography decisions from several teams. The h1 is 28px on one route and 32px on another, body copy shifts between 14px and 16px, and three Sass files define font stacks that disagree about fallbacks. The interface still works, but every new component adds another local correction.

A typography system replaces those corrections with an intentional contract. It defines type roles, scale, spacing, hierarchy, font behaviour and accessibility rules, then expresses them through tokens that designers and developers can use consistently across Vue components, headless primitives, documents and assistive technology. The result isn’t merely a more polished screen. It’s a system that remains understandable when content reflows, users zoom, themes change or the same content leaves the browser and becomes a report.

Table of Contents

What a Typography System Actually Is

A typography system is a documented, tokenised set of decisions about how text behaves. It answers questions that a conventional style guide often leaves open:

  • Which font family serves body text, UI labels and code?
  • Which size belongs to a page heading, card title or helper message?
  • How do line height and spacing change between roles?
  • Which weights are permitted?
  • What happens at smaller viewports or increased text settings?
  • How do the same roles map to HTML, PDF and printable content?

A style guide might show a visual example of a heading. A system binds that heading to a semantic token such as --font-size-heading-xl, a line-height token, a weight token and a component contract. A developer then uses <Heading level="2">, rather than choosing a size by eye. That distinction matters because code can enforce constraints while documentation can only describe them.

From isolated values to roles

The useful abstraction isn’t “24px”. It’s heading-large, body-medium, caption-small or form-label. The implementation may use rem, a CSS custom property or a generated Tailwind utility, but the component consumes intent rather than an implementation detail.

A practical role set might include:

Role Typical use Component
Display Hero or page-level statement HeroHeading
Heading Section and content hierarchy Heading
Body Reading and explanatory content Text
Caption Supporting metadata Caption
Label Controls and compact UI Label
Code Technical values and snippets Code

This role-based approach also helps teams working across disciplines. A studio creating a consistent visual identity for graphic design for Texas companies may think in terms of brand expression, while a product team must also account for semantic HTML, responsive behaviour and user-controlled text size. A shared token model gives both groups a stable vocabulary.

The system must travel with the content

Marketing screens are the easy test. The harder test is a long form, a dense table, a rendered Markdown article, a generated PDF or a screen-reader announcement. Typography needs to preserve relationships between heading levels, paragraphs, lists, labels and supporting text in all of those contexts.

That’s why a production system should define more than a scale. It should document:

  • Semantic mapping, so visual headings don’t replace the actual h1 to h6 structure.
  • Flow rules, including paragraph spacing, list spacing and heading margins.
  • Responsive rules, so large type can reduce without making body copy uncomfortable.
  • Accessibility defaults, including relative sizing, readable line lengths and sufficient contrast.
  • Escape hatches, with clear limits, so a legitimate exception doesn’t become a new pattern.

Practical rule: If a developer can add a new text style without choosing a semantic role, the system hasn’t finished its job.

The Four Principles Behind Every Good Type System

Good typography becomes easier to review when you treat it as four connected levers: scale, rhythm, contrast and hierarchy. Each should exist as a token or a component rule, not as a preference applied during visual polish.

An infographic detailing the four key principles of a good typography system: scale, rhythm, contrast, and hierarchy.

Scale

Scale determines how text changes as the viewport changes and how roles differ from one another. A fluid value can interpolate between a smaller and larger size without making every breakpoint a manual exception:

.type-heading-xl {
  font-size: clamp(1.75rem, 1.4rem + 1.5vw, 3rem);
}

Use clamp() selectively. Body text usually needs a stable readable size, while display headings benefit from fluid behaviour. A fluid value should still resolve to a named semantic role, not appear as an unexplained declaration inside a component.

Rhythm

Rhythm is the vertical pattern created by line height, margins and grouping. Unitless line height travels with the font size, which makes it more resilient when users resize text:

:root {
  --leading-body: 1.5;
  --leading-display: 1.2;
  --space-unit: 0.5rem;
}

.prose p {
  line-height: var(--leading-body);
  margin-block: calc(var(--space-unit) * 3);
}

.prose h2 {
  line-height: var(--leading-display);
  margin-block: calc(var(--space-unit) * 6) calc(var(--space-unit) * 2);
}

The goal isn’t mathematical neatness. It’s a predictable reading cadence that distinguishes related content from separate sections.

Contrast

Contrast includes colour, weight, size and density. A dark text colour such as #111 on #fff creates a strong starting point, but every actual foreground and background pairing still needs testing. Body text should meet the 4.5:1 WCAG AA contrast ratio, while large text should meet 3:1, as defined by the WCAG contrast requirements.

:root {
  --colour-text-primary: #111;
  --colour-surface: #fff;
  --weight-body: 400;
  --weight-emphasis: 600;
}

Don’t use colour alone to communicate hierarchy. Weight, position and semantic structure should reinforce the message.

Hierarchy

Hierarchy connects visual prominence to meaning. A component may expose level="1" through level="6", but it should resolve the level to a semantic token rather than printing the number as a size.

:root {
  --font-size-heading-1: 2.5rem;
  --font-size-heading-2: 2rem;
  --font-size-heading-3: 1.5rem;
  --font-size-body: 1rem;
  --font-size-caption: 0.875rem;
}

.heading-1 { font-size: var(--font-size-heading-1); }
.heading-2 { font-size: var(--font-size-heading-2); }
.heading-3 { font-size: var(--font-size-heading-3); }

For another practical treatment of the underlying principles, partial 3 provides useful design-system context. The important implementation choice is to keep the role, not the raw value, at the centre of the API.

Choosing a Type Scale That Fits Your Product

A modular scale gives a product a repeatable relationship between sizes, but the ratio should serve the content. Starting from a 16px base, a 1.125 minor second creates restrained steps, while a 1.5 perfect fifth creates strong jumps that suit more expressive surfaces.

Ratio Name Step sizes from 16px base Best for
1.125 Minor second 16, 18, 20.25, 22.78 Calm editorial interfaces
1.25 Major third 16, 20, 25, 31.25 Compact products with clear grouping
1.333 Perfect fourth 16, 21.33, 28.43, 37.89 General SaaS and mixed content
1.5 Perfect fifth 16, 24, 36, 54 Marketing and content-led display surfaces

The numbers are useful for comparison, not sacred rules. A strict ratio can produce a heading that looks impressive in a specimen but overwhelms a dashboard where headings appear frequently beside controls, filters and data.

Match the ratio to information density

For dense data products, start with 1.2 or 1.25. These ratios give labels, body copy and section headings enough separation without consuming excessive vertical space. For a general SaaS product, 1.333 often creates a clearer content structure, particularly when cards and settings pages need visible section boundaries.

Content-led sites can tolerate 1.5 or larger for display roles, but don’t apply that ratio indiscriminately to every heading. Large jumps make responsive reflow harder, especially when users enlarge text. The heading may wrap into several lines, push controls below the fold or create awkward gaps around adjacent content.

Test the actual middle of the scale

The most difficult decisions usually sit between body text and the main section headings. A scale can have a convincing display size while making h3, h4 and card titles look interchangeable. Test real interface content, including long labels, translated strings, error messages and multi-line headings.

Use separate tokens for the mathematical foundation and the semantic roles:

:root {
  --scale-base: 1rem;
  --scale-step-1: 1.125rem;
  --scale-step-2: 1.25rem;
  --scale-step-3: 1.5rem;

  --font-size-body-md: var(--scale-base);
  --font-size-heading-sm: var(--scale-step-2);
  --font-size-heading-md: var(--scale-step-3);
}

This lets you adjust a role after testing without pretending that every role must remain a perfect modular progression.

Tokenising Type with CSS, Tailwind and Design Tokens

The same scale should have one source of truth, even when your stack has several output formats. CSS custom properties suit a small prototype, Tailwind tokens fit a utility-first application, and a structured token file makes sense when web, native and design tools need the same vocabulary.

CSS custom properties

Raw CSS is the simplest production starting point:

:root {
  --font-size-1: 0.75rem;
  --font-size-2: 0.875rem;
  --font-size-3: 1rem;
  --font-size-4: 1.125rem;
  --font-size-5: 1.5rem;
  --font-size-6: 2rem;

  --font-size-body-md: var(--font-size-3);
  --font-size-heading-sm: var(--font-size-5);
}

Semantic aliases protect components from changes to the primitive scale. Avoid names such as --font-size-16px, because the name locks intent to an implementation value.

Tailwind tokens

Tailwind CSS 4 can expose the same primitives through the theme layer:

@theme {
  --text-xs: 0.75rem;
  --text-sm: 0.875rem;
  --text-base: 1rem;
  --text-lg: 1.125rem;
  --text-xl: 1.5rem;
  --text-2xl: 2rem;
}

A component can then use utilities such as text-base or text-xl, while semantic component classes document why the value is being used. Teams already standardising themes can compare this approach with the Tailwind CSS themes guide, particularly when typography needs to participate in colour and mode changes.

Structured cross-platform tokens

For a cross-platform system, keep values in a neutral format and transform them for each target:

{
  "font": {
    "size": {
      "body-md": {
        "value": "1rem",
        "type": "dimension"
      },
      "heading-sm": {
        "value": "1.5rem",
        "type": "dimension"
      }
    }
  }
}

A Style Dictionary pipeline can export CSS variables, platform-specific values and design-tool data. The important part is the separation between primitive tokens, semantic tokens and component tokens.

Token name CSS variable Tailwind v4 class Style Dictionary value
font.size.1 --font-size-1 text-xs 0.75rem
font.size.2 --font-size-2 text-sm 0.875rem
font.size.3 --font-size-3 text-base 1rem
font.size.4 --font-size-4 text-lg 1.125rem
font.size.5 --font-size-5 text-xl 1.5rem
font.size.6 --font-size-6 text-2xl 2rem

For older browsers or staged migrations, provide a deliberate fallback rather than duplicating arbitrary values:

.heading {
  font-size: 1.5rem;
}

@supports (font-size: var(--font-size-heading-sm)) {
  .heading {
    font-size: var(--font-size-heading-sm);
  }
}

Mapping Tokens to Components in Your UI Library

Tokens become useful when components consume them predictably. A headless library shouldn’t expose a dozen unrelated size props that let every caller invent a new hierarchy. It should expose semantic inputs, resolve them centrally and preserve the HTML structure that assistive technology expects.

Screenshot from https://placehold.co/1200x800/png?text=DOM+Studio+typography+token+mapping

A practical Vue-facing API might look like this:

<Heading :level="2" intent="heading">
  Account details
</Heading>

<Text intent="body">
  Update the information associated with this account.
</Text>

<Caption intent="caption">
  Last saved locally
</Caption>

The implementation can resolve the tag and token independently:

const headingTag = `h${props.level}`

const headingToken = {
  1: 'heading-1',
  2: 'heading-2',
  3: 'heading-3',
  4: 'heading-4',
  5: 'heading-5',
  6: 'heading-6'
}[props.level]

The component then applies font-size, line-height and font-weight from the resolved role. intent="display" may use a display token, but it shouldn’t change an h2 into an h1. Semantic level and visual intent are related, not interchangeable.

Prefer intent over raw size

Consider a card:

<Card>
  <Heading :level="3" intent="heading">Billing history</Heading>
  <Text intent="body">Review invoices and payment activity.</Text>
  <Caption intent="caption">Updated recently</Caption>
</Card>

The card doesn’t know whether body means 16px or another value. It knows that the content is ordinary reading text and should inherit the body role. If the system changes its base scale, the card remains coherent.

A form group follows the same pattern:

<FormField>
  <Label intent="label" for="email">Email address</Label>
  <Input id="email" />
  <Text intent="caption" id="email-help">
    Use the address associated with your account.
  </Text>
</FormField>

Expose constrained overrides for legitimate cases, such as tone="muted" or density="compact". Avoid size="13" unless the component owns that decision. DOM Studio represents one option for this token-driven approach, combining framework-agnostic primitives with a Vue integration layer and Tailwind CSS 4 styling.

A short implementation walkthrough can make the mapping easier to review visually:

Accessibility, Reflow and Inclusive Typography

Accessibility rules should shape the token model before visual refinement begins. GOV.UK Frontend guidance recommends avoiding digital font sizes below 16px, and its typography scale removed the 14px token while retaining 16px across screen sizes. That decision treats legibility as a system constraint rather than a page-by-page judgement.

Use relative units for roles that users may need to resize. The Home Office layout and typography guidance favours em and % over fixed px, along with left alignment, clear headings and line breaks. It also advises avoiding italics and blocks of all-capital text, choices that reduce unnecessary cognitive load.

Encode behaviour, not just appearance

A useful token set includes:

:root {
  --font-size-body-md: 1rem;
  --leading-body: 1.5;
  --leading-heading: 1.2;
  --measure-reading: 65ch;
  --tracking-body: normal;
}

.prose {
  max-inline-size: var(--measure-reading);
}

.prose p {
  font-size: var(--font-size-body-md);
  line-height: var(--leading-body);
  letter-spacing: var(--tracking-body);
}

The exact measure should be tested against the typeface and content. UK guidance for accessible documents recommends 50 to 65 characters per line, while Office for National Statistics guidance gives a broader 75 to 120 characters per line recommendation for its document context. These aren’t contradictory tokens to paste everywhere. They show why the output format and reading mode must be part of the design decision.

HTML is preferred to PDF in GOV.UK’s accessible communication formats guidance, which also recommends 12pt minimum text in general documents and 16pt for large print. The same system therefore needs document mappings for headings, line spacing, emphasis and printable output.

Preserve the semantic tree

Screen readers announce heading levels from the document structure, not from the apparent font size. A component that renders a visually large div instead of an h2 creates a polished visual hierarchy with a broken navigation hierarchy.

Use level to control the native element, then use tokens to control appearance. Test keyboard navigation, zoom and reflow, including long labels and user-controlled font settings. A focused DesignStack accessible web guide can complement that work, while teams can use an accessibility audit workflow to turn checks into repeatable review rather than a final-stage scramble.

Testing, Maintaining and Evolving the System

A typography system drifts when teams can bypass it faster than they can understand it. Maintenance needs to catch visual regressions, undeclared values, broken mappings and accessibility failures as part of normal delivery.

A practical maintenance checklist

  • Visual regression: Use Playwright or Chromatic to capture headings, labels, tables, forms and long-form content at every scale step.
  • Token audits: Run Style Dictionary diffs and repository searches to find undeclared font sizes, unused roles and semantic aliases that no longer resolve.
  • Lint enforcement: Use Stylelint rules such as declaration-property-value-disallowed-list to prevent hard-coded rem values inside components.
  • Documentation updates: Pair token changes with changelog entries, migration notes and examples for Vue consumers.
  • Accessibility retesting: Recheck contrast, heading structure, zoom, reflow and document exports whenever a role changes.

Run visual diffs on every pull request so contributors see the impact while the context is fresh. A monthly token grep audit catches bypasses that snapshots may miss, and each release should include accessibility retesting across representative components.

Treat metadata as part of the API

Component libraries are easier to maintain when contributors can inspect a token mapping without reading implementation details. Expose the role, resolved value, semantic element and allowed overrides in documentation or component metadata. This is especially useful in headless systems, where the behaviour and markup may live separately from the final visual styling.

Keep a record of why a token changed. A smaller heading might improve a dense workflow but weaken hierarchy in a marketing template. A larger body role might help reading but increase the height of a form. The review should name that trade-off and identify which contexts were tested.

For teams formalising the process, design system documentation practices provide a useful reference point. The system is a living agreement between designers, developers and users. Once it reaches production, the work is preventing the next pile of local exceptions.


If your Vue or headless component library needs a coherent type layer, visit DOM Studio to explore token-driven primitives, Vue integrations and Tailwind CSS 4 theming. Start by mapping your existing roles to semantic components, then use the library’s documentation and inspection workflows to keep typography consistent across interfaces and content.