Slug

Auto-populate a URL slug field from a title or name field as the user types.

Usage

Copy slug_controller.js to app/javascript/controllers/ and register it:

// app/javascript/controllers/index.js
import SlugController from "./slug_controller";
application.register("slug", SlugController);

HTML

<div data-controller="slug">
  <div>
    <label for="post_title">Title</label>
    <input
      id="post_title"
      type="text"
      name="post[title]"
      data-slug-target="source"
      data-action="input->slug#generate"
    />
  </div>
  <div>
    <label for="post_slug">Slug</label>
    <input
      id="post_slug"
      type="text"
      name="post[slug]"
      data-slug-target="output"
      data-action="input->slug#lock"
    />
  </div>
</div>

Once the user manually edits the output field, auto-generation stops. If the output already has a value when the controller connects (e.g. on an edit form), it starts locked. The locked state is stored in a data-slug-locked-value attribute on the controller element, so it survives controller reconnects (e.g. Turbo morphing).

Note: Only Latin-based characters are supported. Non-Latin scripts (CJK, Arabic, Hebrew, emoji, etc.) are stripped entirely and produce an empty slug. If your titles may contain non-Latin text, apply a server-side transliteration step before or after the slug is submitted.

API

Targets

TargetRequiredDescription
sourceYesThe field whose value is transformed into a slug.
outputYesThe field that receives the generated slug.

Values

ValueTypeDefaultDescription
lockedBooleanfalseWhen true, auto-generation is disabled. Stored as data-slug-locked-value on the controller element; survives controller reconnects. Set by the controller on connect (if the output is pre-filled) or when the user edits the output field.

Actions

ActionDescription
generateTransforms the source field value to a slug and writes it to the output field. No-op if the output has been manually edited. Wire to input on the source field.
lockStops further auto-generation. Wire to input on the output field.

Accessibility

The slug field is a standard text input — no additional ARIA attributes are required. Ensure both fields have visible <label> elements.