Skip to content

[useRender] Add defaultTagName parameter#2527

Merged
atomiks merged 7 commits into
mui:masterfrom
atomiks:feat/useRender-default-tag
Sep 1, 2025
Merged

[useRender] Add defaultTagName parameter#2527
atomiks merged 7 commits into
mui:masterfrom
atomiks:feat/useRender-default-tag

Conversation

@atomiks

@atomiks atomiks commented Aug 17, 2025

Copy link
Copy Markdown
Contributor

Adds a defaultTagName: typeof React.JSX.IntrinsicElements property to the useRender options, instead of needing to set a default for the render option (usually a React element), which causes the hook to use React.cloneElement and is a slower default for perf sensitive primitives

Preview: https://deploy-preview-2527--base-ui.netlify.app/react/utils/use-render.

@pkg-pr-new

pkg-pr-new Bot commented Aug 17, 2025

Copy link
Copy Markdown

vite-css-base-ui-example

pnpm add https://pkg.pr.new/mui/base-ui/@base-ui-components/react@2527
pnpm add https://pkg.pr.new/mui/base-ui/@base-ui-components/utils@2527

commit: 1c4d39c

@mui-bot

mui-bot commented Aug 17, 2025

Copy link
Copy Markdown

Bundle size report

Bundle Parsed size Gzip size
@base-ui-components/react 🔺+10B(0.00%) 🔺+7B(+0.01%)

Details of bundle changes

Generated by 🚫 dangerJS against 1c4d39c

@netlify

netlify Bot commented Aug 17, 2025

Copy link
Copy Markdown

Deploy Preview for base-ui ready!

Name Link
🔨 Latest commit 1c4d39c
🔍 Latest deploy log https://app.netlify.com/projects/base-ui/deploys/68b594ec2bb0c0000813372d
😎 Deploy Preview https://deploy-preview-2527--base-ui.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

renderParams.disableStyleHooks = true;

return useRenderElement(undefined, renderParams, renderParams);
return useRenderElement(renderParams.defaultTag, renderParams, renderParams);

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.

The terminology feels wrong. "tag" does not seem part of the React language.

If we follow https://legacy.reactjs.org/docs/implementation-notes.html#mounting-host-elements:

Suggested change
return useRenderElement(renderParams.defaultTag, renderParams, renderParams);
return useRenderElement(renderParams.defaultHostElement, renderParams, renderParams);

If we follow: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/64de0973102a5a89ac3c5c4f9913459fd93cb273/types/react/index.d.ts#L4051

Suggested change
return useRenderElement(renderParams.defaultTag, renderParams, renderParams);
return useRenderElement(renderParams.defaultIntrinsicElement, renderParams, renderParams);

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.

But I wonder, why only support host elements:

Suggested change
return useRenderElement(renderParams.defaultTag, renderParams, renderParams);
return useRenderElement(renderParams.defaultComponent, renderParams, renderParams);

@atomiks atomiks Aug 17, 2025

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yeah I don't know the best word for this 😬

I find the word "host" to be pretty abstract, and sort of implies knowledge of how React's internals work, while HTML "tag" is common knowledge. I also see the word "element" representing the object value when writing JSX, not a string. tag matches ref.current.tagName, except in lowercase

So, maybe defaultTagName.

But I wonder, why only support host elements

It's a shortcut for rendering the JSX element as a function and doesn't need to support components. The render prop itself is for that purpose

@romgrk romgrk Aug 18, 2025

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.

"tag" sounds fine to me, if that prop only supports HTML tag names.

and doesn't need to support components. The render prop itself is for that purpose

render: <Something /> is more expensive, it forces more memory allocations and a React.cloneElement() call. Being able to pass Something the same way we can pass "div" would also allow better perf in the cases where it matters. And it could solve the naming topic by forcing this param to be named defaultComponent.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

The useRender hook is specifically for building primitive components where you aren't rendering another component (yet). The callsite of the component that has useRender is where they do the replacing with render

@oliviertassinari oliviertassinari Aug 20, 2025

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.

The useRender hook is specifically for building primitive components where you aren't rendering another component (yet)

I wonder if we won't see cases where we need to expand the need to support any components. From what I understand of https://github.com/radix-ui/primitives/blob/36d954d3c1b41c96b1d2e875b93fc9362c8c09e6/packages/react/slot/src/slot.test.tsx, this is supported.

not a string. tag matches ref.current.tagName, except in lowercase

Right, ok, there is a way to justify the name, I framed this too strongly with "wrong" 😁.

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.

I wonder if we won't see cases where we need to expand the need to support any components.

And if we pick defaultComponent for this param name now, we could later expand the typings without a breaking change.

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.

I would use defaultTag as it's the only things we support now. If in the future we want to extend the behavior, we can add a new option defaultComponent and deprecate the defaultTag in favor of it. It would feel wrong naming it defaultComponent if it does not support custom components.

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.

It would feel wrong naming it defaultComponent if it does not support custom components.

Agree

@oliviertassinari oliviertassinari Sep 1, 2025

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.

If in the future we want to extend the behavior

@mnajdova Right, I was mostly wondering about either there is a use case or not for any components.

I have tried to push the reflection on it, but I can't find a solid argument for extending support. The rationale I land on: this utile is slow, so we only want to allow React tree leaves to be swapped with it. For an element in the middle of the tree, instead, we can use a slot or composition.

@colmtuite colmtuite self-requested a review September 1, 2025 10:40
@atomiks atomiks changed the title [useRender] Add defaultTag parameter [useRender] Add defaultTagName parameter Sep 1, 2025
@atomiks atomiks marked this pull request as ready for review September 1, 2025 12:50
@atomiks atomiks requested a review from michaldudak as a code owner September 1, 2025 12:50
@atomiks atomiks merged commit 12f2f45 into mui:master Sep 1, 2025
19 checks passed
@atomiks atomiks deleted the feat/useRender-default-tag branch September 1, 2025 12:50
atomiks added a commit to atomiks/base-ui that referenced this pull request Sep 10, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants