Babel plugin for ABEM class names generation in JSX.
Require it as any other babel plugin and add the abem
package to your dependencies
(so Webpack/Rollbar/etc. can use it in the frontend).
$ npm install babel-plugin-transform-jsx-abem --save-dev
$ npm install abem --save
{
plugins: ['transform-jsx-abem']
}
Add ABEM properties in your tags and the plugin will generate the className
for you.
The plugin will try to resolve the className during the compilation (className="block"
) and fallback to runtime if not possible (className={_abem("block")}
- helper will be included automatically)
If the tag already have a className, then it'll be skipped.
name | type |
---|---|
block | string |
elem | string |
mods | string | array | object | expression* |
mix | string | array | object | expression* |
* must return a string, an array or an object
The block
property creates a scope and should only be used at the top-level of the JSX tag. It will be automatically generated if it's inside a class or a function (if the class/function name is prefixed by a A, O or M, then it'll add the prefix 'a-', 'o-', or 'm-')
Input
<div block="m-main" mix="panel" mods={{ warning: true }}>
<div elem="header" mods="header">Title</div>
<div elem="body">Text</div>
</div>
Output
<div className="m-main -warning panel">
<div className="m-main__header -header">Title</div>
<div className="m-main__body">Text</div>
</div>
Input
const Message = ({ title, text }) => {
return <div>
<div elem="header">{title }</div>
<div elem="body">{text}</div>
</div>
}
Output
const Message = ({ title, text }) => {
return <div className="message">
<div className="message__header">{title}</div>
<div className="message__body">{text}</div>
</div>;
};
Input
class OMessage extends Component {
...
render() {
...
return <div mods={this.getMods()}>
<div elem="header">{title}</div>
<div elem="body">{text}</div>
</div>
}
}
Output
class OMessage extends Component {
...
render() {
...
return <div className={_abem("o-message", null, this.getMods())}>
<div className="o-message__header">{title}</div>
<div className="o-message__body">{text}</div>
</div>;
}
}
Input
function OEmailMessage ({ title, html }) {
return <Wrapper>
<div mods={{ disabled: true }}>
<div elem="header">{title}</div>
<div elem="bodyHtml">{html}</div>
</div>
</Wrapper>
}
Output
function OEmailMessage ({ title, html }) {
return <Wrapper>
<div className="o-emailMessage -disabled">
<div className="o-emailMessage__header">{title}</div>
<div className="o-emailMessage__bodyHtml">{html}</div>
</div>
</Wrapper>
}
Set custom naming properties. Default values:
properties: {
block: 'block',
element: 'elem',
modifiers: 'mods',
mixin: 'mix'
}
Set custom abem separators. Default values:
separators: {
element: '__',
modifier: '-',
}
Passing options with spread operator won't work as expected.
In this example, html
modifier won't be added.
const OMessage = ({ title, text, ...props }) => {
return <div {...props}>
<div elem="header">{title}</div>
<div elem="body">{text}</div>
</div>
}
[...]
const html = true
<OMessage title="Hello" text="World" mods={{ html }} />
ABEM propetrties shouldn't be passed this way anyway. Instead, you should do:
const OMessage = ({ title, text, html }) => {
return <div mods={{ html }}>
<div elem="header">{title}</div>
<div elem="body">{text}</div>
</div>
}
[...]
const html = true
<OMessage title="Hello" text="World" html={html} />
You like this package?