npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@momoledev/alpine-components

v1.0.12

Published

Composants Alpine.js réutilisables : Select, Dropdown, InputText, InputTags, Switch, Slider, Form, InputMask, Toast

Readme

Alpine Components

Bibliothèque headless de composants UI pour Alpine.js 3 — compatible Livewire et Laravel.

npm license

Documentationalpine-components.momoledev.com


Composants

| Composant | Rôle | x-modelable | |---|---|---| | apSelect | Select simple/multiple avec recherche | value | | apDropdown | Menu flottant avec auto-flip | — | | apInputText | Champ texte, password, clearable | value | | apInputTags | Saisie de tags | tags | | apSwitch | Toggle booléen | value | | apSlider | Curseur numérique avec tooltip | value | | apForm | État formulaire + submit fetch + erreurs 422 | data | | apInputMask | Masques : tel, carte, SIRET, money… | value | | $store.toast | Notifications globales (store Alpine) | — |


Installation

npm install @momoledev/alpine-components

Intégration — JavaScript / TypeScript

Avec le style prédéfini (recommandé)

import '@momoledev/alpine-components/style'  // classes ap-* + tokens CSS
import Alpine from 'alpinejs'
import AlpineComponents from '@momoledev/alpine-components'

Alpine.plugin(AlpineComponents)
Alpine.start()

Sans style (headless pur)

import Alpine from 'alpinejs'
import AlpineComponents from '@momoledev/alpine-components'

Alpine.plugin(AlpineComponents)
Alpine.start()

Importer uniquement certains composants

import Alpine from 'alpinejs'
import { apSelect, apForm, registerToastStore } from '@momoledev/alpine-components'

registerToastStore(Alpine)
Alpine.data('apSelect', apSelect)
Alpine.data('apForm', apForm)
Alpine.start()

Via CDN

<!-- Style prédéfini -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@momoledev/alpine-components/dist/style.css">
<!-- Alpine.js -->
<script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3/dist/cdn.min.js"></script>
<!-- Composants -->
<script type="module">
  import AlpineComponents from 'https://cdn.jsdelivr.net/npm/@momoledev/alpine-components/dist/index.mjs'
  document.addEventListener('alpine:init', () => Alpine.plugin(AlpineComponents))
</script>

Personnaliser les tokens CSS

Surchargez les variables sur :root après l'import du style :

:root {
  --ap-primary:       #10b981;  /* couleur principale */
  --ap-primary-hover: #059669;
  --ap-primary-light: #ecfdf5;
  --ap-primary-ring:  rgba(16, 185, 129, 0.25);
  --ap-radius:        0.375rem; /* coins */
  --ap-height:        2.25rem;  /* hauteur des champs */
}

Intégration — Laravel + Vite

1. Installer le package

npm install @momoledev/alpine-components

2a. Importer le style dans resources/css/app.css

@import '@momoledev/alpine-components/style';

C'est la méthode recommandée dans Laravel. Vite résout automatiquement le chemin node_modules.

Alternative — importer directement dans resources/js/app.js :

import '@momoledev/alpine-components/style'

2b. Enregistrer Alpine dans resources/js/app.js

import Alpine from 'alpinejs'
import AlpineComponents from '@momoledev/alpine-components'

Alpine.plugin(AlpineComponents)

window.Alpine = Alpine
Alpine.start()

3. vite.config.js (inchangé)

import { defineConfig } from 'vite'
import laravel from 'laravel-vite-plugin'

export default defineConfig({
    plugins: [
        laravel({
            input: ['resources/css/app.css', 'resources/js/app.js'],
            refresh: true,
        }),
    ],
})

4. Layout Blade

{{-- resources/views/layouts/app.blade.php --}}
<!DOCTYPE html>
<html lang="fr">
<head>
    <meta charset="UTF-8">
    <meta name="csrf-token" content="{{ csrf_token() }}">
    @vite(['resources/css/app.css', 'resources/js/app.js'])
</head>
<body>
    @yield('content')

    {{-- Conteneur Toast (une fois dans le layout) --}}
    <div x-data class="ap-toast-container">
        <template x-for="t in $store.toast.items" :key="t.id">
            <div class="ap-toast" :class="`ap-toast-${t.type}`"
                 x-show="t.visible" x-transition>
                <div class="ap-toast-body">
                    <p class="ap-toast-title" x-show="t.title" x-text="t.title"></p>
                    <p class="ap-toast-message" x-text="t.message"></p>
                </div>
                <button class="ap-toast-dismiss" @click="$store.toast.dismiss(t.id)">✕</button>
            </div>
        </template>
    </div>
</body>
</html>

5. Formulaire Blade avec classes ap-*

{{-- resources/views/members/create.blade.php --}}
<form class="ap-form"
      x-data="apForm({
          data: { name: '', email: '', role: null },
          errors: @json($errors->getMessages()),
      })"
      @submit.prevent="submit('{{ route('members.store') }}')">

    <div class="ap-form-field">
        <label class="ap-form-label is-required">Nom</label>
        <input class="ap-input" :class="{ 'is-error': hasError('name') }"
               x-model="data.name" placeholder="Jean Dupont">
        <p class="ap-form-error" x-show="hasError('name')" x-text="getError('name')"></p>
    </div>

    <div class="ap-form-field">
        <label class="ap-form-label is-required">Rôle</label>
        <div x-data="apSelect({ options: [
                 { label: 'Développeur', value: 'dev' },
                 { label: 'Designer',    value: 'design' },
             ] })"
             x-modelable="value" x-model="data.role"
             class="ap-select" @click.outside="close()">
            <button class="ap-select-trigger" :class="{ 'is-error': hasError('role'), 'is-open': open }"
                    @click="toggleOpen()">
                <span class="ap-select-trigger-label"
                      :class="{ 'is-placeholder': !hasValue }"
                      x-text="display || 'Choisir un rôle'"></span>
            </button>
            <div class="ap-select-panel" x-show="open" x-cloak>
                <ul class="ap-select-options">
                    <template x-for="opt in filteredOptions" :key="opt.value">
                        <li class="ap-select-option"
                            :class="{ 'is-selected': isSelected(opt.value) }"
                            @click="select(opt)" x-text="opt.label"></li>
                    </template>
                </ul>
            </div>
        </div>
        <p class="ap-form-error" x-show="hasError('role')" x-text="getError('role')"></p>
    </div>

    <div class="ap-form-success" x-show="success">✓ Enregistré.</div>

    <button type="submit" class="ap-form-submit" :disabled="loading">
        <span x-show="!loading">Enregistrer</span>
        <span x-show="loading">Envoi…</span>
    </button>
</form>

apForm lit meta[name="csrf-token"] automatiquement et gère les réponses 422 de Laravel.


Utiliser avec un agent IA

Le projet inclut un skill prêt à l'emploi avec tous les snippets copy-paste.

Claude Code

# Dans n'importe quel projet qui utilise @momoledev/alpine-components
/alpine-components

Le skill fournit instantanément les snippets HTML complets avec classes ap-* pour tous les composants.

Copier le fichier de référence dans votre projet

curl -O https://raw.githubusercontent.com/momostifler96/alpine-components/master/alpine-components.md

Puis indiquez à votre agent de lire ce fichier comme contexte :

# Cursor / Windsurf / Copilot
@alpine-components.md

# Claude / ChatGPT / autre LLM
"Lis alpine-components.md puis génère un formulaire avec apSelect et apForm"

Contenu du fichier de référence

alpine-components.md contient pour chaque composant :

  • Snippet HTML minimal (sans style)
  • Snippet complet avec classes ap-*
  • Liste des props, état et méthodes
  • Combinaisons courantes (form + select, switch dans form, dropdown dans tableau)

Scripts

| Commande | Action | |---|---| | npm run dev | Dev playground | | npm run build | Build lib (ESM + UMD → dist/) | | npm run docs:dev | Dev VitePress | | npm run docs:build | Build docs statiques |

Licence

MIT — Momoledev