UNPKG

@zemd/react-slottable

Version:

A lightweight concept to customize subcomponents in React

100 lines (77 loc) 3.36 kB
# React Slottable for customizable components > A lightweight concept to customize subcomponents in React [![](https://img.shields.io/npm/v/@zemd/react-slottable?color=%230000ff&labelColor=%23000)](https://www.npmjs.com/package/@zemd/react-slottable) The package provides a lightweight approach to give your component users ability to customize it's subcomponents easily. The idea is highly inspired by [Material-UI](https://mui.com/x/common-concepts/custom-components/). ## Usage ## Installation ```bash npm install --save-dev @zemd/react-slottable pnpm add -D @zemd/react-slottable ``` ## Writing components The core concept of the library is **slot**. A **slot** is a part of a component that can be overridden and/or customized. For example, you want to create a `Calendar`, but you do not want to create a numerous amount of props to customize nested components. Instead, you can divide your components on **slots** and provide your users with the ability to customize them. Let's create a simple `Button` component with `startDecorator` and `endDecorator` slots to show how it works: ```tsx import { type PropsWithSlots, useSlot } from "@zemd/react-slottable"; type ButtonProps = PropsWithSlots< React.PropsWithChildren<{ // here you define your regular component props fullWidth?: boolean; disabled?: boolean; size?: "sm" | "md" | "xl"; variant?: "solid" | "outlined"; color?: "primary" | "secondary"; className?: string; }>, ["startDecorator", "endDecorator"] // here you define your slots >; const DefaultDecorator: React.FC<{ className?: string }> = ({ className }) => { return <div className={className}>Default decorator</div>; }; export const Button: React.FC<ButtonProps> = (rootProps) => { const { slots, slotProps, ...props } = rootProps; const StartDecoratorSlot = useSlot("startDecorator", rootProps, { slot: DefaultDecorator, // provide default decorator, but can be overridden by user }); const EndDecoratorSlot = useSlot("startDecorator", rootProps); return ( <button {...props}> {/* ^^^ do not forget to handle not standard attributes, e.g. fullWidth ...*/} <StartDecoratorSlot className="class-override" /> {/* ^^^ you can provide default className ^^^ */} {props.children} <EndDecoratorSlot /> </button> ); }; ``` Now your users can use this `Button`: ```tsx const MyCustomLabelComponent: React.FC = () => { return <span>My custom label</span>; }; export function HomePage(): React.JSX.Element { return ( <div> <Button slots={{ endDecorator: MyCustomLabelComponent, }} slotProps={{ startDecorator: { prop1: "value", }, }} className="my-custom-button-className" > Click me! </Button> </div> ); } ``` As you can see, `StartDecoratorSlot` was predefined with default component, which will be always shown until user overrides it. However, the `EndDecoratorSlot` was not predefined, so it will be empty until user provides a component for it. ## License The `@zemd/react-slottable` is licensed under **[Apache License 2.0](https://www.apache.org/licenses/LICENSE-2.0)** 😇. ## 💙 💛 Donate [![](https://img.shields.io/static/v1?color=blue&label=UNITED24&message=support+Ukraine)](https://u24.gov.ua/)