Making slugs with JavaScript and regular expressions

You will sometimes want to generate a suitable URL ‘slug’ based on something the user has entered, such as the name of a blog post, or perhaps the name of a file which is being uploaded.

In order to ensure that your URLs are consistent, valid, and unambiguous, it is common to place the following restrictions on your slugs: allow only lowercase letters, numbers, and dashes (-). For example, a blog post called “Hello World!” might have a resulting slug of “hello-world”. Additionally, it is common to remove leading and trailing dashes from the final slug.

In this post, I’ll introduce a way of doing this in JavaScript.

Why JavaScript?

You might wonder why we’d use JavaScript to generate a slug. I don’t recommend relying on it, since form data etc. can be faked (you will need to validate the slug on the server before using it). However, it might be useful to let a form automatically suggest a slug based on something the user has entered, so s/he can see what it will look like. WordPress does that when you type the name of a new blog post, for example.

Also, JavaScript is a nice simple language which anybody with a web-browser can test. I’ll cover something similar in PHP later.


First, convert the string to lowercase:

str = str.toLowerCase();

We then use a regular expression to convert all invalid characters into dashes:

str = str.replace(/[^a-z0-9-]/g, '-');

That line might look a little odd if you are not familiar with regular expressions (see the W3Schools JavaScript reference on the RegExp object for full details). The part in square brackets says “find any character which is not in ranges a-z or 0-9, and which isn’t a dash”. The /g tells it to find all matches (not just the first one). And the ‘-‘ at the end tells it to replace each of these matching characters with a dash (-).

This particular regular expression is quite effective, but if you try putting in “Hello !-# World” then the output slug will be “hello- – – – -world”. This is because each invalid character was replaced by a dash one-by-one. This is not ideal, so we can refine our regular expression to look like this:

str = str.replace(/[^a-z0-9]+/g, '-');

The difference is subtle. Firstly, we’ve taken the dash out of the square brackets. This means that all dashes will be replaced too. Secondly, we’ve put a plus sign after the square brackets. This means it will no longer match one character at a time. Instead, it will match groups of 1 or more consecutive characters, and replace the whole group with a single dash. That means our “Hello !-# World” example becomes simply “hello-world”.

We’re not quite done yet though, because we haven’t taken leading and trailing dashes into account. If we put “!Hello World!” into our code so far, we’d end up with a slug saying “-hello-world-“. The leading and trailing dashes are unsightly, so how do we get rid of them? There are lots of ways.

The simplest (and most readable) way is probably to use string functions to check/replace the first and last characters explicitly. However, a cleaner (and possibly more efficient) way would be to use a second regular expression replace. This is in addition to the one above:

str = str.replace(/^-|-$/g, '');

This regular expression says “find a dash at the beginning of a line or a dash at the end of a line”. The function then replaces any such matches with nothing. It is important to realise that this means a slug consisting of a single invalid character (or just a dash) will be completely emptied by this operation.

Putting it all together

We could put our code into a function. This lets us pass a string to the function, and get a slug back out:

function make_slug( str )
    str = str.toLowerCase();
    str = str.replace(/[^a-z0-9]+/g, '-');
    str = str.replace(/^-|-$/g, '');
    return str;

I hope that’s useful. Happy slugging!

5 comments on “Making slugs with JavaScript and regular expressions

  1. //A different approach to handle some chars:

    var strip = /[^ws-]/g
    , hyphen = /[-s]+/g;

    var map = {
    from: ‘àáäãâèéëêìíïîòóöôõùúüûñç·/_,:;’
    , to : ‘aaaaaeeeeiiiiooooouuuunc——‘

    function slug(str) {

    for (var i=0, j=map.from.length; i

Leave a Reply

Your email address will not be published. Required fields are marked *