npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

use-bem

v2.0.0

Published

Framework-agnostic BEM class name generation, with an optional React hook.

Readme

use-bem

Framework-agnostic BEM class name generation, with an optional React hook.

The core is one small pure function with no dependencies. You give it a block and it builds the block__element--modifier strings for you, so you're not hand-writing the same class names or wiring up conditional logic for every modifier. It runs the same in React, Vue, Svelte, or plain JavaScript, and the output is identical everywhere.

Installation

npm install use-bem
# or
pnpm add use-bem
# or
yarn add use-bem

React is an optional peer dependency. It's only needed if you import use-bem/react.

Core usage

import { createBem } from 'use-bem';

const bem = createBem('badge');

bem();                                  // -> "badge"
bem('label');                           // -> "badge__label"
bem('label', 'large');                  // -> "badge__label badge__label--large"
bem('label', ['large', 'primary']);     // -> "badge__label badge__label--large badge__label--primary"
bem(undefined, { solid: true, soft: false }); // -> "badge badge--solid"

Modifier output always includes the base class, so the result drops straight into a class attribute as-is.

Framework examples

React

import { useBem } from 'use-bem/react';

const Badge = ({ solid }: { solid?: boolean }) => {
  const bem = useBem('badge');

  return (
    <span className={bem(undefined, { solid })}>
      <span className={bem('label')}>New</span>
    </span>
  );
};

useBem is createBem wrapped in useMemo, so the generated function is stable across re-renders. It calls useMemo unconditionally and is SSR-safe (Next.js, Remix, and so on).

Vue

<script setup lang="ts">
import { createBem } from 'use-bem';

defineProps<{ solid?: boolean }>();

const bem = createBem('badge');
</script>

<template>
  <span :class="bem(undefined, { solid })">
    <span :class="bem('label')">New</span>
  </span>
</template>

Svelte

<script lang="ts">
  import { createBem } from 'use-bem';

  export let solid = false;

  const bem = createBem('badge');
</script>

<span class={bem(undefined, { solid })}>
  <span class={bem('label')}>New</span>
</span>

Outside React there's no wrapper to reach for. createBem runs once in component setup and the returned function is just string concatenation.

Custom separators

Pass a config object as the second argument:

const bem = createBem('block', {
  elementSeparator: '-',  // default: '__'
  modifierSeparator: '_', // default: '--'
});

bem('element', 'modifier'); // -> "block-element block-element_modifier"

For app-wide separators, create a preconfigured factory once and import it everywhere:

// utilities/bem.ts
import { createBemFactory } from 'use-bem';

export const createBem = createBemFactory({
  elementSeparator: '-',
  modifierSeparator: '_',
});

// Component file
import { createBem } from './utilities/bem';

const bem = createBem('block');

The React hook takes the same config: useBem('block', { elementSeparator: '-' }).

Validation

Block, element, and modifier names may only contain letters, digits, hyphens, and underscores. Invalid names throw:

createBem('my block');         // Error: should not contain spaces
bem('label', 'large primary'); // Error: pass an array of strings instead

Disabled keys in a boolean record ({ foo: false }) aren't validated, since they never reach the output.

API

createBem

createBem(block: string, config?: BemConfig): BemFunction

Creates a class name generator for a BEM block. Validates the block name immediately.

BemFunction

type BemFunction = (
  element?: string,
  modifier?: string | string[] | Record<string, unknown>
) => string;
  • Call with no arguments for the block class.
  • element is the BEM element name; undefined targets the block itself.
  • modifier is a single name, an array of names, or a record whose keys are applied when their value is truthy. The record value type is unknown because only truthiness is read, so an optional boolean (boolean | undefined) or any condition expression works directly, with no Boolean(...) wrapping.

BemConfig

interface BemConfig {
  elementSeparator?: string;  // default: '__'
  modifierSeparator?: string; // default: '--'
}

createBemFactory

createBemFactory(config?: BemConfig): (block: string) => BemFunction

Returns a createBem variant with the given separators baked in.

useBem (from use-bem/react)

useBem(block: string, config?: BemConfig): BemFunction

Memoized React hook over createBem. Requires React 16.8 or newer.

Migrating from 1.x to 2.0

2.0 makes the core framework-agnostic. The pure createBem function is now the main entry, and the React hook moved to a subpath.

| 1.x | 2.0 | | --- | --- | | import useBem from 'use-bem' | import { useBem } from 'use-bem/react' | | import { createBemHook } from 'use-bem'; createBemHook(config) returns a hook | import { createBemFactory } from 'use-bem'; returns a createBem variant, or pass config directly: createBem(block, config) / useBem(block, config) | | useBem(block) | unchanged (after updating the import) |

Generated class names are identical between 1.x and 2.0, so no CSS changes are needed.

- import useBem from 'use-bem';
+ import { useBem } from 'use-bem/react';

If you used createBemHook for custom separators:

- import { createBemHook } from 'use-bem';
- const useBem = createBemHook({ elementSeparator: '-' });
  // in the component:
- const bem = useBem('block');
+ import { useBem } from 'use-bem/react';
  // in the component:
+ const bem = useBem('block', { elementSeparator: '-' });

License

MIT © Björn Djurnamn