DEV Community

Cover image for data-attributes vs. BEM
Mads Stoumann
Mads Stoumann

Posted on

data-attributes vs. BEM

I used to be a comicbook-letterer, so "BEM" always looked wrong to me. It's either "BAM!" — or "BOOM!" … Sorry, I couldn't resist that!

In a CMS-interface, editors sometimes have the option to customize the rendering of a component.

In an Accordion-Component, as an example, an editor might be able to chose the type of fold-out-icon to use from a drop-down:

  • “Down Arrow”
  • “Right Arrow”
  • “Plus”

The editor might even have the option to chose an icon per item in the accordion — if the accordion has several levels — as we often see in mobile navigation.

The backend for the accordion will most likely store the selection in a SelectionFacory (or similar), which is a bunch of key/value-pairs, where value is the one displayed to the editor, and key is the one we'll use in the rendered markup:

@Model.cssIcon
Enter fullscreen mode Exit fullscreen mode

Now, instead of outputting the value to a class-attribute, we can output it to a data-attribute with the same name (just in kebab-case) as the data-model:

<span data-css-icon="@Model.cssIcon">Item</span>
Enter fullscreen mode Exit fullscreen mode

This way, the backend and frontend is linked, and easy to read for both types of developers.

The key in this example is "down-arrow", so to target that in CSS, we'll use the attribute selector:

[data-css-icon="down-arrow"] { /*…*/ }
Enter fullscreen mode Exit fullscreen mode

If all the accordion-icons have something in common, these — more generic styles — can be placed in:

[data-css-icon] { /* common */ } 
Enter fullscreen mode Exit fullscreen mode

And if he editor should be allowed to add more modifiers, as an example "circle" or "fill", we can use the "contains *"-operator:

[data-css-icon*="circle"] { /*…*/ }
Enter fullscreen mode Exit fullscreen mode

And in HTML:

<span data-css-icon="down-arrow circle fill">Item</span>
Enter fullscreen mode Exit fullscreen mode

Here's a Codepen with a bunch of CSS Only Icons, with (clickable) modifiers:


CSS Badges

Let's look at another example that would typically require a lot of BEM-modifiers.

Imagine a List-Control or a Menu-Component, where an editor will be able to add text either before or after an item. This could be a colored circle with" NEW" after a product-name, the infamous red notification-badge with a number,

The CMS-implementation could be:

  • type (badge, circle, dot, pill)
  • color
  • horizontal position (left, right)
  • vertical position (bottom, top)

Instead of:

<button class="c-txt c-txt--badge c-txt--color-red c-txt--posv-top c-txt--posh-left" data-text="NEW">
Enter fullscreen mode Exit fullscreen mode

It could be:

<button data-text-type="red badge top left" data-text="NEW">
Enter fullscreen mode Exit fullscreen mode

CSS in data-attributes are probably a bit slower to parse (since I'm using the containing: *-selector), but easier to read, and easier for backend-developers to implement/understand.

Here's a Codepen with a bunch of CSS Badges:

What do you think?!

Thanks for reading?

Top comments (2)

Collapse
 
eriksen_dk profile image
Jakob E

👏 Attribute selectors are great. I once wrote a small post on using them to handle responsive styling (shameless self-promotion 😉)

One small thing regarding multiple modifiers. The syntax should be ~= to avoid value name collisions e.g.

[data-color*="lightgray"] { color: whitesmoke; }
[data-color*="gray"] { color: gray; }
Enter fullscreen mode Exit fullscreen mode
<input data-color="lightgray" />
<input data-color="gray" />
Enter fullscreen mode Exit fullscreen mode

Both input will turn out gray because gray is found in both lightgray and gray

If you use ~= (exact word match) you avoid this problem

[data-color~="lightgray"] { color: whitesmoke; }
[data-color~="gray"] { color: gray; }
Enter fullscreen mode Exit fullscreen mode

Thanks for sharing

Collapse
 
madsstoumann profile image
Mads Stoumann

Thanks! You're right about multiple modifiers, of course – I'll update the Pens.