Open siriwatknp opened 1 year ago
@siriwatknp Do you have one example with an existing component of how this would change in practice?
I'm not sure I understand the proposal. In "All MUI components have at least 1 slot, aka root slot.".
component
prop already covers this use vase.Slots
All MUI components have at least 1 slot, aka
root
slot. The slot can be a string (DOM) or a styled component. In MUI Base, the slots are mostly strings because it is unstyled. However, for Material UI, Joy UI, the slots are mostly styled-components.The name of the slot can be seen in the suffix of the className.
Components
Represents the HTML tag used in the slot. For example, Joy UI's
Input
has 2 slots (root
andinput
):
- The component of the
root
slot is<div>
.- The component of the
input
slot is<input>
.,
I think my mental model for how MUI components are structured is actually the opposite of this. 😅
Here's how I see it:
root
slot (a Button is a <button>
), hence you'd use the component
prop to override it.The main thing I take issue with in your model is the use of the word "component" to refer to "the elements that are used to fill the slots." I could be in the minority here, but I don't think of an HTML element as a "component." If we need a general term to describe "React components or HTML elements," I would opt for something like"(interior) elements" instead. Otherwise, how do we differentiate between "the final rendered UI component" and "the interior pieces within the component"?
Here's a very ugly diagram I made to try to elaborate on how I see it—does this make sense? In your description @siriwatknp, it seems like we would be using "component" to refer to both the red blobs and the blue blobs:
Consider the following simplified example - a Button component from a styled library (like Material UI or Joy UI). Its (greatly simplified) implementation could look like that:
const ButtonRoot = styled('button')(`
// CSS styles go here
`);
const Button = (props) => {
return <ButtonRoot />
}
Now, there are two things we can customize here:
ButtonRoot
component with something elsebutton
with something elseAs I understand it, in this particular case, we're referring to the ButtonRoot
as the root slot and to the button
as the root component.
This distinction only makes sense in the styled components. In MUI Base, in most cases, slots are HTML elements, so there's just one thing to customize:
const ButtonRoot = 'button';
const ButtonUnstyled = (props) => {
return <ButtonRoot />
}
Do you have one example with an existing component of how this would change in practice?
@oliviertassinari My intention is to describe better what we have, not changing anything. If you take a look at any component in Joy UI or Material UI, you will see at least 1 slot which is the root slot:
// Typography.js
const TypographyRoot = styled('span', {
name: 'MuiTypography',
slot: 'Root',
...
})({ ... })
const Typography = React.forwardRef(function Typography(inProps, ref) {
...
return (
<TypographyRoot
as={Component}
ref={ref}
ownerState={ownerState}
className={clsx(classes.root, className)}
{...other}
/>
);
})
@samuelsycamore Seems like we are on the same page about what slot
means but the component
is still blurred. What if we add some prefix to be more specific
the component is the final rendered UI element - Slider, Button, etc.
These could refer to as MUI components - Slider, Button, etc.
I would opt for something like"(interior) elements" instead.
I like the word interior
here, so maybe we could refer to them as interior component subcomponents ? The reason I lean toward component
over element
is that our existing API is using component
prop which can receive a React component as well (<Button component={Link} />
)
Here is how I would explain it to the community:
Button, Slider, etc. are MUI components. Each MUI component contains at least 1 **slot** (the root slot) that represents a single DOM node. Each slot is created by an **interior component** which could be an HTML element or a React component.
Some examples to illustrate my explanation:
Joy UI Button
component | slot | subcomponent |
---|---|---|
Button | root | 'button' |
startDecorator | 'span' | |
endDecorator | 'span' |
<Button component="a" />
component | slot | subcomponent |
---|---|---|
Button | root | 'a' |
startDecorator | 'span' | |
endDecorator | 'span' |
<Button component={NextLink} />
component | slot | subcomponent |
---|---|---|
Button | root | NextLink |
startDecorator | 'span' | |
endDecorator | 'span' |
I like the word interior here, so maybe we could refer to them as interior component?
Would it make sense to refer to those as "subcomponents"? So a component has slots that are filled by subcomponents, which can be other React components themselves or simple HTML elements.
Here's an updated ugly visual to better illustrate the terminology:
Would it make sense to refer to those as "subcomponents"?
Yes! that's better.
subcomponents
@samuelsycamore It's not very clear to me. When we say a subcomponent, which component is it exactly down the React tree? Slots are depth 1, but is a subcomponent depth 2, 3, etc?
As the term we are trying to name describes the last component in the React rendering tree, would "leaf component" be clear? It's the highest depth.
When we say a subcomponent, which component is it exactly down the React tree? Slots are depth 1, but is a subcomponent depth 2, 3, etc?
@oliviertassinari my understanding (as I tried to illustrate visually but clearly I'm no designer 😛) is that a slot is the "space" within an MUI component (Slider, Button etc) that is filled by a subcomponent. So neither slot nor subcomponent (as I understand these terms) describe the depth. I don't think we really have any terminology to describe depth at this point. The root
slot (I think) implies depth 1, but the root's relationship to subsequent subcomponents differs (sometimes nested, sometimes not). We might just be overloading the user with information if we try to come up with names to correspond with different depths.
We might just be overloading the user with information if we try to come up with names to correspond with different depths.
@samuelsycamore But isn't the problem that we are trying to solve? The problem was framed like this:
I feel that we are mixing slots and components together even though they are not the same. By having an agreement on the meaning, I believe that it will be easier to decide on the APIs (to override components and slots).
From what I understand, the "slot" prop is depth 1 of the React component tree and the "component" prop is the maximum depth, a.k.a the leaf.
Once described like this, it becomes clear for me, it allows to reason my way thought the concepts.
From what I understand, the "slot" prop is depth 1 of the React component tree and the "component" prop is the maximum depth, a.k.a the leaf.
Once described like this, it becomes clear for me, it allows to reason my way thought the concepts.
Ah I see what you're saying now that you put it this way. I'm happy to adopt this name if you think it will be most easily understood by React devs. (Better to use existing terminology wherever possible rather than coming up with our own.)
@samuelsycamore To be clear, https://github.com/mui/material-ui/issues/34333#issuecomment-1252626049 focus on what the terms mean, I think it was the problem @siriwatknp tried to solve.
Regarding the other problem: how to best describe the terms to the developers in the docs, my only feedback would be that "subcomponent" might not be clear enough https://github.com/mui/material-ui/issues/34333#issuecomment-1251872667. No objections to use the graph tree terminology for the docs.
No objection to "leaf component" as long as we use the same terminology in the docs.
Both Styled Components and Emotion refer to it as the rendered component (https://emotion.sh/docs/styled#as-prop, https://styled-components.com/docs/api#as-polymorphic-prop). While I also understand the term "leaf component", technically it doesn't have to be a leaf of the tree as you can pass in a component with its own deep tree.
I think we are close to the conclusion here, so let's pick one and use it across the documentation:
Available options:
as
componentI vote for option 3 as it is the closest to what actually happens. "rendered component" is what gets rendered on the screen which could be a React component or an HTML element.
here, so let's pick one and use it across the documentation: Available options:
@siriwatknp To be clear, I assume this is for how to call the component
prop. I also assume that we will describe the slots.y
properties as the "slot components". Correct?
I vote for: 5 > 2 > 3 > 1 > 4. 5 and 2 make it clear where the component is rendered in the tree which I think it's where the will developers struggle to understand as a mental model when asking what's the difference with the slot. But in the end, I don't really care, I think that each option works because the docs will detail this regardless.
is what gets rendered on the screen
Based on how React teaches developers the notion of "rendered" https://beta.reactjs.org/learn/render-and-commit#step-2-react-renders-your-components, I think that it can be interpreted in two different ways 1. as the whole processed, getting to the DOM, or 2. as the intermediary step, one React node after the other.
Both Styled Components and Emotion refer to it as the rendered component
@michaldudak For styled()
the tree can only have a height of one. Meaning, the leaf component can only be the component that is rendered. In which case, what's clearer? Personally, I agree with them, I think that "rendered component" is clearer. When I see the name, I understand: "ah yes ok, it's the component that will be rendered, it doesn't matter if it's rendered as the HTML host or as an intermediary React component, it can only be one thing".
I'm extremely well versed in mui 4.x, we are just now moving to 5.x. I want to say as a 5.x novice that slots
and slotProps
are not well defined to outsiders. My first introduction was https://mui.com/material-ui/guides/interoperability/#deeper-elements-3 and there is no drill-down. Given https://stackoverflow.com/questions/71494516/material-ui-slots and my confusion, perhaps the general user could use a guide page @oliviertassinari?
EDIT: I now also see https://mui.com/base/getting-started/usage/#shared-props but it is in base
not material
docs.
To close this issue:
*Props
to slotProps.*
in all components.
- Add a clear definition and explanation about slots in MUI context.
We have this piece in the Base UI docs: Overriding component structure so it should just be a matter of duplicating it in the Material UI docs.
We'll also need to comb through the component demo docs to find the places where the component
prop is mentioned and update the info.
What's the problem? 🤔
From #33416 and #21453, I feel that we are mixing
slots
andcomponents
together even though they are not the same.By having an agreement on the meaning, I believe that it will be easier to decide on the APIs (to override components and slots).
What are the requirements? ❓
There are real use cases where you want to replace the component (HTML tag) or the slot.
Slot override
When: developers want to take control of the logic, and styles of the default slot. Use case: GitHub label example, the popper's logic has to be replaced to show options below the input.
Component override
When: developers want to change the HTML tag, normally for accessibility. (component override is more common than slot override). Alternatively, they want to add custom logic by preserving the default styles. Use case:
button
toa
ul
todiv
in theAutocomplete
for grouped optionsProposed solution 🟢
This can apply to MUI Base, Material UI and Joy UI.
Slots
All MUI components have at least 1 slot, aka
root
slot. The slot can be a string (DOM) or a styled component. In MUI Base, the slots are mostly strings because it is unstyled. However, for Material UI, Joy UI, the slots are mostly styled-components.Components
Represents the HTML tag used in the slot. For example, Joy UI's
Input
has 2 slots (root
andinput
):root
slot is<div>
.input
slot is<input>
.,Resources and benchmarks 🔗
No response