alpine Documentation

A rugged, minimal framework for composing JavaScript behavior in your markup.

31,850 stars HTML HTML 1 file ยท ~5,494 tokens
RAW Doc

File: README.md

Alpine.js

Go to the Alpine docs for most things: Alpine Docs

You are welcome to submit updates to the docs by submitting a PR to this repo. Docs are located in the /packages/docs directory.

Stay here for contribution-related information.

Looking for V2 docs? here they are

Contribution Guide:

Quickstart

  • clone this repo locally
  • run npm install & npm run build
  • Include the /packages/alpinejs/dist/cdn.js file from a <script> tag on a webpage and you're good to go!

Brief Tour

You can get everything installed with: npm install in the root directory of this repo after cloning it locally.

This repo is a "mono-repo" using npm workspaces for managing the packages. Each package has its own folder in the /packages directory.

Rather than having to run separate builds for each package, all package bundles are handled with the same command: npm run build

Here's a brief look at each package in this repo:

Package Description
alpinejs The main Alpine repo with all of Alpine's core
collapse A plugin for expanding and collapsing elements using smooth animations
csp A repo to provide a "CSP safe" build of Alpine
docs The Alpine documentation
focus A plugin that allows you to manage focus inside an element
history A plugin for binding data to query string parameters using the history API (name is likely to change)
intersect A plugin for triggering JS expressions based on elements intersecting with the viewport
mask A plugin for automatically formatting a text input field as a user types
morph A plugin for morphing HTML (like morphdom) inside the page intelligently
persist A plugin for persisting Alpine state across page loads

The compiled JS files (as a result of running npm run [build/watch]) to be included as a <script> tag for example are stored in each package's packages/[package]/dist directory.

Each package should at least have: a "cdn" build that is self-initializing and can be included using the src attribute in a <script defer> tag, and a module.[esm/cjs].js file that is used for importing as a JS module (cjs for node, esm for everything else).

The bundling for Alpine V3 is handled exclusively by ESBuild. All of the configuration for these builds is stored in the scripts/build.js file.

Testing

There are 2 different testing tools used in this repo: Cypress (for integration tests), and Vitest (for unit tests).

All tests are stored inside the /tests folder under /tests/cypress and /tests/vitest.

If you wish to only run Cypress and open it's user interface (recommended during development), you can run: npm run cypress

If you wish to only run Vitest tests, you can run npm run vitest like normal and target specific tests.


File: packages/docs/src/en/advanced/async.md


order: 4 title: Async

Async

Alpine is built to support asynchronous functions in most places it supports standard ones.

For example, let's say you have a simple function called getLabel() that you use as the input to an x-text directive:

js
function getLabel() {
    return 'Hello World!'
}
alpine

Because getLabel is synchronous, everything works as expected.

Now let's pretend that getLabel makes a network request to retrieve the label and can't return one instantaneously (asynchronous). By making getLabel an async function, you can call it from Alpine using JavaScript's await syntax.

js
async function getLabel() {
    let response = await fetch('/api/label')

    return await response.text()
}
alpine

Additionally, if you prefer calling methods in Alpine without the trailing parenthesis, you can leave them out and Alpine will detect that the provided function is async and handle it accordingly. For example:

alpine

File: packages/docs/src/en/advanced/reactivity.md


order: 2 title: Reactivity

Reactivity

Alpine is "reactive" in the sense that when you change a piece of data, everything that depends on that data "reacts" automatically to that change.

Every bit of reactivity that takes place in Alpine, happens because of two very important reactive functions in Alpine's core: Alpine.reactive(), and Alpine.effect().

Alpine uses VueJS's reactivity engine under the hood to provide these functions.
โ†’ Read more about @vue/reactivity

Understanding these two functions will give you super powers as an Alpine developer, but also just as a web developer in general.

Alpine.reactive()

Let's first look at Alpine.reactive(). This function accepts a JavaScript object as its parameter and returns a "reactive" version of that object. For example:

js
let data = { count: 1 }

let reactiveData = Alpine.reactive(data)

Under the hood, when Alpine.reactive receives data, it wraps it inside a custom JavaScript proxy.

A proxy is a special kind of object in JavaScript that can intercept "get" and "set" calls to a JavaScript object.

โ†’ Read more about JavaScript proxies

At face value, reactiveData should behave exactly like data. For example:

js
console.log(data.count) // 1
console.log(reactiveData.count) // 1

reactiveData.count = 2

console.log(data.count) // 2
console.log(reactiveData.count) // 2

What you see here is that because reactiveData is a thin wrapper around data, any attempts to get or set a property will behave exactly as if you had interacted with data directly.

The main difference here is that any time you modify or retrieve (get or set) a value from reactiveData, Alpine is aware of it and can execute any other logic that depends on this data.

Alpine.reactive is only the first half of the story. Alpine.effect is the other half, let's dig in.

Alpine.effect()

Alpine.effect accepts a single callback function. As soon as Alpine.effect is called, it will run the provided function, but actively look for any interactions with reactive data. If it detects an interaction (a get or set from the aforementioned reactive proxy) it will keep track of it and make sure to re-run the callback if any of reactive data changes in the future. For example:

js
let data = Alpine.reactive({ count: 1 })

Alpine.effect(() => {
    console.log(data.count)
})

When this code is first run, "1" will be logged to the console. Any time data.count changes, it's value will be logged to the console again.

This is the mechanism that unlocks all of the reactivity at the core of Alpine.

To connect the dots further, let's look at a simple "counter" component example without using Alpine syntax at all, only using Alpine.reactive and Alpine.effect:

alpine
Increment

Count:
js
let button = document.querySelector('button')
let span = document.querySelector('span')

let data = Alpine.reactive({ count: 1 })

Alpine.effect(() => {
    span.textContent = data.count
})

button.addEventListener('click', () => {
    data.count = data.count + 1
})
text
Increment

Count:

As you can see, you can make any data reactive, and you can also wrap any functionality in Alpine.effect.

This combination unlocks an incredibly powerful programming paradigm for web development. Run wild and free.


File: packages/docs/src/en/directives/bind.md


order: 4 title: bind

x-bind

x-bind allows you to set HTML attributes on elements based on the result of JavaScript expressions.

For example, here's a component where we will use x-bind to set the placeholder value of an input.

alpine

Shorthand syntax

If x-bind: is too verbose for your liking, you can use the shorthand: :. For example, here is the same input element as above, but refactored to use the shorthand syntax.

alpine

Despite not being included in the above snippet, x-bind cannot be used if no parent element has x-data defined. โ†’ Read more about x-data

Binding classes

x-bind is most often useful for setting specific classes on an element based on your Alpine state.

Here's a simple example of a simple dropdown toggle, but instead of using x-show, we'll use a "hidden" class to toggle an element.

alpine
Toggle Dropdown

    
        Dropdown Contents...

Now, when open is false, the "hidden" class will be added to the dropdown.

Shorthand conditionals

In cases like these, if you prefer a less verbose syntax you can use JavaScript's short-circuit evaluation instead of standard conditionals:

alpine

The inverse is also available to you. Suppose instead of open, we use a variable with the opposite value: closed.

alpine

Class object syntax

Alpine offers an additional syntax for toggling classes if you prefer. By passing a JavaScript object where the classes are the keys and booleans are the values, Alpine will know which classes to apply and which to remove. For example:

alpine

This technique offers a unique advantage to other methods. When using object-syntax, Alpine will NOT preserve original classes applied to an element's class attribute.

For example, if you wanted to apply the "hidden" class to an element before Alpine loads, AND use Alpine to toggle its existence you can only achieve that behavior using object-syntax:

alpine

In case that confused you, let's dig deeper into how Alpine handles x-bind:class differently than other attributes.

Special behavior

x-bind:class behaves differently than other attributes under the hood.

Consider the following case.

alpine

If "class" were any other attribute, the :class binding would overwrite any existing class attribute, causing opacity-50 to be overwritten by either hidden or ''.

However, Alpine treats class bindings differently. It's smart enough to preserve existing classes on an element.

For example, if hide is true, the above example will result in the following DOM element:

alpine

If hide is false, the DOM element will look like:

alpine

This behavior should be invisible and intuitive to most users, but it is worth mentioning explicitly for the inquiring developer or any special cases that might crop up.

Binding styles

Similar to the special syntax for binding classes with JavaScript objects, Alpine also offers an object-based syntax for binding style attributes.

Just like the class objects, this syntax is entirely optional. Only use it if it affords you some advantage.

alpine

Conditional inline styling is possible using expressions just like with x-bind:class. Short circuit operators can be used here as well by using a styles object as the second operand.

alpine

One advantage of this approach is being able to mix it in with existing styles on an element:

alpine

And like most expressions in Alpine, you can always use the result of a JavaScript expression as the reference:

alpine

Binding Alpine Directives Directly

x-bind allows you to bind an object of different directives and attributes to an element.

The object keys can be anything you would normally write as an attribute name in Alpine. This includes Alpine directives and modifiers, but also plain HTML attributes. The object values are either plain strings, or in the case of dynamic Alpine directives, callbacks to be evaluated by Alpine.

alpine
Open Dropdown

    Dropdown Contents


<script>
    document.addEventListener('alpine:init', () => {
        Alpine.data('dropdown', () => ({
            open: false,

            trigger: {
                ['x-ref']: 'trigger',
                ['@click']() {
                    this.open = true
                },
            },

            dialogue: {
                ['x-show']() {
                    return this.open
                },
                ['@click.outside']() {
                    this.open = false
                },
            },
        }))
    })
</script>

There are a couple of caveats to this usage of x-bind:

When the directive being "bound" or "applied" is x-for, you should return a normal expression string from the callback. For example: ['x-for']() { return 'item in items' }


File: packages/docs/src/en/directives/cloak.md


order: 12 title: cloak

x-cloak

Sometimes, when you're using AlpineJS for a part of your template, there is a "blip" where you might see your uninitialized template after the page loads, but before Alpine loads.

x-cloak addresses this scenario by hiding the element it's attached to until Alpine is fully loaded on the page.

For x-cloak to work however, you must add the following CSS to the page.

css
[x-cloak] { display: none !important; }

The following example will hide the `` tag until its x-show is specifically set to true, preventing any "blip" of the hidden element onto screen as Alpine loads.

alpine
This will not 'blip' onto screen at any point

x-cloak doesn't just work on elements hidden by x-show or x-if: it also ensures that elements containing data are hidden until the data is correctly set. The following example will hide the `` tag until Alpine has set its text content to the message property.

alpine

When Alpine loads on the page, it removes all x-cloak property from the element, which also removes the display: none; applied by CSS, therefore showing the element.

Alternative to global syntax

If you'd like to achieve this same behavior, but avoid having to include a global style, you can use the following cool, but admittedly odd trick:

alpine
<template x-if="true">
    
</template>

This will achieve the same goal as x-cloak by just leveraging the way x-if works.

Because <template> elements are "hidden" in browsers by default, you won't see the `` until Alpine has had a chance to render the x-if="true" and show it.

Again, this solution is not for everyone, but it's worth mentioning for special cases.


File: packages/docs/src/en/directives/data.md


order: 1 title: data

x-data

Everything in Alpine starts with the x-data directive.

x-data defines a chunk of HTML as an Alpine component and provides the reactive data for that component to reference.

Here's an example of a contrived dropdown component:

alpine
Toggle Content

    
        Content...

Don't worry about the other directives in this example (@click and x-show), we'll get to those in a bit. For now, let's focus on x-data.

Scope

Properties defined in an x-data directive are available to all element children. Even ones inside other, nested x-data components.

For example:

alpine

Methods

Because x-data is evaluated as a normal JavaScript object, in addition to state, you can store methods and even getters.

For example, let's extract the "Toggle Content" behavior into a method on x-data.

alpine
Toggle Content

    
        Content...

Notice the added toggle() { this.open = ! this.open } method on x-data. This method can now be called from anywhere inside the component.

You'll also notice the usage of this. to access state on the object itself. This is because Alpine evaluates this data object like any standard JavaScript object with a this context.

If you prefer, you can leave the calling parenthesis off of the toggle method completely. For example:

alpine
...


...

Getters

JavaScript getters are handy when the sole purpose of a method is to return data based on other state.

Think of them like "computed properties" (although, they are not cached like Vue's computed properties).

Let's refactor our component to use a getter called isOpen instead of accessing open directly.

alpine
Toggle Content

    
        Content...

Notice the "Content" now depends on the isOpen getter instead of the open property directly.

In this case there is no tangible benefit. But in some cases, getters are helpful for providing a more expressive syntax in your components.

Data-less components

Occasionally, you want to create an Alpine component, but you don't need any data.

In these cases, you can always pass in an empty object.

alpine

However, if you wish, you can also eliminate the attribute value entirely if it looks better to you.

alpine

Single-element components

Sometimes you may only have a single element inside your Alpine component, like the following:

alpine
Hide Me

In these cases, you can declare x-data directly on that single element:

alpine
Hide Me

Re-usable Data

If you find yourself duplicating the contents of x-data, or you find the inline syntax verbose, you can extract the x-data object out to a dedicated component using Alpine.data.

Here's a quick example:

alpine
Toggle Content

    
        Content...
    


<script>
    document.addEventListener('alpine:init', () => {
        Alpine.data('dropdown', () => ({
            open: false,

            toggle() {
                this.open = ! this.open
            },
        }))
    })
</script>

โ†’ Read more about Alpine.data(...)


File: packages/docs/src/en/directives/effect.md


order: 11 title: effect

x-effect

x-effect is a useful directive for re-evaluating an expression when one of its dependencies change. You can think of it as a watcher where you don't have to specify what property to watch, it will watch all properties used within it.

If this definition is confusing for you, that's ok. It's better explained through an example:

alpine
Change Message

When this component is loaded, the x-effect expression will be run and "Hello" will be logged into the console.

Because Alpine knows about any property references contained within x-effect, when the button is clicked and label is changed, the effect will be re-triggered and "Hello World!" will be logged to the console.


File: packages/docs/src/en/directives/for.md


order: 8 title: for

x-for

Alpine's x-for directive allows you to create DOM elements by iterating through a list. Here's a simple example of using it to create a list of colors based on an array.

alpine
<template x-for="color in colors">
        <li x-text="color"></li>
    </template>
text
<template x-for="color in colors">
        <li x-text="color"></li>
    </template>

You may also pass objects to x-for.

alpine
<template x-for="(value, index) in car">
        <li>
            : 
        </li>
    </template>
text
<template x-for="(value, index) in car">
        <li>
            : 
        </li>
    </template>

There are two rules worth noting about x-for:

x-for MUST be declared on a <template> element.
That <template> element MUST contain only one root element

Keys

It is important to specify unique keys for each x-for iteration if you are going to be re-ordering items. Without dynamic keys, Alpine may have a hard time keeping track of what re-orders and will cause odd side-effects.

alpine
<template x-for="color in colors" :key="color.id">
        <li x-text="color.label"></li>
    </template>

Now if the colors are added, removed, re-ordered, or their "id"s change, Alpine will preserve or destroy the iterated <li>elements accordingly.

Accessing indexes

If you need to access the index of each item in the iteration, you can do so using the ([item], [index]) in [items] syntax like so:

alpine
<template x-for="(color, index) in colors">
        <li>
            
            
        </li>
    </template>

You can also access the index inside a dynamic :key expression.

alpine
<template x-for="(color, index) in colors" :key="index">

Iterating over a range

If you need to simply loop n number of times, rather than iterate through an array, Alpine offers a short syntax.

alpine
<template x-for="i in 10">
        <li x-text="i"></li>
    </template>

i in this case can be named anything you like.

Despite not being included in the above snippet, x-for cannot be used if no parent element has x-data defined. โ†’ Read more about x-data

Contents of a `