A URL segment derived from a title with locale transliteration — "İşe Alım & Oryantasyon" becomes ise-alim-ve-oryantasyon in Turkish. It follows the title until someone edits it, sanitises as you type without moving the caret, and can check uniqueness and suggest a free alternative.
Installation
The whole kit as one package — get updates by bumping the version. Add the styles to globals.css: @import "@vamos-ui/react/styles.css";
Usage
import { Field, SlugInput } from "@vamos-ui/react";
<Field label="URL">
<SlugInput
source={title}
prefix="vamos.ist/blog/"
validate={(slug, signal) => api.checkSlug(slug, { signal })} // true | "Used by …"
suggestUnique={(slug) => api.suggestSlug(slug)}
name="slug"
/>
</Field>Redirects on slug change ("Create a 301") belong to your publishing flow: listen to onValueChange and keep the previous value.
Examples
Field variant
Always an input. New content follows the source (Auto badge); saved content starts locked; the refresh button regenerates from the title.
Shows Auto while it follows the name. Edit it to lock it; the refresh button re-derives it.
Uniqueness check
validate is debounced and aborted when the slug changes; the result is announced politely and linked to the input.
Locale rules
slugify() lowercases with the locale, transliterates (tr ç→c ı→i, de ä→ae ß→ss), strips marks and turns & into the locale's word.
| Locale | Title | Slug |
|---|---|---|
| en | Q3 Results & Next Steps | q3-results-and-next-steps |
| tr | İşe Alım & Oryantasyon Süreci | ise-alim-ve-oryantasyon-sureci |
| tr | Çağrı Merkezi Yönetimi | cagri-merkezi-yonetimi |
| de | Größe & Übersicht für Bäckereien | groesse-und-uebersicht-fuer-baeckereien |
States
Disabled and a Field error, small size.
Slugs can't be reserved words like admin or api.
API
SlugInput
| Prop | Type | Default |
|---|---|---|
value / defaultValue / onValueChangeThe slug. | string | — |
sourceText to derive from (the title) while unlocked. | string | — |
locked / defaultLocked / onLockedChangeManual mode: stops following source. Editing the slug locks it. | boolean | true when there is an initial slug |
prefixShown before the slug (vamos.ist/blog/). A URL prefix also makes the permalink a link. | string | — |
variantpermalink: a link with Edit; Enter confirms, Escape restores and returns focus. | "field" | "permalink" | "field" |
hrefPermalink target override. | string | — |
maxLengthCut at a word boundary when possible. | number | 80 |
localeTransliteration rules. | string | provider locale |
validateUniqueness check: true when free, else a message. | (slug, signal: AbortSignal) => Promise<string | true> | — |
suggestUniqueOffers "Use spring-menu-2" after a failed check. | (slug) => Promise<string> | — |
validateDelayDebounce in ms. | number | 350 |
nameHidden input with the slug (falls back to the Field's name). | string | — |
size · disabled · invalid · placeholderSame box as Input. | Input props | — |
labelsBuilt-in strings (slug namespace). | Partial<SlugInputLabels> | — |