Skip to content

Conversation

@oliviertassinari
Copy link
Member

@oliviertassinari oliviertassinari commented Jan 25, 2026

Fix #2859. See #2859 (comment) for why a fix. With this PR release, we could then merge shadcn-ui/ui#9444.

You can test this work / the problem in the playground using:

import * as React from 'react';
import { Button } from "@base-ui/react/button"

// A "Fake" component to be loaded
const FakeComponent = (props) => <div style={{ color: 'red' }} {...props} />;
// A "Lazy" version that resolves after 100ms
const LazyMock = React.lazy(() => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve({ default: FakeComponent });
    }, 0);
  });
});

const AsyncServerComponent = async (props) => <div style={{ color: 'blue' }} {...props} />

export default function CloneElement() {
  return (
    <div>
      <React.Suspense fallback={<div>Loading…</div>}>
        Cases
        <Button nativeButton={false} render={<LazyMock />}>
          Lazy
        </Button>
        {/* <Button nativeButton={false} render={(props) => <LazyMock {...props} />}>
          Lazy function
        </Button> */}
        <Button nativeButton={false} render={<AsyncServerComponent />}>
          Async
        </Button>
        {/* <Button nativeButton={false} render={<React.Fragment>Bar</React.Fragment>}>
          Framgnet
        </Button> */}
        {/* <Button nativeButton={false} render={<React.Fragment><div>1</div><div>2</div></React.Fragment>}>
          Array
        </Button> */}
      </React.Suspense>
    </div>
  );
}

While I was at it, I tried to bring it to the next step. There were easy, low-hanging fruits 🍇:

Tests

I have added some missing test cases for useRenderElement().

Error recovery

I have added logic to help developers when they provide wrong values to the render prop.

Before, if you did this: <Button nativeButton={false} render={<React.Fragment>Bar</React.Fragment>}>, the error would be confusing:

SCR-20260125-bxxw

now, you get something clearer. I love it 😌:

SCR-20260125-bxtl

@oliviertassinari oliviertassinari added the type: bug It doesn't behave as expected. label Jan 25, 2026
@oliviertassinari oliviertassinari added external dependency Blocked by external dependency, we can’t do anything about it. scope: all components Widespread work has an impact on almost all components. labels Jan 25, 2026
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Jan 25, 2026

commit: 34e7d17

@mui-bot
Copy link

mui-bot commented Jan 25, 2026

Bundle size report

Bundle Parsed size Gzip size
@base-ui/react 🔺+89B(+0.02%) 🔺+52B(+0.04%)

Details of bundle changes


Check out the code infra dashboard for more information about this PR.

@netlify
Copy link

netlify bot commented Jan 25, 2026

Deploy Preview for base-ui ready!

Name Link
🔨 Latest commit 0e36d98
🔍 Latest deploy log https://app.netlify.com/projects/base-ui/deploys/697569c84e3ed1000847e0d6
😎 Deploy Preview https://deploy-preview-3856--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.

@oliviertassinari oliviertassinari force-pushed the fix-clone-element-async branch 2 times, most recently from 47b1626 to 38d0fa0 Compare January 25, 2026 00:59
@netlify
Copy link

netlify bot commented Jan 25, 2026

Deploy Preview for base-ui ready!

Name Link
🔨 Latest commit f41510f
🔍 Latest deploy log https://app.netlify.com/projects/base-ui/deploys/69756a6aa1b01d0008c12307
😎 Deploy Preview https://deploy-preview-3856--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.

@netlify
Copy link

netlify bot commented Jan 25, 2026

Deploy Preview for base-ui ready!

Name Link
🔨 Latest commit 34e7d17
🔍 Latest deploy log https://app.netlify.com/projects/base-ui/deploys/697753b24e3ed10008613366
😎 Deploy Preview https://deploy-preview-3856--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.

Copy link
Contributor

@atomiks atomiks left a comment

Choose a reason for hiding this comment

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

Nice that there's a workaround 🙌 Have some notes:

`Base UI: Expected to receive a valid React element in the "render" prop but received an invalid one.`,
);
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Could this error message be more helpful? e.g. why is it invalid, how to fix it.

Copy link
Member Author

Choose a reason for hiding this comment

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

Copy link
Member

@Janpot Janpot Jan 26, 2026

Choose a reason for hiding this comment

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

Suggestion, add error writing style in your AGENTS.md like mui/material-ui#47668 so that review bots can suggest improvements.

Signed-off-by: atomiks <cc.glows@gmail.com>
// so we can throw before with custom message.
if (process.env.NODE_ENV !== 'production') {
if (!React.isValidElement(newElement)) {
throw /* minify-error-disabled */ new Error(
Copy link
Member

Choose a reason for hiding this comment

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

Why not just remove that [].join('\n')?

Copy link
Member Author

Choose a reason for hiding this comment

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

We don't need to minify the error, it won't run in production.

Copy link
Member

@Janpot Janpot Jan 26, 2026

Choose a reason for hiding this comment

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

Right, but why not write error messages according to the same rules, regardless of whether there's a production guard around? And why does it matter that this error does not get minified?

Anyway, we can probably automate this check like in mui/mui-public#794

Copy link
Member Author

Choose a reason for hiding this comment

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

but why not write error messages according to the same rules

Fair point

why does it matter that this error does not get minified?

We still need /* minify-error-disabled */ to ignore that error.

Copy link
Member

Choose a reason for hiding this comment

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

Taking care of non-prod errors in mui/mui-public#1069

@atomiks atomiks changed the title [all components] Support Lazy element in render={} [all components] Support lazy element in render prop Jan 26, 2026
@atomiks atomiks merged commit 50e164e into mui:master Jan 26, 2026
21 of 23 checks passed
@atomiks
Copy link
Contributor

atomiks commented Jan 26, 2026

Possibly related to this: support for a render function that returns a lazy component:

<Component render={<Lazy />} />
<Component render={(props) => <Lazy {...props} />} />

@oliviertassinari oliviertassinari deleted the fix-clone-element-async branch January 26, 2026 13:54
@oliviertassinari
Copy link
Member Author

oliviertassinari commented Jan 26, 2026

Possibly related to this: support for a render function that returns a lazy component:

@atomiks AFAIK, this already work; it doesn't go through the .cloneElement() code path. I have updated this PR's description playground, and I could see it working.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

external dependency Blocked by external dependency, we can’t do anything about it. scope: all components Widespread work has an impact on almost all components. type: bug It doesn't behave as expected.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[all components] render prop doesn't work with async components

4 participants