You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
refactor: replace as prop with render prop in Text and Headline (#740)
* refactor: replace `as` prop with `render` prop in Text and Headline
Migrate Text and Headline components from the brittle `as` polymorphic
prop pattern to Base UI's `render` prop + `useRender` hook, matching
the pattern already used by the Flex component. This eliminates manual
type unions, removes a `@ts-expect-error` suppression, and enables
rendering as any element via JSX or render functions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: fix render prop playground controls to use JSX element syntax
The render prop accepts ReactElement values, not strings. Update
playground select options to use JSX element strings (e.g. '<h2 />')
so getPropsString generates correct `render={<h2 />}` syntax.
Also document the render prop in Headline's API Reference section.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs: update V1 migration guide for Text and Headline render prop
Add migration documentation for the breaking change where `as` prop is
replaced by `render` on Text and Headline components. Includes
before/after examples, TypeScript type change notes, and render function
usage. Updates Table of Contents, cross-cutting changes note, and
Migration Checklist.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
> **Note:** Text and Headline also replace their `as` prop with `render`, but using a different pattern. Instead of `asChild` (which forwarded all props to a child element), `as` was a simple string tag name. The new `render` prop accepts a JSX element or a render function, matching the Base UI convention. See [Text](#text) and [Headline](#headline) for details.
116
+
113
117
### Callback Signatures
114
118
115
119
Most `onValueChange`, `onOpenChange`, and `onCheckedChange` callbacks now receive an optional second `eventDetails` argument:
@@ -767,6 +771,35 @@ Type changed to `useRender.ComponentProps<'div'>` -- may cause TypeScript errors
767
771
768
772
---
769
773
774
+
### Headline
775
+
776
+
**`as` prop replaced by `render`:**
777
+
778
+
The `as` prop accepted a string tag name (`'h1'` through `'h6'`). The new `render` prop accepts a JSX element or a render function, consistent with the Base UI pattern used across the library. The default element remains `<h2>`.
**TypeScript:** The type changed from `HeadlineBaseProps & ComponentProps<'h1'> & {as?:'h1'|...|'h6'}` to `HeadlineBaseProps & useRender.ComponentProps<'h2'>`. If you explicitly typed Headline props, update to `HeadlineProps` (now exported).
800
+
801
+
---
802
+
770
803
### InputField
771
804
772
805
**Label, helper text, error, and optional indicator moved to `Field` wrapper.** InputField is now a pure input control — wrap it with the new `Field` component for labels, descriptions, and error messages.
@@ -1283,6 +1316,49 @@ Key changes:
1283
1316
1284
1317
---
1285
1318
1319
+
### Text
1320
+
1321
+
**`as` prop replaced by `render`:**
1322
+
1323
+
The `as` prop accepted a string tag name (`'span'`, `'p'`, `'div'`, `'label'`, `'a'`). The new `render` prop accepts a JSX element or a render function, consistent with the Base UI pattern used across the library. The default element remains `<span>`.
1324
+
1325
+
```tsx
1326
+
// Before
1327
+
<Textas="label">Username</Text>
1328
+
<Textas="p">Paragraph text</Text>
1329
+
<Textas="a"href="/link">Click here</Text>
1330
+
<Text>Default span</Text>
1331
+
1332
+
// After
1333
+
<Textrender={<label />}>Username</Text>
1334
+
<Textrender={<p />}>Paragraph text</Text>
1335
+
<Textrender={<ahref="/link" />}>Click here</Text>
1336
+
<Text>Default span</Text>
1337
+
```
1338
+
1339
+
Note that HTML attributes specific to the rendered element (like `href` for anchors, `htmlFor` for labels) now go on the JSX element inside `render`, not on `Text` itself:
**TypeScript:** The type changed from a discriminated union (`TextSpanProps | TextDivProps | TextLabelProps | TextPProps | TextAProps`) to `TextBaseProps & useRender.ComponentProps<'span'>`. The `render` prop now accepts any element, so you are no longer limited to the five original tag names. The `// @ts-expect-error` that was needed internally for polymorphic refs is also gone.
1359
+
1360
+
---
1361
+
1286
1362
### TextArea
1287
1363
1288
1364
**Label, helper text, error, and optional indicator moved to `Field` wrapper.** TextArea is now a pure textarea control — wrap it with the new `Field` component for labels, descriptions, and error messages.
@@ -1596,6 +1672,8 @@ These are purely additive -- no migration needed.
1596
1672
- [ ] Upgrade to React 19
1597
1673
- [ ] Update CSS import order (`normalize.css` before `style.css`)
1598
1674
- [ ] Global find-and-replace: `asChild` -> `render` prop pattern
1675
+
- [ ] Replace `Text as="..."` with `Text render={<element />}` (see [Text](#text))
1676
+
- [ ] Replace `Headline as="..."` with `Headline render={<element />}` (see [Headline](#headline))
1599
1677
- [ ] Update callback signatures where TypeScript complains
0 commit comments