Skip to content
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] Meaning of components and slots #34333

Open
siriwatknp opened this issue Sep 16, 2022 · 19 comments
Open

[RFC] Meaning of components and slots #34333

siriwatknp opened this issue Sep 16, 2022 · 19 comments
Assignees
Labels
RFC Request For Comments

Comments

@siriwatknp
Copy link
Member

siriwatknp commented Sep 16, 2022

What's the problem? 🤔

From #33416 and #21453, 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).

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:

  • changing button to a
  • changing ul to div in the Autocomplete for grouped options
  • access ownerState and add some logic + styles.

Proposed 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.

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 and input):

  • The component of the root slot is <div>.
  • The component of the input slot is <input>.,

Resources and benchmarks 🔗

No response

@oliviertassinari
Copy link
Member

oliviertassinari commented Sep 16, 2022

@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.".

  • If the component is a single DOM node, which we aim for as much as possible, then I don't see the use case for a root slot. It seems that the component itself is this root slot. If it's about being able to access the ownerState, the component prop already covers this use vase.
  • If the component isn't a single DOM node then I believe we are already adding slots.

@samuelsycamore
Copy link
Contributor

samuelsycamore commented Sep 16, 2022

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 and input):

  • 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:

  • the component is the final rendered UI element - Slider, Button, etc.
  • the slots are the nested/interior nodes within the component, which may be React components or HTML elements
    • For components that only consist of a single DOM node, "component" would be more or less synonymous with the 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:

components-and-slots

@michaldudak
Copy link
Member

michaldudak commented Sep 19, 2022

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:

  1. replace the ButtonRoot component with something else
  2. replace the button with something else

As 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 />
}

@siriwatknp
Copy link
Member Author

siriwatknp commented Sep 19, 2022

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'

@samuelsycamore
Copy link
Contributor

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:
component-slots-subcomponents

@siriwatknp
Copy link
Member Author

Would it make sense to refer to those as "subcomponents"?

Yes! that's better.

@oliviertassinari
Copy link
Member

oliviertassinari commented Sep 20, 2022

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.

@samuelsycamore
Copy link
Contributor

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.

@oliviertassinari
Copy link
Member

oliviertassinari commented Sep 20, 2022

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.

@samuelsycamore
Copy link
Contributor

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.)

@oliviertassinari
Copy link
Member

oliviertassinari commented Sep 20, 2022

@samuelsycamore To be clear, #34333 (comment) 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 #34333 (comment).
No objections to use the graph tree terminology for the docs.

@siriwatknp
Copy link
Member Author

No objection to "leaf component" as long as we use the same terminology in the docs.

@michaldudak
Copy link
Member

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.

@siriwatknp
Copy link
Member Author

I think we are close to the conclusion here, so let's pick one and use it across the documentation:

Available options:

  1. subcomponent
  2. leaf component
  3. rendered component
  4. as component
  5. forwarded component

@siriwatknp
Copy link
Member Author

siriwatknp commented Oct 12, 2022

I 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.

@oliviertassinari
Copy link
Member

oliviertassinari commented Oct 12, 2022

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".

@rosskevin
Copy link
Member

rosskevin commented May 14, 2023

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.

@siriwatknp
Copy link
Member Author

siriwatknp commented Jan 17, 2024

To close this issue:

  • @DiegoAndai is working on the deprecations of *Props to slotProps.* in all components.
  • Add a clear definition and explanation about slots in MUI context.

@DiegoAndai DiegoAndai self-assigned this Jan 17, 2024
@DiegoAndai DiegoAndai added this to the Material UI: v6 milestone Jan 17, 2024
@samuelsycamore
Copy link
Contributor

  • 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.

@DiegoAndai DiegoAndai moved this to Backlog in Material UI Mar 19, 2024
@DiegoAndai DiegoAndai moved this from Backlog to In progress in Material UI Mar 19, 2024
@DiegoAndai DiegoAndai moved this from In progress to Backlog in Material UI Jun 3, 2024
@DiegoAndai DiegoAndai removed this from the Material UI: v6 milestone Jun 3, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
RFC Request For Comments
Projects
Status: Backlog
Development

No branches or pull requests

8 participants