[RFC] What's the best API to override deep/nested elements?
See original GitHub issueA while back, around the alpha & beta iterations on the v1 version, we had to decide what was the best way to override the nested components. It’s meant to help developers customize the rendering. We can find #11204 and #10476 as a legacy.
up until v1
So far, the tradeoff on this problem has been:
- Provide a
XXXComponent
prop when overriding the nested element can be valuable for users. For instance:
- Provide a
XXXProps
prop when providing a customXXXComponent
component is too cumbersome. For instance:
However, this original design constraint is increasingly more challenged by the following:
Autocomplete
The Autocomplete mixes the renderXXX
approach with the XXXComponent
approach. cc @oliviertassinari
https://github.com/mui-org/material-ui/blob/c6b95d2e773088af66823f8995c3e57508c82056/packages/material-ui-lab/src/Autocomplete/Autocomplete.d.ts#L164 https://github.com/mui-org/material-ui/blob/c6b95d2e773088af66823f8995c3e57508c82056/packages/material-ui-lab/src/Autocomplete/Autocomplete.d.ts#L142
Date Picker
The DatePicker mixes the renderXXX
approach with the XXXComponent
approach. cc @dmtrKovalenko
renderLoading?: () => React.ReactNode;
ToolbarComponent?: React.ComponentType<ToolbarComponentProps>;
Data Drid
The DataGrid goes with xXXComponent
approach, however, the name is confusing. Sometimes it’s a render prop, sometimes it’s a React element, it’s never a component as the name suggests cc @dtassone
paginationComponent?: (props: PaginationProps) => React.ReactNode;
loadingOverlayComponent?: React.ReactNode;
noRowsOverlayComponent?: React.ReactNode;
footerComponent?: (params: ComponentParams) => React.ReactNode;
headerComponent?: (params: ComponentParams) => React.ReactNode;
Styled components
Styled components might request something brand new. cc @mnajdova
As the experimentation of #21104 showcases. If we want to keep the CSS specificity at it’s lowest possible level (meaning one level) and expose unstyled components, we will have to expose an API to inject custom component. In older experimentation, I worked around the problem with a components
prop.
components?: {
Root: React.ElementType<React.HTMLAttributes<HTMLDivElement>>;
Label: React.ElementType<React.HTMLAttributes<HTMLSpanElement>>;
}
The problem
I think that it would be great to defines which API works best and in which cases. I would hope that by doing so, we can provide a consistent experience for the developers using the library to build applications and websites. I also think that by reducing the number of approaches we can reduce the learning curve for new users.
When should we use a component, when should we use a render prop, etc.?
Prior-arts
Issue Analytics
- State:
- Created 3 years ago
- Reactions:8
- Comments:22 (22 by maintainers)
Top GitHub Comments
flat vs. deep
@dmtrKovalenko While I think that we should encourage flatten props as much as possible for the reasons mentioned in https://github.com/mui-org/material-ui/issues/21453#issuecomment-656065074. (@dtassone Yes, I very much have the DataGrid API in mind the options could be flattened :p), It’s not without its limitations.
I see a couple of advantages in going deep:
y
, it’s one place, always the same between all the components. You don’t need to scan the whole set of props the component exposes. Take the Autocomplete, we have 59 props, take the DatePicker, we have 65 props, good luck if they aren’t prefixed with the same wording, likerenderX
orcomponentX
.y
prop, not all the props.classes
prop.Closing as we agreed on:
going forward.