-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
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: "root element" #15138
Comments
Thanks for opening this issue.
Given I'm responsible for most of the current behavior, I can put light on the design decision. It's a chicken-egg problem. The props are spread on the "root element", not the other way around. My definition was: the root element is the first outermost element that renders a host element. It should cover 99% of the current implementation. The only exception I'm aware of is |
My problem is that this is only useful if the root element is a host element. For composite components (e.g. Issues also arise with the common In the end it's perfectly fine to add a constraint that the root element should render the first host (first by breadth-first search; it's important for SwipeableDrawer). Strictly from a React selector POV What's really important is that we can't just say we optimize for HTML. Not if we document that excess props are spread to composite components. |
What's the issue with the Paper? I miss one part of the 🧩.
I think that we should optimize for usage, not for the ease of writing tests in the repository. But if the tests are hard to right, it could be a sign of a poor API.
You are right, it's exactly what the definition I have given previously implies. The CSS API works in conjunction with the HTML API. I think that the ref, the
Yes, it's important for the SwipeableDrawer or the Tooltip. Thanks for the precision 👌.
What do you think of? const foo = randomStringValue();
const wrapper = mount(React.cloneElement(element, { 'data-foo': foo }));
assert.strictEqual(findOutermostIntrinsic(wrapper).hasClass(classes.root), true);
assert.strictEqual(findOutermostIntrinsic(wrapper).props()['data-foo'], foo);
testRef(element, mount, current => assert.strictEqual(Array.from(current.classList).indexOf(classes.root) !== -1, true));
It's recursive. We could document the full spread chain down to the root element's host. It would save people clicks. |
This is what I'm getting at. I agree that tests shouldn't be the priority. I'm more focusing on the aspect that in a component tree it's not obvious what the root element is i.e. there is no apparent selector. Apparent meaning that I don't know it by looking at the render implementation of a component. Only by inspecting the implementation of the children I know what the root element is.
Not strictly By your definition (root element = outermost host element) I don't think we disagree what the "root element" is. My definition would just leave no room for interpretation when
This is something I definitely want to solve. I find myself often annoyed by having to open multiple tabs to check what props are allowed. |
If the behavior is consistent, you don't need to look at anything. It's predictable :).
I don't follow. It's not the "outermost host element", it's the outermost element that renders a host element.
The root element is in the React domain, the outermost host element is in the HTML domain, we can't get an equality. What's your definition?
Same for me :). |
How can you infer from
Well yes that is the precise issue. We don't know if a component renders a host element. This information is only available upon inspection of the component.
Host element is a term in the React domain. What is considered a valid host element depends on the renderer. |
You can't, welcome to React 🙃. Seriously, documentation can help our users here 🙂. |
I think "root component = component that renders the outermost host component (where outermost is the first hit when doing BFS)" works (as in it's testable by computers and understandable by humans). We can add a section to the API design section explaining this term. |
💯 |
Our docs currently use the term "root element" to describe where excess props are spread.
This term is currently not explicitly defined and has room for ambiguity. The goal of this issue is to find a definition and apply that to every core component to reduce surprising API behavior.
Definition
root = outermost
If we take the rendered output from a component one could argue that the "root" is the top element e.g.
Drawbacks
This would not apply to many components currently (Popper, TableHead etc.). In general this definition wouldn't be very useful since every component introduced that wouldn't even change the behavior would be a breaking change (e.g.
Context.Provider
,StrictMode
,Fragment
,EventListener
).root = outermost host
Most of the components would currently be covered by defining the "root element" as the outermost element that renders a host element.
Drawbacks
It is not obvious by looking at the implementation what the root is. Maintainers might know this but without any context we don't know what components render host elements. If we look at the example it is not obvious if
NotARootElement
is rendering a host element or not (see our transition components).This definition would break when portaling or when we add wrapper containers for styling purposes.
It is also not very useful for testing. Let's say we define that the
ListItem
is the root element of aMenuItem
. We want to test that props for theListItem
are actually spread to it but the definition provides no selector to find theListItem
and check if every prop is there. What we would find is anli
host element and that shouldn't have any props for theListItem
at that point.root = defined per component
The root element would be what we define via
@inheritComponent
. The definition would add the following constraints to the component:root
classinheritComponent
remarks
about 4.
For measuring it would make sense to apply the ref to the outermost host. Can be mitigated by exposing an additional ref prop that is applied to the outermost host
about "host element"
It might be ok to use it in the following context: "Excess props are spread to the root element". However, saying that "Paper is the root element" is technically not correct. "Paper would be the root component" (or element type; but that's an uncommon term). "
<Paper />
would be an actual root element". This is just nitpicking but while we're at it we might as well do it right./cc @mui-org/core-contributors
The text was updated successfully, but these errors were encountered: