---
title: I built a CSS framework where every class name is an emoji
published: true
description: BEMoji is a fully featured BEM framework that uses emoji as class names. It's stupid. It works. It's on npm.
tags: css, jokes, Tailwind, BEM
cover_image: https://tomhayes.github.io/BEMoji/og-image.png
---
I got into one too many Tailwind vs BEM arguments this month and decided the correct response was to build something that makes both sides equally uncomfortable.
Meet **BEMoji**: a production-grade CSS framework where every class name is an emoji.
```html
<article class="π">
<div class="π__πΌοΈ π__πΌοΈ--π">
<img src="hero.jpg" alt="...">
</div>
<div class="π__π">
<h2 class="π__π ">Card Title</h2>
</div>
<footer class="π__π¦Ά">
<button class="π π--π">Primary</button>
<button class="π π--π»">Disabled</button>
</footer>
</article>
```
That is valid, production HTML. It works in every modern browser. I am not sorry.
## Why does this exist
The core BEM pattern is `block__element--modifier`. BEMoji keeps that structure exactly, just swapping string names for emoji tokens. The double-underscore and double-hyphen delimiters are preserved, so the class names are still machine-parseable even if they're completely illegible to humans.
It started as a joke and then I accidentally made it real.
## It's actually kind of a full framework
This is the part that got out of hand. BEMoji ships with:
- 143 canonical emoji tokens across blocks, elements, modifiers and utilities
- A complete design token system (yes, using emoji as CSS custom property names: `--π-4`, `--π-md`, `--β-full`)
- 24 pre-built components (cards, buttons, badges, alerts, modals, tables, the lot)
- A PostCSS plugin so you can write readable BEM in your source and get emoji compiled at build time
- A Vite plugin with HMR support
- An ESLint plugin that enforces correct token usage
- A React `bem()` helper
- A CLI with `init`, `compile`, `audit`, `decode`, `encode` and `export` commands
The CLI's `decode` command is probably my favourite part:
```bash
npx bemoji decode "π__πΌοΈ--π"
# card__image--featured
```
## The PostCSS workflow
You don't have to write emoji by hand in your source files. The PostCSS plugin lets you use a bracket shorthand:
```css
.[card] {
border-radius: var(--β-md);
box-shadow: var(--π-sm);
}
.[card__image--featured] {
outline: 2px solid var(--π‘);
}
```
Which compiles to:
```css
.π {
border-radius: var(--β-md);
box-shadow: var(--π-sm);
}
.π__πΌοΈ--π {
outline: 2px solid var(--π‘);
}
```
So the output is emoji soup but your source stays readable. Or as readable as it was before, anyway.
## The React helper
```jsx
import { useBem } from 'bemoji/react';
function Card({ featured }) {
const b = useBem('card');
return (
<article className={b()}>
<div className={b('image', { featured })}>
...
</div>
</article>
);
}
// When featured=true, className becomes "π__πΌοΈ π__πΌοΈ--π"
```
## There are legitimate arguments for this
I feel compelled to make the honest case, because it genuinely surprised me:
**Free obfuscation.** Your production CSS is meaningless to anyone without the config file. You get the obfuscation benefits of CSS Modules without the build complexity.
**Enforced vocabulary.** Every UI concept maps to one canonical emoji. The config file is your design system contract. Changing a concept's emoji is a one-line config change that propagates everywhere.
**It's faster to type than you think.** Once you have emoji picker shortcuts set up, `π` is two keystrokes. `.card__image--featured` is 24. The maths eventually works out.
None of this makes it a good idea. But they are real arguments.
## The config
```js
// bemoji.config.js
export default {
blocks: {
card: 'π',
navbar: 'π§',
modal: 'πͺ',
alert: 'π',
},
elements: {
image: 'πΌοΈ',
title: 'π ',
body: 'π',
button: 'π',
},
modifiers: {
primary: 'π',
danger: 'π΄',
disabled: 'π»',
loading: 'β³',
},
};
```
## Install
```bash
npm install bemoji
npx bemoji init
```
The init command scaffolds a config, imports the base CSS, and wires up PostCSS.
## Links
- **Docs + demo**: https://tomhayes.github.io/BEMoji/
- **GitHub**: https://github.com/tomhayes/BEMoji
- **npm**: https://npmjs.com/package/bemoji
My personal favourite token is π¦Ά for footer. If you find a better use for it than I have, open a PR.