{"id":17166224,"url":"https://github.com/textkernel/bem","last_synced_at":"2026-01-31T13:04:42.658Z","repository":{"id":34917892,"uuid":"189058758","full_name":"textkernel/bem","owner":"textkernel","description":"✨ Magically generates class names for React components","archived":false,"fork":false,"pushed_at":"2023-01-04T21:47:21.000Z","size":2393,"stargazers_count":0,"open_issues_count":17,"forks_count":1,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-06-09T11:49:25.999Z","etag":null,"topics":["bem","css-modules","react"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/textkernel.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-05-28T15:48:40.000Z","updated_at":"2023-04-11T15:26:09.000Z","dependencies_parsed_at":"2023-01-15T10:23:06.951Z","dependency_job_id":null,"html_url":"https://github.com/textkernel/bem","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/textkernel/bem","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/textkernel%2Fbem","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/textkernel%2Fbem/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/textkernel%2Fbem/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/textkernel%2Fbem/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/textkernel","download_url":"https://codeload.github.com/textkernel/bem/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/textkernel%2Fbem/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260451551,"owners_count":23011298,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bem","css-modules","react"],"created_at":"2024-10-14T23:05:04.987Z","updated_at":"2026-01-31T13:04:37.639Z","avatar_url":"https://github.com/textkernel.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build Status](https://travis-ci.com/textkernel/bem.svg?branch=master)](https://travis-ci.com/textkernel/bem)\n[![Coverage Status](https://coveralls.io/repos/github/textkernel/bem/badge.svg?branch=master)](https://coveralls.io/github/textkernel/bem?branch=master)\n[![Language grade: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/textkernel/bem.svg?logo=lgtm\u0026logoWidth=18)](https://lgtm.com/projects/g/textkernel/bem/context:javascript)\n![Package dependencies](https://img.shields.io/david/textkernel/bem.svg?style=flat)\n![npm bundle size](https://img.shields.io/bundlephobia/minzip/@textkernel/bem.svg)\n![Maintenance](https://img.shields.io/maintenance/yes/2019.svg)\n[![npm version](https://img.shields.io/npm/v/@textkernel/bem.svg)](https://www.npmjs.com/package/@textkernel/bem)\n\nBEM\n===\n\n![css modules + bem + react = love](https://raw.githubusercontent.com/textkernel/bem/master/docs/logo.svg?sanitize=true)\n\n**Magically generates class names for React component.**\n\nInstallation\n------------\n\n```sh\nnpm install @textkernel/bem --save\n```\nor\n```sh\nyarn add @textkernel/bem\n```\n\n\nUsage\n-----\n\n## 1. Create and export your own **bem** function using `make`.\n\n```js\n// initBem.js\n\nimport make from 'bem';\n\n// `make` allows you to customize bem prefixes\nexport default make({\n    elemPrefix: '__',\n    modPrefix: '--',\n    valuePrefix: '_',\n});\n```\n\n## 2. Import **bem** into a React component, create `block` and `elem` functions and use them in render method\n\n```js\n// Button.js\nimport React, { Component } from 'react';\nimport PropTypes from 'prop-types';\nimport bem from './initBem';\nimport classnamesMap from './Button.scss';\n\nconst { block, elem } = bem(\n    'Button', // Block name\n    classnamesMap // Class names dict generated by CSS modules loader\n);\n\nconst Button = (props) =\u003e (\n    \u003cbutton\n        {/* If needed, `props` should be spread before `block` or `elem in order to avoid className overwrite. */}\n        {...props}\n        {/* Spread `block` to add class names to the top level node */}\n        { ...block(props) }\n    \u003e\n        \u003cspan\n            {/* Spread `elem` to add class names to an element. */}\n            { ...elem('label', props) }\n        \u003e\n            {props.children}\n        \u003c/span\u003e\n        \u003cspan\n            {/* Custom modifiers combined with props. */}\n            {...elem('icon', {\n                ...props,\n                almostRandomValue: 42\n            })}\n        \u003e\n            {props.children}\n        \u003c/span\u003e\n    \u003c/button\u003e\n);\n\n\nButton.propTypes = {\n    active: PropTypes.bool,\n};\n\nButton.defaultProps = {\n    active: false,\n};\n\nexport default Button;\n```\n\n### Passing custom class names to `block` and `elem` functions.\n\n#### block\n\nIf `props` object that you pass to `block` contains `className` property, then this `className` is applied to the resulting class name list. In case of `elem` function though it is ignored.\n\n```ts\nconst result = block('Button', { size: 'big', className: 'custom-class-name' });\n\nresult.className === 'Button Button--size_big custom-class-name' // true\n```\n\n#### elem\n\nIf `props` object that you pass to `elem` contains `elemClassName` property, then this `elemClassName` is applied to the resulting class name list. In case of `block` function though it is ignored.\n\n```ts\nconst result = elem('label', { position: 'right', elemClassName: 'custom-elem-class-name' });\n\nresult.className === 'Button__label Button__label--position_right custom-elem-class-name' // true\n```\n\n## 3. Write css respecting BEM methodology and it will be automatically picked up.\n\n```css\n/* Button.scss */\n\n/* Component's root node class name */\n.Button {\n\n    display: inline-block;\n\n    /*\n    Block: \"Button\", modifier: \"active\" (based on props.active), value: true.\n    Is applied to the component's root node when props.active = true is set.\n    */\n    \u0026--active {\n        color: red;\n    }\n\n    /*\n    Block: \"Button\", modifier: \"type\" (based on props.type), any truthy value.\n    Is applied to the component's root node when `props.type = \"normal\"` is set.\n    */\n    \u0026--type {\n        border: 1px;\n    }\n\n    /*\n    Block: \"Button\", modifier: \"type\" (based on props.type), value: \"normal\".\n    Is applied to the component's root node when `props.type = \"normal\"` is set.\n    */\n    \u0026--type_normal {\n        background-color: grey;\n    }\n\n    /*\n    Block \"Button\", modifier \"type\" (based on props.type), value \"extraordinary\".\n    Is applied to the component's root node when `props.type = \"extraordinary\"` is set.\n    */\n    \u0026--type_extraordinary {\n        background-color: red;\n    }\n\n    /*\n    Block \"Button\", modifier \"clicked\" (based on state.clicked), value true.\n    Is applied to the component's root node when `state.clicked = true` is set.\n    */\n    \u0026--clicked {\n        border-style: dashed;\n    }\n\n    /*\n    Block \"Button\", element \"label\"\n    Is applied to the component's label node.\n    */\n    \u0026__label {\n        color: blue;\n    }\n\n    /*\n    Block \"Button\", element \"label\", modifier: \"active\" (based on props.active), value: true.\n    Is applied to the component's label node when props.active = true is set.\n    */\n    \u0026__label--active {\n        color: yellow;\n    }\n\n\n/*\n    Block \"Button\", element \"label\", modifier \"extraordinary\" (based on props.type), value \"extraordinary\".\n    Is applied to the component's label node when `props.type = \"extraordinary\"` is set.\n    */\n    \u0026__label--type_extraordinary {\n        color: orange;\n    }\n}\n```\n\nExamples of outcome\n-------------------\n\nHaving the example above we can get the following results.\n`bem` decorator adds only classnames that are declared in a stylesheet and\nrespectively exists in classnames map.\n\n### No props:\n```html\n\u003cButton /\u003e\n ↓ ↓ ↓\n\u003cbutton class=\"Button\"\u003e\n    \u003cspan class=\"Button__label\" /\u003e\n\u003c/button\u003e\n```\n\n### Prop `active` is set:\n\n```html\n\u003cButton active={true} /\u003e\n\n    ↓ ↓ ↓\n\n\u003cbutton class=\"Button Button--active\"\u003e\n    \u003cspan class=\"Button__label Button__label--active\" /\u003e\n\u003c/button\u003e\n```\n\n### Prop `active` and `type` are set:\n\n**Note** that property of a boolean type `active={true}` produces `Button__label--active` (*without* mod value), when property of a string type `type='extraordinary'` gives us two class names: `Button__label--type` (*without* mod value) and `Button__label--type_extraordinary` (*with* mod value).\n\n```html\n\u003cButton active={true} type='extraordinary' /\u003e\n\n    ↓ ↓ ↓\n\n\u003cbutton class=\"Button Button--active Button--type Button--type_extraordinary\"\u003e\n    \u003cspan class=\"Button__label Button__label--active Button__label--type Button__label--type_extraordinary\" /\u003e\n\u003c/button\u003e\n```\n\n### Prop `active` equals false\n\nNo classnames will be produced if boolean property has `false` value.\n```html\n\u003cButton active={false} /\u003e\n\n    ↓ ↓ ↓\n\n\u003cbutton class=\"Button\"\u003e\n    \u003cspan class=\"Button__label\" /\u003e\n\u003c/button\u003e\n```\n\n### Clicked state\n```html\n\u003cButton /\u003e \u003c!-- this.setState({ clicked: true }) --\u003e\n\n    ↓ ↓ ↓\n\n\u003cbutton class=\"Button Button--clicked\"\u003e\n    \u003cspan class=\"Button__label Button__label--clicked\" /\u003e\n\u003c/button\u003e\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftextkernel%2Fbem","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftextkernel%2Fbem","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftextkernel%2Fbem/lists"}