C&C Docs
Log in
Code

More directives — modifiers, transitions, tooltips

Three more things a template can say with an attribute: when a handler runs, how an element appears, and what it says on hover. Every example below is live.

Event modifiers

A dotted suffix on an @event changes when the handler runs: only on a key (.enter), on a click anywhere else (.outside), once typing stops (.debounce.500ms), or only the first time (.once).

@keydown.enter
<div x-data="{ msg: '', submitted: '' }">
  <input @keydown.enter="submitted = msg; msg = ''" x-model="msg" placeholder="Type, then press Enter" class="" />
  <p class="">Last submitted: <span class="" x-text="submitted || '—'"></span></p>
</div>
Result

Last submitted: —

@click.outside: a menu that closes itself
<div x-data="{ open: false }" class="relative inline-block">
  <button @click="open = !open" class="">Menu ▾</button>
  <ul x-show="open" @click.outside="open = false" class="">
    <li class="">Profile</li>
    <li class="">Settings</li>
    <li class="">Sign out</li>
  </ul>
</div>
Result
@input.debounce.500ms
<div x-data="{ query: '', ran: 0 }">
  <input @input.debounce.500ms="ran++" x-model="query" placeholder="Search…" class="" />
  <p class="">Query fired <span class="" x-text="ran"></span> time(s) — 500ms after you stop typing.</p>
</div>
Result

Query fired 0 time(s) — 500ms after you stop typing.

@click.once
<div x-data="{ n: 0 }">
  <button @click.once="n++" class="">Claim (once)</button>
  <p class="">Runs <span class="" x-text="n"></span> time — clicking again does nothing.</p>
</div>
Result

Runs 0 time — clicking again does nothing.

Transitions

On its own x-show snaps. Add x-transition:* classes and the flip animates: the change from -start to -end is what moves, and hiding waits for the animation to finish.

Fade
<div x-data="{ open: true }">
  <button @click="open = !open" class="">Toggle fade</button>
  <div
    x-show="open"
    x-transition:enter="duration-500 ease-out"
    x-transition:enter-start="opacity-0"
    x-transition:enter-end="opacity-100"
    x-transition:leave="duration-500 ease-in"
    x-transition:leave-start="opacity-100"
    x-transition:leave-end="opacity-0"
    class=""
  >
    I fade in and out. <code class="font-mono">x-show</code> flips <code class="font-mono">display</code>; the six hooks animate the flip.
  </div>
</div>
Result
I fade in and out. x-show flips display; the six hooks animate the flip.

Tooltips

x-tooltip="text" shows a tooltip on hover or focus. x-tooltip="#id" shows the content of that element, so a <template> can hold markup, and :x-tooltip follows state.

Plain text
<div class="">
  <button x-tooltip="Removes the row. This cannot be undone." class="">Delete</button>
  <button x-tooltip="Saves and stays on this page" class="">Save</button>
  <span x-tooltip="Any element works — this is a plain span." class="">what is this?</span>
</div>
Result
what is this?
#id: a template's markup
<div class="flex items-center gap-3">
  <template id="tip-plan">
    <strong class="block">Pro plan</strong>
    <span class="">Unlimited blocks, 5 seats, priority support.</span>
  </template>
  <button x-tooltip="#tip-plan" class="">Upgrade</button>
  <span class="">the tooltip is the template's markup, not a flattened string</span>
</div>
Result
the tooltip is the template's markup, not a flattened string
:x-tooltip follows state
<div x-data="{ dirty: false }" class="">
  <button @click="dirty = !dirty" class="">Toggle unsaved changes</button>
  <button :x-tooltip="dirty ? 'You have unsaved changes' : 'Everything is saved'" class="">Hover me</button>
  <span class="" x-text="dirty ? 'dirty' : 'clean'"></span>
</div>
Result
clean