@puck/react-bem
v1.0.2
Published
Automate creating BEM classes in React components
Downloads
79
Readme
React BEM template functions
Installation
npm install @puck/react-bem
Usage
[!NOTE] Learn how to inject the
bem
prop in the next chapter
Simplest way to create a block with some elements
function Acme({ bem: { className, element } }) {
return <div className={className}>
<h1 class={element`heading`}>Hello</h1>
</div>
}
<div class="acme">
<h1 class="acme__heading">Hello</h1>
</div>
BEM helper as a shorthand if there are no elements
function Acme({ bem }) {
return <div className={bem}>Hello</div>
}
<div class="acme">Hello</div>
Adding block modifiers
function Acme({ bem: { block } }) {
const [toggle, setToggle] = useState(true);
const onClick = useCallback(
() => setToggle(current => !current),
[setToggle],
);
return <div className={block`${{ toggle }} always-enabled`}>
<button onClick={onClick}>Toggle</button>
</div>
}
<div class="acme acme--toggle acme--always-enabled"/>
Mixing the block with other classes
function Acme({ bem: { block } }) {
return <div className={mix`me-2 d-flex`}>
</div>
}
<div class="acme me-2 d-flex">...</div>
Mixing with parent block
To mix a block with a parent element just pass the element name as className
and it will be appended automatically
function Child({ bem: { block } }) {
return <div className={block`${{ active: true }}`.mix`me-2`}/>
}
function Parent({ bem: { className, element } }) {
return <div className={className}>
<Child className={element`element`}/>
</div>
}
<div class="parent">
<div class="child parent__element child--active me2"/>
</div>
Using elements with modifiers
function Acme({ bem: { block, element } }) {
return <div className={block}>
<div class={element`item ${{ selected: true }} me-2`} />
<div class={element`item ${{ variant: 'primary' }}`} />
<div class={element`item ${['theme-dark']}`} />
<div class={element`item`.mix`d-flex`} />
</div>
}
<div class="acme">
<div class="acme__item acme__item--selected me-2" />
<div class="acme__item acme__item--variant-primary" />
<div class="acme__item acme__item--theme-dark" />
<div class="acme__item d-flex" />
</div>
Adding the BEM helper to your components
Let’s assume you have a component you’d like to use BEM with:
type Props = {
title: string;
}
export default function AcmeBanner({ title }: Props) {
return <div>
Hello {title}
</div>;
}
BEM is a naming strategy, so let’s reuse the same name between your React component
display name and your CSS block name. The CSS name will be converted to snake-case
.
- Import the
withBem
Higher Order Component - Add a
displayName
to your component - (Typescript): Wrap your prop types with
withBem.props<>
type - Wrap your export in a
withBem()
HOC
import { withBem } from '@puck/react-bem'
type Props = {
title: string;
}
function AcmeBanner({ bem: { className }, title }: withBem.props<Props>) {
return <div className={className}>
Hello {title}
</div>;
}
AcmeBanner.displayName = 'AcmeBanner';
export default withBem(AcmeBanner);
Optionally, you might pass the component name explicitly using withBem.named()
:
export default withBem.named('AcmeComponent', ({ bem, title }) => {
return <div className={bem}>
Hello {title}
</div>;
});