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

@bento/icon

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/icon

Icon component

latest
Source
npmnpm
Version
0.1.2
Version published
Maintainers
3
Created
Source

Icon

The @bento/icon package provides a way to render SVG-based icons in your application. This package does not ship any icons but instead allows you to introduce your own icons.

Installation

npm install --save @bento/icon

Props

The @bento/icon package exports the Icon component:

import { Icon } from '@bento/icon';

<Icon icon="icon-name" />

The following properties are available to be used on the Icon component:

PropTypeRequiredDescription
iconstringYesThe name or identifier of the icon to be displayed.
mode"sprite" | "svg"NoThe rendering mode when outputting the icon.
Either sprite or svg where svg will return the full SVG element,
and the sprite mode will add the icon to the sprite sheet and reference it.
childrenReactNodeNoOptional children elements to be rendered within the Icon component when the icon isn't loaded yet.
titlestringNoScreen reader accessible title that explains the illustration.
Introducing this property automatically changes the role attribute from presentation to img.
rotate90 | 180 | 270NoRotate the illustration by 90, 180, or 270 degrees.
flip"horizontal" | "vertical"NoFlip the illustration horizontally or vertically.
slotstringNoA named part of a component that can be customized. This is implemented by the consuming component.
The exposed slot names of a component are available in the components documentation.
slotsRecord<string, object | Function>NoAn object that contains the customizations for the slots.
The main way you interact with the slot system as a consumer.

For all other properties specified on the Icon component, the component will pass them down to the root SVG element of the component. Which would be the equivalent of you adding them directly to the child component.

Example

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

Introducing content

By default, the icon component ships with no icon sets or libraries. You need to introduce the icons to the included store. The icon library exposes the following API methods:

  • set - Introduce content synchronously.
  • ondemand - Introduce content asynchronously.

Both methods expect the Icon content to be a valid React SVG element. If you have SVG content that is not a React SVG element, you can use the included @bento/svg-parser method to transform a string into the required React SVG element.

NOTE: If you want to learn more about the store, please refer to the @bento/create-external-store package.

set

The set method allows you to synchronously introduce content to the store. The method expects an object where the key is the icon’s name, as you would specify in the icon prop name, and the value is the React SVG element that should be used to render the icon.

import { set } from '@bento/icon';

set({
  'icon-name': <svg />,
  'another-icon': <svg />,
  'yet-another-icon': <svg />
});

If you have SVG content that is not a React SVG element, you can use the included @bento/svg-parser method to transform a string into the required React SVG element:

import { parser } from '@bento/svg-parser';
import { set } from '@bento/icon';

set({ 'icon-name': parser(icon) });

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

ondemand

The ondemand method allows you to asynchronously introduce content to the store. The method expects a function that should return a promise that resolves to the React SVG element that should be used to render the icon. It receives the icon’s name, which should be loaded as the first argument.

import { parser } from '@bento/svg-parser';
import { ondemand } from '@bento/icon';

ondemand(async function hosted(name:string) {
  const icon:string = await fetch(`{name}.svg`).then((res) => res.text());

  return parser(icon);
});

You can have multiple ondemand loaders specified in your application, and they will be called in the order that they are specified. The first loader that returns a valid React SVG element will be used to render the icon.

If your loader throws an error, the next loader will be called. If all loaders throw an error or no content is returned, the icon will return a null response and renders the placeholder content if it's specified.

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

Accessibility

The icons are rendered with role="presentation" and should be considered decorative and should not be used to convey information to the user. They should only be used for visual or branding purposes.

Semantic Icons

Semantic icons convey information to the user rather than just pure decoration. This includes icons without text next to them that are used for interactive elements. To ensure they are accessible to all users, you should always describe the icon.

The title prop is used to describe the icon. This sets the role="img" attribute on the SVG element and adds a title element to the SVG element with the contents of the title prop.

import { Icon } from '@bento/icon';

<Icon icon="wand" title="A magic wand" />

Performance

When introducing content to the store, you should consider the performance impact of the content you are introducing. The icons should always be optimized using the appropriate tools and techniques to reduce the size of the icons. Tools such as svgo can be used to optimize the SVG content.

The Icon component will render the icon as a full SVG element by default.

import { Icon } from '@bento/icon';

<Icon icon="icon-name" />
<Icon icon="icon-name" />
<Icon icon="icon-name" />

When rendering the same icon multiple times, this can lead to a lot of duplication in the DOM. Depending on the amount of icons you are rendering and the size of the icons, this can lead to a lot of bytes being transferred over the network.

<svg>
  <path d="...full..path..here" />
</svg>
<svg>
  <path d="...so..much..duplication" />
</svg>
<svg>
  <path d="...much..more..bytes..here" />
</svg>

It's worth noting that there are distinct advantages to rendering the icons as full SVG elements when it comes to server-side rendering.

Sprite

To reduce the amount of duplication in the DOM, you can render the icons as a sprite. The optional mode prop is used to specify how the icon should be rendered. Switching the mode to sprite instructs the Icon component to render a use element that references the icon from a sprite sheet automatically injected sprite sheet.

import { Icon } from '@bento/icon';

<Icon icon="icon-name" mode="sprite" />
<Icon icon="icon-name" mode="sprite" />
<Icon icon="icon-name" mode="sprite" />

Would result in the following DOM:

<svg>
  <use xlink:href="#bento-svg-sprite-icon-name" />
</svg>
<svg>
  <use xlink:href="#bento-svg-sprite-icon-name" />
</svg>
<svg>
  <use xlink:href="#bento-svg-sprite-icon-name" />
</svg>

Once your application is hydrated on the client, the icons sprite sheet is generated and injected into the DOM. The browser will trigger a paint event and the icons are displayed. The sprite sheet is generated as follows:

<svg id="bento-svg-sprite" style="display: none;">
  <symbol id="bento-svg-sprite-icon-name" data-symbol="icon-name" viewBox="0 0 24 24">
    <path d="...massive..long..string..here" />
  </symbol>
</svg>

The sprite sheet container is only created if it doesn't already exist in the DOM. The icons are added to the sprite sheet as they are requested. If an icon is requested multiple times, it will only be added to the sprite sheet once.

This also means that you can inject the spritesheet into the DOM yourself as part of the SSR response to ensure they are available and displayed before the client-side hydration.

Server side rendering

While the Icon component can render the icon content during the server-side rendering, the content must be available during the rendering of the icons. When loading the content Asynchronously using the recommended ondemand method, the content is not available during the server-side rendering resulting in an empty response.

import { Icon } from '@bento/icon';

<Icon icon="icon-name" />
// null - The icon doesn't have content, so it can't render anything.

Depending on your requirements this might be acceptable. If you want to return content during the server-side rendering, you have the following options:

SVG element as a response

As noted above, the Icon component can only render the icon if the content is available during the server-side rendering. If you want to render the icon as part of the SSR response, you should use the set method to introduce the content to the store.

import { set } from '@bento/icon';
set({ 'icon-name': <svg /> });

<Icon icon="icon-name" />
// <svg>...</svg> - The icon has content that can render the icon.

The set method is synchronous. If you are using the ondemand method in your application, please refer to the Asynchronously section.

Asynchronously

When loading your content asynchronously using the ondemand method, it's unavailable during the server-side rendering. These icons will default render an empty (null) response. Once your application is hydrated on the client, the icons will be available, requested in the ondemand method, and rendered accordingly.

To avoid the empty response, you can either use Placeholders as mentioned below or change the mode to sprite to render the icon as a sprite. When an icon is rendered as a sprite, it will return an SVG element with a use element that references the icon from the sprite.

import { Icon } from '@bento/icon';

<Icon icon="icon-name" mode="sprite" />
// <svg><use xlink:href="#icon-name"></use></svg>

See sprite for more information.

Placeholders

When the icon content is loading or the requested icon doesn't exist the Icon component will render the provided children as placeholder. This allows you to render skeleton loaders, loading spinners, or any other content that should be displayed while the icon is loading.

import { Icon } from '@bento/icon';

<Icon icon="icon-name">
  <svg>...</svg>
</Icon>

While it might be tempting to use render props to render the conditionally icon fallback differently on the server and client; this is not recommended for applications that need to hydrate the server-rendered content on the client. This will cause a mismatch between the server and client content, which will result in the client-side hydration failing, forcing a complete re-render of the content.

import { Icon } from '@bento/icon';

//
// ANTI PATTERN causes hydration errors:
//
<Icon icon="icon-name" mode="sprite">
  {() => server ? <svg>{icon}</svg> : null }
</Icon>

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

Customization

As the Icon component is a wrapper around the Illustration component, you can use the Illustration's properties to customize the icon. The Icon component will pass all properties down to the Illustration component allowing you to rotate or flip the icon. This is useful when you need to support RTL languages that requires the icon to be altered.

Slots

The component is created using our @bento/slots package and allows the assignment of the custom slot property to be used for overrides.

The @bento/icon is registered as BentoIcon and introduces the following slots:

  • content: Assigned to the Illustration component that renders the icon content.

See the @bento/slots package for more information on how to use the slot and slots properties.

Styling

Once you assign the className property to the component, you take full responsibility for the styling of the component, and it will remove any default styling that might be applied as part of this component.

import { Illustration } from '@bento/icon';

<Icon icon="magic-wand" className="my-component" />

The following data- attributes are introduced as part of the component render state:

  • data-loading=true: The Icon component will add a data-loading attribute to the component’s root element when the icon is loading. This can be used to style the component while the icon is loading.
  • data-icon="icon-name": The name of the icon that is currently being rendered.
  • data-mode="sprite": The component is rendering the icon as a sprite.
  • data-flip=horizontal|vertical: The component is flipped horizontally or vertically using the provided flip property.
  • data-rotate=90|180|270: The component is rotated by the provided angle using the rotate property.

These data- attributes are introduced on the root element of the component and can be targeted using your previously provided custom className:

.my-component[data-loading] {
  /* The component is loading */
}

.my-component[data-flip] {
  /* The component is flipped */
}

.my-component[data-rotate] {
  /* The component is rotated */
}

.my-component[data-icon="magic-wand"] {
  /* The component is rendering the magic wand icon */
}

Keywords

asset

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