by

A Small Guide for Naming Stuff in Front-end Code

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 teammates or a future version of you.

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 questions, “what relies on this class and under what conditions will I see it applied?”

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 true;
 } else {
   return false;
 }
}

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 messages= prepareMessages();

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.

Footnotes, Sources, and Whatnots

1 Give or take one thing


Credits

Special thanks to @SomeRandomDev for sharing ideas on naming principles and Dani Meyer for collaborating on complex and complicated function naming.

15 Comments


  1. I think there is a mistake in “Is the loop using for in or for of ?”. The code block shows a forEach example instead of for in/of.


    1. Thank you! I can’t believe no one’s called that out. I had to go back to the original gist but I’ve made the update.


    1. Whoops.

      Fixed. Thank you.


  2. Using i and j for loop index variables is decades-old and very well-known. I’m really not sure why replacing these with ‘idx’-derivatives is in any way beneficial. You know from the context what you’re looping through, so it seems spurious in the majority of cases.


    1. This is a valid criticism, and there are three reasons I advise against it
      The first is the potential to become meaningles with code entropy. In small loops where there’s just 2-3 lines, I really get it. But I’ve seen cases (too many to count) where the loop grew to up to 100 lines and now the loops start and end aren’t even on the screen together any more and i is no longer meaningful. Most of us don’t plan on writing gigantic loops, but it happens all the same. So when that loop grows, i is now an arbitrary letter.

      The second reason I advise against it is because we can’t always predict how our code grows. I’ve seen cases where nested loops made it to k and I think even l. The single-letter arbitrary variable name sets a foundation for increasingly hard-to-follow code. A friend of mine once encountered code that made it all the way to double letters (that’s right, 26+ nested loops). It’s not like the code started that way. But that’s how it ended.

      The third reason is findability. A single loop in a single file is no big deal. But as soon as there’s multiple loops (nested or not), it becomes increasingly difficult to find how that variable affects code. I really don’t enjoy having to search for i in code.

      But, keep in mind, this is a guide, not a set of rules. You’re allowed to disagree and that’s perfectly fine. I share this particular guidance because I have stories of how single-letter variables became a nightmare.


      1. Thanks for responding, but I still don’t see how your minimal recommendation of using idx is any better than i when i is canonical in the field.

        To answer your other points:

        If you have very long functions or deeply-nested code, you have problems with code structure, not variable naming.

        If you’re searching for a particular loop, I imagine you’d be searching for the thing being iterated over, not the indexing variable name, i.e. you’d be searching for foodGroup rather than foodGroupIdx. Otherwise you’d miss the times you’d called the indexing variable something different, like just idx (as you did in your example above).

        I’d regard the need to introduce more than 2 or 3 indexing variables in a single place as a bad code smell, and a sign that you should extract some code into separate functions. The same goes for if the use of the variable is far from where it is declared, e.g. functions running for longer than a page or so. Yes, sometimes imperfect code may be unavoidable, and that’s exactly where your recommendation would be relevant.

        If you’re naming variables “just in case” the function blows up into a monster further down the road, again it’s refactoring which need attention, and updating variable names is a valid part of that process.

        I totally agree with the rest of your recommendations; this one just stood out as a bit arbitrary. Thanks for posting such a thought-provoking piece.


        1. The reason for idx over i really just boils down to the behavior of ctrl + f in the IDE. Searching for the single letter i is much more of a nuisance (and risks more false positives) than searching for idx. And yes, I know that I could write a quick regex for word boundaries, but…again. It’s a nuisance.

          BTW, I absolutely agree that deeply nested loops is a code-structure problem and of course should be avoided.

          The reason for this very peculiar recommendation is because I have too often been at the mid-life-crisis of a piece of code where it was fragile-enough that I couldn’t refactor it but not so fragile I had time. Single-letter variables have burned me too many times to count.

          I know it’s the industry standard, and fundamentally I think it’s a bad standard that doesn’t account for entropy. I am A-Ok with people objecting to it, but if they’d lived my experiences, I’m pretty sure they’d understand why I oppose it.


  3. In the section “Naming things in JavaScript”, your “isHot” function is probably better renamed “isNotHot”.

    As long as I’m suggesting a fix, why not this construction:


    function isHot() {
    return (temperature >= 100 );
    }

    Thank you for a very important article, on a subject that developers should pay more attention to!


    1. That’s a typo if ever I’ve made one. Thank you for calling it out; I’ve corrected it.

      I intentionally chose the more drawn-out construction so that it might be a little more clear to folks newer to JavaScript.


  4. Very interesting guide – thank you!

    Two small comments:

    1. Although I agree with the principle in general, in the example const number = addNumbers(), assigning the result to const sum seems clearer. Maybe not the best example to illustrate the principle?
    2. (2) In the function isHot(), the return statements appear to be switched (temperature > 100 should return true, and vice-versa).

    1. That’s a really good point! const sum seems much clearer. But in the one case, I was actually trying to explain parity between the variable name and function name. So while yours is a substantial improvement, it’s an improvement on my unsuitable example. I’ll change the example to something that better illustrates the point (maybe messages = getMessages() or something). Thank you for calling this out.


  5. Your function `addNumbers` doesn’t really check whether it gets numbers, and also may concatenate strings. So I would rename its parameters to `firstAddition`, `secondAddition`, and the arguments to `firstNumber`, `secondNumber`. The function itself should be renamed to concatenate, for example.


    1. I appreciate your feedback and that is a 100% valid criticism. We know that the function will do both: if passed two numbers, it will add them. If passed number and non-number, it will coerce them into strings and concatenate.

      My goal in providing the example was not to provide a thoroughly planned and type-checked function with sanitized inputs, because that would distract from my very basic goal of discussing how to name things. Maybe the function is better named, addOrConcatenateNumbersOrStrings, but I don’t personally feel that helps keep focus where I want it: maintaining name-parity between arguments and parameters.

      I am glad that you came along to highlight this example, though! Maybe I’ll write another guide called, “a small guide for small(ish) JavaScript functions” and use this discussion to highlight the importance of type-checking and sanitizing inputs.

Comments are closed.