-
-
Notifications
You must be signed in to change notification settings - Fork 32.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[RFC][base] Customization of unstyled components #28189
Comments
I like this, it's much easier to reason about 👍 The components that would use the unstyled can add the `component prop and the forwarded props if needed. Off-topic, should we start referencing the unstyled components as "core"? :) |
It looks a lot like what we are doing in the |
I remember @eps1lon was in favor of this change when we discussed it. @oliviertassinari, @siriwatknp, @hbjORbj, do you have any opinions on this topic? |
@michaldudak I agree with you. Even if some developers are more used to the first approach, maintaining only one way to customize is much clearer over the long term. |
@michaldudak I'm good with this proposal. |
I don't think that any developers would enjoy doing Regarding the alternative solutions to the pain, pushing the reasoning:
|
Consider #33709, I wonder if the two are equivalent.
|
Just checking my understanding again here. It is not perfect for MUI Base to receive Let's take const ButtonUnstyled = React.forwardRef(function ButtonUnstyled<
BaseComponentType extends React.ElementType = ButtonUnstyledTypeMap['defaultComponent'],
>(props: ButtonUnstyledProps<BaseComponentType>, forwardedRef: React.ForwardedRef<any>) {
...
const classes = useUtilityClasses(ownerState);
const Root: React.ElementType = components.Root ?? 'button';
const rootProps = useSlotProps({...})
// This works for styled-components but not for general React components.
return <Root as={component} {...rootProps}>{children}</Root>;
}) as OverridableComponent<ButtonUnstyledTypeMap>; @michaldudak I think the question here is "do you want MUI Base to support subcomponents customization?" In my opinion, maybe not. We can say that "developers can only replace the slots" and it is their responsibility to deal with subcomponents customization, so 👍 with your proposal to remove
|
From my perspective, with unstyled components, the value of the
import ButtonUnstyled from '@mui/base/ButtonUnstyled';
import './button.css';
export function ReusableButton = ({ component, ...props }) => (
<ButtonUnstyled slots={{ root: component ?? 'button' }} slotsProps={{ root: props }} />
) when you could do: import ButtonUnstyled from '@mui/base/ButtonUnstyled';
import './button.css';
export function ReusableButton = ({ component, ...props }) => (
<ButtonUnstyled component="span" {...props} />
) On a related note, the unstyled components that have more that a root slot might not the best DX. For example, it might be great to breakdown the SliderUnstyled into one component for each of its sub components: root, rail, track, thumb.
|
No. We don't want to assume any particular shape of slot components. Specifically, we can't assume they will have the @oliviertassinari to me, the biggest value of the
I'm happy to discuss the pros and cons of different approaches here. If I understand you correctly, you propose something similar to the pattern Radix UI uses (https://www.radix-ui.com/docs/primitives/components/switch), yes? In our case, it would be: <SwitchUnstyled>
<SwitchTrack component="span" />
<SwitchThumb component={MyCustomThumb} />
</SwitchUnstyled> At first glance, this seems like a lot to write - it's much more verbose than But, I admit, this pattern looks quite pretty, and it's easy to scan. Note that using hooks can give a similar experience: const { getInputProps } = useSwitch();
/* ... */
<span className="root">
<span className="track" />
<span className="thumb" />
<input {...getInputProps()} />
</span>
It's a great goal, however, we have to be careful to keep the same meaning of the props across different products. So if we have a |
@michaldudak Correct, it's more: this could have potential, it could be interesting to test this path (test market validation or disapproval).
It's what put me on the track that this could have potential. If we look at the arrow of progress, on Material UI/Joy UI, we have tried to abstract API so developers could customize the components but mostly use the same API in their real apps once customized.
It helps but I think that it the hook is failing one dimension: you are forced to "wire" the hook inside ONE component. You can't easily break it down into multiple components to later compose. For hooks, I think that the equivalent pattern would multiple hooks per component. I propose we park this one component/hook vs. multiple components/hooks discussion here as it's not directly related to this issue. |
We've discussed this topic with @mnajdova, @siriwatknp, and @hbjORbj on the refinement today, and the following options were considered: 1. Regarding the
|
I vote (1.2) to remove the Will benefit #32088 and work with Tailwind CSS. // just an example
<MenuButtonUnstyled
slotProps={{
root: ownerState => ({
className: ownerState.active ? '...' : '...',
}),
}} |
Comments:
Overall, for long-term and structural decisions like this, I think that the developers are the ones that hold the cards. As a developer, I think that I would have a better experience with 1.1 and 2.1, and with the removal of the slot props for all the components where there is only one slot, e.g. ButtonUnstyled. |
It's explained in #34334. In Base, the
Yes and no :) |
At the meeting on Tuesday, the @mui/core team decided to remove the component prop.
We'll treat is as an experiment. If the we receive feedback from the community that the component prop is missed, we'll add it back. Restoring the current behavior won't be a breaking change. |
I'm closing the issue as the decision was made and the implementation of the first component is mostly complete. |
🖼 Background
Currently, there are two ways of providing custom components and their props to Unstyled components:
component
prop and additional props on the unstyled component,components
/componentsProps
propsIt has several drawbacks:
component
, orcomponents.Root
component
creates a polymorphic component, which causes performance problems in the type system and is hard to get right.💡 Proposal
I suggest keeping only the
components
/componentsProps
props and remove thecomponent
and the ability to forward the extra props to the root slot.The unstyled component would accept only the props it needs to work. Everything on top of that would be provided through
componentsProps
.🎉 Advantages
😟 Disadvantages
The text was updated successfully, but these errors were encountered: