Skip to content

feat!: rework latest typography styles into polymorphic Text component - #1152

Open
pawelgrimm wants to merge 18 commits into
mainfrom
pawel/feat/typography-updates
Open

feat!: rework latest typography styles into polymorphic Text component#1152
pawelgrimm wants to merge 18 commits into
mainfrom
pawel/feat/typography-updates

Conversation

@pawelgrimm

@pawelgrimm pawelgrimm commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Short description

We are reworking our typography components in a couple of ways:

  • Adding line-heights, as specified in the design mocks
  • Reworking the <Text> API to accept a variant along with render, to specify the component to render
  • Merging <Heading> into <Text>'s variants
  • Adding the Display variants

Demo

(left: Figma; right: Storybook)

CleanShot 2026-08-13 at 16 14 05

References

PR Checklist

  • Added tests for bugs / new features
  • Updated docs (storybooks, readme)
  • Reviewed and approved Chromatic visual regression tests in CI

@pawelgrimm
pawelgrimm force-pushed the pawel/feat/typography-updates branch from 438db49 to 957f289 Compare August 12, 2026 21:10
@pawelgrimm pawelgrimm changed the title feat!: update typography components feat!: rework typography around a polymorphic Text component Aug 12, 2026
@pawelgrimm pawelgrimm self-assigned this Aug 12, 2026
@pawelgrimm pawelgrimm added the 🙋 Ask PR Used for PRs that need a review before merging. label Aug 12, 2026
@pawelgrimm
pawelgrimm force-pushed the pawel/feat/typography-updates branch 2 times, most recently from 5997e45 to fe534c0 Compare August 12, 2026 21:34
Text now covers the full typography scale with a single variant prop:
display-*, heading-*, subheader, body, callout, caption, and footnote
styles from the Figma reference. Heading variants render the matching
heading element and all other variants render a div; use render to
override the element.

BREAKING CHANGE: Text no longer accepts size, weight, or as props.
Pick a variant instead, and use render for custom elements.
BREAKING CHANGE: Heading is removed. Use Text with a heading variant,
e.g. <Heading level={2}> becomes <Text variant="heading-2">, which
renders an h2. Use render to decouple semantics from the visual style.
@pawelgrimm
pawelgrimm force-pushed the pawel/feat/typography-updates branch from fe534c0 to 4c4e703 Compare August 12, 2026 21:36
Move the SF web font stack to design-tokens.css and use literal font
weights in the variant classes, matching their literal px sizes. Removes
the module-local :root tokens whose 'medium' (500) collided with the
canonical --reactist-font-weight-medium (600).
Inline getTextClassName into Text — its options-object API was a fossil
of the deleted typography layer with a single caller. Replace heading
element string-building with a plain lookup map.
@pawelgrimm pawelgrimm changed the title feat!: rework typography around a polymorphic Text component feat!: rework latest typography styles into polymorphic Text component Aug 13, 2026
@pawelgrimm
pawelgrimm requested a review from pedroalves0 August 13, 2026 21:01
@pawelgrimm

Copy link
Copy Markdown
Contributor Author

@pedroalves0 I made some small changes since we've worked on this, namely:

  • Consolidating <Display> and <Heading> into <Text>, since the design mocks just list all of them under "Text Styles" (no subcategories)
  • Extracting the codemod into a follow-up PR (todo)
  • Removing the variant and decoration constraints, since the design had been updated to remove those restrictions (i.e. every variant can be underlined or strikethoughed)

@pawelgrimm
pawelgrimm marked this pull request as ready for review August 13, 2026 21:03
@doistbot

doistbot commented Aug 13, 2026

Copy link
Copy Markdown
Member

⚠️ PR size is large: Review quality may be affected

👋 @pawelgrimm This PR is large enough that Doistbot's review may miss details.

Current diff: 613 review-load lines across 32 files (+613 / -926). I will still run the review, but this would be easier for your colleagues to review as smaller PRs or a PR stack 😅

ℹ️ To make it easier to review, the recommended diff size is < 750 review-load lines and < 25 files changed

To be mindful of their time I would suggest you split this PR

🪄 Suggested slicing plan 👇

Split the PR into a two-part stack: first rework the Text component into a polymorphic typography scale supporting named variants and render props (along with updating all Text call sites), then drop the Heading component and migrate all remaining heading usages across stories to the new Text component.

PR order

  1. slice-1-feat-rework-text-around-named-typography → base main
  2. slice-2-feat-drop-heading-component-in-favor-of- → base slice-1-feat-rework-text-around-named-typography

PR 1 feat!: rework Text around named typography variants and Ariakit polymorphic render

Introduces the new typography scale (display, heading, body, callout, caption, footnote variants) to Text using Ariakit Role for polymorphic rendering, and migrates existing Text usages across components and stories to the new API.

Files (18):

  • src/avatar/avatar.stories.tsx
  • src/base-field/base-field.tsx
  • src/box/box.stories.tsx
  • src/expansion-panel/expansion-panel.stories.tsx
  • src/menu/menu.stories.jsx
  • src/modal/modal.stories.tsx
  • src/password-field/password-field.stories.jsx
  • src/select-field/select-field.stories.jsx
  • src/text-area/text-area.stories.jsx
  • src/text-field/text-field.stories.jsx
  • src/text/index.ts
  • src/text/text.mdx
  • src/text/text.module.css
  • src/text/text.stories.tsx
  • src/text/text.test.tsx
  • src/text/text.tsx
  • src/toast/static-toast.tsx
  • src/tooltip/tooltip.stories.tsx

PR 2 feat!: drop Heading component in favor of Text heading variants

Removes the standalone Heading component and migrates all remaining Heading usages across stories and storybook utilities to polymorphic Text heading and subheader variants.

Files (16):

  • src/box/box.stories.tsx
  • src/button/button.mdx
  • src/button/button.stories.jsx
  • src/button/icon-button.mdx
  • src/button/icon-button.stories.jsx
  • src/heading/heading.module.css
  • src/heading/heading.stories.tsx
  • src/heading/heading.test.tsx
  • src/heading/heading.tsx
  • src/heading/index.ts
  • src/index.ts
  • src/inline/inline.stories.tsx
  • src/modal/modal.stories.tsx
  • src/stack/stack.stories.tsx
  • src/toast/toast.stories.tsx
  • src/utils/storybook-helper.tsx

This plan is based on the current PR head. Keep each slice buildable and move tests with the behavior they cover.

You can use your agent of choice (Codex/Claude etc) to help you split this PR 😊 Just copy the link to this comment and ask them Can you please create a PR stack based on the suggestions in this comment

@doistbot doistbot left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

This PR reworks the typography system into a polymorphic Text component with named variants, merging Heading and Display into Text, and adding line-heights and Display variants from the design mocks.

Few things worth tightening:

  • The new typography scale hardcodes font sizes, line heights, letter-spacing, and weights as raw values instead of --reactist-* design tokens. Several of these duplicate existing tokens (e.g. 14px = --reactist-font-size-body, 13px = --reactist-font-size-copy, 700 = --reactist-font-weight-strong), and new values like the display sizes and line heights should be defined as tokens (either in design-tokens.css or component-local :root) so consumers can theme the scale.

I also included a few optional follow-up notes in the details below.

Optional follow-up notes (5)
  • P3 src/text/text.stories.tsx:8: The full variant list is rebuilt from displayVariants, headingVariants, and bodyVariants in three places (here, text.test.tsx:9, and text.test.tsx:36). Export a single combined textVariants array from text.tsx and consume it in both files so the variant set stays a single source of truth.
  • P3 src/text/text.tsx:76: isHeadingVariant and the display flag (line 102) re-derive variant categories by matching string prefixes ('heading-', 'display-') even though headingVariants/displayVariants already define those categories. That splits the categorization across three places. Prefer membership checks against the arrays (e.g., a Set built from each array) so the arrays stay the single source of truth.
  • P3 src/text/text.module.css:194: text-underline-position only affects underlines, so it's dead on .decoration-strikethrough, and text-decoration-skip-ink is duplicated between the two rules. Drop text-underline-position from the strikethrough rule (or move the shared declarations into a common rule) so it doesn't imply an effect it doesn't have.
  • P3 src/text/text.test.tsx:202: This matrix generates 21 variants × 2 decorations = 42 near-identical cases. decoration is applied independently of variant (decoration ? styles['decoration-' + decoration] : null), so the variant dimension adds no regression signal — every case asserts the same decoration-<x> class. One test per decoration (plus the existing footnote-1 uppercase+decoration case) covers this behavior.
  • P3 src/text/text.test.tsx:237: This test asserts nothing at runtime: @ts-expect-error only matters to tsc (type-check), which Jest's transform ignores, and expect(invalidCase).toBeDefined() always passes. The uppercase restriction is a compile-time contract enforced by npm run type-check, not by this test. Delete it or leave the guard to the type checker.

Share FeedbackReview Logs

Comment thread src/text/text.module.css
@pawelgrimm pawelgrimm mentioned this pull request Aug 13, 2026
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🙋 Ask PR Used for PRs that need a review before merging.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants