Skip to content

spec(AST-102): typography stays theme-owned; unbranded shipped themes may use the system body font - #8351

Merged
cixzhang merged 11 commits into
mainfrom
spec/typography-theme-owned
Oct 25, 2026
Merged

cixzhang merged 11 commits into
mainfrom
spec/typography-theme-owned

Conversation

@cixzhang

@cixzhang cixzhang commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Exact decision needed

Whether components may set fonts themselves (such as iOS's -apple-system-body), and when Astryx's shipped themes may use the system body font.

Existing authority searched

  • design:typography-hierarchy (draft) and design:mobile-typography (DR1 reading base, DR2 pin target) own roles and sizes, not who may set a family or which themes use the system font.
  • architecture:theme-tokens owns token names and defaults; architecture:component-style-authoring owns how components consume tokens. Neither decides this observable cross-component rule, so it gets a system spec (architecture:knowledge-contracts INV18). AST-102 is the next number not used by a record on main or an open specification pull request.
  • Search terms: font-family, -apple-system, system font, Dynamic Type, typography tokens, body font, branded theme. Overlapping open work: a Dynamic Type proposal on a contributor stack (fix(core): text follows the reader's text size on iOS in every theme #8230 on fix(Badge): a badge grows with its text #8236's stack) reads -apple-system-body in a hidden probe from the root Theme and lets an opted-in theme scale its own size tokens; under FR3 and DEC-3 it reads the size internally for every theme, with no public option or attribute.

Decision

New system spec spec:AST-102, decided by Cindy (DEC-1 2026-10-24; DEC-2 and DEC-3 2026-10-25):

  • FR1: Core and Lab web components take the family, size, and line height of text they render only from theme tokens; inherited values conform; icon sizing, native text, a hidden measuring element, and the iOS 16 px text-entry floor (family:input-fields FR9) are outside it.
  • FR2: an unbranded shipped theme MAY set its body font token to the system body font family; branded themes keep their brand font.
  • FR3 (DEC-2): a text size the person set (iOS Dynamic Type, Android font scale, browser default font size, zoom) wins in every theme, branded included, with the theme's scale relative to it and its family kept; with no size set or no signal, text is exactly the theme's.
  • FR3 (DEC-3): no public theme option, prop, or document attribute; the document-root font size is unchanged (design:mobile-typography DR4). A size the person set replaces DR1's mobile reading base, smaller or larger; DR1 applies when none is set; the iOS text-entry floor still holds. design:mobile-typography DR1 gains one sentence saying so.
  • FR4: everything works up to 200% (WCAG 1.4.4); above that reading text keeps growing, dense fixed-size control labels may stop at 200% but are never cut off, and controls grow with their text.
  • Current-state defects: iOS ignores Dynamic Type; Butter, Stone, and Y2K fix supporting text at 12 px; fixed control heights (40 px elements, component:Badge FR1's block, InputGroup's row); the Chrome on Android font-scale check.

Rejected alternatives

  • Components applying a platform font such as -apple-system-body directly.
  • Only unbranded or opted-in themes following the person's text size.
  • A public theme option or document attribute for the person's text size.

Claim scope and non-goals

Font family, size, and line height ownership, and following the person's text size. The type scale, branded typefaces, and native platforms are outside.

Evidence and implementation relationship

Spec-only. Core's default body font is already the system font stack; each shipped theme package sets a brand body font.

Writing rubric results

  • R1 narration: none.
  • R2 research in the record: none.
  • R3 evidence naming a change: none.
  • R4 rejected alternatives over one line or outside a decision: none; one line each inside DEC-1, DEC-2, and DEC-3.
  • R5 pull request or issue references remaining: none.
  • R6 ruled open questions still listing options: none; the record has no open questions.

Scope

  • This PR contains specification records only.
  • It records observable behavior and preserves equivalent internal implementations.
  • Any named internal mechanism is intentionally public, names its dependent caller/system, and explains why an equivalent implementation would not satisfy the contract.
  • Verification states the evidence layer and failure signal without prescribing CI job/workflow topology.
  • It records one intentional durable decision, not a rescue for a separable tagalong.
  • The canonical knowledge owner, affected current claims, and overlapping open work are named; any ownership collision is resolved or called out for human decision.
  • Adjacent API, visual, accessibility, composition, and implementation facts remain outside scope unless this exact decision depends on them.
  • Public text and artifacts contain no internal Meta context.

Validation

  • pnpm check:knowledge (CI lint)
  • Prettier
  • git diff --check

@vercel

vercel Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
astryx Ready Ready Preview Oct 25, 2026 5:52pm UTC

Request Review

@astracat-bot

astracat-bot Bot commented Oct 25, 2026 •

Copy link
Copy Markdown

AI review status for this pull request.

Review status Updated
🟢 Reviewed (for maintainers only) Oct 25, 2026, 6:19 PM UTC

@github-actions github-actions Bot added the needs:spec-owner-review Current knowledge records await owner approval label Oct 25, 2026
@github-actions

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

PR Analysis Report

View Storybook for this PR · View Sandbox for this PR

Current run: The current change has no visual or preview-producing scope. Visual checks are not applicable; preview links are not shown.


Generated by PR Enrichment workflow | View current CI run

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Oct 25, 2026

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This spec isn't ready to approve: FR1, FR2 and DEC-1 add new requirements, and the spec-owner check is still waiting for an engineering owner to record a decision on this head by commenting /approve-spec <full head SHA> (the author may do so as an engineering owner). Whatever that decision, these fixes are needed:

  • FR1 forbids the iOS 16 px text-entry floor that family:input-fields FR9 and DEC-6 require, so name that floor as an exception (or narrow FR1) and list family:input-fields in affects_families.
  • pnpm check:knowledge fails INV25 because no repository path links the record, which a path-applicability:v1 block or a source check that cites AST-102 would fix.
  • Current-state impact says no component sets a platform font keyword, but Lab's Sankey labels use system-ui, and several Core and Lab components set their own sizes or line heights.
  • FR2 says the -apple-system-body text style in the body font token follows the person's iOS system setting, but that setting is text size, which a font-family token cannot carry without deciding OQ1, so name the system body family instead or move that behaviour into OQ1.

[Automated review]

Comment on lines +43 to +47
- **FR1 — Components never override typography.** No component sets a font
family, font size, or line height except through the theme's typography
tokens. That includes platform font keywords such as `-apple-system-body`
and system font stacks: a component never applies one directly, on any
pointer or platform. Typography values come only from the theme.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FR1 allows no component-set font size outside the theme's typography tokens ("Typography values come only from the theme"), but family:input-fields FR9 and DEC-6 require text-entry controls to floor editable text at 16 CSS px on iOS touch, which 19 sources do with max(1rem, var(--text-body-size)) (see packages/core/src/inputFontFloor.test.ts). Name that floor as an exception here, or narrow the size clause, and add family:input-fields to affects_families.

template_version: 2
kind: system-spec
id: spec:AST-102
authority: current

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pnpm check:knowledge fails on this record: "current record spec:AST-102 is not reached from any repository path that is not itself a record (INV25)". A path-applicability:v1 block over the paths FR1 and FR2 govern, or a source check that cites AST-102, would link it.

Comment on lines +48 to +53
- **FR2 — Unbranded shipped themes may use the system body font.** An Astryx
shipped theme whose body font is not branded MAY set its body font token to
the platform's system body font, including iOS's `-apple-system-body` text
style, which follows the person's system setting on iOS. A branded theme
keeps its brand font for body text. The choice lives in the theme's token
value, so components pick it up without change (FR1).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The body font token is the --font-family-body list (family, then fallbacks), and size still comes from --text-body-size, so a family entry cannot make text follow the iOS text-size setting. That behaviour comes with the font: -apple-system-body shorthand, which also sets size and line height and is what OQ1 leaves open. Consider naming the system body family (-apple-system or system-ui) and dropping the setting clause, or moving it into OQ1.


## Current-state impact

- No component on `main` sets a platform font keyword.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lab's Sankey sets font: '500 10px/1 system-ui' and '600 10px/1 system-ui' inline (packages/lab/src/Sankey/SankeyGrid.tsx:55, packages/lab/src/Sankey/SankeyLabel.tsx:142), so this is not true on main. This section should also list the component-set sizes and line heights FR1 makes non-conforming: Avatar initials, ChatComposerInput's 22 px line height, the Table sortable rank and Lab chart legends.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This spec isn't ready to approve yet: FR1, FR2 and DEC-1 add new requirements, and the spec-owner check is waiting for an engineering owner to record a decision on this head by commenting /approve-spec <full head SHA> (the author may do so as an engineering owner). Whatever that decision, these fixes are needed:

  • FR1 says "No component" and "on any pointer or platform", but its paths and verification cover only Core and Lab in browsers; scope it to those or extend it, since native text already follows the platform's text-size setting under spec:AST-082 FR11 and Charts, RichText and Vega components are not routed.
  • FR1's ban on component-set font sizes also catches the font-size that sizes Core's 1em icons to spec:AST-087 FR10's sizes, so limit it to the text a component renders.
  • The description's FR2 bullet still says -apple-system-body is included, which the record now leaves to OQ1.

[Automated review]

Comment on lines +54 to +55
and system font stacks: a component never applies one directly, on any
pointer or platform. Typography values come only from the theme. The one

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FR1 says "No component" and "on any pointer or platform" (and the Intent says "every Astryx component, on every platform"), but the path block, Platform support and Verification cover only Core and Lab components in browsers. On native, spec:AST-082 FR11 already requires that "text follows the platform's text-size setting", and native components grow every theme's token sizes with Dynamic Type; Charts, RichText and Vega components fall under these words with no declared path (INV26). Consider scoping this to the browser components of the listed packages, or extending the paths and Verification and naming spec:AST-082 FR11.


| Contract | Verification | Representative states | Mutation or failure expectation |
| -------- | ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| FR1 | Source check over Core and Lab component styles plus token review | font family, size, and line height in component styles; coarse and fine pointer; a platform font keyword; the iOS text-entry floor | A component sets a font family, size, or line height outside typography tokens, or applies a platform font keyword directly |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This failure expectation also fires on Icon: Core's built-in icons are 1em SVGs that Icon's and Button's icon boxes size by setting font-size (packages/core/src/Icon/IconSize.stylex.ts), which is how spec:AST-087 FR10's 12, 16, 20 and 24 px defaults are met. Scoping FR1 to the font family, size and line height of text a component renders would keep glyph sizing and line-height: 0 layout resets outside it.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This spec isn't ready to approve yet: FR1, FR2 and DEC-1 add new requirements, and the spec-owner check is waiting for an engineering owner to record a decision on this head by commenting /approve-spec <full head SHA> (the author may do so as an engineering owner). Scoping FR1 to the text of Core and Lab web components, with icon sizing and native text outside it, settles its overlap with the icon and native records; two wording fixes remain whatever that decision:

  • The Intent ("every Astryx component, on every platform") and DEC-1 ("the theme decides, everywhere") still claim more than FR1 covers.
  • FR1's verification row fails any component-set font family, size or line height, so a check built from it would flag Icon's 1em sizing and inherited fonts such as Badge's fontFamily: 'inherit'; word it as FR1 is worded and say whether an inherited value conforms.

[Automated review]

Comment on lines +33 to +34
People see the typography their theme chose in every Astryx component, on
every platform: no component swaps in a platform font or its own text size.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FR1 now covers only the text of Core and Lab web components and sends native text to spec:AST-082 FR11, but this sentence, and DEC-1's "the theme decides, everywhere" (line 103), still promise every Astryx component on every platform. Charts axis labels keep fontSize={12} (packages/charts/src/ChartAxis.tsx:244) with no typography rule covering them, and native text grows with the person's Dynamic Type size in every theme. Consider scoping the Intent and DEC-1 to Core and Lab web component text, matching FR1.


| Contract | Verification | Representative states | Mutation or failure expectation |
| -------- | ----------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| FR1 | Source check over Core and Lab component styles plus token review | font family, size, and line height in component styles; coarse and fine pointer; a platform font keyword; the iOS text-entry floor | A component sets a font family, size, or line height outside typography tokens, or applies a platform font keyword directly |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FR1 now says "of text it renders" and exempts icon sizing, but this failure expectation still fails any component-set font family, size or line height: Icon's 1em sizing (packages/core/src/Icon/IconSize.stylex.ts:53-68, which component:Icon FR3 requires), lineHeight: 0 media wrappers, and 88 Core and Lab inherit declarations such as Badge's fontFamily: 'inherit', which component:Badge FR1 requires. Consider wording it as FR1 is worded, listing icon sizing beside the floor as a passing state, and saying whether an inherited value conforms.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This spec isn't ready to approve yet: FR1, FR2 and DEC-1 add new requirements, and the spec-owner check is waiting for an engineering owner to record a decision on this head by commenting /approve-spec <full head SHA> (the author may do so as an engineering owner). The Intent, DEC-1 and FR1's verification row now match FR1's Core and Lab web scope, so no other change is required. Two points to settle with that decision:

  • As written, FR1's "a component never applies one directly" also covers a hidden element that only measures font: -apple-system-body, as the open Dynamic Type work does; say whether such a probe conforms.
  • FR1's "Typography values come only from the theme" sits beside its new inherited-value clause; "Values a component sets come only from the theme" would remove the clash.

[Automated review]

and system font stacks: a component never applies one directly, on any
pointer. A font size that sizes an icon, such as a `1em` icon at a
`spec:AST-087` FR10 size, is not text typography. Native components follow
the platform's own text settings (`spec:AST-082` FR11). Typography values come only from the theme. The one

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sentence now disagrees with the new "a value inherited from the surrounding text conforms" (lines 53-54): an inherited value comes from whatever text surrounds the component, which a product may style itself, and "the one exception" that follows no longer counts it. "Values a component sets come only from the theme", or dropping the sentence, would match the verification row, which already passes inheritance.

Comment on lines +54 to +56
surrounding text conforms. That includes platform font keywords such as `-apple-system-body`
and system font stacks: a component never applies one directly, on any
pointer. A font size that sizes an icon, such as a `1em` icon at a

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As written, "a component never applies one directly" also covers a hidden element that only measures font: -apple-system-body, which is how the open Dynamic Type work reads the reader's text size from the root Theme (an aria-hidden span holding one letter). If that probe is meant to conform, consider saying that an element that renders no visible text and only measures a keyword is outside FR1, or leave it to OQ1.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This spec isn't ready to approve yet: FR1, FR2 and DEC-1 add new requirements, and the spec-owner check is waiting for an engineering owner to record a decision on this head by commenting /approve-spec <full head SHA> (the author may do so as an engineering owner). The reworded FR1 sentence now agrees with the inherited-value clause, so no other change is required. One point to settle with that decision: as written, FR1's "a component never applies one directly" also covers a hidden element that only measures font: -apple-system-body, as the open Dynamic Type work does, so say whether such a probe conforms.

[Automated review]

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This spec isn't ready to approve yet: FR1 to FR4 and DEC-1 to DEC-3 add new requirements, and the spec-owner check is waiting for an engineering owner to record a decision on this head by commenting /approve-spec <full head SHA> (the author may do so as an engineering owner). That decision should settle how FR3 composes with design:mobile-typography DR1 on iOS, and whether spacing and control sizes follow the person's text size there. Whatever it is, these fixes are needed:

  • FR3 takes iPhone body text below DR1's 16 px mobile base at small Dynamic Type sizes while fields keep the 16 px floor, so state how a set size composes with DR1 and amend that record to match.
  • FR4's “a control grows with its text” conflicts with the fixed --spacing-5 block of component:Badge FR1 and the fixed row height family:input-fields gives InputGroup, so name them, and architecture:theme-tokens, in Current-state impact and affects_*.
  • approved_at predates DEC-2 and DEC-3, DEC-3's rejected alternative runs past one line, and the description's R4 rubric result still counts only DEC-1.

[Automated review]

Comment on lines +70 to +75
every theme, branded included: the theme's sizes scale from the person's
size, each role keeps its order, and the family stays the theme's. When the
person has not set one, or the platform gives no signal, text uses exactly
the theme's family and size. Following the setting adds no public theme
option, prop, or document attribute and does not change the document-root
font size (`design:mobile-typography` DR4).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As written, a smaller Dynamic Type size scales iPhone body text below the 16 px mobile base that design:mobile-typography DR1 sets (M = max(B, 16), with 1rem as the 16 px reference), because this requirement keeps the root font size: about 13 px at the smallest size (16 × 14 / 17), while fields keep FR9's 16 px floor. Say how a set size composes with DR1, and amend that record to match.

Comment on lines +78 to +81
1.4.4). Above 200%, reading text keeps growing; a label inside a dense,
fixed-size control, such as a tab, badge, table cell, or segmented control,
MAY stop growing at 200% but is never cut off. A control grows with its text
rather than holding a fixed height.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This conflicts with component:Badge FR1, which fixes the badge at --spacing-5 with no block padding, and with the fixed row height family:input-fields gives InputGroup (and FR8's fixed-height attached status). On iOS the root font size, and so --spacing-5, stays put while a 200% label needs a 40 px line box. Say whether spacing and control sizes follow the person's size on iOS, name these claims in Current-state impact and affects_*, and call these controls dense rather than fixed-size.

archive_reason: null
superseded_by: null
approved_by: cixzhang
approved_at: 2026-10-24

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

approved_at: 2026-10-24 predates DEC-2 and DEC-3, both decided on 2026-10-25; set it to the date an owner approves this revision.

Comment on lines +161 to +162
Rejected: a public theme option to opt in, and a public document attribute
carrying the size.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

R4 asks for one Rejected: line; this one spans two, and the description's R4 result still counts only DEC-1's rejected alternative.

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This spec isn't ready to approve yet: FR1 to FR4, DEC-1 to DEC-3 and the new design:mobile-typography DR1 sentence add requirements, and the spec-owner check is waiting for an engineering owner to record a decision on this head by commenting /approve-spec <full head SHA> (the author may do so as an engineering owner). That decision should settle whether spacing and control sizes follow the person's size on iOS and how DR2's pin behaves under a set size. Whatever it is, these fixes are needed:

  • With a set size replacing DR1's base and DR2's pin unchanged, a large size keeps Heading 2 at 25 px under 32 px body text in DR1's own worked example, against FR3's "each role keeps its order"; say how the pin composes with a set size in both records.
  • FR4's "never cut off" and "a cut-off label at any size" contradict the ellipsis truncation that component:Badge FR3, component:Button FR5 and component:Token FR7 require; scope it to the control's height or name those claims.
  • affects_architecture lists architecture:theme-tokens, but Current-state impact never says what changes there, and FR4 still calls dense controls "fixed-size" beside "rather than holding a fixed height".

[Automated review]

Comment thread docs/design/mobile-typography.md Outdated
## Design principles

- **DR1 — Reading base.** The mobile base MUST be `M = max(B, 16)`; 16px-reference is `1rem`.
- **DR1 — Reading base.** The mobile base MUST be `M = max(B, 16)`; 16px-reference is `1rem`. When the person has set a text size, it replaces this base (`spec:AST-102` FR3).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With M replaced by a set size while DR2 keeps the pinned role at its desktop size, r_pin = r * (B / M)^(1/a) drops below 1 once M passes that role: in this record's worked example (B 14, r 1.333, a 2) a 32 px set base gives body 32 px, Heading 2 25 px and Display 1 about 15 px, against spec:AST-102 FR3's "each role keeps its order". Consider saying that the pin yields when a size is set and every role scales by one factor.

component keeps all of its content and function (WCAG 2.2 success criterion
1.4.4). Above 200%, reading text keeps growing; a label inside a dense,
fixed-size control, such as a tab, badge, table cell, or segmented control,
MAY stop growing at 200% but is never cut off. A control grows with its text

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"is never cut off", and the verification failure "a cut-off label at any size", contradict component:Badge FR3 ("a label that does not fit is clipped with a trailing ellipsis"), component:Button FR5 ("truncates the label with an ellipsis") and component:Token FR7 ("clips overflow"). Consider scoping this to the control's block size, so width truncation stays, or naming those claims in Current-state impact. "fixed-size" also sits oddly beside the next sentence's "rather than holding a fixed height".

approved_at: 2026-10-25
phase: accepted
owners: [cixzhang]
affects_architecture: [architecture:theme-tokens]

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Current-state impact never says what changes in architecture:theme-tokens. On iOS FR3 grows text while the root font size, and so rem spacing, stays put, which its INV9 ("the way the type scale does") and DEC-1 (rejected: "text grows into fixed boxes") speak to; one line naming that change, or the decision that spacing stays put, would close it.

…control height and keeps defined truncation; theme-tokens impact
@cixzhang

Copy link
Copy Markdown
Contributor Author

/approve-spec 863c806

@github-actions github-actions Bot added spec-auto-merge Auto-merge was enabled by the spec owner gate and removed needs:spec-owner-review Current knowledge records await owner approval labels Oct 25, 2026

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This spec has an engineering owner's approval for this head, but a few record fixes are still needed before it lands. FR4 says controls grow with their text, yet the Badge component record (FR1, a fixed --spacing-5 block) and the input-fields family (InputGroup's fixed row height) still require the fixed heights this spec lists as defects, so please amend those records in this PR to defer to FR4 and keep today's geometry as an implementation gap, as the PR already does for design:mobile-typography.

  • The architecture:theme-tokens line in Current-state impact should say whether spacing and element sizes follow a set size on iOS, where FR3 keeps the root font size (Core's size tokens are px, not rem).
  • design:mobile-typography State representation still says the mobile profile keeps the desktop base when B >= 16, which stops being true once a size is set.

[Automated review]

Comment on lines +115 to +117
- Controls hold fixed heights, such as 40 px elements, `component:Badge`
FR1's fixed block size, and the fixed row height `family:input-fields`
gives InputGroup, so a larger label can overflow.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FR4 makes these fixed heights defects, but component:Badge FR1 (“with block size --spacing-5, no block padding”) and family:input-fields (“InputGroup owns the fixed row height”, the grouped-row concept, and FR8's fixed-height condition for attached) stay current and unchanged. Under architecture:knowledge-contracts DEC-1 a newer record does not override them, so please amend those claims in this PR to defer to FR4, keeping today's geometry as an implementation gap, as this PR already does for design:mobile-typography DR1.

Comment on lines +109 to +110
- `architecture:theme-tokens`: size tokens stay rem; Butter, Stone, and Y2K's
12 px supporting-size token is the token-level gap below.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Core's size tokens (--size-element-sm, -md, -lg) are 28, 32 and 36 px, not rem, and this line doesn't say what happens to architecture:theme-tokens INV9 (spacing follows “the reader's root font size the way the type scale does”) on iOS, where FR3 grows text but keeps the root font size. Please say whether spacing and element sizes follow a set size there, and amend INV9 if they don't.

## Design principles

- **DR1 — Reading base.** The mobile base MUST be `M = max(B, 16)`; 16px-reference is `1rem`.
- **DR1 — Reading base.** The mobile base MUST be `M = max(B, 16)`; 16px-reference is `1rem`. When the person has set a text size, it replaces this base and DR2's pin does not apply (`spec:AST-102` FR3).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With a set size replacing the base, this record's State representation (“When B >= 16, the mobile profile retains the desktop base and ratio.”) no longer holds; please condition it on no size being set.

…acing tokens unchanged; mobile-typography state
@cixzhang

Copy link
Copy Markdown
Contributor Author

/approve-spec f25d162

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This spec has an engineering owner's approval for this head, but FR4 (“a control grows with its text rather than holding a fixed height”) still contradicts a few current records that keep a fixed control height. Please give them the same treatment component:Badge FR1 gets in this PR (at least the element size, growing with a set text size under FR4, today's fixed height recorded as a gap), so the records agree when this lands:

  • component:Button FR4: “Height comes from the shared element size for the resolved size”.
  • component:Token FR1: block size --size-element-sm, -md or -lg minus 8px.
  • family:input-fields: the grouped-row concept (“InputGroup owns fixed height”) and the fixed-height condition for attached in FR8 and DEC-4.

[Automated review]

Comment on lines +117 to +119
- Controls hold fixed heights, such as 40 px elements, `component:Badge`
FR1's fixed block size, and the fixed row height `family:input-fields`
gives InputGroup, so a larger label can overflow.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Besides Badge FR1 and InputGroup, component:Button FR4 (“Height comes from the shared element size for the resolved size”) and component:Token FR1 (“block size --size-element-sm, -md, or -lg minus 8px”) still require these fixed heights. Under architecture:knowledge-contracts DEC-1 this record does not override them by being newer, so please amend both in this PR the way Badge FR1 is amended (at least the element size, growing with a set text size under FR4, today's height a gap).

Comment on lines +101 to +102
- `InputGroup` owns the row height (fixed today; it grows with a set text size
under `spec:AST-102` FR4, and the fixed height is a gap), connected outer surface, edge alignment,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line now defers to FR4, but the same record's grouped-row concept still says “InputGroup owns fixed height, connected edges, and group focus”, and FR8 and DEC-4 keep fixed-height as the condition for attached, which no control meets once FR4 has controls grow with their text. Please move those statements behind FR4 too, and reword the attached condition to what the overlap actually needs.

@cixzhang

Copy link
Copy Markdown
Contributor Author

/approve-spec f88008b

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This spec has an engineering owner's approval for this head and the record conflicts raised earlier are fixed, but two verification rows in docs/specs/AST-102-typography-theme-owned/spec.md still fail behaviour their requirements allow, so please correct them before it lands:

  • FR1's row (line 129) fails any component that applies a platform font keyword directly and exempts only icon sizing and the family floor; add the hidden measuring element that FR1 says conforms and DEC-3's iOS size read relies on.
  • FR3's row (line 131) fails text that differs from the theme's size when none is set; add the family:input-fields FR9 iOS text-entry floor that FR3 says still holds.

After the fix, an engineering owner records approval of the new head by commenting /approve-spec <full head SHA>; the author may do so as an engineering owner.

[Automated review]


| Contract | Verification | Representative states | Mutation or failure expectation |
| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| FR1 | Source check over Core and Lab component styles plus token review | family, size, and line height of rendered text in component styles; an inherited value; a `1em` icon size; coarse and fine pointer; a platform font keyword; the iOS text-entry floor | A Core or Lab web component sets the family, size, or line height of text it renders outside typography tokens and not by inheritance, or applies a platform font keyword directly; icon sizing and the family floor are not failures |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This row fails any component that "applies a platform font keyword directly" and exempts only icon sizing and the family floor, but FR1 (lines 53-54) says a hidden element that only measures a platform text style conforms, and DEC-3 reads the iOS size that way. Please add that element to the representative states and to the "not failures" list.

| -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| FR1 | Source check over Core and Lab component styles plus token review | family, size, and line height of rendered text in component styles; an inherited value; a `1em` icon size; coarse and fine pointer; a platform font keyword; the iOS text-entry floor | A Core or Lab web component sets the family, size, or line height of text it renders outside typography tokens and not by inheritance, or applies a platform font keyword directly; icon sizing and the family floor are not failures |
| FR2 | Theme token review plus Safari on iOS, top-level document | an unbranded shipped theme using the system body font family; a branded theme; the default theme | A branded theme's body font replaced by the system font, or a system body font applied by a component instead of a theme token |
| FR3 | Safari on iOS across Dynamic Type categories; Chrome on Android in the emulator with font scale; a desktop browser with a larger default font size and with zoom; theme review | a branded and an unbranded theme; no size set; default category; a size set on each platform; macOS Safari | Text that ignores a size the person set; text that differs from the theme's family or size when none is set; a theme family replaced; a public option, prop, or document attribute; a changed root font size |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Text that differs from the theme's family or size when none is set" also fails the family:input-fields FR9 floor that FR3 (lines 78-79) says still holds: with no size set, an iPad in landscape keeps desktop sizes (DR3) while fields render at 16 px over a 14 px theme. Please name the floor in this row's states and exceptions.

@cixzhang

Copy link
Copy Markdown
Contributor Author

/approve-spec 4f4e058

@astracat-bot astracat-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This spec set is ready to land: an engineering owner approved this exact head, the FR1 and FR3 verification rows now match their requirements, and no current record is left contradicting the new typography and text-size rules. Nothing more is needed from you here; the pull requests that implement it will owe the Safari on iOS, Android emulator and desktop browser evidence the record names. If you push another commit, an engineering owner needs to approve the new head by commenting /approve-spec <full head SHA>.

[Automated review]

@cixzhang
cixzhang merged commit b023d1c into main Oct 25, 2026
54 checks passed
@github-actions
github-actions Bot deleted the spec/typography-theme-owned branch October 26, 2026 06:31

This branch was successfully deployed

1 active deployment
Preview — 4f4e0581 Deployed Oct 25, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot. spec-auto-merge Auto-merge was enabled by the spec owner gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant