DEV Community

Alex Spinov
Alex Spinov

Posted on

Alpine.js Has a Free API — The JavaScript Framework for HTML Enthusiasts

Alpine.js is a lightweight JavaScript framework that lets you add interactivity directly in your HTML markup. No build step, no virtual DOM, no JSX — just HTML attributes.

Why Alpine.js?

  • 14KB — tiny footprint, CDN-ready
  • No build step — works with a single <script> tag
  • HTML-first — logic lives in your markup with x- directives
  • Perfect companion for HTMX, Tailwind, server-rendered HTML

Quick Start

<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>

<div x-data="{ count: 0 }">
    <p x-text="`Count: ${count}`"></p>
    <button @click="count++">Increment</button>
</div>
Enter fullscreen mode Exit fullscreen mode

That's it. No npm, no webpack, no config files.

Core Directives

<!-- x-data: reactive state -->
<div x-data="{ open: false, name: '' }">

    <!-- x-show: toggle visibility -->
    <div x-show="open">
        <p>This is visible when open is true</p>
    </div>

    <!-- x-bind: dynamic attributes -->
    <button :class="open ? 'bg-blue' : 'bg-gray'">Toggle</button>

    <!-- x-on / @: event listeners -->
    <button @click="open = !open">Toggle</button>

    <!-- x-model: two-way binding -->
    <input x-model="name" placeholder="Your name">
    <p x-text="`Hello, ${name}`"></p>

    <!-- x-if: conditional rendering -->
    <template x-if="name.length > 0">
        <p>Welcome!</p>
    </template>

    <!-- x-for: loops -->
    <template x-for="item in ['a', 'b', 'c']">
        <li x-text="item"></li>
    </template>
</div>
Enter fullscreen mode Exit fullscreen mode

Dropdown Component

<div x-data="{ open: false }" @click.outside="open = false">
    <button @click="open = !open">
        Menu
    </button>
    <div x-show="open" x-transition>
        <a href="/profile">Profile</a>
        <a href="/settings">Settings</a>
        <a href="/logout">Logout</a>
    </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Fetching Data

<div x-data="{ users: [], loading: true }"
     x-init="fetch('/api/users')
       .then(r => r.json())
       .then(data => { users = data; loading = false })">

    <p x-show="loading">Loading...</p>

    <template x-for="user in users" :key="user.id">
        <div>
            <h3 x-text="user.name"></h3>
            <p x-text="user.email"></p>
        </div>
    </template>
</div>
Enter fullscreen mode Exit fullscreen mode

Alpine Store (Global State)

<script>
    document.addEventListener('alpine:init', () => {
        Alpine.store('cart', {
            items: [],
            add(item) {
                this.items.push(item);
            },
            get total() {
                return this.items.reduce((sum, i) => sum + i.price, 0);
            },
        });
    });
</script>

<div x-data>
    <p>Cart: <span x-text="$store.cart.items.length"></span> items</p>
    <p>Total: $<span x-text="$store.cart.total"></span></p>
    <button @click="$store.cart.add({ name: 'Widget', price: 9.99 })">
        Add Widget
    </button>
</div>
Enter fullscreen mode Exit fullscreen mode

Plugins

<!-- Mask plugin -->
<script src="https://cdn.jsdelivr.net/npm/@alpinejs/mask@3.x.x/dist/cdn.min.js"></script>
<input x-mask="(999) 999-9999" placeholder="Phone">
<input x-mask="99/99/9999" placeholder="Date">

<!-- Intersect plugin -->
<script src="https://cdn.jsdelivr.net/npm/@alpinejs/intersect@3.x.x/dist/cdn.min.js"></script>
<div x-intersect="visible = true">Lazy load this</div>

<!-- Persist plugin -->
<script src="https://cdn.jsdelivr.net/npm/@alpinejs/persist@3.x.x/dist/cdn.min.js"></script>
<div x-data="{ theme: $persist('dark') }">
    <button @click="theme = theme === 'dark' ? 'light' : 'dark'">Toggle</button>
</div>
Enter fullscreen mode Exit fullscreen mode

Need dynamic data for your Alpine.js app? Check out my Apify actors for web scraping APIs, or email spinov001@gmail.com for custom solutions.

Alpine.js, Petite Vue, or vanilla JS — what do you use for lightweight interactivity? Share below!

Top comments (0)