A simple js object providing BEM class naming support and consistency for an individual or software team. Provides consistent BEM class names, and a clean api that doesn't bloat a component with untidy string concatenations.
The code has been thoroughly tested and test scripts are available, with source, in the npm-utils project here github. If you discover any bugs then please report. Thank you :).
Install from npm:
npm install @gtechdoodler/bem-it
The examples provided are implemented in a React functional component...
Start by importing the BemIt object into your component, then create a new instance passing your component name to the constructor.
import React from 'react';
import BemIt from '@gtechdoodler/bem-it';
export default function() {
const bem = new BemIt('Container');
return (
<div className={bem.out()}>
</div>
)
}
Calling bem.out()
will output: Container
You always call .out()
to output the class name value. Calling .out()
also flushes the bem object, ensuring it's in a clean state, ready for your next statement.
The examples from this point on, will include only the component, omitting the import statements.
export default function() {
const bem = new BemIt('Container');
return (
<div className={bem.out()}>
<div className={bem.el('content').out()}>
</div>
</div>
)
}
Calling bem.el('content').out()
will output: Container__content
export default function() {
const bem = new BemIt('Container');
return (
<div className={bem.out()}>
<div className={bem.el('content').mod('show').out()}>
</div>
</div>
)
}
Calling bem.el('content').mod('show').out()
will output: Container__content Container__content--show
Notice we are following the official BEM standard here, outputting the Block__element and an additional Block__element--modifier to represent the modifier.
For ternary operand false, pass an empty string, undefined, or null. This will ensure the exclusion of the modifier.
export default function({isFullScreen, isLoading, ...props}) {
const bem = new BemIt('Container');
const className = bem.mod([
isFullScreen ? 'full-screen' : '',
isLoading ? 'loading' : ''
]).out();
return (
<div className={className}>
</div>
)
}
Anything falsy will be ignored.
export default function({isFullScreen, isLoading, ...props}) {
const bem = new BemIt('Container');
const className = bem.mod({
'full-screen' isFullScreen,
'loading': isLoading
}).out();
return (
<div className={className}>
</div>
)
}
To combine a class name passed as a prop, with bem output, you can import a function called addClass
.
import BemIt, { addClass } from '@gtechdoodler/bem-it';
And implement as follows:
export default function({className, ...props}) {
const bem = new BemIt('Container');
return (
<div className={addClass(className).before(bem)}>
</div>
)
}
If the className is falsy then it will be ignored, outputting only the bem class name. Also, you can flip the
class names around, adding a custom class after a bem output, by calling addClass(className).after(bem)
.
If you really must represent an element with mutiple class names, this is achieveable with chaining. Call and
.
export default function() {
const bem = new BemIt('Container');
return (
<div className={bem.out()}>
<div className={bem.el('content').and.el('detail').out()}>
</div>
</div>
)
}
Calling bem.el('content').and.el('detail').out()
will output: Container__content Container__detail
These are exported, so if you're using TypeScript then have a play around... the api is light and chainable, so, if you want something wacky like:
bem.el('content').mod('show').and.el('content').el('summary').mod('highlight').out()
But please don't write code like this :).