Str::kebab
Converts a camelCase or space-separated string to kebab-case using hyphens as word boundaries.
Str::kebab(string $value): stringParameters
| Parameter | Type | Description |
|---|---|---|
$$value | string | The string to convert. An empty string returns an empty string. |
Return value
stringThe input rewritten with a hyphen before each case boundary, lowercased.
Str::kebab is a thin wrapper around Str::snake with a hyphen delimiter, so it inherits that method's rules exactly. Reach for it when you need a URL segment, a CSS class, a Blade component tag or an HTML attribute name derived from a PHP identifier.
What it actually does
If the string is entirely lowercase letters it is returned untouched. Otherwise whitespace is stripped, a hyphen is inserted before every uppercase letter that has a character before it, and the whole thing is lowercased. That is the entire algorithm — there is no dictionary, no transliteration and no punctuation handling.
Two consequences catch people out. Underscores are not treated as word boundaries, because nothing in the transformation looks at them, so user_profile_url comes back exactly as it went in. And a run of capitals is split letter by letter, because each capital after the first is preceded by a character, so HTTPResponse becomes h-t-t-p-response.
Not a slug helper
Kebab-casing is not URL-slugging. It will happily leave accents, slashes and question marks in place. If the input is arbitrary text rather than an identifier, use Str::slug, which transliterates and strips anything that is not a word character.
Results are memoised in a static cache keyed by input and delimiter, so calling it in a loop over unbounded user input grows memory until Str::flushCache() is called.
Example
When to use it
- Derive a Blade component tag such as user-avatar from the class name UserAvatar.
- Turn a config key or enum case into a CSS class or data-* attribute name.
- Build a route segment from a PascalCase controller or action name.
Frequently asked questions
How do I convert snake_case to kebab-case in Laravel?
Str::kebab will not do it — replace the underscores yourself with Str::replace('_', '-', $value), or Str::of($value)->replace('_', '-'). Underscores are invisible to the kebab algorithm, which only reacts to capital letters and whitespace.
Why does Str::kebab turn HTTPResponse into h-t-t-p-response?
Because a hyphen is inserted before every uppercase letter that is preceded by any character, and in a run of capitals each one qualifies. Lowercase the acronym first (Http, Api) if you want Http-Response style output.
What is the difference between Str::kebab and Str::slug?
kebab only reinterprets case and whitespace boundaries and leaves everything else intact, while slug transliterates accented characters, strips punctuation and collapses separators. Use kebab on identifiers you control and slug on arbitrary text such as a post title.
More examples
Deriving a component tag from a class name
class_basename strips the namespace and kebab turns the PascalCase remainder into the tag Blade expects. This is the same mapping Laravel itself uses to resolve <x-...> tags back to component classes.
<?php
use Illuminate\Support\Str;
$classes = [
'App\\View\\Components\\UserAvatar',
'App\\View\\Components\\NavDropdown',
'App\\View\\Components\\FormInput',
];
foreach ($classes as $class) {
$tag = Str::kebab(class_basename($class));
echo "<x-{$tag} />\n";
}
// <x-user-avatar />
// <x-nav-dropdown />
// <x-form-input />Fixing snake_case input before kebab-casing
Replacing underscores with spaces gives kebab a boundary it recognises. The third row shows the acronym behaviour surviving the fix: VAT is still exploded into v-a-t, because each capital after the first triggers a hyphen.
<?php
use Illuminate\Support\Str;
$keys = ['billing_address', 'shippingAddress', 'VAT_number'];
foreach ($keys as $key) {
// kebab alone leaves the underscores alone, so normalise first.
$attribute = Str::kebab(Str::replace('_', ' ', $key));
echo str_pad($key, 18), '=> ', $attribute, "\n";
}
// billing_address => billing-address
// shippingAddress => shipping-address
// VAT_number => v-a-t-number
Discussion