Typography
Sections marked as "Note" or "Example" are non-normative. Everything else is normative.
Typography tokens group font-related metrics such as font family and size.
Consumers MUST ignore unrecognised properties within a typography value.
Future revisions MAY introduce additional typography sub-properties. Producers SHOULD isolate experimental fields within $extensions
using a unique prefix, and consumers MUST continue ignoring unknown members to preserve forward compatibility.
Typography tokens MAY include a typographyType
property to classify intended usage. Canonical values include body
, heading
, and caption
. Vendors MAY register additional types or use identifiers matching the pattern ^[a-zA-Z][\w-]*$
. Unregistered values are outside compatibility guarantees and consumers MUST treat them as vendor-specific. When omitted, consumers SHOULD infer usage from context.
INFO
See Token types for shared $value
requirements that apply to typography tokens.
Composition
Minimal typography tokens define only fontFamily
and fontSize
. Additional properties MAY be layered to build complete styles.
{
"$version": "1.0.0",
"typography": {
"body": {
"$type": "typography",
"$value": {
"fontFamily": "Inter",
"fontSize": { "dimensionType": "length", "value": 16, "unit": "px" }
}
}
}
}
{
"$version": "1.0.0",
"typography": {
"body": {
"$value": { "fontWeight": 700, "lineHeight": 1.5 }
}
}
}
{
"$version": "1.0.0",
"typography": {
"body": {
"$type": "typography",
"$value": {
"fontFamily": "Inter",
"fontWeight": 700,
"lineHeight": 1.5,
"fontSize": { "dimensionType": "length", "value": 16, "unit": "px" }
}
}
}
}
Later layers override earlier properties for matching JSON Pointer paths. Example documents are available in the examples
directory: base, layer, and merged.
Only fontFamily
and fontSize
MUST be supplied. All other members, including lineHeight
, are optional and inherit from the surrounding context when omitted. Implementations SHOULD fall back to platform defaults when a property is not provided.
Common optional properties defer to platform specifications as follows:
wordSpacing
-dimension
or keywordnormal
conforming to theword-spacing
grammar.color
-color
tokens referencing CSS colour spaces or the native colour APIs cited in the colour section.textDecoration
- keyword or shorthand lists matching thetext-decoration
grammar.textTransform
- keyword sequences that satisfy thetext-transform
grammar.fontFeatures
- array of OpenType feature tags registered in OpenType Feature Tag Registry.fontVariant
- keywords from thefont-variant
grammar.fontStretch
- keywords from thefont-stretch
grammar.underlineThickness
-font-dimension
.underlineOffset
-font-dimension
.overlineThickness
-font-dimension
.overlineOffset
-font-dimension
.
Typography values MAY reuse shared tokens via alias objects whose only member is $ref
. The pointer MAY resolve through additional aliases before reaching the source measurement; consumers MUST follow the chain until a concrete token is located. Each $ref
MUST ultimately resolve to a token declaring the expected $type
: fontSize
, letterSpacing
, wordSpacing
, and lineHeight
references MUST terminate at dimension
tokens whose $value.dimensionType
is "length"
, while color
references MUST resolve to color
tokens. Consumers MUST reject $ref
targets that do not meet these requirements so typography tokens remain well-typed composites.
{
"$version": "1.0.0",
"dimension": {
"shared": {
"body-size": {
"$type": "dimension",
"$value": { "dimensionType": "length", "value": 16, "unit": "px" }
},
"body-letter-spacing": {
"$type": "dimension",
"$value": { "dimensionType": "length", "value": -0.5, "unit": "px" }
}
},
"typography": {
"body-size": {
"$type": "dimension",
"$ref": "#/dimension/shared/body-size"
},
"body-letter-spacing": {
"$type": "dimension",
"$ref": "#/dimension/shared/body-letter-spacing"
}
}
},
"typography": {
"body": {
"$type": "typography",
"$value": {
"fontFamily": "Inter",
"fontSize": { "$ref": "#/dimension/typography/body-size" },
"letterSpacing": { "$ref": "#/dimension/typography/body-letter-spacing" }
}
}
}
}
The table below maps typography members to their authoritative references.
Table: Normative references for typography members.
Typography member | Normative references |
---|---|
fontFamily | font-family , iOS font registration, Android font resources |
fontWeight | font-weight , UIFont.Weight, Typeface.Builder#setWeight |
fontStyle | font-style , UIFontDescriptor.SymbolicTraits, UIFontDescriptor.AttributeName.variations, FontVariationAxis, Typeface.Builder#setFontVariationSettings |
letterSpacing | letter-spacing , NSAttributedString.Key.kern, TextView#setLetterSpacing |
wordSpacing | word-spacing |
textDecoration | text-decoration , NSUnderlineStyle, Paint underline flags |
textTransform | text-transform , NSStringTransform, Java String case conversion |
fontFeatures | font-feature-settings , OpenType feature registry |
{
"$type": "typography",
"$value": {
"fontFamily": "Inter",
"fontSize": { "dimensionType": "length", "value": 16, "unit": "px" },
"lineHeight": 1.5,
"letterSpacing": { "dimensionType": "length", "value": 0.5, "unit": "px" },
"wordSpacing": { "dimensionType": "length", "value": 2, "unit": "px" },
"color": { "colorSpace": "srgb", "components": [0.2, 0.25, 0.3, 1] },
"textDecoration": "underline",
"textTransform": "uppercase",
"fontFeatures": ["smcp", "liga"]
}
}
Vendors MAY define additional typography members. Consumers MUST ignore unrecognised properties to maintain interoperability. Producers adding experimental members SHOULD follow the extension naming guidelines (reverse-DNS prefixes, registry reuse, and published documentation) to avoid collisions and clarify proprietary semantics.
Font fallbacks
Font tokens record the canonical family in family
and MAY supply an ordered fallbacks
array. The fallbacks
member MUST contain one or more trimmed strings that satisfy the <family-name>
grammar or the generic-family keywords defined in CSS Fonts Module Level 4. Consumers MUST preserve the supplied order when generating CSS font-family
lists or native descriptors so the stack mirrors DTCG semantics.
When migrating DTCG fontFamily
arrays, producers MUST assign the first entry to family
and the remaining entries to fallbacks
. Typography tokens that reference a font
token—either by string name or $ref
pointer—MUST surface the same ordered stack when emitting CSS or native descriptors. Typography tokens serialised with only a string fontFamily
carry no additional fallback data beyond the primary family name.
Font dimensions
A font-dimension
is a constrained dimension object. The dimensionType
MUST be "length"
, the value
MUST be numeric, and the resulting measurement MUST conform to the <length>
or <percentage>
productions defined in CSS Values and Units. Native consumers MUST interpret points per Apple's layout guidance and density- or scale-independent units per Android's pixel density guidance. Negative values remain valid so designers can intentionally tighten spacing. Producers MAY include fontScale
to indicate whether the value participates in user-controlled font scaling.
A font-dimension
MAY also be expressed as an alias object whose only member is $ref
. Such aliases MUST resolve to tokens declaring $type
"dimension"
and a $value.dimensionType
of "length"
. Alias chains MAY include additional dimension
tokens that themselves forward to shared measurements; consumers MUST resolve the chain until a concrete measurement is found.
Typography members such as lineHeight
, letterSpacing
, and underline metrics reuse font-dimension
so that consumers can apply consistent conversions. Consumers MUST reject font-dimension
objects whose dimensionType
is not "length"
or whose units do not satisfy the grammars cited above. When fontScale
is present, consumers MUST apply the platform scaling behaviour referenced for dimension
tokens.
Line height
lineHeight
MAY be expressed as a unitless number or a font-dimension
.
Unitless numbers represent ratios and inherit as raw numbers so descendants scale with their own fontSize
. Font-dimension values provide an explicit height and inherit as absolute lengths. When lineHeight
is expressed as a font-dimension
, the measurement MUST conform to the <length>
or <percentage>
productions in CSS Values and Units and MUST observe the point and density-scaling semantics defined in Apple's layout guidance, Apple's typography guidance, and Android's pixel density guidance.
- Web consumers MUST multiply ratios by the computed
font-size
and interpret lengths per CSS Values and Units. - Android consumers MUST map ratios to
setLineSpacing
and honour the scaling behaviour for density- and scale-independent units described in Android's pixel density guidance whenfontScale
istrue
. - iOS consumers MUST map ratios to
lineHeightMultiple
, treat absolute points per Apple's layout guidance, and apply Dynamic Type behaviour per Apple's typography guidance whenfontScale
istrue
.
The lineHeight
value MUST represent the baseline-to-baseline distance between lines of text. Additional leading above or below this region is not part of the measurement.
{
"$type": "typography",
"$value": {
"fontSize": { "dimensionType": "length", "value": 16, "unit": "px" },
"lineHeight": 1.5
}
}
The example above yields a baseline distance of 24px
.
The value MUST be non‑negative. Consumers MUST treat strings or negative numbers as invalid. When lineHeight
is omitted, consumers MAY derive a default or inherit from context. Implementations MAY fall back to platform defaults, commonly about 1.2 × fontSize
on the web. Authors should use unitless numbers when the baseline distance ought to scale with fontSize
, and dimension objects when a fixed baseline distance is required (for example to align to a baseline grid). This union of types preserves compatibility in the core specification. A future revision may adopt a dedicated lineHeight
object with members such as value
, unit
, and isRelative
to unify these representations and reduce ambiguity for implementers.
Omitting lineHeight
signals that consumers should inherit baseline spacing from the surrounding context. Authors SHOULD prefer omission over copying resolved platform defaults when native typography metrics are desired.
When multiple representations of lineHeight
are supplied through document layering or overrides, consumers MUST resolve them as follows:
- If a
font-dimension
value is present, convert it to the consumer's internal unit and use it. - Otherwise, if a unitless number is present, multiply it by
fontSize
to obtain an absolute length in the unit offontSize
. - Discard any additional
lineHeight
values.
Consumers MUST normalise lineHeight
font-dimension
values using standard CSS unit conversion rules prior to comparison or inheritance.
Misinterpreting fontScale
, providing unsupported units, or relying on platform-specific defaults can yield inconsistent line spacing. Implementers SHOULD test tokens on target platforms and verify that values marked with fontScale: true
respond to user settings. Cross-platform test suites SHOULD include ratio, absolute, and inherited lineHeight
examples to confirm interoperability.
Letter spacing
letterSpacing
MAY be expressed as the keyword normal
or a font-dimension
measurement.
When letterSpacing
is normal
, the value MUST conform to the letter-spacing
grammar defined in CSS Text. When a font-dimension
is supplied, the measurement MUST conform to the <length>
production in CSS Values and Units and MUST honour the point and density semantics defined in Apple's layout guidance and Android's pixel density guidance.
Native consumers MUST map absolute adjustments using NSAttributedString.Key.kern (points) and TextView#setLetterSpacing (em space deltas). Android implementations MUST divide the resolved absolute length by the computed fontSize
to obtain the em delta expected by the platform API. Negative values remain valid on all platforms.
When provided, the optional fontScale
flag continues to describe whether the spacing participates in user-controlled font scaling, following the conversion rules defined for font-dimension
.
Word spacing
wordSpacing
MAY be expressed as the keyword normal
or a dimension
matching the word-spacing
grammar.
The value MUST conform to the <length-percentage>
production. When a length is supplied, the measurement MUST follow the <length>
grammar. When a percentage is supplied, consumers MUST resolve it against the current fontSize
per CSS Text. Native implementations MUST reuse the unit conversions defined for dimension
tokens so that pt
, dp
, and sp
map to the platform units defined in Apple's layout guidance and Android's pixel density guidance.
Platforms without a dedicated word-spacing API MAY approximate the behaviour by adjusting letter spacing or by emitting a warning and preserving the authored text. When fontScale
appears on a wordSpacing
dimension, consumers MUST adopt the same scaling rules as font-dimension
values.
Font weight
fontWeight
MAY encode keywords, numbers, or axis values defined by the font-weight
grammar.
The value MUST conform to the <font-weight-absolute>
or <font-weight-relative>
productions. Numeric weights MUST fall within the 1
-1000
range defined by CSS Fonts, and consumers MUST treat negative numbers as invalid. Relative keywords such as bolder
and lighter
MUST resolve using the algorithm defined in CSS Fonts.
iOS consumers MUST map the resolved weight to UIFont.Weight or the wght
variation axis. Android consumers MUST map weights to Typeface.Builder#setWeight, clamping to the platform's 1
-1000
range when necessary. Web consumers MUST apply the CSS weight resolution algorithm when cascading values through the DOM.
{
"$type": "typography",
"$value": {
"fontFamily": "Inter",
"fontSize": { "dimensionType": "length", "value": 16, "unit": "px" },
"fontWeight": 700
}
}
Font style
fontStyle
MUST be serialised as a string matching the font-style
grammar defined by CSS Fonts. Producers MAY supply the keywords normal
and italic
or the oblique
form with an explicit angle. Any angle MUST conform to the <angle>
production so that CSS and native consumers interpret the token consistently.
When the resolved value is italic
or oblique
without an explicit angle, consumers MUST toggle the italic traits documented for UIFontDescriptor.SymbolicTraits and legacy Android style enums exposed alongside FontVariationAxis. When an angle is provided, consumers MUST normalise the CSS <angle>
to degrees before passing it to the slnt
variation axis defined by UIFontDescriptor.AttributeName.variations and Typeface.Builder#setFontVariationSettings. Fonts that omit a slnt
axis MAY fall back to italic traits while preserving the authored angle for downstream consumers.
{
"$type": "typography",
"$value": {
"fontFamily": "Inter",
"fontSize": { "dimensionType": "length", "value": 16, "unit": "px" },
"fontStyle": "oblique -12deg"
}
}
Text decoration
textDecoration
MAY encode the shorthand defined for the text-decoration
property, including line, style, colour, and thickness components.
Values MUST conform to the <text-decoration-line>
, <text-decoration-style>
, and <text-decoration-thickness>
productions when present. CSS colour values MUST reuse the colour token guidance in this specification. iOS consumers MUST map resolved decorations to NSUnderlineStyle, while Android consumers MUST apply the appropriate Paint underline and strike-through flags and interpret thickness using the same conversion rules as font-dimension
.
Text transform
textTransform
MAY encode sequences defined by the text-transform
grammar, including multiple keywords and language-sensitive casing rules.
Values MUST conform to the <text-transform-list>
production. Consumers MUST apply keywords in source order using the algorithms defined in CSS Text. Native implementations MUST rely on platform casing APIs such as NSStringTransform and Java String case conversion to preserve locale awareness. When a platform lacks direct support for a requested transform, consumers SHOULD emit a warning and fall back to the closest available behaviour.
Color
color
MAY specify a colour value for the text.
When omitted, consumers MAY derive a default from context.
Font features
fontFeatures
MAY provide an array matching the font-feature-settings
property, where each string MUST be a registered OpenType feature tag from the OpenType Feature Tag Registry or a vendor tag defined by the referenced font.
Consumers MUST ignore tags they do not recognise and MUST forward axis settings to the underlying font subsystem on web and native platforms.
Maturity roadmap
All properties described in this section are part of the stable core specification.
Font face
Font face tokens describe downloadable or local font resources so multiple typography tokens can reference a shared family. The $value
object MUST provide a fontFamily
that conforms to the <family-name>
production defined by CSS Fonts and MUST include a src
array describing one or more sources from the src
descriptor.
Each src
entry MUST be either a url()
-style record that references font data or a local()
record naming an installed font. URL entries MUST resolve to the same font file a browser would load for the @font-face
src
list and MUST be registered with the native font catalog- using CTFontManagerRegisterFontsForURL or the process described in Apple's font registration guidance on iOS, and font-family XML or Font.Builder on Android- before creating a font instance. Local entries MUST use the <family-name>
grammar and MUST reference families that the target platform exposes through UIFontDescriptor or Typeface lookups.
Optional hints on URL entries such as format
and tech
MUST mirror the format()
and tech()
functions from the CSS src
grammar. Platform consumers MAY ignore unsupported hints but MUST respect them when the platform provides equivalent capability checks.
Additional descriptors reuse CSS Fonts productions: fontWeight
MUST follow the <font-weight-absolute>
grammar, fontStyle
the font-style
grammar (including the <angle>
production for oblique slants), and fontStretch
the <font-stretch-absolute>
grammar. The unicodeRange
descriptor MUST conform to the unicode-range
syntax, and fontDisplay
MUST use keywords defined by font-display
. Native platforms treat these descriptors as metadata for UIFontDescriptor traits and Typeface.Builder configuration.
Typography tokens MAY reference font faces using $ref
so that fontFamily
values, variation descriptors, and registration metadata stay aligned across CSS, iOS, and Android implementations.
Font face member | Normative references |
---|---|
fontFace.$value.fontFamily | <family-name> , Apple font registration, Android font resources |
fontFace.$value.src[].url | @font-face src , CTFontManagerRegisterFontsForURL, Font.Builder |
fontFace.$value.src[].local | local() , UIFontDescriptor, Typeface |
fontFace.$value.src[].format | format() |
fontFace.$value.src[].tech | tech() |
fontFace.$value.fontWeight | font-weight , UIFont.Weight, Typeface.Builder#setWeight |
fontFace.$value.fontStyle | font-style , UIFontDescriptor.SymbolicTraits, UIFontDescriptor.AttributeName.variations, FontVariationAxis, Typeface.Builder#setFontVariationSettings |
fontFace.$value.fontStretch | <font-stretch-absolute> |
fontFace.$value.unicodeRange | unicode-range |
fontFace.$value.fontDisplay | font-display |
{
"fontFace": {
"brand": {
"$type": "fontFace",
"$value": {
"fontFamily": "Brand Sans",
"fontWeight": 400,
"fontStyle": "normal",
"fontStretch": "semi-expanded",
"unicodeRange": "U+000-5FF, U+13A0-13F5",
"fontDisplay": "swap",
"src": [
{ "local": "Brand Sans" },
{
"url": "https://cdn.example.com/fonts/BrandSans-Regular.woff2",
"format": ["woff2"],
"tech": ["variations"]
},
{
"url": "https://cdn.example.com/fonts/BrandSans-Regular.ttf",
"format": ["truetype"]
}
]
}
}
},
"typography": {
"body": {
"$type": "typography",
"$value": {
"typographyType": "body",
"fontFamily": { "$ref": "#/fontFace/brand/$value/fontFamily" },
"fontSize": { "dimensionType": "length", "value": 16, "unit": "px" },
"lineHeight": 1.5
}
}
}
}
A complete example document is available at font-face.tokens.json.