BEM methodology inspired util that let's you create classNames in React by passing proper configuration. You can also use library outside of React since there are no React dependencies
classNameGenerator
is using some key concepts and names from BEM methodology. By default BEM naming is disabled but can be enabled via configuration. It's compatible with AMD, CommonJS and also can be used as browser global.
Before describing classNameGenerator
it's important to understand some key concepts of classNames naming convention. There are three main entities that should be explained:
A logically and functionally independent page component that can be reused.
A constituent part of a block that can't be used outside of it.
className that defines appearance or behavior of an element/block. For example 'active' class on active menu element or 'hidden' class on hidden element are modifiers.
classNameGenerator
is an instance of ClassNameGenerator
class which is created by passing configuration object with desired block and element names.
classNameGenerator.Class
is ClassNameGenerator Class and can be used to create custom classNameGenerator with different configuration.
Following are examples of desired markup, configuration object that should be passed to classNameGenerator
to achieve relevant classNameBlock
Let's say you want to create this kind of markup:
<div class="test-container">
<div class="panel"></div>
<div class="card"></div>
</div>
In this case "test-container" is a block with two elements "panel" and "card"
In order to create classNameObject with classNameGenerator
do the following:
var classNameGenerator = require('classname-generator');
var classNameBlock = classNameGenerator({
name: 'test-container',
elements: [{
name: 'panel'
},
{
name: 'card'
}]
})
var Element = React.createClass({
render: function() {
return (
<div className={classNameBlock}>
<div className={classNameBlock.panel}></div>
<div className={classNameBlock.card}></div>
</div>
)
}
})
React.render(<Element />,document.body);
The interesting part starts when you start using modifiers.
Let's say you need the following markup:
<div class="tab-container active">
<div class="panel wide"></div>
<div class="card hidden"></div>
</div>
As you can see from the markup above 'active', 'wide', 'hidden' logically define appearance of 'tab-container', 'panel' and 'card' respectively
So they will be called modifiers and the syntax of classNameGenerator will be as following:
var classNameGenerator = require('classname-generator');
var classNameBlock = classNameGenerator({
name: 'test-container',
elements: [{
name: 'panel',
modifiers: {
wide: true,
hidden: false,
}
},
{
name: 'card'
modifiers: {
hidden: true
}
}],
modifiers: {
active: true
}
})
var Element = React.createClass({
render: function() {
return (
<div className={classNameBlock}>
<div className={classNameBlock.panel}></div>
<div className={classNameBlock.card}></div>
</div>
)
}
})
React.render(<Element />,document.body);
All elements can be accessed through elements object or directly
classNameBlock.elements.panel = classNameBlock.panel
classNameBlock.elements.card = classNameBlock.card
Calling toString will print element name:
//calling toString method
classNameBlock.toString();
//Appending to string (will automatically call toString);
"" + classNameBlock;
//ES6 template strings usage
`${classNameBlock}`
Modifiers values can be changed on the fly by assigning new value to modifier. For example with the same config object as above let's change hidden modifier on panel element:
classNameBlock.panel.hidden = true;
classNameBlock.panel.name === classNameBlock.panel.toString === classNameBlock.elements.panel.name === classNameBlock.elements.panel.toString() === 'panel wide hidden'
Alias is used in order to differentiate elements with the same name. Aliases as names cannot have duplicate values.
Let's say you want to create the following markup:
<nav>
<ul class="menu">
<li class="item active"></li>
<li class="item"></li>
<li class="item"></li>
</ul>
</nav>
As you can see we have several elements with duplicate names but one of them will have active modifier set to true.
The javascript will be as following:
var classNameGenerator = require('classname-generator');
var classNameBlock = classNameGenerator({
name: 'menu',
elements: [{
name: 'item',
modifiers: {
active: false,
}
},
{
name: 'item',
alias: 'activeItem',
modifiers: {
active: true,
}
}]
})
var Element = React.createClass({
render: function() {
return (
<nav>
<ul className={classNameBlock}>
<li className={classNameBlock.activeItem}></li>
<li className={classNameBlock.item}></li>
<li className={classNameBlock.item}></li>
</ul>
</nav>
)
}
});
React.render(<Element />,document.body);
In BEM methodology the block level element will have unique class and child elements or child element modifiers inside the block will have prefix of parent class
For example class naming will be as following
<div class="tab-container tab-container--active">
<div class="tab-container__panel tab-container--wide"></div>
<div class="tab-container__card tab-container--hidden"></div>
</div>
classNameGenerator supports BEM naming convention if you create it like this:
var ClassNameGenerator = require('classname-generator').Class;
var customGenerator = new ClassNameGenerator({bemEnabled: true});
var classNameBlock = customGenerator({
name: 'test-container',
elements: [{
name: 'panel',
modifiers: {
wide: true,
hidden: false,
}
},
{
name: 'card',
modifiers: {
hidden: true
}
}],
modifiers: {
active: true
}
})
var Element = React.createClass({
render: function() {
return (
<div className={classNameBlock}>
<div className={classNameBlock.panel}></div>
<div className={classNameBlock.card}></div>
</div>
)
}
})
React.render(<Element />,document.body);
There are several other configurable properties:
Configuration Option | Value type | Default | Description |
---|---|---|---|
elementSeperator | String | "__" | separator between parent block name and element |
modSeperator | String | "--" | separator between element name and modifier name |
modValueSeperator | String | "-" | In case modifier value is other than boolean this separator wil be between modifier key name and value. |
classSeperator | String | " " | This is default separator between class names |
bemEnabled | bool | false | passing false will strip generated classNames of seperators and will use only raw element and modifiers names. For example some-class some-class--hidden will be generated as some-class hidden |