Skip to main content

Overview

The slugify utility function converts any string into a URL-friendly slug format. It’s used throughout the application to create clean, readable URLs for podcast episodes.

Function Signature

sluggify(text: string): string

Parameters

text
string
required
The text string to convert into a slug. Can include spaces, special characters, uppercase letters, and Unicode characters.

Return Value

slug
string
A lowercase, hyphen-separated string with special characters removed, suitable for use in URLs.

Transformation Process

The function applies the following transformations in order:
  1. Convert to string - Ensures the input is a string
  2. Lowercase - Converts all characters to lowercase
  3. Trim - Removes leading and trailing whitespace
  4. Replace spaces - Converts spaces to hyphens
  5. Remove special characters - Keeps only word characters and hyphens
  6. Collapse hyphens - Replaces multiple consecutive hyphens with a single hyphen
  7. Remove leading hyphens - Removes hyphens from the start
  8. Remove trailing hyphens - Removes hyphens from the end

Source Code

From /home/daytona/workspace/source/src/utils/slugify.js:
export function slugify(text) {
    return text
        .toString()                  // Convert to string
        .toLowerCase()               // Convert to lowercase
        .trim()                      // Remove whitespace from both ends
        .replace(/\s+/g, "-")        // Replace spaces with hyphens
        .replace(/[^\w-]+/g, "")     // Remove all non-word chars except hyphens
        .replace(/-+/g, "-")         // Replace multiple hyphens with single hyphen
        .replace(/^-+/, "")          // Remove hyphens from start
        .replace(/-+$/, "");         // Remove hyphens from end
}

Usage Examples

Creating Podcast URLs

From /home/daytona/workspace/source/src/components/PodcastList/PodcastList.jsx:63:
import { slugify } from "../../utils/slugify";

const PodcastList = ({ onPlayPodcast }) => {
    const navigate = useNavigate();
    
    const handlePodcastClick = (song) => {
        navigate(`/podcast/${slugify(song.title)}`);
    };
    
    return (
        <div>
            {podcasts.map((song) => (
                <div 
                    key={song.id} 
                    onClick={() => handlePodcastClick(song)}
                >
                    {song.title}
                </div>
            ))}
        </div>
    );
};

Finding Podcasts by Slug

From /home/daytona/workspace/source/src/components/PodcastDetail/PodcastDetail.jsx:187:
import { slugify } from "../../utils/slugify";
import { useParams } from "react-router-dom";

const PodcastDetail = ({ onPlayPodcast }) => {
    const { id } = useParams(); // This is the slug from the URL
    
    // Find the podcast by comparing slugified titles
    const foundPodcast = songs.find((song) => slugify(song.title) === id);
    
    if (!foundPodcast) {
        return <NotFound />;
    }
    
    return <div>{foundPodcast.title}</div>;
};

Input/Output Examples

slugify("Hello World");
// Output: "hello-world"

slugify("Nadie Sabe Nada");
// Output: "nadie-sabe-nada"

slugify("Episode #123: The Best Episode!");
// Output: "episode-123-the-best-episode"

Common Use Cases

URL Generation

Create SEO-friendly URLs from podcast titles:
const podcastUrl = `/podcast/${slugify(podcast.title)}`;
// Result: "/podcast/nadie-sabe-nada-episodio-350"

Route Matching

Match URL slugs to podcast titles:
const podcast = allPodcasts.find(p => slugify(p.title) === urlSlug);

Unique Identifiers

Generate consistent identifiers from titles:
const podcastId = slugify(podcast.title);
localStorage.setItem(`podcast-${podcastId}-progress`, currentTime);

Search Indexing

Create searchable keys:
const searchIndex = podcasts.map(p => ({
    id: p.id,
    slug: slugify(p.title),
    title: p.title
}));

Best Practices

Always use slugify consistently when creating and matching URLs. If you slugify when creating a URL, you must slugify when looking it up.
The function removes special characters including accented characters (á, é, í, ó, ú, ñ). Two different podcast titles could theoretically produce the same slug. Consider adding a unique identifier if this is a concern.
The slugified version is not reversible - you cannot get the original title back from the slug. Always store both the original title and use the slug only for URLs.

Character Handling

InputOutputReason
SpacesHyphensURL-friendly
UppercaseLowercaseConsistency
Accents (á, é, etc.)RemovedASCII-only
Special chars (!@#$%)RemovedURL-safe
Multiple hyphensSingle hyphenClean format
Leading/trailing hyphensRemovedClean format

Technical Details

Regular Expressions Used

/\s+/g           // Matches one or more whitespace characters
/[^\w-]+/g       // Matches any character that's not a word char or hyphen
/-+/g            // Matches one or more consecutive hyphens
/^-+/            // Matches hyphens at the start
/-+$/            // Matches hyphens at the end

Word Characters

The \w character class matches:
  • Lowercase letters (a-z)
  • Uppercase letters (A-Z)
  • Digits (0-9)
  • Underscore (_)

Alternatives and Extensions

For more advanced slug generation with better Unicode support, consider:
// With transliteration for better accent handling
import slugify from 'slugify';

const advancedSlugify = (text) => {
    return slugify(text, {
        lower: true,
        strict: true,
        remove: /[*+~.()'\";:@]/g
    });
};

advancedSlugify("¡Vuelve Nadie Sabe Nada!");
// Output: "vuelve-nadie-sabe-nada" (with proper accent handling)
However, the current implementation is lightweight with zero dependencies and works well for the application’s needs.

Build docs developers (and LLMs) love