🚨 Shai-Hulud Strikes Again:834 Packages Compromised.Technical Analysis →
Socket
Book a DemoInstallSign in
Socket

@bento/slots

Package Overview
Dependencies
Maintainers
3
Versions
2
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@bento/slots

The slots implementation of Bento

latest
Source
npmnpm
Version
0.1.3
Version published
Maintainers
3
Created
Source

Slots

The @bento/slots package provides a way to customize components using slots. Allowing developers full control over every part of the component. It automatically intercepts the slot and slots props of the components and introduces the requested changes.

This package should be used in conjunction with the @bento/use-props package.

Installation

npm install --save @bento/slots @bento/use-props

<Source language='tsx' code={ SourceNestedSlots } />

withSlots

The withSlots function is used to create a new component that supports slots.

import { useProps } from '@bento/use-props';
import { withSlots } from '@bento/slots';

export const Button = withSlots('BentoButton', function BentoButton(args) {
  const { props, apply } = useProps(args);

  // Do your magic ✨
});

The withSlots function accepts three arguments:

The name argument does not need to match the name of under which you export your component but it is recommended to use the same name to avoid confusion. The reason why we require the name to be unique is because it's used to identify the component. This allows the component to be targeted with a global slot override, but it will also be used as displayName to ensure a readable component name in the React DevTools.

Modifiers

Modifiers are functions that are ran when the supplied component is rendered. They can be used to modify the component or received props. This allows common modifications to be shared between components.

Each modifier is a function that takes an object with the following properties:

The modification happen based on the return value of the modifier. If nothing is returned, the component will be rendered as is. If you want to introduce a new Component to be rendered, you can return an object with a Component property. If you want to modify or introduce props that are passed to the component, you can return an object with a props property. The same applies to context.

For the props and contex the returned object is merged with the existing values of their respective properties. So you don't need to merge the existing values yourself. The Component is always replaced by the returned Component.

In the example below, the modifier function introduces a new prop to the component:

export function modifier({ Component, context, props }) {
  return {
    props: {
      newProp: 'new value'
    }
  }
}

This modifier should then be passed in the third argument to withSlots:

import { replaces } from '@bento/slots/modifiers/replaces';
import { override } from '@bento/slots/modifiers/override';
import { withSlots } from '@bento/slots';
import { modifier } from './modifier';

const Button = withSlots('MyButton', function MyButton(props) {
  return <button {...props} />;
}, [override, replaces, modifier]);

// Input: <Button>Hello</Button>
// Output: <button newProp="new value">Hello</button>

If you don't want any modifiers to be applied to your component, you can supply an empty array as the third argument to withSlots:

import { withSlots } from '@bento/slots';

export const Example = withSlots('Example', function Example(props) {
  return (
    <div {...props}>
      <Header slot="header" />
      <Body slot="content" />
      <Footer slot="footer" />
    </div>
  );
}, [/* Supply an empty array if you don't want to use the modifers */]);

The following modifiers are applied to the created component by default:

override

The override modifier is used to introduce a data-override prop to the component when it detects that certain overrides are applied to the component. This attribute makes it easier to determine where the difference between the original Component and the current rendered component are originating from.

For you as a developer, this means you can easily see which components can be easily upgrade to the new version without any problems, and which components would require some additional attention and which areas specifically.

The data-override attribute is a space-separated list of the names that indicates the following modifications:

  • style: Custom styling has been applied to the component using the `style prop.
  • className: Custom className has been applied to the component using the className prop.
  • slot: The component has been modified using slots. When the slots make changes to style or className, these are also included in the resulting data-override attribute.
  • context: The whole component or parent component has been modified using the replaces modifier and a different component has been rendered in its place.
import { override } from '@bento/slots/modifiers/override';

replaces

The replaces modifier is used to introduce "global" override of components in your application. The slot functionality that this package provides is great for making small changes to a few components, but there might be use-case where you need to make changes to every instance of a Component, e.g., in the case of experimentation.

import { replaces } from '@bento/slots/modifiers/replaces';

Slot Merging

Slot merging allows slots to be progressively enhanced as they flow through a component tree. When multiple components define slots for the same slot name, these slots are merged together.

Object Slot Merging

When both parent and child define object slots (props), they are merged with parent taking precedence:

// Child defines props
<Component slots={{ label: { className: 'child', id: 'child-id' } }} />

// Parent adds more props
<Child slots={{ label: { className: 'parent', title: 'parent-title' } }} />

// Result: { className: 'parent', id: 'child-id', title: 'parent-title' }

Function Slot Merging

When function slots are merged, the parent function becomes active but receives access to all previous implementations via the previous parameter:

import { MergedFunction } from './examples/merged-function.tsx';

// Each enhancement level adds its own function
const FirstEnhancement = () => (
  <BaseComponent slots={{
    container: function firstWrapper() {
      return <div>First Enhancement</div>;
    }
  }} />
);

const SecondEnhancement = () => (
  <FirstEnhancement slots={{
    container: function secondWrapper() {
      return <div>Second Enhancement</div>;
    }
  }} />
);

// Final component can access all previous functions
<ThirdEnhancement slots={{
  container: function wrapper({ previous }) {
    return (
      <div>
        {previous[0]()}  {/* First Enhancement */}
        {previous[1]()}  {/* Second Enhancement */}
        {previous[2]()}  {/* Third Enhancement */}
      </div>
    );
  }
}} />

Function Slot Parameters

Function slots receive an object with:

  • props: The component's props
  • original: The original React element
  • previous: Array of previous slot implementations (child → parent order)

Key Rules

  • Object slots: Parent props override child props for same keys
  • Function slots: Parent function is called, previous functions available in previous array
  • Mixed types: Function slots take precedence over object slots
  • Previous array: Ordered from closest child to furthest ancestor

Keywords

bento

FAQs

Package last updated on 06 Nov 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts