{"id":15046107,"url":"https://github.com/frontendr/bemmed","last_synced_at":"2026-02-23T23:15:50.290Z","repository":{"id":34544960,"uuid":"180014625","full_name":"frontendr/bemmed","owner":"frontendr","description":"JavaScript class to compose reusable objects that result in a `block__element--modifier` string.","archived":false,"fork":false,"pushed_at":"2025-04-22T14:31:49.000Z","size":531,"stargazers_count":2,"open_issues_count":6,"forks_count":0,"subscribers_count":2,"default_branch":"develop","last_synced_at":"2025-10-25T20:43:20.667Z","etag":null,"topics":["bem","block","class","css","element","javascript","jsx","modifier","reusable"],"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/frontendr.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,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2019-04-07T19:41:20.000Z","updated_at":"2025-01-28T08:29:58.000Z","dependencies_parsed_at":"2024-09-25T01:59:54.112Z","dependency_job_id":"45245e32-7e93-4c1f-b277-f421902925a3","html_url":"https://github.com/frontendr/bemmed","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/frontendr/bemmed","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frontendr%2Fbemmed","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frontendr%2Fbemmed/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frontendr%2Fbemmed/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frontendr%2Fbemmed/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/frontendr","download_url":"https://codeload.github.com/frontendr/bemmed/tar.gz/refs/heads/develop","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/frontendr%2Fbemmed/sbom","scorecard":{"id":412144,"data":{"date":"2025-08-11","repo":{"name":"github.com/frontendr/bemmed","commit":"802c9cbcd5e032cc14995cf0a05559a8b166320e"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":3.9,"checks":[{"name":"Code-Review","score":0,"reason":"Found 0/3 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/codeql-analysis.yml:1","Warn: no topLevel permission defined: .github/workflows/node.js-ci.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":2,"reason":"dependency not pinned by hash detected -- score normalized to 2","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:38: update your workflow using https://app.stepsecurity.io/secureworkflow/frontendr/bemmed/codeql-analysis.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:42: update your workflow using https://app.stepsecurity.io/secureworkflow/frontendr/bemmed/codeql-analysis.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:53: update your workflow using https://app.stepsecurity.io/secureworkflow/frontendr/bemmed/codeql-analysis.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/codeql-analysis.yml:67: update your workflow using https://app.stepsecurity.io/secureworkflow/frontendr/bemmed/codeql-analysis.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/node.js-ci.yml:22: update your workflow using https://app.stepsecurity.io/secureworkflow/frontendr/bemmed/node.js-ci.yml/develop?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/node.js-ci.yml:25: update your workflow using https://app.stepsecurity.io/secureworkflow/frontendr/bemmed/node.js-ci.yml/develop?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/node.js-ci.yml:40: update your workflow using https://app.stepsecurity.io/secureworkflow/frontendr/bemmed/node.js-ci.yml/develop?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/node.js-ci.yml:52: update your workflow using https://app.stepsecurity.io/secureworkflow/frontendr/bemmed/node.js-ci.yml/develop?enable=pin","Info:   0 out of   6 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   2 third-party GitHubAction dependencies pinned","Info:   1 out of   1 npmCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":10,"reason":"SAST tool is run on all commits","details":["Info: SAST configuration detected: CodeQL","Info: all commits (27) are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":3,"reason":"7 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-968p-4wvh-cqc8","Warn: Project is vulnerable to: GHSA-xffm-g5w8-qvg7","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-18T22:59:20.045Z","repository_id":34544960,"created_at":"2025-08-18T22:59:20.045Z","updated_at":"2025-08-18T22:59:20.045Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29760257,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-23T21:02:23.375Z","status":"ssl_error","status_checked_at":"2026-02-23T20:58:31.539Z","response_time":90,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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","block","class","css","element","javascript","jsx","modifier","reusable"],"created_at":"2024-09-24T20:52:43.014Z","updated_at":"2026-02-23T23:15:50.273Z","avatar_url":"https://github.com/frontendr.png","language":"TypeScript","readme":"# BEMMED\n\n\u003e JavaScript reusable composer class for BEM (Block Element Modifier) CSS classes.\n\n## Installation\n\n```bash\nnpm install bemmed\n```\n\n[![Build Status](https://img.shields.io/github/actions/workflow/status/frontendr/bemmed/node.js-ci.yml)](https://github.com/frontendr/bemmed/actions/workflows/node.js-ci.yml)\n[![npm version](https://img.shields.io/npm/v/bemmed.svg)](https://www.npmjs.com/package/bemmed)\n[![npm downloads](https://img.shields.io/npm/dm/bemmed.svg)](https://www.npmjs.com/package/bemmed)\n[![Size (gzipped)](https://img.shields.io/bundlephobia/minzip/bemmed?label=size%20%28gzipped%29)](https://bundlephobia.com/package/bemmed)\n[![Coverage Status](https://coveralls.io/repos/github/frontendr/bemmed/badge.svg?branch=develop)](https://coveralls.io/github/frontendr/bemmed?branch=develop)\n[![License: MIT](https://img.shields.io/github/license/frontendr/bemmed)](https://github.com/frontendr/bemmed/blob/master/LICENSE)\n[![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier)\n\n## The problem solved\n\nUsing BEM notation usually involves a lot of repetition. The name of the block gets\nrepeated for every element and when adding a modifier, it is not uncommon that the\n`className` of an element gets quite long and unwieldy.\n\nThe goal of this package is to be able to create a reusable object which can be used to\nbuild every possible BEM class we want without any repetition of its parts.\n\n### The old way:\n\nHere an example of a simple component using JSX:\n\n```jsx harmony\nfunction Profile({theme, collapsed, avatar, name}) {\n  return (\n    \u003carticle className={\"profile profile--\" + theme}\u003e\n      \u003cheader className=\"profile__header profile__header--with-avatar profile__header--extra-space\"\u003e\n        \u003ch2\n          className={\n            \"profile__title\" +\n            (collapsed ? \" profile__title--small\" : \"\") +\n            (theme === \"dark\" ? \" profile__title--inverted\" : \"\")\n          }\n        \u003e\n          {name}\n        \u003c/h2\u003e\n        \u003cfigure\n          className={\n            \"profile__avatar\" + (collapsed ? \" profile__avatar--collapsed\" : \"\")\n          }\n        \u003e\n          \u003cimg src={avatar} alt={name} /\u003e\n        \u003c/figure\u003e\n      \u003c/header\u003e\n      ...\n    \u003c/article\u003e\n  );\n}\n```\n\nResults in 521b of code when transpiled with [babel](https://babeljs.io/repl/#?babili=false\u0026browsers=\u0026build=\u0026builtIns=false\u0026spec=false\u0026loose=false\u0026code_lz=GYVwdgxgLglg9mABABQE52DANgUwBQDeUAFjgLY4A0iEcWWAhgA4DOOAJtQwG4NQOpqYBhQC-ASkQEAUIkSocUEKiR5ZcxAB4BsCLhqMWLAHIicAXgIAiJukz7bGbDgC0Lq4gDUiEuRyiAPnUNLVIGdhxUAwYjUwpzGztnAH1ksIiox3scVPTItwB3GBIXHj4BRCyUtJxw_JccAA8oVAYXFiYGCBwrIJCQzWIAJmjYs0tEp1xU2ChcD288WnpmNnZEAH5EDyrp5NncNxYyBnoPAC5tq0lF3wpEc0ft9gEAaw8tnaS9g9cXGDA3EiUA4Fyu4kCBGEYk0AHphn1-nJNJgAObKHCjEzjay7HLJMr8VALRBLOiMVgcTbbSrffGEgRuZYUtZgqzXQLBJFaGBkVGIFioCCWBmoUSIU5QSzQ_yIWGIpFwtEYhUaOF5VCquQAOl1XLhOhgehwARC6nEAG5pKIgA\u0026debug=false\u0026forceAllTransforms=false\u0026shippedProposals=false\u0026circleciRepo=\u0026evaluate=false\u0026fileSize=false\u0026timeTravel=false\u0026sourceType=module\u0026lineWrap=true\u0026presets=es2017%2Creact%2Cstage-2\u0026prettier=false\u0026targets=\u0026version=7.4.3\u0026externalPlugins=)\nand then minified with [terser](https://xem.github.io/terser-online/).\n\nThis is not an uncommon pattern. Ok, some modifiers are a bit weird, but we've all\nseen worse right? As you can see, there is quite a lot of repetition. The word `profile`\nis used 10 times in `className` attributes, not to mention the `header`, `title` and\n`avatar` elements.\n\nUsually I would add newlines inside the `className` to make the ternary operators more\nreadable or compose the `className`s outside the JSX, but we want roughly the same\nnumber of lines in both examples.\n\n### The new way:\n\n```jsx harmony\n// we can pre-initialize the classes used in this component, we don't have to but we can.\nconst [profileCls, headerCls, titleCls, avatarCls] = new BEM(\"profile\").withElem(\n  \"header\",\n  \"title\",\n  \"avatar\"\n);\n\nfunction Profile({theme, collapsed, avatar, name}) {\n  return (\n    \u003carticle className={profileCls}\u003e\n      \u003cheader className={headerCls.withMod(\"with-avatar\", \"extra-space\")}\u003e\n        \u003ch2\n          className={titleCls.withMod({small: collapsed, inverted: theme === \"dark\"})}\n        \u003e\n          {name}\n        \u003c/h2\u003e\n        \u003cfigure className={avatarCls.withMod({collapsed})}\u003e\n          \u003cimg src={avatar} alt={name} /\u003e\n        \u003c/figure\u003e\n      \u003c/header\u003e\n      ...\n    \u003c/article\u003e\n  );\n}\n```\n\nResults in 452b of code when transpiled with [babel](https://babeljs.io/repl/#?babili=false\u0026browsers=\u0026build=\u0026builtIns=false\u0026spec=false\u0026loose=false\u0026code_lz=MYewdgzgLgBA2gBwE4gGYEsA2BTAwpiAGhgAtsBDAE2yXyJinShzuPIDdypzaCBdGAF4YYbAHcYAIQCiAWQAUAImRos2RQEoAdGKYlpOALZKyVGouKLGzdZY5cemgNwAoF6gCuYYI3AwACigYOPIA3lBkhtjEoJiY5AgQ2JRsnNxIxGDkUQC-GjChLjAwSNhQHkhgMPJFxTAAPDyMwDgwLeQQEABy2diCoSrBeAQ5AHy1dQ2m1Eht8Z09Uf3TNHQ6erIglEq6EQC09ukWMIrYAB5QSOR7EAjkwOoaYxOTUwBMcx3dvf3WLATrCKbbahCCGchxABcbRAcQSSRSMHQYHYNCgyWhEWwUSEgmEikoPAA1oo8mNQllcvUAPQkN7jV51eoYADmFWwnwWP1Chx4a12JGBYVi8USyTJDMZTPQhhZMAgSGA_V5SByMAhUH6lOwaupksZNNZ7P1TNpFBmJuKWmtLxpTXQLWwko0rhyQA\u0026debug=false\u0026forceAllTransforms=false\u0026shippedProposals=false\u0026circleciRepo=\u0026evaluate=false\u0026fileSize=false\u0026timeTravel=false\u0026sourceType=module\u0026lineWrap=true\u0026presets=es2017%2Creact%2Cstage-2\u0026prettier=false\u0026targets=Node-11\u0026version=7.4.3\u0026externalPlugins=)\nand then minified with [terser](https://xem.github.io/terser-online/).\n\nThat's 69 bytes (-14%) _and_ we gained the ability to reuse the classes allowing even\ngreater benefits.\n\nAs you can see in the example above, there is **no** repetition. The className variables\ncan be easily minified and mangled. Each `BEM` instance stays reusable, so it can be\nmodified later which you can see when we use `withMod` inside the component based on its\nprops.\n\n## Features\n\n- ✅ 1.8 kB minified / 837 B minified+gzipped (see: [Bundlephobia](https://bundlephobia.com/package/bemmed) for the latest numbers)\n- ✅ `BEM` instances are reusable and can be modified.\n- ✅ `BEM` methods are plain or short english, no letters.\n- ✅ Methods to ease the creation of multiple classes without duplication.\n- ✅ Arguments can be passed consistently without specific syntax requirements such\n  as `$dollar` variables.\n- ✅ `BEM` or `BEMList` instances can be converted to a string by simply concatenating\n  them with a string, using their `.s` property or just calling `.toString()`\n  like any other JavaScript object.\n- ✅ Adding multiple modifiers, requesting the base _with_ an element or modifier or\n  concatenating it results in a `BEMList`. This is a subclass of `Array` and renders\n  as proper CSS classes separated by a space character.\n- ✅️ Acts like `block__element--modifier` by default.\n- ✅ The separators (`__` and `--`) can be changed by creating a new class using the\n  `setup()` function.\n\n## Usage\n\nImporting in ES6:\n\n```js\nimport BEM from \"bemmed\";\n```\n\nor in CommonJS:\n\n```js\n// require the named export:\nconst { BEM } = require(\"bemmed\");\n```\n\nExample usage:\n\n```jsx\nconst cls = new BEM(\"block\", \"element\", \"modifier\");\n//=\u003e BEM(b: \"block\", e: \"element\", m: \"modifier\")\n\n// Convert to String:\nString(cls);\n//=\u003e \"block__element--modifier\"\ncls.toString();\n//=\u003e \"block__element--modifier\"\n\"\" + cls;\n//=\u003e \"block__element--modifier\"\n`${cls}`;\n//=\u003e \"block__element--modifier\"\ncls.s;\n//=\u003e \"block__element--modifier\"\n\n// Convert to an array of strings:\ncls.toArray();\n//=\u003e [\"block__element--modifier\"]\n\n// Use in JSX:\n\u003cdiv className={cls}\u003ex\u003c/div\u003e;\n//=\u003e \u003cdiv class=\"block__element--modifier\"\u003ex\u003c/div\u003e\n\n// Just a block\nString(new BEM(\"block\"));\n//=\u003e \"block\"\n\n// Block with element\nString(new BEM(\"block\", \"element\"));\n//=\u003e \"block__element\"\n\n// Set modifier\nconst modified = cls.modifier(\"mod2\"); // aliased as .mod()\nString(modified);\n//=\u003e \"block__element--mod2\"\n\n// Modifications return a new instance, original is unmodified:\nString(cls);\n//=\u003e \"block__element--modifier\"\n\n// Set multiple modifiers\nString(cls.mod(\"mod-a\", \"mod-b\", \"mod-c\"));\n//=\u003e \"block__element--mod-a block__element--mod-b block__element--mod-c\"\n\n// Modify using an object, only keys of truthy values are applied:\nString(\n  cls.mod({\n    foo: true,\n    bar: false,\n    \"foo-bar\": \"yes\",\n  })\n);\n//=\u003e \"block__element--foo block__element--foo-bar\"\n\n// New instance with another element\nconst newElement = cls.element(\"el2\"); // aliased as elem()\nString(newElement);\n//=\u003e \"block__el2--modifier\"\n\n// New instance with another element and modifiers\nconst newElementWithMod = cls.element(\"el3\", \"modifier\");\nString(newElementWithMod);\n//=\u003e \"block__el3 block__el3--modifier\"\n\n// Combine the class with a modified variant\nconst withMod = new BEM(\"block\", \"element\").withMod(\"modifier\");\n//=\u003e BEMList\u003c[BEM(b: \"block\", e: \"element\", m: null), BEM(b: \"block\", e: \"element\", m: \"modifier\")]\u003e\nString(withMod);\n//=\u003e \"block__element block__element--modifier\"\n\n// Get several elements (useful to pre-generate reusable classes):\nconst block = new BEM(\"block\");\nconst [header, body, footer] = block.elements(\"header\", \"body\", \"footer\");\nString(header);\n//=\u003e \"block__header\"\nString(body);\n//=\u003e \"block__body\"\nString(footer);\n//=\u003e \"block__footer\"\n\n// Concatenate with multiple strings, Array's, BEM instances or BEMList's\nString(\n  new BEM(\"block\").concat(\n    \"just-a-string\", // String\n    new BEM(\"b\", \"e\", \"m\"), // BEM instance\n    new BEM(\"foo\").withMod(\"bar\") // BEMList\n  )\n);\n//=\u003e \"block just-a-string b__e--m foo foo--bar\"\n\n// Create a custom class with modified separators using the setup function.\nimport {setup} from \"bemmed\";\n\nconst UnderBEM = setup({\n  // or just name it `BEM`.\n  elementSeparator: \"_\",\n  modifierSeparator: \"__\",\n});\nnew UnderBEM(\"block\", \"element\", \"modifier\").toString();\n//=\u003e \"block_element__modifier\"\n\n// Export this custom BEM class and import it in your application from here.\n```\n\n## API\n\n### Creating a new instance\n\nCreate a new instance. Usually only with a block\n\n```\nconst cls = new BEM(block: string[ element: string[ modifier: string]]): BEM\n```\n\n### Setting the element or modifier parts\n\nUsing the `element()` (or `elem()` alias) method returns a new `BEM` instance with the\nprovided element part. When adding modifiers, a `BEMList` is returned as if `.withMod()`\nwas used after adding the element.\n\n```\ncls.element(element: string, ...modifiers: string): BEM|BEMList\ncls.elem(element: string, ...modifiers: string): BEM|BEMList\n```\n\nUsing the `modifier()` (or `mod()` alias) method returns a new `BEM` instance with the\nprovided modifier part. When given multiple modifiers, a `BEMList` is returned.\n\n```\ncls.modifier(...modifiers: string): BEM|BEMList\ncls.mod(...modifiers: string): BEM|BEMList\n```\n\n### Adding an element\n\nTo create a block together with one or more elements\n\n```\ncls.withElem(...elements: string): BEMList\n```\n\n```js\nnew BEM(\"block\").withElem(\"foo\", \"bar\").toString();\n//=\u003e \"block block__foo block__bar\"\n```\n\nVery useful when destructuring:\n\n```js\nconst [tableClass, rowClass, cellClass] = new BEM(\"table\").withElem(\"row\", \"cell\");\n```\n\n### Adding a modifier\n\nUsually you want to output a base class **and** the modifier class. Returns a new\n`BEMList` with `BEM` instances for each part.\n\n```\ncls.withMod(...modifiers: string|Object): BEMList\n```\n\n```js\nnew BEM(\"block\")\n  .withMod(\"always-add-this\", {\n    \"and-this\": true,\n    \"but-not-this\": false,\n  })\n  .toString();\n//=\u003e \"block block--always-add-this block--and-this\"\n```\n\nA `BEMList` is just a subclass of `Array` with a modified `toString()` method, so it\nrenders as a proper `className` with spaces between the classes.\n\n### Creating multiple elements\n\nPre-initializing a set of elements for a block is also a common use case. Returns a new\n`BEMList` with `BEM` instances for the given elements.\n\n```\ncls.elements(...element: string): BEMList\n```\n\n```js\nnew BEM(\"block\").elements(\"foo\", \"bar\").toString();\n//=\u003e \"block__foo block__bar\"\n```\n\n### Combining or concatenating classes\n\nSame method as [`Array.concat`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/concat).\nReturns a new `BEMList` with the items appended. Remember: Arrays will be flattened!\nAlso removes any duplicates from the given arguments and works on both `BEM` and\n`BEMList` instances.\n\n```\ncls.concat(...items: any): BEMList\n```\n\n```js\nnew BEM(\"b1\")\n  .concat(new BEM(\"b2\"), \"just-a-string\", [\"array\", \"of\", \"items\"])\n  .toString();\n// =\u003e \"b1 b2 just-a-string array of items\"\n```\n\n### Converting to a string\n\nReturns a string with the class names separated by spaces.\n\n```js\nconst cls = new BEM(\"block\", \"element\", \"modifier\");\ncls.toString();\n//=\u003e \"block__element--modifier\"\n\n// or use the getter:\ncls.s;\n//=\u003e \"block__element--modifier\"\n```\n\nThe `s` getter is a shorthand for `toString()` and is especially useful if\nusing a BEM instance causes inspection errors. Although most projects don't mind\na BEM instance as a value for `className` at all.\n\n```jsx\nconst cls = new BEM(\"block\", \"element\", \"modifier\");\nreturn (\n    \u003cdiv className={cls.s}\u003eBemmed + JSX = 😀\u003c/div\u003e\n);\n//=\u003e JSX: \u003cdiv class=\"block__element--modifier\"\u003eBemmed + JSX = 😀\u003c/div\u003e\n```\n\n### Using an array of strings\nWHen using a `BEMList` or `BEM` instance, the `.toString()` method returns a\nstring with all BEM instances joined by a space character. The `.toArray()`\nmethod returns an array of strings instead. This removes the need to add `.s` or\n`.toString()` every time a class is used and to easily pass individual classes\nto tools that only expect strings.\n\nFor example, using a `BEM` instance with [clsx](https://www.npmjs.com/package/clsx)\nwould cause it to iterate the internal properties, but when we pass it an array\nit's all good.\n```jsx\nconst [element, modifier] = new BEM(\"block\", \"element\").withMod(\"modifier\").toArray();\nreturn (\n    \u003cdiv className={clsx(element, modifier)}\u003eBemmed + clsx() = 😀\u003c/div\u003e\n);\n```\nOf course this is a silly example, but the last thing we want is having to type\nmore than we need to right?\n\n### Customizing separators\n\nUse the `setup()` function to create a customized BEM class.\n\nThe function takes an object literal which can contain the following properties:\n\n| Property            | Default | Description                                             |\n| ------------------- | ------- | ------------------------------------------------------- |\n| `elementSeparator`  | `\"__\"`  | Separator string between the block and element part.    |\n| `modifierSeparator` | `\"--\"`  | Separator string between the element and modifier part. |\n\nCreate a module in your project e.g. `utils/bem.js`.\n\n```js\nimport {setup} from \"bemmed\";\nexport const BEM = setup({\n  elementSeparator: \"_\",\n  modifierSeparator: \"__\",\n});\n\n// This would produce classes like \"block_element__modifier\"\n```\n\nThen in your project just import `BEM` from that module:\n\n```js\nimport {BEM} from \"./utils/bem\";\n// BEM is now your customized version that only uses underscores.\n```\n\n## PropTypes\n\n`BEM` provides several [PropTypes](https://www.npmjs.com/package/prop-types) to ease the\nusage with libraries such as React. All propTypes also support an `.isRequired` property\nto allow `undefined` values.\n\nImport the prop types from `bemmed/proptypes`:\n\n```js\n// exported as propTypes:\nimport {propTypes} from \"bemmed/proptypes\";\n// but also available as default export for easier renaming\nimport BEMTypes from \"bemmed/proptypes\";\n```\n\n| PropType                  | Description                                                                                                                                   |\n| ------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |\n| `propTypes.bem`       | Valid `BEM` or `BEMList` instances.                                                                                                           |\n| `propTypes.className` | Utility PropType for checking any valid value which can be used in a `className` attribute in `JSX` (including `BEM` or `BEMList` instances). |\n| `propTypes.element`   | Valid value for `BEM.element()`.                                                                                                              |\n| `propTypes.modifier`  | Valid value for `BEM.modifier()`.                                                                                                             |\n\n## FAQ\n\n### Why bother, doesn't gzip solve this already?\n\nYes it does help in some cases, but it can never yield the same results and does not\ngive any of the benefits such as reusable objects, readability and ease of development.\n\n### Improved readability? I find it harder to read\n\nI can imagine never seeing a fully written `className` can be harder to read at first,\nbut I got used to it quite fast. The habit of destructuring `BEM` element classes into\nseparate variables makes it more clear what each `className` is for.\n\nFor example, I find `className={titleClass.withMod({inverted: myInvertedState})}` much\neasier to read than `className={\"header__title\" + (myInvertedState ? \" header__title--inverted\" : \"\")`.\nAnd I think we've all seen worse classes with more inline logic than that.\n\nDon't forget about the benefits of keeping your code *[DRY](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself)*\nby not repeating the same base class over and over again. This makes changes\nin your code much easier to make and modifying the class based on a condition\nis baked in, so no need to use a ternary operator or helper functions.\n\n### Now my IDE can't find the usages of a specific class!\n\nTrue, but are your classes that scattered throughout your application? Also, if that's\nthe case then reusing a `BEM` instance for that class could help you by simply looking\nfor the usages for that instance instead of searching for the css class string.\n\n## Developing\n\n- Build with `npm run build`\n- Run tests with `npm run test`.\n\n## LICENSE\n\nMIT\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffrontendr%2Fbemmed","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffrontendr%2Fbemmed","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffrontendr%2Fbemmed/lists"}