Skip to content

x-model & x-modelable

x-model

x-model allows you to bind the value of an input element to Alpine data.

html
<div x-data="{ message: '' }">
    <input type="text" x-model="message">
 
    <span x-text="message"></span>
</div>

When the user types into the text field, the message will be reflected in the <span> tag.

x-model is two-way bound, meaning it both "sets" and "gets". In addition to changing data, if the data itself changes, the element will reflect the change. For example:

html
<div x-data="{ message: '' }">
    <input type="text" x-model="message">
 
    <button x-on:click="message = 'changed'">Change Message</button>
</div>

When the <button> is clicked, the input element's value will instantly be updated to "changed".

Supported input elements

x-model works with the following input elements:

  • <input type="text">
  • <textarea>
  • <input type="checkbox">
  • <input type="radio">
  • <select>
  • <input type="range">

Multiple Checkboxes bound to array

html
<input type="checkbox" value="red" x-model="colors">
<input type="checkbox" value="orange" x-model="colors">
<input type="checkbox" value="yellow" x-model="colors">
 
Colors: <span x-text="colors"></span>

Multiple selection will be stored as an array

Multiple Select

Similar to checkbox, the selection will be stored as an array.

html
<select x-model="color" multiple>
    <option>Red</option>
    <option>Orange</option>
    <option>Yellow</option>
</select>
 
Colors: <span x-text="color"></span>

Modifiers

.lazy

On text inputs, by default, x-model updates the property on every keystroke. By adding the .lazy modifier, you can force an x-model input to only update the property when user focuses away from the input element.

This is handy for things like real-time form-validation where you might not want to show an input validation error until the user "tabs" away from a field.

html
<input type="text" x-model.lazy="username">
<span x-show="username.length > 20">The username is too long.</span>

.number

By default, any data stored in a property via x-model is stored as a string. To force Alpine to store the value as a JavaScript number, add the .number modifier.

html
<input type="text" x-model.number="age">
<span x-text="typeof age"></span>

.boolean

Similarly, to force Alpine to store the value as a JavaScript boolean, add the .boolean modifier. Both integers (1/0) and strings (true/false) are valid boolean values.

html
<select x-model.boolean="isActive">
    <option value="true">Yes</option>
    <option value="false">No</option>
</select>
<span x-text="typeof isActive"></span>

.debounce

This is very similar to the .debounce modifier of x-on directive, and can be used to debounce the updating of bound input.

html
<input type="text" x-model.debounce="search">

The default debounce time is 250 milliseconds, you can easily customize this by adding a time modifier like so:

html
<input type="text" x-model.debounce.500ms="search">

.throttle

Similarly, this is very much like the .throttle modifier of x-on to update the bound input on a specified interval.

html
<!-- default throttle interval is 250 milliseconds -->
<input type="text" x-model.throttle="search">

<!-- Updated the throttle interval to 500ms -->
<input type="text" x-model.throttle.500ms="search">

.fill

By default, if an input has a value attribute, it is ignored by Alpine and instead, the value of the input is set to the value of the property bound using x-model.

But if a bound property is empty, then you can use an input's value attribute to populate the property by adding the .fill modifier.

html
<input type="text" value="This is the default message" x-model.fill="message">

x-modelable

x-modelable allows you to connect any Alpine property as the target of the x-model directive, which is usually used for binding input elements to Alpine data.

html
<div x-data="{ number: 5 }">
    <div x-data="{ count: 0 }" x-modelable="count" x-model="number">
        <button @click="count++">Increment</button>
    </div>
 
    Number: <span x-text="number"></span>
</div>

When you click the button that increases count, the outer number is also updated because of the x-model binding. That is, the outer scope property number is now bound to the inner scope property count.

This feature would be typically used in conjunction with a backend templating framework like Laravel Blade. It's useful for abstracting away Alpine components into backend templates and exposing state to the outside through x-model as if it were a native input.