Skip to main content
config/settings_schema.json declares everything a merchant can change about your theme. The editor renders it as the theme panel, and infers structure from it — from IDs, types, labels, and a few reserved keys. Most of that inference goes into typography. A text preset is one font-size setting plus the font and weight it uses, and the editor groups each into a single card so a merchant edits H1 rather than three unrelated controls, then applies H1 to content from the rich-text toolbar. A schema that passes fluid theme lint can still render controls the panel cannot draw, produce a flat list where you expected presets, or produce presets that resolve to nothing. This page covers the shape that works. For the linking mechanics behind presets, see linked CSS presets. For the wider settings flow, see root theme configuration. For settings inside a section’s {% schema %}, see theme schemas.

Setting types the theme panel renders

The theme panel renders a narrower set of types than a section schema does. Anything outside this list renders as a red Unsupported setting type message in the panel. Two of these behave differently from the section-schema equivalents documented in theme schemas:
  • Use font_picker for every font. The editor also treats font and font_family as fonts when resolving a preset, so a reference to one still links — but neither renders a control in the theme panel, leaving a merchant unable to change it.
  • header is dropped, not rendered. The panel discards any setting without an id and a label, which every header entry lacks.
For the full set of types available inside a section’s {% schema %}, see theme schemas.

Name the group typography

Only a group named exactly typography becomes preset cards. Any other name renders a flat list, however the settings inside it are shaped.
Typography, type, and text all miss. The match is exact and case-sensitive.
The editor drops any setting without an id, a type, and a label. That includes every {"type": "header"} entry, so headers do not separate settings in the theme panel. Use separate groups instead.

Declare fonts and weights once

Give each typeface one font_picker, and each step in your weight scale its own setting.
Fonts and presets may share one group. The editor gathers every font into whichever group declares the first one, so a merchant finds them all in one place.

Name fonts by role in the ID

A preset’s font picker labels each choice from the setting’s ID, with the font_family_ prefix removed — not from its label. Most themes label both font settings “Font family”, which tells a merchant nothing about which is which. font_family_heading and font_family_body are also reserved: they are what a preset falls back to when it names no font of its own. Declare at least one of them. Weights are labelled from their label, because “Normal” and “Bold” are already the names a merchant wants.

Declare each preset

Put size settings in typography and point each at a font and a weight.
Set role explicitly on every preset. Without it, an ID beginning font_size_h reads as a heading and everything else reads as body — a legacy convention that breaks the moment you name a heading preset something else. Both references are optional and resolve anywhere in the schema, so the font may live in another group. Prefer them over the role fallback: a renamed ID then shows up as a visible break rather than a silent change in meaning.
The two references behave differently when they point at nothing. A font_family_ref that resolves to no setting leaves the preset with no font — it does not fall back to the role font. A font_weight_ref that resolves to nothing does fall back to the role weight. A missing weight has a sensible universal default; a missing typeface does not.

Know what counts as a preset

Every setting in typography is tested against the same questions. It becomes a preset card only if it is neither a font nor a weight. Presets are identified by exclusion, so a size may be typed range, number, font_size, or anything else — older themes that typed sizes inconsistently keep working.
The label test is why a size setting labelled “Heading font weight scale” never becomes a preset card. Nothing in the schema overrides the classification, so rename the setting instead.
The rule exists because themes overwhelmingly author weights as range rather than as a dedicated type. Without it, font_weight_body would appear as a preset card sitting between H1 and H2.

Make preset changes reach existing content

Declare a CSS variable for every font, weight, and size, then read the variables from your CSS. Without this step a merchant’s edits change nothing on the page.
Name each variable after its setting ID. Any name resolves for reading, but the editor writes and removes --<setting_id> when it manages a variable for you, and matching keeps the two conventions from diverging.

Read the preset’s own variable first

The editor also maintains a variable per preset property, written the first time a merchant applies that preset to content:
Content styled as H1 records var(--font_size_h1_font_family) — named for the preset, not for the font it happens to use today. When a merchant repoints H1 to a different font, that one declaration changes and every piece of content styled as H1 follows. Write your own CSS the same way, with the target as a fallback:
Reading only var(--font_family_heading) is the most common reason a merchant reports that they changed a preset and nothing happened. The panel looks correct, rich-text content updates, and your own headings keep the old font.

Expect the editor to write to your schema

The editor edits config/settings_schema.json in place. Leave these alone: Merchants can also add fonts from the panel with Add font, which appends one more font_picker alongside your heading and body fonts. Presets can then point at it like any other font.
Never strip generated_for by hand. It is the only thing separating a setting the editor may remove from one it must not.

Troubleshoot presets

Checklist

  • Every setting uses a type the theme panel renders, and fonts use font_picker
  • The preset group is named exactly typography
  • Every preset sets role and unit
  • Font IDs carry their role, and at least one of font_family_heading or font_family_body exists
  • Every font_family_ref and font_weight_ref points at an ID that exists
  • No size setting’s ID or label contains “font weight”
  • layouts/theme.liquid declares a variable for every font, weight, and size
  • Your CSS reads preset variables with the target variable as a fallback