agentsclimarketplace

Alpine

Skill ComeOnOliver/skillshub/skills/TerminalSkills/skills/alpine

🧠 The right skill, one API call. AI agent skills registry with token-efficient skill resolution. 5,000+ skills from 500+ top repos.From the repository description

Install
npx -y skills add ComeOnOliver/skillshub --skill alpine

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

SKILL.md

7.5 KB, ~2.1k tokens by cl100k_base, as published. Nobody here has run it

Alpine.js

Alpine.js adds reactive behavior directly in HTML markup using x- attributes. It's ideal for adding interactivity to server-rendered pages without a build step or SPA framework.

Installation

<!-- index.html β€” add Alpine via CDN -->
<script defer src="https://cdn.jsdelivr.net/npm/[email protected]/dist/cdn.min.js"></script>
<!-- Or: npm install alpinejs -->
// main.js β€” npm module setup
import Alpine from 'alpinejs';
window.Alpine = Alpine;
Alpine.start();

Core Directives

<!-- templates/basics.html β€” fundamental Alpine directives -->
<div x-data="{ open: false, count: 0 }">
  <!-- Toggle visibility -->
  <button @click="open = !open">Toggle</button>
  <div x-show="open" x-transition>
    <p>This content can be toggled</p>
  </div>

  <!-- Reactive counter -->
  <p>Count: <span x-text="count"></span></p>
  <button @click="count++">Increment</button>

  <!-- Conditional rendering (removes from DOM) -->
  <template x-if="count > 5">
    <p>Count is greater than 5!</p>
  </template>
</div>

Data Binding

<!-- templates/binding.html β€” two-way binding and attribute binding -->
<div x-data="{ name: '', color: 'blue' }">
  <!-- Two-way binding -->
  <input x-model="name" placeholder="Your name" />
  <p>Hello, <span x-text="name || 'stranger'"></span>!</p>

  <!-- Attribute binding -->
  <div :class="{ 'text-red': color === 'red', 'text-blue': color === 'blue' }">
    Colored text
  </div>
  <select x-model="color">
    <option value="blue">Blue</option>
    <option value="red">Red</option>
  </select>

  <!-- Style binding -->
  <div :style="{ color: color, fontWeight: name ? 'bold' : 'normal' }">
    Dynamic styles
  </div>
</div>

Loops

<!-- templates/loops.html β€” iterating over data -->
<div x-data="{ items: ['Apples', 'Bananas', 'Cherries'], newItem: '' }">
  <ul>
    <template x-for="(item, index) in items" :key="index">
      <li>
        <span x-text="item"></span>
        <button @click="items.splice(index, 1)">Γ—</button>
      </li>
    </template>
  </ul>

  <form @submit.prevent="items.push(newItem); newItem = ''">
    <input x-model="newItem" placeholder="Add item" />
    <button type="submit">Add</button>
  </form>
</div>

Event Handling

<!-- templates/events.html β€” event modifiers and custom events -->
<div x-data="{ count: 0 }">
  <!-- Modifiers -->
  <button @click.prevent="count++">Prevent default</button>
  <button @click.once="alert('Only once!')">Click once</button>
  <input @keydown.enter="submitForm()" @keydown.escape="cancel()" />

  <!-- Debounce -->
  <input @input.debounce.300ms="search($event.target.value)" placeholder="Search..." />

  <!-- Listen to events from window -->
  <div @custom-event.window="count++">
    Count: <span x-text="count"></span>
  </div>

  <!-- Dispatch custom event -->
  <button @click="$dispatch('custom-event')">Dispatch</button>
</div>

Component Patterns

<!-- templates/dropdown.html β€” dropdown component -->
<div x-data="{ open: false }" @click.outside="open = false">
  <button @click="open = !open">
    Menu
    <span :class="{ 'rotate-180': open }" x-text="open ? 'β–²' : 'β–Ό'"></span>
  </button>

  <div x-show="open" x-transition.origin.top.left
    @keydown.escape.window="open = false"
    class="dropdown-menu">
    <a href="/profile">Profile</a>
    <a href="/settings">Settings</a>
    <button @click="$dispatch('logout')">Logout</button>
  </div>
</div>
<!-- templates/tabs.html β€” tabs component -->
<div x-data="{ activeTab: 'general' }">
  <nav>
    <button @click="activeTab = 'general'" :class="{ active: activeTab === 'general' }">General</button>
    <button @click="activeTab = 'security'" :class="{ active: activeTab === 'security' }">Security</button>
  </nav>

  <div x-show="activeTab === 'general'">General settings...</div>
  <div x-show="activeTab === 'security'">Security settings...</div>
</div>

Reusable Data with Alpine.data

<!-- templates/reusable.html β€” extracting reusable components -->
<script>
  // Register reusable component
  document.addEventListener('alpine:init', () => {
    Alpine.data('todoList', () => ({
      items: [],
      newItem: '',
      add() {
        if (this.newItem.trim()) {
          this.items.push({ text: this.newItem, done: false });
          this.newItem = '';
        }
      },
      remove(index) {
        this.items.splice(index, 1);
      },
      get remaining() {
        return this.items.filter(i => !i.done).length;
      },
    }));
  });
</script>

<!-- Use anywhere -->
<div x-data="todoList">
  <form @submit.prevent="add">
    <input x-model="newItem" placeholder="New todo" />
    <button type="submit">Add</button>
  </form>
  <p x-text="`${remaining} remaining`"></p>
  <template x-for="(item, i) in items" :key="i">
    <div>
      <input type="checkbox" x-model="item.done" />
      <span x-text="item.text" :class="{ 'line-through': item.done }"></span>
      <button @click="remove(i)">Γ—</button>
    </div>
  </template>
</div>

Working with htmx

<!-- templates/alpine-htmx.html β€” Alpine + htmx together -->
<div x-data="{ editing: false }" id="article-42">
  <div x-show="!editing">
    <h2>Article Title</h2>
    <button @click="editing = true">Edit</button>
    <button hx-delete="/articles/42" hx-target="#article-42" hx-swap="outerHTML">Delete</button>
  </div>
  <form x-show="editing" hx-put="/articles/42" hx-target="#article-42" hx-swap="outerHTML">
    <input name="title" value="Article Title" />
    <button type="submit">Save</button>
    <button type="button" @click="editing = false">Cancel</button>
  </form>
</div>

Stores (Global State)

<!-- templates/stores.html β€” Alpine stores for shared state -->
<script>
  document.addEventListener('alpine:init', () => {
    Alpine.store('notifications', {
      items: [],
      add(msg) { this.items.push({ text: msg, id: Date.now() }) },
      remove(id) { this.items = this.items.filter(n => n.id !== id) },
    });
  });
</script>

<div x-data @click="$store.notifications.add('Button clicked!')">Click me</div>

<div x-data>
  <template x-for="n in $store.notifications.items" :key="n.id">
    <div class="toast" x-text="n.text" @click="$store.notifications.remove(n.id)"></div>
  </template>
</div>

Magic Properties

<!-- templates/magic.html β€” Alpine magic properties -->
<div x-data="{ items: [] }">
  <!-- $refs β€” reference DOM elements -->
  <input x-ref="input" />
  <button @click="$refs.input.focus()">Focus input</button>

  <!-- $nextTick β€” run after DOM update -->
  <button @click="items.push('new'); $nextTick(() => $refs.list.scrollTo(0, 99999))">
    Add & scroll
  </button>
  <div x-ref="list" style="max-height:200px;overflow:auto">
    <template x-for="item in items"><p x-text="item"></p></template>
  </div>

  <!-- $watch β€” react to data changes -->
  <div x-init="$watch('items', (val) => console.log('items changed:', val))"></div>
</div>

Key Patterns

  • Use x-data on a parent element to define reactive scope β€” everything inside shares that state
  • Use x-show for toggling visibility (CSS), x-if for conditional DOM insertion
  • Use x-model for two-way binding on inputs, selects, checkboxes
  • Use event modifiers (.prevent, .stop, .debounce, .outside) to reduce boilerplate
  • Use Alpine.data() to extract reusable components with methods and computed properties
  • Use Alpine.store() for global state shared across components
  • Pairs excellently with htmx: Alpine handles UI state, htmx handles server communication

What ships with it

Read from the repository

Just SKILL.md. No reference files, no scripts.

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.