Skip to content

Instantly share code, notes, and snippets.

@Munawwar
Last active January 17, 2023 06:34
Show Gist options
  • Save Munawwar/9458a153f873ad7f22f9a86a1cf3aeec to your computer and use it in GitHub Desktop.
Save Munawwar/9458a153f873ad7f22f9a86a1cf3aeec to your computer and use it in GitHub Desktop.
PEM

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.

Why?

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.

Naming

Prefix

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.

Element or "Part"

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.

Bad naming examples

.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!

Modifier

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.

Do's & Dont's

Use CSS properties that affect child elements at the lowest level

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.

Try not to affect child elements

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.

Don't override utlity clesses with named classes

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>

"How do I reuse CSS?"

There are two ways to reuse CSS. Either

  1. 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

  1. 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.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment