generate-bem-classes
coreUsing useBem() to generate BEM class name arrays for component templates. Covers block(), element(), modifier() with boolean, string, number, and key-only values. Returns string[] — works natively with Vue :class bindings, needs .join(' ') for React className. Import from @yeeroen/use-bem.
@yeeroen/use-bem — Generate BEM Classes
Setup
import useBem from '@yeeroen/use-bem'
const { block, element, modifier } = useBem('button')
useBem is a plain factory function (not a React hook). Call it anywhere — top-level, inside conditionals, in loops.
Core Patterns
Block with modifiers
const { block, modifier } = useBem('button')
block()
// ['button']
block(modifier('primary', true), modifier('size', 'large'))
// ['button', 'button--primary', 'button--size-large']
Element with modifiers
const { element, modifier } = useBem('button')
element('icon')
// ['button__icon']
element('icon', modifier('color', 'red'), modifier('visible', true))
// ['button__icon', 'button__icon--color-red', 'button__icon--visible']
Conditional modifiers with boolean values
const { block, modifier } = useBem('button')
const isActive = true
const isDisabled = false
block(modifier('active', isActive), modifier('disabled', isDisabled))
// ['button', 'button--active']
// modifier('disabled', false) returns '' which block() filters out
Key-only modifiers (shorthand)
const { block, modifier } = useBem('button')
block(modifier('primary'))
// ['button', 'button--primary']
// Omitting the value is shorthand for an always-on modifier
Vue template usage
<script setup lang="ts">
import useBem from '@yeeroen/use-bem'
const { block, element, modifier } = useBem('card')
const isExpanded = ref(false)
</script>
<template>
<div :class="block(modifier('expanded', isExpanded))">
<h2 :class="element('title')">Title</h2>
<p :class="element('body')">Content</p>
</div>
</template>
Vue's :class accepts arrays natively — no .join(' ') needed.
Common Mistakes
CRITICAL Treating block()/element() return value as a string
Wrong:
// React — passing array directly to className
<div className={block(modifier('active', true))} />
Correct:
// React — join the array into a space-separated string
<div className={block(modifier('active', true)).join(' ')} />
block() and element() return string[], not string. Vue's :class accepts arrays natively, but React's className and vanilla DOM element.className expect a string.
Source: src/use-bem.ts:8-10, src/types.ts:6-7
HIGH Treating useBem as a React hook
Wrong:
function MyComponent({ variant }: Props) {
// Agent treats useBem as a hook and avoids calling it conditionally
const { block, modifier } = useBem('my-component')
// Agent refuses to call useBem inside a condition, thinking it violates hook rules
}
Correct:
// useBem is a plain function — call it anywhere
const { block, modifier } = useBem('my-component')
if (needsOther) {
const other = useBem('other-component')
}
Despite the use prefix, useBem is a plain factory function with no framework dependency. It has no internal state, no side effects, and no hook rules.
Source: src/use-bem.ts:28-34
HIGH Using modifier() result directly in templates
Wrong:
<div :class="modifier('active', isActive)" />
Correct:
<div :class="block(modifier('active', isActive))" />
modifier('active', false) returns an empty string ''. block() and element() filter out empty strings, but using modifier() directly passes the raw empty string to the template.
Source: src/use-bem.ts:16-26
HIGH Writing BEM strings manually instead of using the library
Wrong:
<div :class="`button button--${size} button--${variant}`" />
Correct:
<div :class="block(modifier('size', size), modifier('variant', variant))" />
Manual string concatenation bypasses the library's boolean filtering, null handling, and consistent separator formatting. It also produces broken class names when modifier values are false or undefined.
Source: README.md
MEDIUM Using wrong BEM separator conventions
Wrong:
// Manual strings with wrong separators
const classes = ['button', 'button-primary', 'button_icon']
Correct:
const { block, element, modifier } = useBem('button')
block(modifier('primary', true)) // ['button', 'button--primary']
element('icon') // ['button__icon']
BEM uses double-dash (--) for modifiers and double-underscore (__) for elements. The library enforces these separators automatically.
Source: src/use-bem.ts:3-6, src/use-bem.ts:12-14
Version
Targets @yeeroen/use-bem v1.0.4.