Pulse · Alpine-style

Attribute binding

:disabled="current === 0", :src="art(current)", :aria-current="…" — any attribute can follow state.

The value of a bound attribute is a JavaScript expression. Three rules cover every case:

  • false, null or undefined remove the attribute — exactly what disabled and aria-current need.
  • true sets an empty attribute (disabled="").
  • :class is added to the element's static classes instead of replacing them.

Binding ARIA attributes this way keeps what assistive technology hears in lockstep with what sighted users see.

Live · Gallery — keyboard arrows work too

View the source for this demo
HTML
<div kj-data="gallery" tabindex="0" @keydown="key($event)" aria-label="Gallery. Use the left and right arrow keys." role="group">
  <figure class="gal-main">
    <img :src="art(current)" :alt="titles[current]" width="640" height="360">
    <figcaption kj-text="(current + 1) + ' / ' + titles.length + ' — ' + titles[current]" aria-live="polite"></figcaption>
  </figure>
  <div class="row" style="margin-top:12px">
    <button type="button" @click="current--" :disabled="current === 0" aria-label="Previous">←</button>
    <button type="button" class="thumb" @click="current = 0" :class="current === 0 ? 'on' : ''" :aria-current="current === 0 ? 'true' : false" aria-label="Artwork 1"><img :src="art(0)" alt="" width="64" height="36"></button>
    <button type="button" class="thumb" @click="current = 1" :class="current === 1 ? 'on' : ''" :aria-current="current === 1 ? 'true' : false" aria-label="Artwork 2"><img :src="art(1)" alt="" width="64" height="36"></button>
    <button type="button" class="thumb" @click="current = 2" :class="current === 2 ? 'on' : ''" :aria-current="current === 2 ? 'true' : false" aria-label="Artwork 3"><img :src="art(2)" alt="" width="64" height="36"></button>
    <button type="button" class="thumb" @click="current = 3" :class="current === 3 ? 'on' : ''" :aria-current="current === 3 ? 'true' : false" aria-label="Artwork 4"><img :src="art(3)" alt="" width="64" height="36"></button>
    <button type="button" @click="current++" :disabled="current === titles.length - 1" aria-label="Next">→</button>
  </div>
</div>
JavaScript
$.component('gallery', () => ({
  current: 0,
  titles: ['Signal, blue hour', 'Hypermedia at dusk', 'Mint pulse', 'Amber motion'],
  colors: ['#4D7CFF', '#FF4F8B', '#22CFA2', '#FFB224'],
  art(i) {                                           // a generated SVG "photo" per slide
    const c = this.colors[i];
    const svg = '<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 360"><rect width="640" height="360" fill="#13152B"/>' +
      '<circle cx="' + (170 + i * 100) + '" cy="170" r="' + (80 + i * 14) + '" fill="' + c + '" opacity=".9"/>' +
      '<path d="M0 ' + (300 - i * 25) + ' C 210 ' + (110 + i * 35) + ', 430 380, 640 ' + (130 + i * 30) + '" stroke="' + c + '" stroke-width="12" fill="none" opacity=".55"/></svg>';
    return 'data:image/svg+xml,' + encodeURIComponent(svg);
  },
  key(e) {
    if (e.key === 'ArrowRight' && this.current < this.titles.length - 1) this.current++;
    if (e.key === 'ArrowLeft' && this.current > 0) this.current--;
  },
}));

More examples

Bindings

HTML
<a :href="'/users/' + user.id" kj-text="user.name"></a>
<button :disabled="saving" :aria-busy="saving">Save</button>
<li class="tab" :class="active ? 'is-active' : ''">…</li>
<div :style="'width:' + progress + '%'"></div>

API

:src="expr" · kj-bind:class="expr"

Bind any attribute to an expression. :class merges with the element’s static classes; false/null removes the attribute.

Reference: :attr / kj-bind:attr →

Migrating

Coming from Alpine.jsx-bind:/: work the same for strings. Alpine's object syntax for :class="{ active: on }" and :style="{ … }" is not included — use a string expression.

Related features