DEV Community

Cover image for Generating Random Human-Readable Slugs in JavaScript
Nick Scialli (he/him)
Nick Scialli (he/him)

Posted on • Originally published at typeofnan.dev

Generating Random Human-Readable Slugs in JavaScript

Often, we'll see random, human-readable slugs (e.g., brave-purple-penguin) in the web development world. These slugs offer the uniqueness of a number ID but can be more playful and fun.


Please give this post a 💓, 🦄, and 🔖 if this was useful!


How to Generate Random Slugs

The key to generating random slugs is:

  • Identify the parts of speech in each slug position
  • Have a list of words for each part of speech
  • Randomly select from that list as you iterate through the positions.

For example, a common pattern for these slugs is adjective-adjective-noun. You might therefore have a list of adjectives, a list of nouns, and a list of your word order:

const adjective = ['blue', 'smiley', 'funny', 'smelly'];
const noun = ['brick', 'kangeroo', 'penguin', 'laptop'];
const words = { adjective, noun };
const order = ['adjective', 'adjective', 'noun'];
Enter fullscreen mode Exit fullscreen mode

Then, you can map over your order and grab a random element from the corresponding word list:

const selected = order.map(partOfSpeech => {
  const choices = words[partOfSpeech];
  return choices[Math.floor(Math.random() * choices.length)];
});
console.log(selected);
// ['funny', 'blue', 'laptop']
Enter fullscreen mode Exit fullscreen mode

Finally, you will want to join this array with a - character so it's kebob-cased:

const slug = selected.join('-');
console.log(slug);
// 'funny-blue-laptop'
Enter fullscreen mode Exit fullscreen mode

Using a Package (I Wrote It!)

Of course, this is a pain because you have to come up with the words yourself and it's not very configurable. Also, you run out of combinations pretty quickly.

To help with this, I made an npm package! It's called random-word-slugs and it has over 15 million slug combinations (and counting)! Plus, there are a bunch of configuration options, such as being able to specify categories of words that you want.

Read on to see how it works!

Installation

Install with npm

npm i random-word-slugs
Enter fullscreen mode Exit fullscreen mode

Install with yarn

yarn add random-word-slugs
Enter fullscreen mode Exit fullscreen mode

Usage

The random-word-slugs package can be used without any parameters and defaults to a three-word, kebab-cased slug. Currently, the default configuration has 15,660,175 unique slug combinations.

import { generateSlug } from 'random-word-slugs';

const slug = generateSlug();
console.log(slug);
// "elegant-green-coat"
Enter fullscreen mode Exit fullscreen mode

The generateSlug function takes up to two arguments. The first argument is the numberOfWords in the slug (defaulting to three) and the secon argument is the package options. The following example makes use of both parameters and provides an option to title-case the output:

const slug = generateSlug(4, { format: 'title' });
console.log(slug);
// "Elegant Happy Green Coat"
Enter fullscreen mode Exit fullscreen mode

Available Options

The options object can have any partial set of the following key/value pairs:

{
  format: "kebab" | "camel" | "sentence" | "lower" | "title",
  partsOfSpeech: ("adjective" | "noun")[],
  categories: {
    adjective: ("colors" | "appearance" | etc...)[],
    noun: ("person" | "animals" | etc...)[]
  }
}
Enter fullscreen mode Exit fullscreen mode

Note that, if provided, partsOfSpeech must be an array the same length as the number of words you're requesting. If using Typescript, the compiler will check this for you.

An example of a completed options object might look like this for a three-word slug:

const options = {
  format: 'camel',
  partsOfSpeech: ['adjective', 'noun', 'adjective'],
  categories: {
    adjective: ['colors', 'appearance'],
    noun: ['animals'],
  },
};
Enter fullscreen mode Exit fullscreen mode

Based on these options, our output might look something like blueBearTall.

Typescript Support for Options

The package exposes a RandomWordOptions<N> type, with N being the number of words in the slug. If you want to use this type to specify an options object, it might look something like this (although a Partial options object is certainly allowed and probably more common):

import { RandomWordOptions } from 'random-word-slugs';

const options: RandomWordOptions<3> = {
  format: 'title',
  categories: {
    noun: ['animals', 'places'],
    adjective: ['colors', 'emotions'],
  },
  partsOfSpeech: ['adjective', 'noun', 'adjective'],
};
Enter fullscreen mode Exit fullscreen mode

Importantly, the generic 3 here will enforce partsOfSpeech being a three-element tuple.

Categories

The categories option allows you to generate your random slug from a subset of categories. Perhaps you only want colorful animals! You can specify one or many categories for the adjectives and nouns that comprise your random slug. The following is a list of categories currently in the repository:

Adjective Categories:

  • time
  • appearance
  • color
  • condition
  • personality
  • shapes
  • size
  • sounds
  • taste
  • touch
  • quantity

Noun Categories:

  • people
  • family
  • education
  • religion
  • business
  • animals
  • transportation
  • thing
  • technology
  • place

Assessing the Combinatorics

When using the package, you might be curious about how many different slug combinations exist. The package exposes a function to help with this called totalUniqueSlugs. This function can be used without arguments and will assume a three-slug adjective-adjective-noun format:

import { totalUniqueSlugs } from 'random-word-slugs';

const totalSlugs = totalUniqueSlugs();
console.log(totalSlugs);
// 100000
Enter fullscreen mode Exit fullscreen mode

Note: The 100000 number shown here is just an example and not a representation of the total number of slugs in the package at any moment (that evolves as words are added).

You can also assess the combinatoric space if you have a different number of words, word ordering, or a subset of categories. In the following example, we'll assume a four-word slug, in the order adjective-noun-adjective-noun, with only color adjectives and animal nouns:

import { totalUniqueSlugs } from 'random-word-slugs';

const totalSlugs = totalUniqueSlugs(4, {
  partsOfSpeech: ['adjective', 'noun', 'adjective', 'noun'],
  categories: {
    adjective: ['colors'],
    noun: ['animals'],
  },
});
console.log(totalSlugs);
// 1000
Enter fullscreen mode Exit fullscreen mode

Again, this 1000 is just an example. Importantly, this could help you determine that you're not comfortable with this limited combinatoric space and you can choose to add additional categories.

Top comments (5)

Collapse
 
marcellothearcane profile image
marcellothearcane

How do you guard against duplication of adjectives, or whatever else you might specify two of?

Collapse
 
nas5w profile image
Nick Scialli (he/him)

It's not included currently, but could pretty easily be adapted:

const adjective = ['blue', 'smiley', 'funny', 'smelly'];
const noun = ['brick', 'kangeroo', 'penguin', 'laptop'];
const words = { adjective, noun };
const order = ['adjective', 'adjective', 'noun'];
const used = new Set();

const selected = order.map(partOfSpeech => {
  const choices = words[partOfSpeech].filter(word => !used.has(word));
  const newWord = choices[Math.floor(Math.random() * choices.length)];
  used.add(newWord);
  return newWord;
});

const slug = selected.join('-');
console.log(slug);
Enter fullscreen mode Exit fullscreen mode
Collapse
 
marcellothearcane profile image
marcellothearcane

That's true, but then if the lists are long it might take a while to filter through. I would use the indexes I think, then you can check much more simply.

Collapse
 
devtony101 profile image
Miguel Manjarres

Cool idea!

Collapse
 
nas5w profile image
Nick Scialli (he/him)

Thanks!