AgentStack
SKILL verified MIT Self-run

Alpinejs

skill-brettatoms-agent-skills-alpinejs · by brettatoms

AlpineJS best practices and patterns. Use when writing HTML with Alpine.js directives to avoid common mistakes like long inline JavaScript strings.

No reviews yet
0 installs
2 views
0.0% view→install

Install

$ agentstack add skill-brettatoms-agent-skills-alpinejs

✓ scanned · ✓ verified — works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • Prompt-injection patterns
  • Secret / credential exfiltration
  • Dangerous shell & filesystem operations
  • Untrusted network calls
  • Known-malicious package signatures

What it can access

  • Network access No
  • Filesystem access No
  • Shell / process execution No
  • Environment & secrets No
  • Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

Are you the author of Alpinejs? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

AlpineJS Best Practices

Golden Rule: Keep Attributes Short

Never put complex logic in HTML attributes. If your x-data, x-init, or any directive exceeds ~50 characters, extract it.

Directive Cheatsheet

| Directive | Purpose | Example | |-----------|---------|---------| | x-data | Declare reactive component state | x-data="{ open: false }" | | x-init | Run code on component init | x-init="fetchData()" | | x-show | Toggle visibility (CSS display) | x-show="open" | | x-if | Conditional rendering (must wrap `) | | | x-for | Loop (must wrap ) | | | x-bind: / : | Bind attribute to expression | :class="{ active: isActive }" | | x-on: / @ | Listen to events | @click="open = !open" | | x-model | Two-way bind form inputs | x-model="email" | | x-text | Set text content | x-text="message" | | x-html | Set inner HTML | x-html="htmlContent" | | x-ref | Reference element via $refs | x-ref="input" | | x-cloak | Hide until Alpine initializes | x-cloak (add CSS: [x-cloak] { display: none; }) | | x-transition | Apply enter/leave transitions | x-transition or x-transition.duration.300ms | | x-effect | Run reactive side effects | x-effect="console.log(count)" | | x-ignore | Skip Alpine initialization | x-ignore | | x-teleport | Move element to another location | x-teleport="#modals" | | x-modelable | Expose property for external binding | x-modelable="value"` |

Magic Properties

| Property | Description | |----------|-------------| | $el | Current DOM element | | $refs | Access elements with x-ref | | $store | Access global Alpine stores | | $watch | Watch a property for changes | | $dispatch | Dispatch custom events | | $nextTick | Run after DOM updates | | $root | Root element of component | | $data | Access component data object | | $id | Generate unique IDs |

Patterns

❌ BAD: Long Inline JavaScript

✅ GOOD: Extract to Function


function itemList() {
  return {
    items: [],
    loading: true,
    error: null,
    
    async fetchItems() {
      this.loading = true;
      try {
        const res = await fetch('/api/items');
        this.items = await res.json();
      } catch (e) {
        this.error = e.message;
      } finally {
        this.loading = false;
      }
    }
  };
}

  

✅ GOOD: Simple Inline State


  Toggle
  Content

✅ GOOD: Global Store for Shared State


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); }
  });
});

  

✅ GOOD: Reusable Component with Alpine.data()


document.addEventListener('alpine:init', () => {
  Alpine.data('dropdown', () => ({
    open: false,
    toggle() { this.open = !this.open; },
    close() { this.open = false; }
  }));
});

  Menu
  
    Item 1
  

✅ GOOD: Form with Validation


function contactForm() {
  return {
    email: '',
    message: '',
    errors: {},
    
    validate() {
      this.errors = {};
      if (!this.email.includes('@')) this.errors.email = 'Invalid email';
      if (this.message.length 

  
  
  
  
  
  
  Send

Event Modifiers

@click.prevent     
@click.stop        
@click.outside     
@click.window      
@click.document    
@click.once        
@click.debounce    
@click.throttle    
@keydown.enter     
@keydown.escape    

Transition Modifiers

x-transition                           
x-transition.duration.300ms            
x-transition.opacity                   
x-transition.scale.90                  
x-transition:enter.duration.500ms      
x-transition:leave.duration.200ms      

Quick Decision Guide

  1. State is 1-3 simple properties? → Inline x-data="{ open: false }"
  2. Has methods or complex logic? → Extract to function componentName() { return {...} }
  3. Reused across pages? → Use Alpine.data('name', () => ({...}))
  4. Shared global state? → Use Alpine.store('name', {...})
  5. Long attribute string? → You're doing it wrong. Extract it.

Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet — be the first.

Versions

  • v0.1.0 Imported from the upstream source.