Skip to content

Instantly share code, notes, and snippets.

@thevangelist
Created September 21, 2016 10:11
Show Gist options
  • Star 19 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save thevangelist/8ff91bac947018c9f3bfaad6487fa149 to your computer and use it in GitHub Desktop.
Save thevangelist/8ff91bac947018c9f3bfaad6487fa149 to your computer and use it in GitHub Desktop.
JS: convert to kebab-case
const convertToKebabCase = (string) => {
return string.replace(/\s+/g, '-').toLowerCase();
}
@Tiliavir
Copy link

Tiliavir commented Apr 18, 2017

return string.replace(/([a-z])([A-Z])/g, "$1-$2")
             .replace(/\s+/g, '-')
             .toLowerCase();

could be used to handle Caml cased input as well

@csi-lk
Copy link

csi-lk commented Aug 24, 2017

@Tiliavir 's solution works well

const kebabCase = string => string.replace(/([a-z])([A-Z])/g, '$1-$2').replace(/\s+/g, '-').toLowerCase()

@b4dnewz
Copy link

b4dnewz commented Jul 26, 2018

it should include low dash as well for a better conversion

str
  .replace(/([a-z])([A-Z])/g, '$1-$2')    // get all lowercase letters that are near to uppercase ones
  .replace(/[\s_]+/g, '-')                // replace all spaces and low dash
  .toLowerCase()                          // convert to lower case

Some examples:

radius changed -> radius-changed
radiusChanged -> radius-changed
radius_changed -> radius-changed
raDiuScHan_ge d -> ra-diu-sc-han-ge-d

@Illizion
Copy link

this is awesome! since i'm using it in my Lodash replacement library, i'll link back here ;)

@sekoyo
Copy link

sekoyo commented Jan 24, 2019

None of these solutions work for ThisIsATest, it becomes this-is-atest instead of this-is-a-test

@GerardRodes
Copy link

GerardRodes commented Feb 15, 2019

str
  .replace(/([A-Z])([A-Z])/g, '$1-$2')
  .replace(/([a-z])([A-Z])/g, '$1-$2')
  .replace(/[\s_]+/g, '-')            
  .toLowerCase()  
"thisIsATest"
  .replace(/([A-Z])([A-Z])/g, '$1-$2')
  .replace(/([a-z])([A-Z])/g, '$1-$2')
  .replace(/[\s_]+/g, '-')            
  .toLowerCase()
// "this-is-a-test"

@Vadorequest
Copy link

None of those exemples are good enough, they miss special chars like comma and parens.

See https://www.w3resource.com/javascript-exercises/fundamental/javascript-fundamental-exercise-123.php for one that actually does work as expected.

const toKebabCase = str =>
    str &&
    str
      .match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
      .map(x => x.toLowerCase())
      .join('-');

image

@MaximBazarov
Copy link

@Vadorequest great code, could you also filter out —   etc?

@Vadorequest
Copy link

Unfortunately, I'm not really good at regexes, I just found out a better version and shared it but ain't competent for improving it.

@tehpsalmist
Copy link

tehpsalmist commented Jul 31, 2019

Some small improvements (perhaps some personal taste involved, as well):

const kebabCase = str => str.match(/[A-Z]{2,}(?=[A-Z][a-z0-9]*|\b)|[A-Z]?[a-z0-9]*|[A-Z]|[0-9]+/g)
  .filter(Boolean)
  .map(x => x.toLowerCase())
  .join('-')

What @Vadorequest provided would cut off a word at any digit followed by a letter, and this solution allows those digits to fall within words like so:
Previously: Som3thing\3lse => som3-thing-3-lse
My version: Som3thing\3lse => som3thing-3lse

@Vadorequest
Copy link

@tehpsalmist Could you edit your post to provide an example with your regex vs mine? That'd be even better ;)
I like yours, may indeed be an improvement! But could depend on the needs.

@hawkeye64
Copy link

hawkeye64 commented Sep 30, 2019

Just adding to this conversation:

function kebabCase (str) {
  const result = str.replace(
    /[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,
    match => '-' + match.toLowerCase()
  )
  return (str[0] === str[0].toUpperCase())
    ? result.substring(1)
    : result
}
console.log(kebabCase('TestMe'))
console.log(kebabCase('test-me'))
console.log(kebabCase('testMe'))
'test-me'
'test-me'
'test-me'

Tested at: https://playcode.io/

@alextrastero
Copy link

Just adding to this conversation:

function kebabCase (str) {
  const result = str.replace(
    /[A-Z\u00C0-\u00D6\u00D8-\u00DE]/g,
    match => '-' + match.toLowerCase()
  )
  return (str[0] === str[0].toUpperCase())
    ? result.substring(1)
    : result
}
console.log(kebabCase('TestMe'))
console.log(kebabCase('test-me'))
console.log(kebabCase('testMe'))
'test-me'
'test-me'
'test-me'

Tested at: playcode.io

American Flag -> american -flag

@alextrastero
Copy link

For me the issue lies with toLowerCase, this should only happen IF string was replaced.

  • chDe -> ch-de
  • American Flag -> American Flag

@oravecz
Copy link

oravecz commented Jun 6, 2020

Previously: Som3thing\3lse => som3-thing-3-lse
My version: Som3thing\3lse => som3thing-3lse

Sorry @tehpsalmist
kebabCase('ABC_123') -> 'ab-c-123'

@oravecz
Copy link

oravecz commented Jun 6, 2020

const toKebabCase = str =>
    str &&
    str
      .match(/[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g)
      .map(x => x.toLowerCase())
      .join('-');

Sorry @Vadorequest
toKebabCase('FOO-BAR') -> ''f-o-o-bar''

@oravecz
Copy link

oravecz commented Jun 6, 2020

str
  .replace(/([A-Z])([A-Z])/g, '$1-$2')
  .replace(/([a-z])([A-Z])/g, '$1-$2')
  .replace(/[\s_]+/g, '-')            
  .toLowerCase() 

Sorry @GerardRodes
'FOO-BAR' -> ''f-oo-b-ar''

@tehpsalmist
Copy link

@oravecz That's a shame! Do you think you have a fix handy?

@Vadorequest
Copy link

Vadorequest commented Jun 6, 2020

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment