PEM is a CSS naming convention. Inspired by BEM CSS and Suit CSS naming convention.
P = Prefix
E = Element
M = Modifier
Acceptable CSS class name formats:
Prefix-element
Prefix-element--modifier
For root element of a component:
Prefix
Prefix--modifier
tl:dr; CSS class names are strictly in the format as above. Name your class names well and dont use CSS props that affect child elements unless necessary.
The underlying idea behind CSS BEM convention is useful but it's naming is not the most appealing to the eye (underscores sometimes, dashes some other times etc). And furthermore people either misunderstand it or do things that reduces it's benefits. PEM is like a simpler but stricter variation of BEM.
That said, if you can use CSS modules / Vanilla extract or scoped CSS (provided by frameworks) or shadow dom then go for that over PEM. Naming convention methodology is for projects where those cannot be used.
Prefix could be a component name or a page name or a backend view partial's name (e.g. jinja or nunjucks, button.html would have "Button" as prefix).
All CSS names in a component or partial needs to begin with the component or partial's name in PascalCase.
(Make sure that the Prefix you have chosen is not used in the page/project by other components or 3rd party CSS.)
Prefix alone is also a valid CSS class name for root element of component or partial. If component/partial dont have a root element, then avoid using Prefix alone as class name there.
For elements within a component/partial use a name in camelCase prefixed by Prefix
name and a single dash.
Example: Component-settingsIcon
.
Be specific when naming. Name the element based on what it does, an not based on utility.
.Component-icon
- What icon? A component could have many icons. Better name it settingIcon
or editIcon
or something.
.Component-mr2
- mr2? Do you mean margin right scale 2? I suggest to not name based on the style, rather name based on the purpose of the element. Is this element just a wrapper div over some icons? Then name it .Component-icons
or .Component-iconsWrapper
.
.Page .Section-icon
- Dont add unnecessary specificity. Correct way is .Page-sectionIcon
. If you are trying to override the section's CSS based on state, then take a look at the Modifier section in this page.
.Component-section-icon
- Nope. use camelCase for element .Component-sectionIcon
.
.Component-section__icon
- Get outta here!
Sometimes your elements/components needs to look different based on states. Like a toggle button, that can have an "on" and an "off" state. In this case you need an additional CSS class to be added to the element. We call this a "modifier" name that is prefixed by Prefix name, Element name and double dash.
.CheckoutPage-toggleButton {
/* ... */
}
.CheckoutPage-toggleButton--on {
/* ... */
}
<button class="CheckoutPage-toggleButton CheckoutPage-toggleButton--on"></button>
If you have used a Prefix
only class on root element of your component/partial then it is allowed to name modifier classes on that element as Prefix--modifier
. For all other cases, add Element name to the class name.
What happens if I were to add line-height: 100
to your body element?
Your page is going to look terrible for sure. line-height
is not like display: flex
which only affects one level of child elements.
CSS properties like line-height
, font-size
affects the it's entire sub-tree.
So add them at the lowest element as possible.
It feels tempting to write something like:
.Panel > * {
display: inline-block;
}
But the next day you changed the component's implementation to accept child element's from it's parent component, but forgot to remove that CSS.
You've got a bug now, since the CSS above is affecting the child elements regardless of what it is. Had you used a named CSS class you could have avoided the bug.
So avoid child selectors, sibling selectors, and anything that increases specificity beyond one level.. unless absolutely needed.
It is easier to explain this with an example and inline comments:
<button class="Button mb-2">A button</button>
<style>
.mb-2 {
margin-botton: 20px;
}
.Button {
margin-bottom: 10px;
/* ^ this is not good. You are overriding a utlity class mb-2. Why not remove the utility class or use another utlity mb-* class? */
}
</style>
There are two ways to reuse CSS. Either
-
reuse the component/partial (html+css), not just the CSS alone. Split components/partial as needed to smaller reusable components/partials. If you cannot do that, then either:
-
duplicate the CSS classes to under new class names.
-
OR duplicate the component/partial and it's CSS to a new component/partial with new CSS class names.
Some duplication is ok. You dont have to take the "Dont Repeat Yourself" principle to the extreme.
-
Or
- share CSS alone via utility CSS classes like how tailwind does this. I suggest using tailwind or an established utlity framework, over implementing it yourself, as an unstable utility implementation causes a lot of rewrites/refactors.