It's no secret — I'm a huge fan of Alpine. For me, it hits that goldilocks zone between minimalistic and powerful. Alpine is straightforward to get started with, especially if you have a VueJS background. However, there are a few hidden features (okay, they're documented, not actually hidden) that you may not notice if you're just quickly scanning the readme.
Alpine includes support for custom transition classes via x-transition
, but did you know there's also an easier way to add show/hide transitions to your components? The x-show
directive also has an optional modifier transition
. Check it out:
1<!-- no transition -->2<div x-show="open">I will appear abruptly with no transition.</div>34<!-- easy fade + scale -->5<div x-show.transition="open">I come and go with a nice transition.</div>
1<!-- no transition -->2<div x-show="open">I will appear abruptly with no transition.</div>34<!-- easy fade + scale -->5<div x-show.transition="open">I come and go with a nice transition.</div>
Beats having six lines of x-transition
class mappings for 80% of cases. However, it doesn't stop there! The transition modifier on x-show
also has other optional modifiers.
1<!-- Modify the transition -->2<div x-show.transition.in="open">Only transition in.</div>3<div x-show.transition.out="open">Only transition out.</div>4<div x-show.transition.opacity="open">Only fade (no scaling).</div>5<div x-show.transition.scale="open">Only scaling (no fade).</div>6<div x-show.transition.duration.2000ms="open">7 Transition in for two seconds. Out for half of that.8</div>9<div x-show.transition.origin.top.left="open">10 Transition starts and ends from the top left11</div>1213<!-- Combine modifiers. Go crazy! -->14<div x-show.transition.in.origin.top.left.opacity="open">15 Only transition in from the top left with a fade.16</div>
1<!-- Modify the transition -->2<div x-show.transition.in="open">Only transition in.</div>3<div x-show.transition.out="open">Only transition out.</div>4<div x-show.transition.opacity="open">Only fade (no scaling).</div>5<div x-show.transition.scale="open">Only scaling (no fade).</div>6<div x-show.transition.duration.2000ms="open">7 Transition in for two seconds. Out for half of that.8</div>9<div x-show.transition.origin.top.left="open">10 Transition starts and ends from the top left11</div>1213<!-- Combine modifiers. Go crazy! -->14<div x-show.transition.in.origin.top.left.opacity="open">15 Only transition in from the top left with a fade.16</div>
For more examples, check out the full documentation of x-show
.
Both x-bind
and x-on
support a .camel
modifier. I find the latter one is more useful (especially when working with Livewire), but they're both good to know about.
x-bind
1<div x-bind:attribute-name.camel="someVar">...</div>23<!-- Result -->4<div attributeName="(value of someVar)">...</div>
1<div x-bind:attribute-name.camel="someVar">...</div>23<!-- Result -->4<div attributeName="(value of someVar)">...</div>
x-on
1<div x-on:your-event.camel="doSomething">2 <!-- Result -->3 <div @yourEvent="doSomething"></div>4</div>
1<div x-on:your-event.camel="doSomething">2 <!-- Result -->3 <div @yourEvent="doSomething"></div>4</div>
There are two modifiers you can use with x-model
— debounce
and number
. Both can be useful in the right situations. I didn't know that number
existed before writing this article!
Debounce
Delay updating the binding until a certain amount of time has passed since inputting something. In other words, when you stop typing it waits a little bit before updating the data. By default the time is 250ms
, but you can customize the debounce time if you wish.
1<input x-model.debounce="name" />2<!-- 250ms default -->3<input x-model.debounce.500="name" />4<!-- 500ms -->5<input x-model.debounce.500ms="name" />6<!-- 500ms -->
1<input x-model.debounce="name" />2<!-- 250ms default -->3<input x-model.debounce.500="name" />4<!-- 500ms -->5<input x-model.debounce.500ms="name" />6<!-- 500ms -->
Number
This modifier tries to cast the value to a number instead of the string representation of that number. If it can't cast it easily to a number, the original value is returned unmodified.
1<input x-model.number="age" />
1<input x-model.number="age" />
x-spread
OperatorWhen you start to create more complex components, separating the logic and the template is a great pattern. If you come from a Vue background, you'll know this as single file components (.vue files). Separating template and logic is a great step, but the x-spread
object lets you take it even further by encapsulating the attribute bindings too! Take this component example:
1<div x-data="dropdown()">2 <button @click="show">Open</button>34 <div x-show="open" @click.away="hide">5 Dropdown contents6 </div>7</div>89<script>10 function dropdown() {11 return {12 open: false,13 show() { this.open = true },14 hide() { this.open = false },15 }16 }17</script>
1<div x-data="dropdown()">2 <button @click="show">Open</button>34 <div x-show="open" @click.away="hide">5 Dropdown contents6 </div>7</div>89<script>10 function dropdown() {11 return {12 open: false,13 show() { this.open = true },14 hide() { this.open = false },15 }16 }17</script>
Here's how it might look if we used x-spread
.
1<div x-data="dropdown()">2 <button x-spread="trigger">Open</button>34 <div x-spread="contents">5 Dropdown contents6 </div>7</div>89<script>10 function dropdown() {11 return {12 open: false,13 trigger: {14 ['@click']() { this.open = true }15 }16 contents: {17 ['x-show']() { return this.open },18 ['@click.away']() {19 this.open = false20 },21 }22 }23 }24</script>
1<div x-data="dropdown()">2 <button x-spread="trigger">Open</button>34 <div x-spread="contents">5 Dropdown contents6 </div>7</div>89<script>10 function dropdown() {11 return {12 open: false,13 trigger: {14 ['@click']() { this.open = true }15 }16 contents: {17 ['x-show']() { return this.open },18 ['@click.away']() {19 this.open = false20 },21 }22 }23 }24</script>
I tried to keep the example small for this article, but you can imagine how useful this might be when you have many attributes on a component. You no longer have to cross-reference the HTML and the Javascript sections of components to figure out what's happening. Instead, x-spread
allows you to put everything in one spot.
Thanks for reading!