High Mountains 🏔️
A Gleam library for working with Alpine.js through Lustre attributes
High Mountains provides a type-safe, idiomatic Gleam wrapper for Alpine.js directives, allowing you to build interactive web applications using Alpine.js features within the Lustre ecosystem.
Features
- Complete Alpine.js coverage: All Alpine.js directives are supported
- Type safety: Strongly typed modifiers and parameters prevent runtime errors
- Lustre integration: Seamlessly works with Lustre attributes
- Modular design: Import only what you need
- Comprehensive modifiers: Full support for event, model, and transition modifiers
Installation
Add High Mountains to your Gleam project:
gleam add high_mountains
Quick Start
import lustre/element/html
import high_mountains as alpine
pub fn counter_component() {
html.div([
alpine.data("{count: 0}"),
alpine.cloak()
], [
html.button([
alpine.on("click", [], "count++")
], [html.text("Increment")]),
html.span([
alpine.text("count")
], [])
])
}
Core Directives
Data Binding
data(js_object)
- Initialize Alpine component databind(attribute, js)
- Bind attributes to expressionsmodel(modifiers, js)
- Two-way data binding for inputstext(js)
- Set text contenthtml(js)
- Set innerHTML
Control Flow
x_if(js)
- Conditional rendering (use with<template>
)show(js)
- Toggle visibilityfor(key, value)
- Loop through collections
Events
on(event, modifiers, js)
- Handle DOM events with optional modifiers
Effects and Lifecycle
init(js)
- Run code when component initializeseffect(js)
- Re-run when dependencies change
Modifiers
Event Modifiers
import high_mountains/event_modifier.{Prevent, Stop, Debounce}
import gleam/option
html.form([
alpine.on("submit", [Prevent], "submitForm()")
], [...])
html.input([
alpine.on("input", [Debounce(option.Some(300))], "search()")
], [])
Available event modifiers:
Prevent
- preventDefault()Stop
- stopPropagation()Outside
- Listen for clicks outside elementWindow
- Listen on window objectDocument
- Listen on documentOnce
- Listen only onceDebounce(ms)
- Debounce event handlingThrottle(ms)
- Throttle event handlingSelf
- Only trigger if target is element itselfCamel
- Convert kebab-case to camelCaseDot
- Allow periods in key namesPassive
- Add as passive listenerCapture
- Add in capture phase
Model Modifiers
import high_mountains/model_modifier.{Lazy, Number}
html.input([
alpine.model([Lazy, Number], "price")
], [])
Available model modifiers:
Lazy
- Sync on change instead of inputNumber
- Cast to numberBoolean
- Cast to booleanDebounce(ms)
- Debounce model updatesThrottle(ms)
- Throttle model updatesFill
- Auto-fill form data
Transition Modifiers
import high_mountains/transition_modifier.{Duration, Scale, Opacity}
import gleam/option
html.div([
alpine.transition_helper([Duration(300), Scale(option.Some(95), []), Opacity])
], [...])
Available transition modifiers:
Duration(ms)
- Set transition durationDelay(ms)
- Add transition delayOpacity
- Fade in/outScale(percentage, origins)
- Scale transitions with optional origins
Advanced Features
References
html.input([alpine.ref("email")], [])
// Access with $refs.email in Alpine expressions
Teleporting
html.template([
alpine.teleport("body")
], [
// Modal content will be moved to body
])
ID Scoping
html.div([
alpine.id("['tab-content', 'tab-trigger']")
], [
// Use $id('tab-content') for unique IDs
])
Preventing Initialization
html.div([alpine.ignore()], [
// Alpine won't initialize this section
])
Preventing Flash
html.div([alpine.cloak()], [
// Hidden until Alpine loads
])
CSS required for x-cloak:
[x-cloak] { display: none !important; }
Examples
Toggle Component
import lustre/element/html
import high_mountains as alpine
pub fn toggle() {
html.div([
alpine.data("{open: false}")
], [
html.button([
alpine.on("click", [], "open = !open")
], [html.text("Toggle")]),
html.div([
alpine.show("open"),
alpine.transition_helper([])
], [
html.text("Content that toggles")
])
])
}
Form with Validation
import lustre/element/html
import high_mountains as alpine
import high_mountains/event_modifier
pub fn form() {
html.form([
alpine.data("{email: '', valid: false}"),
alpine.on("submit", [event_modifier.Prevent], "submit()")
], [
html.input([
alpine.model([], "email"),
alpine.on("input", [], "valid = email.includes('@')")
], []),
html.button([
alpine.bind("disabled", "!valid")
], [html.text("Submit")])
])
}
Dynamic List
import lustre/element/html
import high_mountains as alpine
pub fn todo_list() {
html.div([
alpine.data("{todos: [], newTodo: ''}")
], [
html.input([
alpine.model([], "newTodo"),
alpine.on("keyup.enter", [], "todos.push(newTodo); newTodo = ''")
], []),
html.template([
alpine.for("todo", "todos")
], [
html.div([
alpine.key("todo")
], [
html.span([alpine.text("todo")], [])
])
])
])
}
API Reference
Core Functions
All functions return Lustre attributes that can be used with HTML elements:
Function | Alpine Directive | Description |
---|---|---|
data(js_object) | x-data | Initialize component data |
init(js) | x-init | Run on initialization |
show(js) | x-show | Toggle visibility |
show_important(js) | x-show.important | Force visibility toggle |
bind(attr, js) | x-bind:attr | Bind attribute to expression |
on(event, modifiers, js) | x-on:event | Handle events |
text(js) | x-text | Set text content |
html(js) | x-html | Set innerHTML |
model(modifiers, js) | x-model | Two-way data binding |
modelable(js) | x-modelable | Make property modelable |
for(key, value) | x-for | Loop through collections |
key(js) | :key | Unique key for iterations |
x_if(js) | x-if | Conditional rendering |
effect(js) | x-effect | Watch dependencies |
ignore() | x-ignore | Prevent Alpine initialization |
ref(id) | x-ref | Element reference |
cloak() | x-cloak | Hide until Alpine loads |
teleport(selector) | x-teleport | Move element in DOM |
id(js) | x-id | ID scoping |
Transition Functions
Function | Description |
---|---|
transition_helper(modifiers) | Basic transition with modifiers |
transition_helper_enter(modifiers) | Enter transition with modifiers |
transition_helper_leave(modifiers) | Leave transition with modifiers |
transition_enter(classes) | Enter phase classes |
transition_enter_start(classes) | Enter start classes |
transition_end(classes) | Enter end classes |
transition_leave(classes) | Leave phase classes |
transition_leave_start(classes) | Leave start classes |
transition_leave_end(classes) | Leave end classes |
Testing
gleam test
Development
gleam build
gleam format
gleam docs build
Contributing
- Fork the repository on GitHub
- Create a feature branch
- Make your changes
- Add tests if applicable
- Ensure code passes
gleam format
andgleam test
- Submit a pull request
License
MIT License - see LICENSE file for details.
Resources
- Alpine.js Documentation - Official Alpine.js docs
- Lustre Documentation - Lustre web framework
- Gleam Language Guide - Learn Gleam
- Hex Documentation - API reference
Made with ❤️ for the Gleam and Alpine.js communities