$ snippet slugify
Slugify a string for URLs
Turn 'Crème Brûlée & Friends!' into 'creme-brulee-and-friends' — strips accents, handles symbols, trims dashes.
const SPECIAL = { "ß": "ss", "æ": "ae", "œ": "oe", "ø": "o", "ł": "l", "đ": "d", "þ": "th" };
function slugify(str, { maxLength = 80 } = {}) {
return str
.toLowerCase()
.replace(/[ßæœøłđþ]/g, (c) => SPECIAL[c])
.normalize("NFKD") // split accented chars into base + mark
.replace(/[\u0300-\u036f]/g, "") // drop the marks
.replace(/&/g, " and ")
.replace(/[^a-z0-9\s-]/g, "") // remove anything else
.trim()
.replace(/[\s_-]+/g, "-") // collapse whitespace/dashes
.replace(/^-+|-+$/g, "")
.slice(0, maxLength)
.replace(/-+$/, "");
}How it works
normalize("NFKD") decomposes é into e + a combining accent, which the next line removes — that single trick handles most Latin-script languages. Everything not alphanumeric is dropped, whitespace becomes one dash, and edge dashes are trimmed so you never get -hello-.
Gotchas
- Non-Latin scripts (Cyrillic, CJK, Arabic) are removed entirely by this version. If you need them, allow
\p{L}\p{N}with theuflag instead ofa-zA-Z0-9, and keep in mind browsers percent-encode them in URLs. - Slugs are not unique. Append an id or a counter when storing them.
- Some letters are not decomposable by NFKD (
ß ø ł æ) — that's what theSPECIALmap is for. Extend it for languages you serve.
Ad slot