Skip to content

Isilin/react-slot

📦 React Slot Components

npm version npm downloads Storybook Build Status License: MIT

Create reusable React components with simple, typed, and powerful slots.


🗺️ Table of Contents


🧪 Try the Project

🛠️ Prerequisites

  • Node.js (recommended version: >=18.x)
  • Yarn or npm

📚 Install and Run Storybook

npm install
npm run dev
# ou
yarn install
yarn dev

This will open Storybook at http://localhost:6006.

🧩 The "Slot" Pattern in React

The slot pattern is an approach inspired by advanced libraries like Radix UI and Headless UI. It allows dynamic content injection into a component while preserving structure and encapsulated logic.

📘 Why Use Slots?

  • Build a clear and declarative API
  • Offer complete flexibility to component users
  • Add or remove optional parts without breaking the component
  • Separate structure from content
  • Create reusable and composable components
  • Provide explicit injection points for content

📦 Example: Card Component with Slots

// Card.tsx
import { PropsWithChildren } from 'react';
import { defineSlotComponent, getSlots } from '../../lib';

import classNames from 'classnames/bind';
import styles from './Card.module.css';
const cx = classNames.bind(styles);

export const Card = defineSlotComponent(
  ({ children }: PropsWithChildren) => {
    const { body, footer, header } = getSlots(children, Card);

    return (
      <div className={cx('card')}>
        {header && <div className={cx('card-header')}>{header}</div>}
        {header && (body || footer) && <Card.Separator />}
        {body && <div className={cx('card-body')}>{body}</div>}
        {body && footer && <Card.Separator />}
        {footer && <div className={cx('card-footer')}>{footer}</div>}
      </div>
    );
  },
  {
    slots: {
      header: ({ children }: PropsWithChildren) => <>{children}</>,
      body: ({ children }: PropsWithChildren) => <>{children}</>,
      footer: ({ children }: PropsWithChildren) => <>{children}</>,
    },
    extras: {
      Separator: () => <span className={cx('separator')} />,
    },
  },
);

🧪 Usage

// App.tsx
export const App = () => {
  return (
    <Card>
      <Card.Header>Ma jolie carte</Card.Header>
      <Card.Body>
        Ceci est le contenu principal de la carte. Tu peux y mettre n'importe
        quoi : du texte, des images, ou même d'autres composants.
      </Card.Body>
      <Card.Footer>Dernière mise à jour : aujourd’hui.</Card.Footer>
    </Card>
  );
};

Under the hood, each slot (Header, Footer, Content, etc.) is automatically detected and placed in the right structure.

📚 Additional Resources

Feel free to explore the component live in Storybook to better understand how the slots are used!

☕ Support this Project

If you like this project, you can support me on Ko-fi ❤️

Soutenir sur Ko-fi

🪪 Licence

This project is licensed under the MIT License.

🤝 Contributing

Contributions are welcome! Feel free to open an issue or submit a pull request.


Made with Love by Isilin

About

Create reusable React components with simple, typed, and powerful slots.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Sponsor this project

Packages

No packages published

Contributors 2

  •  
  •