Table of Contents & Menu
Navigation

Alpine CSP x-model

Alpine CSP prevents `x-model` due to its reliance on JavaScript expression evaluation. Fortunately, simple workarounds exist, varying by input type.

For inputs with user-specified values

For inputs where users type values (e.g., `text`, `email`, `date`), replace `x-model` with `:value="prop"` and `@input="setProp"`.

Example text input

<script>
    window.addEventListener('alpine:init', () => {
        Alpine.data('initExample', () => ({
            prop: '',
            setProp() {
                this.$event.target.value;
            }
        }))
    }, {once: true})

</script>
<form x-data="initExample">
    <input type="text" :value="prop" @input="setProp">
</form>

Textarea inputs

Textareas are similar, but use `x-text` for content instead of `:value` for an attribute:

<form x-data="initExample">
    <textarea @input="setProp" x-text="prop"></textarea>
</form>

Radio buttons and Checkboxes

For checkboxes and radio buttons, use `@change` (instead of `@input`) and `:checked="isChecked"` (instead of `:value`).

Example checkbox example

<script>
    window.addEventListener('alpine:init', () => {
        Alpine.data('initExample', () => ({
            prop: [],
            updateSelection() {
                const checkbox = this.$event.target;
                if (checkbox.checked && ! this.prop.includes(checkbox.value)) {
                    this.prop.push(checkbox.value);
                }
                if (! checkbox.checked && this.prop.includes(checkbox.value)) {
                    this.prop.splice(this.prop.indexOf(checkbox.value), 1);
                }
            },
            isChecked() {
                return this.prop.includes(this.$el.value);
            }
        }))
    }, {once: true})
</script>
<form x-data="initExample">
    <input type="checkbox" name="example[]" value="1" @change="updateSelection" :checked="isChecked">
    <input type="checkbox" name="example[]" value="2" @change="updateSelection" :checked="isChecked">
</form>

Select and multiple select inputs

For single and multiple `<select>` inputs, the approach is similar to checkboxes, but bind the `selected` property of the `<option>` instead of `checked`.

<script>
    window.addEventListener('alpine:init', () => {
        Alpine.data('initExample', () => ({
            prop: '',
            updateSelection() {
                this.prop = this.$el.value;
            },
            isSelected() {
                return this.prop === this.item.id;
            }
        }))
    }, {once: true})
</script>
<form x-data="initExample">
    <select name="example" @change="updateSelection">
        <template x-for="item in items">
            <option value="item.id" :selected="isSelected" x-text="item.label"></option>
        </template>
    </select>
</form>

x-model modifiers

To replicate the `.number` modifier, use `hyva.safeParseNumber` to convert input values to numbers.

this.numericProp = hyva.safeParseNumber(this.$event.target.value);

Currently, there are no utility methods for other `x-model` modifiers like `.lazy`, `.boolean`, `.debounce`, `.throttle`, and `.fill`.