Skip to content

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

Merged
pawelgrimm merged 19 commits into
mainfrom
pawel/feat/typography-updates
Aug 18, 2026
Merged

feat!: rework latest typography styles into polymorphic Text component#1152
pawelgrimm merged 19 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

Mappings

<Text>

Legacy Text size weight="regular" (default) weight="semibold" weight="bold"
subtitle subheader-2 subheader-1 subheader-1
body (default) body-3 body-2 body-1
copy callout-2 callout-1 callout-1
caption caption-3 caption-2 caption-1

Bold subtitle and copy text use the nearest named variant and change from 700 to 600 weight. Other
Text mappings preserve size and weight.

<Heading>

Legacy Heading metrics Text variant
32px/700 header-1
24px/700 header-2
20px/700 header-3
16px/700 or 16px/600 subheader-1
16px/400 subheader-2
14px/700 body-1
14px/600 body-2
14px/400 body-3
12px/700 caption-1
12px/600 caption-2
12px/400 caption-3

The 24px/700 mapping changes to 26px/700. The 16px/700 mapping changes to 16px/600. Other Heading
mappings preserve size and weight.

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 3 times, most recently from fe534c0 to 4c4e703 Compare August 12, 2026 21:36
@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

@pedroalves0 pedroalves0 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.

Looks good! The change from <Heading /> to just <Text /> might take some time for us to get used to, but we can always iterate on this implementation if needed 🚀

@pawelgrimm
pawelgrimm force-pushed the pawel/feat/typography-updates branch 2 times, most recently from ef0c996 to 7e6e3dd Compare August 17, 2026 17:19
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.
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 force-pushed the pawel/feat/typography-updates branch from 7e6e3dd to 1d938fa Compare August 18, 2026 16:00
@pawelgrimm
pawelgrimm merged commit ad28bbe into main Aug 18, 2026
10 of 12 checks passed
@pawelgrimm
pawelgrimm deleted the pawel/feat/typography-updates branch August 18, 2026 17:58
@doist-release-bot

Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 37.0.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@doist-release-bot doist-release-bot Bot added the Released PRs that have been merged and released label Aug 18, 2026
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. Released PRs that have been merged and released

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants