@zemd/react-slottable
Version:
A lightweight concept to customize subcomponents in React
100 lines (77 loc) • 3.36 kB
Markdown
# React Slottable for customizable components
> A lightweight concept to customize subcomponents in React
[](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://u24.gov.ua/)