Alpine.js Complete Guide | Lightweight JavaScript Framework
이 글의 핵심
Alpine.js is a lightweight JavaScript framework that offers reactive and declarative nature of Vue.js at a fraction of the cost. Perfect for adding interactivity to server-rendered HTML.
Introduction
Alpine.js is a rugged, minimal framework for composing JavaScript behavior in your markup. It offers the reactive and declarative nature of big frameworks like Vue or React at a much lower cost.
Created by Caleb Porzio (also creator of Livewire), Alpine.js has become the de facto JavaScript framework for server-rendered applications, especially in the Laravel ecosystem.
Why Alpine.js Matters
The “just right” amount of JavaScript:
- 15KB gzipped (React: 40KB, Vue: 34KB, jQuery: 30KB)
- No build step required ??drop in via CDN, works immediately
- Perfect for server-rendered HTML ??enhances Laravel Blade, Rails ERB, Django templates
Real-world adoption:
- Laravel Jetstream/Breeze ??Alpine.js is the default JavaScript framework
- GitHub uses Alpine.js for interactive components on github.com
- Stripe Docs ??interactive API examples powered by Alpine.js
- ~2 million weekly npm downloads (one of the most popular micro-frameworks)
Why developers choose Alpine.js:
- Laravel/Rails developers ??adds interactivity without leaving the server-rendered mindset
- WordPress/PHP developers ??modern JavaScript without webpack/babel complexity
- Static site generators ??Jekyll, Hugo, Eleventy benefit from no-build interactivity
- Progressively enhancing content ??works alongside existing jQuery, doesn’t require full rewrite
Production use cases:
- E-commerce product filters ??without full SPA complexity
- Admin dashboards ??tabs, modals, dropdowns in server-rendered pages
- Marketing sites ??interactive components without React overhead
- WordPress plugins ??add modern UX without conflicting with existing code
When to use Alpine.js:
- Building with Laravel, Rails, Django, or WordPress
- Need dropdowns, modals, tabs on mostly static pages
- Want React-like syntax without build tools
- Progressive enhancement of existing server-rendered site
When to use React/Vue instead:
- Building a complex SPA with heavy client-side routing
- Need a large ecosystem of UI libraries
- App logic lives primarily on the client
- Real-time collaborative features (Google Docs-style)
The Problem
Traditional approach with vanilla JavaScript:
<button id="toggle">Toggle</button>
<div id="content" style="display: none;">Content</div>
<script>
const button = document.getElementById('toggle');
const content = document.getElementById('content');
let isOpen = false;
button.addEventListener('click', () => {
isOpen = !isOpen;
content.style.display = isOpen ? 'block' : 'none';
});
</script>
The Solution
With Alpine.js:
<div x-data="{ open: false }">
<button @click="open = !open">Toggle</button>
<div x-show="open">Content</div>
</div>
1. Installation
CDN (Quick Start)
<!DOCTYPE html>
<html>
<head>
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>
</head>
<body>
<div x-data="{ count: 0 }">
<button @click="count++">Increment</button>
<span x-text="count"></span>
</div>
</body>
</html>
NPM
npm install alpinejs
import Alpine from 'alpinejs';
window.Alpine = Alpine;
Alpine.start();
2. Core Directives
x-data (State)
<div x-data="{ name: 'John', age: 30 }">
<p x-text="name"></p>
<p x-text="age"></p>
</div>
x-show / x-if (Conditional)
<!-- x-show: toggles display CSS -->
<div x-data="{ open: false }">
<button @click="open = !open">Toggle</button>
<div x-show="open">I'm visible!</div>
</div>
<!-- x-if: adds/removes from DOM -->
<template x-if="user">
<div x-text="user.name"></div>
</template>
x-for (Loop)
<div x-data="{ items: ['Apple', 'Banana', 'Orange'] }">
<template x-for="item in items" :key="item">
<li x-text="item"></li>
</template>
</div>
x-on / @ (Events)
<div x-data="{ count: 0 }">
<!-- Long form -->
<button x-on:click="count++">Increment</button>
<!-- Short form -->
<button @click="count++">Increment</button>
<!-- With modifiers -->
<form @submit.prevent="handleSubmit">
<input @keyup.enter="submit">
</form>
</div>
x-bind / : (Attributes)
<div x-data="{ isActive: true, color: 'blue' }">
<!-- Long form -->
<div x-bind:class="{ active: isActive }"></div>
<!-- Short form -->
<div :class="{ active: isActive }"></div>
<!-- Multiple attributes -->
<div :class="isActive && 'active'" :style="`color: ${color}`"></div>
</div>
x-model (Two-way Binding)
<div x-data="{ search: '' }">
<input type="text" x-model="search" placeholder="Search...">
<p>Searching for: <span x-text="search"></span></p>
</div>
x-text / x-html
<div x-data="{ message: 'Hello World', html: '<strong>Bold</strong>' }">
<!-- Text content -->
<p x-text="message"></p>
<!-- HTML content -->
<div x-html="html"></div>
</div>
3. Practical Examples
Dropdown Menu
<div x-data="{ open: false }" @click.away="open = false">
<button @click="open = !open">Menu</button>
<div x-show="open" x-transition>
<a href="#">Profile</a>
<a href="#">Settings</a>
<a href="#">Logout</a>
</div>
</div>
Tabs
<div x-data="{ tab: 'home' }">
<nav>
<button @click="tab = 'home'" :class="{ active: tab === 'home' }">
Home
</button>
<button @click="tab = 'profile'" :class="{ active: tab === 'profile' }">
Profile
</button>
</nav>
<div x-show="tab === 'home'">Home content</div>
<div x-show="tab === 'profile'">Profile content</div>
</div>
Modal
<div x-data="{ open: false }">
<button @click="open = true">Open Modal</button>
<div x-show="open"
x-transition
@click.away="open = false"
class="modal">
<div class="modal-content">
<h2>Modal Title</h2>
<p>Modal content</p>
<button @click="open = false">Close</button>
</div>
</div>
</div>
Search Filter
<div x-data="{
search: '',
items: ['Apple', 'Banana', 'Cherry', 'Date'],
get filteredItems() {
return this.items.filter(i =>
i.toLowerCase().includes(this.search.toLowerCase())
);
}
}">
<input type="text" x-model="search" placeholder="Search fruits...">
<template x-for="item in filteredItems" :key="item">
<li x-text="item"></li>
</template>
</div>
4. Advanced Features
Alpine.data (Component)
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('dropdown', () => ({
open: false,
toggle() {
this.open = !this.open;
}
}));
});
</script>
<div x-data="dropdown">
<button @click="toggle">Toggle</button>
<div x-show="open">Dropdown content</div>
</div>
$watch (Reactive)
<div x-data="{ count: 0 }" x-init="$watch('count', value => console.log('Count:', value))">
<button @click="count++">Increment</button>
</div>
$refs (DOM Access)
<div x-data="{}">
<input x-ref="input" type="text">
<button @click="$refs.input.focus()">Focus Input</button>
</div>
5. Transitions
<div x-data="{ open: false }">
<button @click="open = !open">Toggle</button>
<!-- Simple transition -->
<div x-show="open" x-transition>
Fade in/out
</div>
<!-- Custom transition -->
<div x-show="open"
x-transition:enter="transition ease-out duration-300"
x-transition:enter-start="opacity-0 transform scale-90"
x-transition:enter-end="opacity-100 transform scale-100"
x-transition:leave="transition ease-in duration-300"
x-transition:leave-start="opacity-100 transform scale-100"
x-transition:leave-end="opacity-0 transform scale-90">
Custom animation
</div>
</div>
6. Ajax Example
<div x-data="{
users: [],
loading: false,
async fetchUsers() {
this.loading = true;
const res = await fetch('/api/users');
this.users = await res.json();
this.loading = false;
}
}" x-init="fetchUsers()">
<div x-show="loading">Loading...</div>
<template x-for="user in users" :key="user.id">
<div x-text="user.name"></div>
</template>
</div>
7. Best Practices
1. Keep State Close
<!-- Good: state is scoped to component -->
<div x-data="{ count: 0 }">
<button @click="count++">Increment</button>
<span x-text="count"></span>
</div>
<!-- Bad: global state -->
<script>
let globalCount = 0;
</script>
2. Use Alpine.data for Reusability
Alpine.data('counter', (initial = 0) => ({
count: initial,
increment() {
this.count++;
}
}));
<div x-data="counter(5)">
<button @click="increment">Increment</button>
<span x-text="count"></span>
</div>
3. Use x-cloak to Prevent Flash
[x-cloak] { display: none !important; }
<div x-data="{ show: false }" x-cloak>
<!-- Won't flash before Alpine loads -->
</div>
8. Framework Comparison
| Feature | Alpine.js | React | Vue |
|---|---|---|---|
| Size | 15KB | 40KB | 34KB |
| Learning Curve | Easy | Medium | Medium |
| Use Case | Sprinkles | SPA | SPA |
| Build Required | No | Yes | Optional |
Summary
Alpine.js is perfect for adding interactivity to server-rendered pages:
- Lightweight - only 15KB
- No build step - works with CDN
- Declarative - Vue-like syntax
- Progressive - enhance existing HTML
- Simple - learn in minutes
Key Takeaways:
- Use
x-datato define component state - Use
@clickfor event handling - Use
x-show/x-iffor conditionals - Use
x-forfor loops - Perfect for dropdowns, modals, tabs
Next Steps:
- Learn [HTMX](/en/blog/htmx-complete-guide/
- Build with [Astro](/en/blog/astro-blog-complete-guide/
- Compare with Vanilla JavaScript
Resources:
?�주 묻는 질문 (FAQ)
Q. ???�용???�무?�서 ?�제 ?�나??
A. Complete Alpine.js guide for reactive UIs. Learn directives, state management, and interactive components with minimal J???�무?�서????본문???�제?� ?�택 가?�드�?참고???�용?�면 ?�니??
Q. ?�행?�로 ?�으�?좋�? 글?�?
A. �?글 ?�단???�전 글 ?�는 관??글 링크�??�라가�??�서?��?배울 ???�습?�다. C++ ?�리�?목차?�서 ?�체 ?�름???�인?????�습?�다.
Q. ??깊이 공�??�려�?
A. cppreference?� ?�당 ?�이브러�?공식 문서�?참고?�세?? 글 말�???참고 ?�료 링크???�용?�면 좋습?�다.
같이 보면 좋�? 글 (?��? 링크)
??주제?� ?�결?�는 ?�른 글?�니??
- [Qwik Complete Guide | Resumable JavaScript Framework](/en/blog/qwik-complete-guide/
- [Solid.js Complete Guide | Fast Reactive JavaScript Framework](/en/blog/solid-js-complete-guide/
- The Complete HTMX Guide | HTML-First Development, Hypermedia, AJAX, Without an SPA, Production Use
??글?�서 ?�루???�워??(관??검?�어)
Alpine.js, JavaScript, Frontend, Lightweight, Reactive, UI ?�으�?검?�하?�면 ??글???��????�니??