When developing user interfaces with React, you often create a set of basic primitives. Another option is to consume them from a third-party library and perhaps build more complex components yourself.
To learn about a potential solution to the problem, I am interviewing Anurag Hazra.
Hi! My name is Anurag, and I'm a frontend engineer from India currently working at timelessco. I enjoy building interactive user interfaces and also love to do creative coding in my free time.
I love to contribute to open source projects and even created a few of my own.
Renderlesskit React is a component library that's focusing on flexibility, reusability, and accessibility. We are developing the solution at timelessco and I have been working with my colleague Navin Moorthy on this project for the past six months.
It's a renderless component library. The solution handles behaviors, logic, and accessibility via React hooks. The approach enables the consumers to have full control over styling while tackling the other concerns.
Check out our Storybook preview
Under the hood, Renderlesskit uses Reakit created by Diego Haz. The toolkit comes with excellent base components and helpful utilities for handling accessibility and hooks based component systems.
There are two parts for creating any components in Reakit: component hook and state hook.
The component hook handles all the logic which the component needs and returns the component's accesibility logic and HTML props. We can also add event listeners/refs/a11y props in this hook too.
Reakit provides a wonderful createHook
function which is used to create the hooks. The cool thing is that we can even combine multiple hooks together to supercharge our components easily. It looks something like this:
export const useAccordionPanel = createHook<
AccordionPanelOptions,
AccordionPanelHTMLProps
>({
name: "AccordionPanel",
// We can compose with other hooks
compose: [unstable_useId, useDisclosureContent],
// Keys are generated automatically
keys: ACCORDION_PANEL_KEYS,
useProps(options, { ref: htmlRef, ...htmlProps }) {
const accordionId = getAccordionId(options);
// Add event listeners, do a11y logic, and other things
return {
"aria-labelledby": accordionId,
...htmlProps,
};
},
});
Reakit also provides a createComponent
function that connects the hook to a React component.
The state hook is the main hook which handles all of the component state. It's a plain custom React hook:
const useAccordionState = (props) => {
// logic
return { ...state };
};
Then we can create our components by combining those two hooks and use them in our app:
const App = () => {
const state = useAccordionState();
return (
<Accordion {...state}>
<AccordionTrigger {...state}>
Trigger 1
</AccordionTrigger>
<AccordionPanel {...state}>Panel 1</AccordionPanel>
<AccordionTrigger {...state}>
Trigger 2
</AccordionTrigger>
<AccordionPanel {...state}>Panel 2</AccordionPanel>
</Accordion>
);
};
With this approach, the benefit we get is that all our components are hook based and completely unstyled. The users can compose one or multiple hooks together to extend the system, just like Lego bricks.
You can learn how Reakit works from the interview of Diego Haz.
The main difference is that unlike traditional component libraries, Renderlesskit does not have any styling opinions nor does it depend on any CSS frameworks while providing as much flexibility as possible.
It also differs from other libraries in the aspect of the core system. We are only extending the Reakit component ecosystem using reakit-system. It is similar to react-aria but uses reakit-system to achieve the same behaviors.
There are other similar hooks/component libraries out there that solve the issue nicely too. Consider the examples below:
These are all amazing libraries which are very similar at core, but what we wanted is an in-house component library at timelessco to use as a foundation for our next design system.
You can read more about our core concepts online.
Our CEO, Sandeep Prabhakaran, came up with the idea as we needed an in-house component library which we can manage and support our requirements in the future. The hope is that we can build a UI library and ultimately to create a nocode design system designer.
The next step is to create an in-house design system for our company using Renderlesskit itself.
We have already started working on it, and we are using Tailwind for styling and the solution as a base.
After finishing the design system, we plan on creating a system for our design tokens in Figma so that these tokens can be in sync with our code via a common theme specification. We are still researching this topic.
You can find the source code of our design system here: @renderlesskit/react-tailwind
In general, I'm seeing a trend in web development which is "rediscovering lost patterns". We are now leaning towards making things less complicated and using the platform. For example:
I also think that tooling will become more and more sophisticated and faster in the future. We already have Snowpack, swc, Rome, and Vite doing excellent work on pushing the limits.
The only advice I can give them is to stay focused, don't feel overwhelmed, start slow, and keep trying! :)
Learn the fundamentals first and then jump to more advanced topics later. Grasping the fundamentals goes a long way.
Kumar Abhirup is doing excellent work on his project propagate.at.
From the past few month we worked on this project and learned a lot about accessibility and building a component library.
Renderlesskit would not have been possible without the following people:
Thanks for the interview, Anurag! I like the approach you chose as it avoids the pitfalls of coupling styling to components. I've seen this cause trouble many times.
To learn more, check out Renderlesskit React on GitHub.