React Slots: a New Way of Composition
From Author:
In this talk we will learn what is Slots and what does it mean to the React ecosystem, what's the current state and the future.
This talk has been presented at React Advanced Conference 2022, check out the latest edition of this React Conference.
FAQ
The React Slots RFC introduces APIs to create placeholders and templates that manage component layout and interactions. This approach provides detailed component control and visibility, allowing for dynamic content insertion while maintaining design consistency.
Gongwu Nie identifies the main challenge in designing component APIs as deciding which properties should be passed to the component wrapper and which to the input. This complexity can make the component behave like a black box, confusing consumers.
A common issue in the current approach is that adding margins to the component can inadvertently increase the margin between internal elements like the label and input, rather than around the component itself. This happens because properties are spread to the inner input element.
Gongwu Nie suggests using a composition approach, where each sub-component is responsible for its own functionality. This method enhances clarity, simplicity, and flexibility, allowing for better customization without bloating the API.
The composition approach can lead to issues with semantic and style inconsistencies, especially when sub-components are repositioned or modified. It also makes the component less aware of its children, which can complicate accessibility compliance.
Slots in web component design are named placeholders in a template that can be filled with any markup fragment. This approach allows for flexibility while maintaining layout consistency, as the arrangement of components is predefined in the template, not by the order of composition.
Gongwu Nie favors a centralized control model because it combines the flexibility of the composition approach with the predictability of the configuration approach. This model allows the host component to remain the single source of truth, enhancing the component's consistency and predictability.
Forwarding ref is crucial in building shareable components because it allows direct access to the DOM node, which is necessary for functionalities like focusing an input during form validation or attaching UI enhancements such as popovers or tooltips.
Video Transcription
1. Introduction to React Snots and API Design
Today, my topic is React Snots, a new way of composition. Every time I found a new design system, the first thing I would do is to see how they implement the text input component. The fix is simple. We can pass the class name and style to the component wrapper instead. Similar to WrapRef, we can introduce wrapper prompts, label prompts, and description prompts. Here is the API of text input from man time.
Hey, it's my great honor to be here to share with you some of my thoughts on the design system. My name is Gongwu Nie, you can call me Neo. Today, my topic is React Snots, a new way of composition.
Before we dive into the topic, I'd like to tell the backstory first. When working on the design system, I'm always thinking, how to build flexible and future-proof components? For me, the hardest thing is not creating new components or fixing weird bugs. It's the component API design.
Every time when I found a new design system, the first thing I would do is to see how they implement the text input component, because it's one of the most mysterious components. Let me show you. Text input is simple and straightforward. It comes with a label, an input, and has a test. Let's add accessibility support first. When building a shareable component, please don't forget to forward ref. We need the ref to the input to focus it in form validation. But what about the wrapper? We also need the ref to the wrapper to attach propover or tootip to it in some cases. Well, we can add a wrapper for it.
But wait, have you noticed a potential problem with the current approach? What will happen if we are trying to add some margins to the component from the other component? It will increase the margin between label, input and description instead, because we spread all the rest prompts to the inner input element. The fix is simple. We can pass the class name and style to the component wrapper instead. Looks good? The problem is that the component is getting confusing for the consumers. Which prompt will be passed to the wrapper? Which prompt will be passed to the input? The component becomes a black box. In reality, the product team will keep asking for more options to access the internal elements, like attaching point events or adding data attributes to the label or description. Similar to WrapRef, we can introduce wrapper prompts, label prompts, and description prompts. It works. But it doesn't end here. What if we need to add surroundings to the input, more prompts. Now you can see how API gets bloated with this approach. Here is the API of text input from man time. Don't get me wrong. Man time is a great components library. I love it a lot.
2. Configuration Way and Component Composition
They choose the configuration way to design the component API. In the configuration way, we have to support flexibility with API bloating, and the components become a completely black box for consumers. Let's take one step back and think, how do we build our web app in React? We compose components. Each component just do its own job and that's it. Simple and flexible.
They choose the configuration way to design the component API. In the configuration way, we have to support flexibility with API bloating, and the components become a completely black box for consumers.
Let's take one step back and think, how do we build our web app in React? We compose components. Each component just do its own job and that's it. Simple and flexible.
Then, what if we use the same approach for shareable components? We gain the same clearance, simplicity, and flexibility. A lot of popular components libraries are using the CompositionWay to implement accessible components like Chakra UI, Redux primitives, Hedonist UI, and more.
To support accessibility, we have to use React Context to communicate between parent and children to coordinate the accessibility attributes. Configuration is simple to use. You really want to write your module in the left style rather than the right style. But the CompositionWay is not the final answer.
Comments