Skip to content

feat(text): add element components Text.h1 to Text.h6, Text.p, Text.span, and Text.div - #654

Merged
wemra3 merged 5 commits into
mainfrom
claude/reverent-hellman-83a597
Oct 28, 2026
Merged

wemra3 merged 5 commits into
mainfrom
claude/reverent-hellman-83a597

Conversation

@wemra3

@wemra3 wemra3 commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Add element components to Text: Text.h1 to Text.h6, Text.p, Text.span, and Text.div.

<Text.h1>Purchase orders</Text.h1>
<Text.h3 variant="heading-lg">Line items</Text.h3>
<Text.p className="text-muted-foreground">Orders sent this month.</Text.p>
<Text.span variant="body-sm">Updated recently</Text.span>

Each component always renders its named HTML element. It takes variant, className, the element's own attributes, and a ref typed for the element. It does not take render. Text and its render prop do not change.

Refs tailor-inc/platform-planning#2225 (part of tailor-inc/platform-planning#2214).

Decisions from the Slack discussion (#pf-app-shell, 2026-10-27)

  • Scope: the elements in the issue (h1 to h6, p, span) and div. Other elements, such as code, small, pre, blockquote, figcaption, time, kbd, and label, keep using Text with render and a lint disable comment. We can add more later if they are used often.

  • No as prop. It would do the same thing as Text.h1.

  • Defaults:

    Component Default variant
    Text.h1 heading-lg
    Text.h2 heading-md
    Text.h3–Text.h6 heading-sm
    Text.p body-md
    Text.span label-md
    Text.div body-md

    Text.span uses label-md, not body-md, to follow the default elements of Text (body roles render p, label and code roles render span). Text.div uses body-md, the default role of Text.

Changes

  • packages/core/src/components/text/text.tsx: a small factory creates each element component. It renders the element directly, without Base UI's useRender, because there is no render prop. It sets data-slot="text" and the same classes as Text. The Text export keeps an explicit type, as Layout and Autocomplete do.
  • No new exported props type. React.ComponentProps<typeof Text.h2> gives it, and the docs show this. Adding a named type later is not a breaking change; removing one would be.
  • Tests: tag and default role for every component, variant override, null variant, className merge, native attributes, typed refs, displayName (the root stays Text), and @ts-expect-error checks that render and as are rejected.
  • Docs: the Text page has a new "Element Components" section. The heading level, lint, and accessibility sections now point to Text.h1 to Text.h6.
  • Docs: the heading examples in the quickstart, the styling guide (Typography), and the app-shell-patterns skill rule now use Text.h1 and Text.h3 instead of render={<h1 />} and render={<h3 />}.

Decision record

decisions/typography-roles.md:

  • New "Fourth change: element components" section: API, defaults, scope, lint, no exported props type, and follow-ups. It also explains why this is not the "second way to choose the element" that the second change rejected for a level prop: plain HTML elements use Text.<element>, and composition uses render.
  • The "Lint" item of the second change now notes that headings use Text.h1 to Text.h6, and the disable comment remains only for other elements in render.

Lint check

With oxlint 1.64 and the core config, jsx-a11y/heading-has-content reports <Text variant="heading-lg" render={<h1 />}> but not <Text.h1> or <Text.h3 variant="heading-lg">. I did not check the ESLint version of jsx-a11y.

Not in this PR

  • AppShell's own components keep render={<h3 />} for now. Changing them to element components is a separate change.
  • After that, update the Typography section of .agents/references/component-design.md, which still shows render={<h3 />} with the disable comment.

Checks

pnpm fmt:check, lint, type-check, test, build, and docs:check pass locally.

🤖 Generated with Claude Code

Hiroki Uemura and others added 2 commits October 27, 2026 17:47
…pan, and Text.div

Each element component always renders its named HTML element with a
default typography role, and takes variant, className, the element's own
attributes, and a ref typed for the element. It does not take render.

Defaults: h1 heading-lg, h2 heading-md, h3-h6 heading-sm, p body-md,
span label-md, div body-md. Headings written this way do not trigger
jsx-a11y/heading-has-content, so they need no disable comment.

Text and its render prop do not change. The decision record gets a
"Fourth change" section, and the Text docs page documents the new API.

Refs tailor-inc/platform-planning#2225

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@wemra3
wemra3 requested a review from a team as a code owner October 27, 2026 08:54
@wemra3 wemra3 self-assigned this Oct 27, 2026
@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

Code Metrics Report

main (f16bacc) #654 (b5d95bb) +/-
Coverage 89.5% 89.5% +0.0%
Test Execution Time 2m33s 2m36s +3s
Details
  |                     | main (f16bacc) | #654 (b5d95bb) |  +/-  |
  |---------------------|----------------|----------------|-------|
+ | Coverage            |          89.5% |          89.5% | +0.0% |
  |   Files             |            236 |            236 |     0 |
  |   Lines             |           7504 |           7512 |    +8 |
+ |   Covered           |           6719 |           6727 |    +8 |
- | Test Execution Time |          2m33s |          2m36s |   +3s |

Code coverage of files in pull request scope (100.0% → 100.0%, patch 100.0%)

Files Coverage +/- Patch Coverage Status
packages/core/src/components/text/text.tsx 100.0% 0.0% 100.0% modified

Reported by octocov

@interacsean interacsean left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Looks like we just need to still update docs-src/skill/SKILL.template.md:70, docs-src/guides/quickstart.docs.outline.md:83 (also lines 123 and 141), docs-src/concepts/styling-theming.docs.outline.md:295
and then run pnpm docs:sync

…nd skill

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@wemra3

wemra3 commented Oct 28, 2026 •

Copy link
Copy Markdown
Contributor Author

@interacsean Thanks, updated in dca3d7a:

  • docs-src/guides/quickstart.docs.outline.md: the three page examples use <Text.h1>.
  • docs-src/concepts/styling-theming.docs.outline.md: the Typography example uses <Text.h3 variant="heading-md">, and the text before it points to the element components.
  • docs-src/skill/SKILL.template.md: the heading level is set with Text.h1 to Text.h6. Other plain elements use Text.p, Text.span or Text.div, and render is only for composing with another component.
  • Ran pnpm docs:sync.

This PR now covers these docs, so I removed them from the follow-up list in decisions/typography-roles.md and from "Not in this PR" in the PR description.

@wemra3
wemra3 requested a review from interacsean October 28, 2026 12:27
…an-83a597

# Conflicts:
#	decisions/typography-roles.md
#	docs-manifest.json
…an-83a597

# Conflicts:
#	docs-manifest.json
@wemra3
wemra3 merged commit 5db7473 into main Oct 28, 2026
8 checks passed
@wemra3
wemra3 deleted the claude/reverent-hellman-83a597 branch October 28, 2026 23:15
wemra3 pushed a commit that referenced this pull request Oct 30, 2026
The rendered output does not change, and the skill rule change shipped
with #654, so consumers have nothing to act on.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants