A library for developing user interfaces using the BEM methodology in React. BEM React Core supports TypeScript and Flow type annotations.
- Installation
- Quick Start
- Basics
- Working with CSS
- API reference
- Migrating to API v2.0
- API versions
- Contribute
- License
Using npm:
npm init
npm install --save bem-react-core react react-dom
Using Yarn:
yarn init
yarn add bem-react-core react react-dom
This example shows how to create an application that will show the user a dialog box with the message "Hello, World!" when clicked.
A quick way to deploy a React project from scratch and start working with bem-react-core
is by using the BEM React Boilerplate utility.
git clone git@github.com:bem/bem-react-boilerplate.git bem-in-react
cd bem-in-react
npm install
npm start
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Block } from 'bem-react-core';
class Button extends Block {
block = 'Button';
tag() {
return 'button';
}
handleClick = () => {
alert('Hello, World!');
}
attrs() {
return {
onClick: this.handleClick
};
}
}
ReactDOM.render(
<Button>Click me</Button>,
document.getElementById('root')
);
Then open localhost:3000 to see your app.
To create more complex projects in bem-react-core
, take a look at the Basics and the API reference sections.
A block is a functionally independent component of the user interface that can be reused. To create a block, you need to import the Block class from the bem-react-core
library. This is the base class for creating block instances.
Example:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Block } from 'bem-react-core';
class Button extends Block {
block = 'Button';
tag() {
return 'button';
}
}
ReactDOM.render(
<Button>Click me</Button>,
document.getElementById('root')
);
Result:
<button class="Button">Click me</button>
An element is a part of a block that cannot be used without the block itself. To create an element, you need to import the Elem class from the bem-react-core
library. This is the base class for creating element instances.
Example:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Block, Elem } from 'bem-react-core';
interface IButtonProps {
children: string;
}
// Creating the Text element
class Text extends Elem {
block = 'Button';
elem = 'Text';
tag() {
return 'span';
}
}
// Creating the Button block
class Button extends Block<IButtonProps> {
block = 'Button';
tag() {
return 'button';
}
content() {
return (
<Text>{this.props.children}</Text>
);
}
}
ReactDOM.render(
<Button>Click me</Button>,
document.getElementById('root')
);
Result:
<button class="Button">
<span class="Button-Text">Click me</span>
</button>
Modifiers define the appearance, state, or behavior of a block or element. To modify a block or element, use the HOC function withMods() from the bem-react-core
library. The withMods()
function gets a base block or element with a list of its modifiers as arguments, and returns a modified block or element.
Example:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Block, Elem, withMods } from 'bem-react-core';
interface IButtonProps {
children: string;
}
interface IModsProps extends IButtonProps {
type: 'link' | 'button';
}
// Creating the Text element
class Text extends Elem {
block = 'Button';
elem = 'Text';
tag() {
return 'span';
}
}
// Creating the Button block
class Button<T extends IModsProps> extends Block<T> {
block = 'Button';
tag() {
return 'button';
}
mods() {
return {
type: this.props.type
};
}
content() {
return (
<Text>{this.props.children}</Text>
);
}
}
// Extending functionality of the Button block when the "type" property is set to the value "link"
class ButtonLink extends Button<IModsProps> {
static mod = ({ type }: IModsProps) => type === 'link';
tag() {
return 'a';
}
mods() {
return {
type: this.props.type
};
}
attrs() {
return {
href: 'www.yandex.ru'
};
}
}
// Combining the Button and ButtonLink classes
const ButtonView = withMods(Button, ButtonLink);
ReactDOM.render(
<React.Fragment>
<ButtonView type="button">Click me</ButtonView>
<ButtonView type="link">Click me</ButtonView>
</React.Fragment>,
document.getElementById('root')
);
Result:
<button class="Button Button_type_button">
<span class="Button-Text">Click me</span>
</button>
<a href="www.yandex.ru" class="Button Button_type_link">
<span class="Button-Text">Click me</span>
</a>
To create an additional HTML element with the name of the CSS class formed using the BEM methodology, you need to import the Bem helper from the bem-react-core
library.
Note: Learn more about generating CSS classes.
Example:
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { Bem } from 'bem-react-core';
ReactDOM.render(
<React.Fragment>
<Bem block="MyBlock" />
<Bem block="MyBlock" elem="Inner" />
<Bem block="MyBlock" tag="span" />
<Bem block="MyBlock" mods={{theme: 'default'}} />
</React.Fragment>,
document.getElementById('root')
);
Result:
<div class="MyBlock"></div>
<div class="MyBlock-Inner"></div>
<span class="MyBlock"></span>
<div class="MyBlock MyBlock_theme_default"></div>
Classes are generated using the fields block, elem and method mods() in accordance with the React naming scheme for CSS classes that is shown below. Separators of block, element, and modifier names are generated automatically.
React scheme for forming CSS class names:
BlockName-ElemName_modName_modVal
Note: Learn more about CSS class naming schemes.
Example:
// Creating a block
class Button extends Block {
block = 'Button';
}
// Creating an element
class Text extends Elem {
block = 'Button';
elem = 'Text';
}
// Creating a block modifier
class Button extends Block {
block = 'Button';
mods() {
return {
theme: 'default'
};
}
}
// Creating an element modifier
class Text extends Elem {
block = 'Button';
elem = 'Text';
elemMods() {
return {
theme: 'default'
};
}
}
Result:
<!-- Block -->
<div class="Button"></div>
<!-- Element -->
<div class="Button-Text"></div>
<!-- Block modifier -->
<div class="Button Button_theme_default"></div>
<!-- Element modifier -->
<div class="Button-Text Button-Text_theme_default"></div>
For more information about the API, see: REFERENCE.md.
For detailed instructions on switching to v2.0 of the API, see: MIGRATION.md.
The API is versioned according to Semantic Versioning. We recommend using the latest stable version of the library.
Note: The history of API edits can be found in CHANGELOG.md. To learn about switching between different versions of the API, see: MIGRATION.md.
Bem React Core is an open source library that is under active development and is also used within Yandex.
If you have suggestions for improving the API, you can send us a Pull Request.
If you found a bug, you can create an issue describing the problem.
For a detailed guide to making suggestions, see: CONTRIBUTING.md.
© 2018 Yandex. Code released under Mozilla Public License 2.0.