A small guide for naming stuff in front-end code
Advertisement

Reading Time: 9 minutes

Phil Karlton has famously said that the two hardest things in computer science are naming things and cache invalidation1. That’s still kinda true in front-end development. Naming stuff is hard, and so is changing a class name when your stylesheet is cached.

For quite a few years, I’ve had a gist called “Tiny Rules for How to Name Stuff.” Which is what you think: little tiny rules to follow for naming thing. I think maybe now it’s time to turn those tiny rules into a small guide where I give some principles behind those rules.

A screen grab of terrible css class names
Once you’ve started down this path, it’s time to stop walking

The Foundations for a Guide

The Four Cardinal Rules for Writing Code

Before we start, I want to share these rules that I enforce on all my teams:

  • Don’t make code fast before it is good
  • Don’t make code good before it works
  • Don’t write code that would make a teammate curse your name
  • Don’t forget that future-you is a teammate

Any styleguide or guideline for how to write code is about those final three points: Write good code that won’t piss off your teammate or a future version of you.

Advertisement

A Guidebook is not a Rulebook

Rules will beget rule-followers and rule-breakers; rule-enforcers and rule-lawyers. A team of these kinds of folks becomes toxic very quickly.

Guidelines are suggestions and warnings based on experience. Guidelines make story tellers out of experienced teammates and daredevils out of the new ones.

A guideline is merely a cautionary tale based on past experiences. That’s how guidelines should be written, and that’s how they should be followed. That is why this guide uses words like “favor”, “prefer”, “try”, and “avoid” over “do” and “don’t”. It’s also why this has principles behind the naming convention.

Deviate when it makes sense, but always tell your team why you deviated, lest they curse your name.

Naming CSS Classes

Stateful Class names

Is it a state that is only one of two conditions? (i.e. a boolean)

  • Prefix with is/has
Is it a state that is determined by something on its own element?
  • Use .is; that describes the element’s own state

Prefer this:

.isOverflowHidden
.isHidden
.isScrollable
Is it a state that is determined by its children?
  • Use .has; this describes the state of something inside the element
  • Try to make the end part a noun

Prefer this:

hasOverflowHidden
.hasHiddenChildren
.hasScrollableChildren

Is it a state that is a negative ?

  • If you can, avoid this because it can be hard to use; try to re-write as a positive
  • Use isNot and/or hasNo
  • Use an adjective for “is”
  • Try to stick a noun at the end for “has”; “Els” is a fine abbreviation for elements
  • If all else fails, add “able”

Prefer this:

.isNotHidden
.hasNoHiddenEls
.isNotScrollable
.hasNoScrollable
.hasNoScrollableEls

In general, try to write the class in a way that it directly answers a close-ended question that could start with is, has, will, did, can, or should.

Is it a CSS class that JavaScript needs?

  • Prefix with js/ui

Does JavaScript need it just to find it (no CSS being set)?

  • Use .js

Prefer .jsSubmitButton .jsVideoPlay

Does JavaScript need to change it so that CSS can style it?

  • Use .ui
  • Use an adjective or a past-tense

Prefer .uiSubmitted .uiVideoPlayed

Does a Test need it?

  • Use .qa

In general try to write a class in a way that answers the question, “what relies on this class”

Are these class names for a component or module?

  • Avoid words that prescribe the content
  • Avoid words that prescribe the markup
  • Avoid ambiguously describing scope or presentation
  • Avoid using words to describe variation or relationships

Avoid this:

.logos // suggests it can only have logos (prescribed content)
.logoList // suggests can only be used with ul, ol, dl (prescribed markup)
.logoGridList // suggests it always makes it looks like a grid (ambiguous presentation)
.darkLogoGridList //not obviously related, (words describe variation or relation)
.logoGridListBlack // Not clear what is black (ambiguous scope) 
  • Prefer words that describe the purpose
  • Prefer describing scope
    • Consider abbreviating scope if meaning can be obvious
  • Prefer convention to prescribe variations
  • Prefer convention to describe relationships

Prefer this:

.mediaSet // 'Set' ->; purpose, 'media' -> scope (could apply to video, picture, img)
.mediaSet--grid-md // '--' ->; variation by convention, 'grid' -> purpose  , 'md' -> scope (abbreviated)
.mediaSet--theme-dark // '--' ->; variation by convention, 'theme' -> scope, '-dark' -> variation
.mediaSet__media // '__' ->; relationship by convention , 'media' ->  purpose

BEM is a well-known convention that helps address relationships and variations. You don’t have to use BEM; you just have to be consistent.

In general write class names that answer the question, “What content could I use this on and how will it present that content?”

Should I Use hyphens or underscores to separate a class prefix?

  • Be consistent
  • If everyone else is using hyphens, you should, too.
  • If you’re the first person on the project, use camelCase; it’s easier to select camelCased text in an IDE than it is hyphenated text

In general, choose the convention that’s the least disruptive to the team.

Is this a SRP (single responsibility principle) kind of class?

Sometimes a class only has one property because it’s used in combination with other classes.

  • Don’t use the value of a specific CSS property
  • Do give the purpose of that specific CSS property
  • Avoid suggesting usage with only specific HTML elements
  • Try suggesting usage with kinds of content

Avoid this:

 .button--yellow {
  color: yellow;
 }

Prefer this:

 .button--warn {
   color: yellow 
 }

Avoid this:

 .imgFloatLeft {
  float: left;
 }
 
 .imgFloatRight {
  float: right;
 }

Try this instead:

.rtfMedia--left {
 float: left;
}

.rtfMedia--right {
 float: right;
}

In general try to write classes that won’t mislead developers if a property changes.

CSS Pre-processor Naming (SCSS, SASS, Less, Stylus)

Are these variables for colors?

  • Don’t let the variable name indicate the variable value (what if the value changes?)
  • Indicate meaningful aspects of the value like hue, lightness, or darkness
  • Use relatives and superlatives (er, est) for variations on a hue
--colorNeutralDarkest
--colorNeutralDarker
--colorNeutralDark
--colorWarmDarker
--colorWarmerDarkest

In general try to write variable names that wouldn’t confuse or mislead a teammate who’s colorblind or visually impaired.

Generic Variables

Is the variable going to be used more than once?

  • Start with the UI element name
  • Be more descriptive in the middle
  • End with the CSS property it affects
  • Avoid putting any information about the value of the variable in the name
$linkColor: rgb(165,220,220,220);
--linkColor: var(--colorCoolDark);
$formControlVerticalPadding: .375em;

In general prefer variable names that indicate how they are to be used instead of what they do.

Is this variable used more than once, but there’s a different variable for pseudo classes?

  • Start with the UI element name
  • Then add the CSS property it affects
  • End with the state
$linkColor: rgb(165,220,220); 
$linkColorHover: rgb(165,165,220); 
--linkColorFocus: var(--colorCoolDarker);

In general choose variable names that make it easy to identify their relationship to one another while a developer is skimming.

Is the variable used once?

  • Start with class name that the variable is used in
  • End with the CSS property it affects
.foo { 
  $fooHeight: $containerHeight / 3; 
  width: $fooHeight / 2; 
  height: $fooHeight; 
}

In general show that a variable is meant to be used in a particular scope.

Naming things in JavaScript

Functions that return things

Does the function return a boolean?

  • Prefix with “is” or “has”
  • Use “is” with an adjective
  • Use “has” with a noun
  • Avoid using a negative

Prefer this:

function isHot() {
 if (temperature > 100 ) {
   return false;
 } else {
   return true;
 }
}

function hasEggs(carton) { 
  if (carton.eggs.length > 0 ) { 
    return true;
  } else { 
    return false;
  }
}

In general name the function to answer a close-ended question about a subject that could start with is, has, will, did, can, or should.

Does the function return anything else ?

  • Prefix with get
  • End with thing it returns
  • Use a plural form if it returns an enumerable
function getTemperature () { 
  return temperature; 
} 
function getEggs() { 
  const eggs = []; 
  return eggs; 
}

In general name the function to answer an open-ended question you have about a subject.

Are you assigning the thing that the function returns to a variable?

Use the noun part of the function

const foods = getFoods();
const number = addNumbers();

In general name a variable in a way that shows a relationship to the function that created its value.

Functions that do things (don’t have a return)

  • Start with a verb, end with a noun
  • Make the noun the thing that is the recipient of the action:

Prefer this:

calculateTemperature()
findThermometer();

In general name a function that describes an event happening to a subject.

Looping through stuff

  • Avoid using single-letter variable names (e.g. i);
  • Use at least-three letters
  • Prefer a name that easily indicates what it represents
  • Prefer being as long as is helfpul

Is the loop a.forEach on an array or array-like (iterable) structure?

  • Make the array/iterable a plural noun
  • Make the item iterated on the singular
const fruits = ['banana', 'avocado', 'tomato']; 

fruits.forEach((fruit) => { });

Does the .forEach need an index?

  • At the very least, use idx
  • Avoid single-letter variable names
const fruits = ['banana', 'avocado', 'tomato']; 
fruits.forEach((fruit, idx) => { });

If you have nested loops append idx to the item name in at least the nested loop.

    const foodGroups = [ ['banana', 'avocado', 'tomato'], ['steak', 'sausage' ] ];
    
    foodGroups.forEach((foodGroup, idx ) => {
    
        foodGroup.forEach((food, foodIdx) => {
        
        });
    });

Is the loop using for in or for of ?

  • Make the object/array’s noun a plural form
  • Start any counter variables with idx if you need a counter
    • If you have to go more than one level deep, append idx to the name of the nested item
  for (let idx = 0, fruit; idx < fruits.length; ++idx) {
   fruit = fruits[idx];

   for (let goodFruitIdx = 0; goodFruit; goodFruitIdx < goodFruits.length; ++goodFruitIdx) {
       goodFruit = goodFruits[goodFruitIdx]
   }
 }

In general name things in loops with the expectation that the block will get big enough that someone will forget what you are looping over.

Functions in General

Complex Functions (Functions with many parts)

Sometimes, the difficulty in naming a function comes from the fact that it does many things (i.e., it has complexity).

  1. Identify all of the tasks within this function (units of work that have single, testable activities)
  2. Name those tasks (they either do or they return)
  3. Create functions whose names represent their tasks
  4. Re-evaluate the function now that it is a collection of named tasks and create a name that summarizes those tasks

Instead of this:

function getLiElement(titleNode) { // function name somewhat generic
    const listEl = document.createElement('li');

    const { tagName} = titleNode;
    let type = 'biggest';

    switch (tagName) { // task that determines a part of a class name
        case 'H3':
            type = 'bigger';
            break;
        case 'H4':
            type = 'big';
            break;
        case 'H5':
            type = 'base';
            break;
        default:
            break;
    }

    const itemTypeClass = `articleTOC__item--${type}`; // operation that concatenates strings
    listEl.classList.add('articleTOC__item');
    listEl.classList.add(itemTypeClass);
    
    return listEl;
}

Prefer This:

// function that does one thing with name that reflects what it does
function getTOCItemType(titleNode) {
     if (!titleNode) return;
    const { tagName} = titleNode;
    let type = 'biggest';
		
    switch (tagName) {
        case 'H3':
             type = 'bigger';
            break;
        case 'H4':
            type = 'big';
            break;
        case 'H5':
            type = 'base';
            break;
        default:
            break;
    }
	
    return `articleTOC__item--${type}`;
}

function getTOCItemElement(titleNode) {
    const listEl = document.createElement('li');
    // variable that summarizes what the other function has done
    const tocElementTypeClassname = getTOCItemType(titleNode);
	
    listEl.classList.add('articleTOC__item');
    listEl.classList.add(tocElementTypeClassname);
    return listEl;																		
}

In general, smaller functions are easier to name. Try to make a function small enough that its purpose reveals itself so that you can name it.

Complicated Functions (Functions that are difficult to read)

Sometimes, the difficulty in naming a function comes from the fact that parts of it are confusing to read (i.e., it’s complicated).

  1. Determine if it is complex. If it is, make it less so.
  2. Look at comparison operations (if, switch) and determine if it is self-evident what the logic is doing
    • Consider creating a variable for each logical comparison (follow the guidance for how to name boolean variables)
    • Consider creating a variable that summarizes the logical comparisons
  3. Eliminate “magic numbers” and “magic strings” (values that exist, but their reason for being those values is not self-evident)
    • Consider moving numbers in a setTimeout to variables
    • Consider making values used for validating parameters their own variables
    • Consider naming all of the parts of a concatenated string

Instead of this:

function getTOCItemType(titleNode) {
    if (!titleNode) return;
    const { tagName} = titleNode;
    let type = 'biggest'; // variable name whose purpose isn't explained

    switch (tagName) {
        case 'H3':
            type = 'bigger';
            break;
        case 'H4':
            type = 'big';
            break;
        case 'H5':
            type = 'base';
            break;
        default:
            break;
    }
   	
    return `articleTOC__item--${type}`; // "magic string" ; unclear why type is added to a string
   }

Prefer this:

function getTOCModifierClass(titleNode) { // name more clearly explains purpose
    if (!titleNode) return;
    const { tagName} = titleNode;
    const blockName = 'articleTOC__item'; // variable that explains its value
    const modifierSeparator = '--' // variable that explains its value
    let modifierName = 'biggest'; // changed variable name that explains why it changes

    switch (tagName) {
        case 'H3':
            modifierName = 'bigger';
            break;
        case 'H4':
            modifierName = 'big';
            break;
        case 'H5':
            modifierName = 'base';
            break;
        default:
            break;
   }
   	
    return `${blockName}${modifierSeparator}${modifierName}`; // clarity that this is returning a BEM class
}

In general, functions that contain unnamed operations are hard to name. Try to name the complex operations so that the code reads like a summary of the work it does. This helps you discover its name.

Using Functions (Function / argument parity)

Keep function parameters similar — but not the same, as the function arguments:

/* parameters are firstNum, secondNum */
function addNumbers(firstNum, secondNum) {
    return firstNum + secondNum;
};

const first = 1;
const second = 2;
const sum = addNumbers(first, second); /* arguments are first, second */

In general show a relationship between parameters and arguments, but doesn’t cause a search to yield confusing results.

Parameter names

  • Avoid putting the type as part of the name; that’s what JSDOC is for
  • But, if you feel like it’s super important to include the type, put it at the beginning function
function addNumbers(numberFirst, numberSecond) {
}

In general give the right information in the right way.

This is a Living Guide

I still update the gist that inspired this every few months as I discover some other little way to name something consistently. I’m still trying to sort out how to name Classes, static methods, private properties, and even file names. As I figure out a naming pattern that works for me and for my teams, I’ll share them.

Regardless of whether you use my guide or make your own, make sure it’s always telling the stories of what you’ve learned.