Skip to content

Instantly share code, notes, and snippets.

@mike-at-redspace
Created June 6, 2025 07:50
Show Gist options
  • Save mike-at-redspace/a9c5d6e456b49ad90f935d57d98da6c9 to your computer and use it in GitHub Desktop.
Save mike-at-redspace/a9c5d6e456b49ad90f935d57d98da6c9 to your computer and use it in GitHub Desktop.
Reusable Slug Generator with Stop Word & Format Options
/**
* A simple, customizable slug generator for browser-based inputs.
*
* Features:
* - Optionally lowercases text
* - Removes special characters
* - Filters out stop words
* - Removes numeric digits
* - Supports dash or underscore delimiters
* - Copy-to-clipboard functionality
*/
// Common English stop words to filter out
const STOP_WORDS = new Set([
'a', 'an', 'the', 'and', 'or', 'but', 'for', 'nor', 'on', 'at', 'to', 'by',
'in', 'of', 'is', 'are', 'am', 'was', 'were', 'be', 'been', 'being',
'have', 'has', 'had', 'do', 'does', 'did', 'will', 'would', 'shall', 'should',
'may', 'might', 'must', 'can', 'could', 'with', 'from', 'as', 'this', 'that',
'these', 'those', 'they', 'them', 'their', 'we', 'us', 'our', 'i', 'me', 'my',
'he', 'him', 'his', 'she', 'her', 'it', 'its', 'you', 'your'
])
// DOM references
const titleInput = document.getElementById('title-input')
const slugOutput = document.getElementById('slug-output')
const copyButton = document.getElementById('copy-button')
/**
* Transforms a string into a URL-friendly slug based on active options.
* @param {string} text - The original input string
* @param {Object} options - Customization options
* @returns {string} - The generated slug
*/
function createSlug(text, options = {}) {
const {
lowercase = false,
removeSpecial = false,
removeStopWords = false,
removeNumbers = false,
delimiter = '-'
} = options
if (!text) return ''
let result = text
if (lowercase) {
result = result.toLowerCase()
}
if (removeSpecial) {
result = result.replace(/[^\w\s-]/g, '')
}
if (removeStopWords) {
result = result
.split(' ')
.filter(word => !STOP_WORDS.has(word.toLowerCase()))
.join(' ')
}
if (removeNumbers) {
result = result.replace(/[0-9]/g, '')
}
result = result.trim().replace(/\s+/g, delimiter)
result = result
.replace(new RegExp(`${delimiter}+`, 'g'), delimiter)
.replace(new RegExp(`^${delimiter}|${delimiter}$`, 'g'), '')
return result
}
/**
* Reads the UI controls and generates a new slug in the output field.
*/
function generateSlugFromInput() {
const slug = createSlug(titleInput.value, {
lowercase: document.getElementById('lowercase').checked,
removeSpecial: document.getElementById('remove-special').checked,
removeStopWords: document.getElementById('remove-stop').checked,
removeNumbers: document.getElementById('remove-numbers').checked,
delimiter: document.getElementById('dash-delimiter').checked ? '-' : '_',
})
slugOutput.value = slug
}
/**
* Copies the slug to the clipboard and shows feedback.
*/
function copySlugToClipboard() {
slugOutput.select()
document.execCommand('copy')
copyButton.textContent = 'Copied!'
setTimeout(() => (copyButton.textContent = 'Copy to Clipboard'), 1500)
}
// --- Event Bindings ---
titleInput.addEventListener('input', generateSlugFromInput)
document
.querySelectorAll('input[type="radio"], input[type="checkbox"]')
.forEach(input => input.addEventListener('change', generateSlugFromInput))
copyButton.addEventListener('click', copySlugToClipboard)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment