Skip to content

@bem-broom/webcomponents

@bem-broom/webcomponents builds BEM class names for plain custom elements — no framework required. The current block flows down the DOM via the framework-agnostic Context Protocol; a component supplies its element, and — through the @bem decorator or the BemElement mixin — that element becomes the block for its descendants.

Terminal window
npm install @bem-broom/webcomponents @bem-broom/core

There is no framework peer dependency. Unlike @bem-broom/lit, these helpers drive the standard custom-element lifecycle directly, so they run on a bare HTMLElement.

Class decorator, the analog of react’s withBem. It reads the block from context, applies the computed BEM class(es) to the host element, observes the attributes listed in config.modifiers as modifiers, and provides config.element as the block for descendants. It uses standard (TC39) decorators, so it needs a build step (TS ≥5.2, or the @babel/plugin-proposal-decorators 2023-11 transform).

import { bem } from '@bem-broom/webcomponents';
@bem({ element: 'card', modifiers: ['active'] })
class Card extends HTMLElement {}
customElements.define('bb-card', Card);
// <bb-card active> → host class="card card--active"; descendants see block "card"

A class decorator returns the wrapped subclass, so register the decorated binding (Card) — or apply @bem below a registration decorator if you use one.

The decorator-free form, for projects with no build step (e.g. ESM straight to the browser). Same behavior as @bem.

import { BemElement } from '@bem-broom/webcomponents';
class Card extends BemElement(HTMLElement, {
element: 'card',
modifiers: ['active'],
}) {}
customElements.define('bb-card', Card);

bemBlockContext carries the current block (provided automatically by @bem / BemElement); bemConfigContext carries tree-wide prefix / verbose / syntax. Both ride the framework-agnostic Context Protocol, and their keys are shared via Symbol.for, so they interoperate with any protocol-speaking library or element — including @bem-broom/lit. A Lit @bem ancestor and a plain-element @bem descendant re-root correctly in one tree.

consumeContext(host, context, onChange) is exported for consuming a context on a bare element without a Lit ReactiveControllerHost.

Full signatures, options, and types are in the API reference.