public
Last active

Experimenting with component-based HTML/CSS naming and patterns

  • Download Gist
README.md
Markdown

NOTE I now use the conventions detailed in the SUIT framework

Template Components

Used to provide structural templates.

Pattern

t-template-name
t-template-name--modifier-name
t-template-name__subcomponent-name--subcomponent-modifier-name

Examples

t-icon
t-icon--large

t-btn
t-btn--large

t-media
t-media__img
t-media__img--large
t-media__opt
t-media__body

State Components

Used to indicate the state of a component

Pattern

is-state-type

Examples

is-hidden
is-collapsed
is-expanded
is-selected

JavaScript Components

Used to provide JS-only hooks for a component. Can be used to provide a JS-enhanced UI or to abstract other JS behaviours.

Pattern

js-action-name

Examples

js-submit
js-action-save
js-ui-collapsible
js-ui-dropdown
js-ui-dropdown--control
js-ui-dropdown--menu
js-ui-carousel

About theming Components

Could reuse the Template Component naming convention, for example:

specific-name
specific-name--modifier-name
specific-name__subcomponent-name
specific-name__subcomponent-name--subcomponent-modifier-name

Or just let anything go.

html-example.html
HTML
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
<!--
What if we used more white-space around class values?
Does it make the code more readable and surface/separate the components
among the rest of the info in the HTML?
-->
 
<div class=" t-unit t-media ">
<div class=" t-media__img ">
<a href="#">
<img class=" product-img " src="http://example.com" alt="">
</a>
</div>
<form class=" t-media__opt js-action-rate ">
<button class=" product-rating " type="submit">
<div class=" product-rating__panel ">
<span class=" product-rating__points ">
5
</span>
<span class=" product-rating__label ">
upvotes
</span>
</div>
<strong class=" product-rating__action t-btn btn-normal ">
Upvote
</strong>
</button>
</form>
<div class=" t-media__body ">
<h2 class=" h2 ">
<a href="#">Product title</a>
</h2>
<p>[content]</p>
<ul class=" t-uilist--hz ">
<li><a class=" tag " href="#">tag name</a></li>
<li><a class=" tag " href="#">tag name</a></li>
<li><a class=" tag " href="#">tag name</a></li>
</ul>
</div>
</div>

Patterns in class names are great.

Adding more white-space doesn't make it more readable to me and as far as it makes sense, I believe we should try not to go too far away from grammar rules e.g. not " syntax " but "syntax".

Spaces around class names are perfectly acceptable with the existing grammar. I don't actually use it, because I think something like smarter syntax highlighting could be more effective.

Yea, agree. What I meant was, that I prefer tying coding style to typographical rules or conventions. Guess it's not grammar per se.

Something that is a little unfortunate: Double-clicking the names to just edit parts of them doesn't work well since underscores are selected together, but dashes not. So for example with this t-template-name__subcomponent-name, if you wanna select "subcomponent-name" by double-clicking, name__subcomponent gets selected or only name.

An option would be the other way around: t_template_name--subcomponent_name. But I also don't like it that much since underscores visually separate the parts more than dashes.

I'm interested in this approach.

One question, doesn't prefixing your classes with the parent classname ignore the benefit of hierarchy? For instance:

.product-rating {}
  .product-rating .panel {}

Insead of:

.product-rating {}
.product-rating__panel {}

Or worse yet:

.product-rating {}
  .product-rating .product-rating__panel {}

The second option could lead to .product-rating_panel being used without any regard for whether the DOM node is actually nested inside .product-rating.

The third option just seems redundant.

Andrew, I believe the logic is that name spacing your selectors allows devs that come along behind you to understand that .product-rating__panel is meant to be a sub-component of .product-rating. Thus, it should always be used inside that DOM node. It isn't meant to stand alone or outside that node.

The other benefit I see is, avoiding descendent selectors where possible allows you to utilize the cascade more fully. You can modify the .panel rule with another single class rule that comes later in the cascade. You don't have to use another descendent selector or !important to override the original class like you would if you used:

.product-rating .panel {}

Adding the modifier class .foo to the original .panel would not override the original rule unless you wrote the new rule as:

.product-rating .foo {}

Or

.panel.foo {}

(Chaining selectors, as above, can give you a performance hit and so should be avoided where possible.)

If you had used the .product-rating__panel style of naming, a second single class would modify the necessary properties. For example:

.product-rating__panel--foo {}.

Yes, it does get long... and yes, I've struggled with this as well (in fact, I'm reevaluating naming conventions now for an extremely large project). But for keeping the code maintainable on a site with a large number of developers, this seems logical. You'd be left with these rules (all with the same specificity):

.product-rating {}
    .product-rating__panel {}
    .product-rating__panel--foo {}

(Harry Roberts suggests indenting the rules in your CSS, so that they mirror the DOM instead of nesting rules so that specificity is increased.)

For JS hooks you could use data-attributes, e.g.

<form class="t-media__opt" data-behavior="action-rate">

With options:

<form class="t-media__opt" data-behavior="action-rate" data-scale="[0..5]">

As used in Twitter Bootstrap, Rails.

You could use data attributes, but does that make more semantic sense than using a class? My weakly held position is that they are roughly equal. If there isn't a clear benefit to using data attributes then it's worth noting that they carry a querying performance penalty.

Meleyal as a point... class should be used for styling, not add functionnality. So using "data" parameter should be a better choice.

@asakurayoh Looking at the jsperf tests for querying class selectors vs. data attribute selectors, I lean towards keep JS hooks as classes. It would be nice if querying performance was the same or at least not as big of a diff between the two. It would be nice to keep JS hooks separate from CSS hooks in the HTML markup.

I've started to adopt this BEM like syntax as well and mixing it with my understanding of SMACSS.

.module {...}
.module--modifier {...}
.module__component {...}
.module__component--modifier {...}

I've seen Jonathan Snook talk about using a syntax like:

.module {...}
.module-submodule {...} /* Module Modifier */
.module--subcomponent{...}

.product-rating {...}
.product-rating-modifier {...}
.product-rating--label {...}

I like this naming convention as well, though I like the double dash for modifiers.

Another naming convention I've thought about similar to the one above looks like:

.module {...}
.module--modifier {...}
.module-component {...} /* Single dash instead of underscores */
.module-component--modifier {...} 

.product-rating {...}
.product-rating--modifier {...}
.product-rating-label {...}

The issue I see with this is it is hard to see the difference between modules and components when module names are made up of multiple words like product rating.

product-rating {...} /* Module */
product-rating-label /* Component with single dash. Harder to understand label is component of product rating. */
product-rating__label /* Component with double underscores. Easier to understand */

One way to get around this would be to use camelCase for module names and not use dashes in module names, only for modifiers (double) and components (single)

.productRating {...}
.productRating-label {...}
.productRating--modifier {...}

All of the naming conventions look odd at first. I think it is important to remind others the overall goal of a HTML class naming convention would be to add clarity for developers, I prefer the BEM like syntax the most, though it can take a while for other developers to understand the thinking behind it and go accustom to it .

I've put together a repo with a collection of common class naming patterns I've seen. CSS-Modules-Subcomponents-And-Modifiers-Collection

Here's a pattern I've been experimenting with:

http://jsfiddle.net/mindplay/XmfBa/

I know the leading hyphen looks odd at first glance, but give it a chance - read through the description in the comments and review the example.

I'd love to get your feedback.

We've been playing around with the BEM syntax since late 2012, and we arrived at the following naming convention:

.componentName {...}
.componentName_Element {...}
.componentName_Element.componentName_Element--modifier {...}

  • camelCase is used for names that a single word can't depict (ex: displaySwitcher)
  • A single underscore is used to separate Blocks and Elements (Perhaps we'll get back to __ if we realize that some coders in our team use the _ wrongfully, but for now _ seems enough)
  • We separate modifiers with two dashes to make it stick out and make its role obvious. Also text editors will usually stop the selection on the hyphen when double-clicking, so it makes sense to use it there and not in any other separator.
  • We prefix all modifier classes with the non modified class to ensure the specificity will always be a bit higher, as we've had issues with that (due to modernizr classes iirc).

This convention along with the use of Sass and a semantical file system organisation has boosted our productivity and made maintenance a breathe.

I love the BEM approach in cases where there's a strict hierarchy, but I find it very verbose when working with more global components.

For example:

.header {}
.article .header {}

is much more flexible and reusable than:

.article__header {}

which is very specific to that block.

I use BEM mainly for widgets and cases where I know I really need the namespace, but doing everything the BEM way kind of defeats the Cascading part of CSS in my opinion.

I totally love the states and js hooks though, I think that's great practice as it instantly shows what the component is for.

Let's say I have a menu and within this menu I have the list of items. What's the correct naming then?

Menu and menu list should be:

.menu {}
.menu--list {}

But what about the items? Should be .menu--list--item or .menu__list--item?

rafaelrinaldi

.menu {}
.menu--list {}

The item naming would then fall like this if you needed to modify the menu item

.menu__item--list {}

You could call the modifier what you wanted but it makes sense to keep the modifier name the same as the parent modifier. Then you can couple the new menu item modifier with the parent modifier.

Gotcha! Thanks @mykz.

Zeokat interesting code, i have to adjust it a little. Thanks.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.