Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

@arraypress/slug

URL slug generation with transliteration, collision handling, and flexible options. Zero dependencies.

Works in Node.js, Cloudflare Workers, Deno, Bun, and browsers.

Install

npm install @arraypress/slug

Functions

slugify(input, options?)

Generate a URL-safe slug from any string.

import { slugify } from '@arraypress/slug';

slugify('Hello World!')              // 'hello-world'
slugify('Crème Brûlée Recipe')       // 'creme-brulee-recipe'
slugify('Rock & Roll')               // 'rock-and-roll'
slugify('Straße nach Berlin')        // 'strasse-nach-berlin'

// Options
slugify('Hello World', { separator: '_' })     // 'hello_world'
slugify('Hello World', { lowercase: false })   // 'Hello-World'
slugify('Long Title Here', { maxLength: 10 })  // 'long-title'
slugify('The Art of War', { stopWords: ['the', 'of'] }) // 'art-war'

Options: separator (default '-'), lowercase (default true), transliterate (default true), maxLength (default 0 = unlimited), stopWords (default []).

uniqueSlug(input, exists, options?)

Generate a unique slug by appending a counter if needed. Accepts sync or async exists functions.

import { uniqueSlug } from '@arraypress/slug';

// With a database check
const slug = await uniqueSlug('My Product', async (s) => {
  const row = await db.prepare('SELECT 1 FROM products WHERE slug = ?').bind(s).first();
  return !!row;
});
// => 'my-product' or 'my-product-2' if taken

// With a Set
const taken = new Set(['hello-world', 'hello-world-2']);
const slug = await uniqueSlug('Hello World', (s) => taken.has(s));
// => 'hello-world-3'

isValidSlug(slug, options?)

Check if a string is a valid slug.

import { isValidSlug } from '@arraypress/slug';

isValidSlug('hello-world')     // true
isValidSlug('Hello World')     // false
isValidSlug('hello--world')    // false
isValidSlug('hello_world', { separator: '_' }) // true

STOP_WORDS

Common English stop words for slug generation.

import { slugify, STOP_WORDS } from '@arraypress/slug';

slugify('The Art of War', { stopWords: STOP_WORDS }) // 'art-war'

formatLabel(slug, options?)

Convert a slug back into a Title Case display label — the inverse of slugify for display purposes.

import { formatLabel } from '@arraypress/slug';

formatLabel('future-bass')                              // 'Future Bass'
formatLabel('best-of-the-year')                         // 'Best Of The Year'
formatLabel('138bpm-trance')                            // '138bpm Trance'  (numeric-leading token kept lowercase)
formatLabel('sound_design', { separator: '_' })         // 'Sound Design'
formatLabel('ai-tools', { preserveCase: ['AI'] })       // 'AI Tools'
formatLabel('daw-midi-export', { preserveCase: ['DAW', 'MIDI'] })  // 'DAW MIDI Export'

Use for taxonomy archive headings (/tags/future-bass → "Future Bass"), breadcrumbs, sitemap entries — anywhere you have a slug and don't have the original title cached. Unlike slugify, it preserves stop words because they're usually part of the proper display name.

preserveCase matches case-insensitively against tokens, so passing ['AI', 'DAW'] matches lowercase ai/daw tokens in the slug.

Transliteration

Built-in support for Latin accented, German, Nordic, Turkish, Polish, Czech, and common symbols. &and, @at, eur, £gbp, ©c, etc.

License

MIT

About

URL slug generation with transliteration, collision handling, and flexible options.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages