Lustre Prefab 🎨
A UI component library for Lustre built on lustre_stylish. Inspired by prefab-ui (Elm) and the Clarity Design System.
Installation
gleam add lustre_prefab
Quick Start
import lustre/stylish as el
import lustre/prefab/button
import lustre/prefab/card
import lustre/prefab/theme
import gleam/option.{Some}
pub fn view(model: Model) {
card.view(
[el.padding(20)],
el.column([el.spacing(15)], [
el.el([
font.size(24),
font.color(theme.primary()),
], el.text("Welcome!")),
button.new("Get Started", Some(StartClicked))
|> button.with_style(button.Primary)
|> button.with_size(button.Large)
|> button.view([]),
])
)
}
Components
✅ Available Now
button- Buttons with multiple styles (Primary, Secondary, Success, Danger, Warning, Info), sizes (Normal, Small, Large, Block), and variants (Solid, Outline, Flat)card- Container with white background, rounded borders, and shadowtheme- Comprehensive color palette with semantic colorstext- Predefined text styles (h1-h6, body, label, helpText, sectionHeader)alert- Alert/notification messages with types and dismiss functionalitylink- Hyperlinks styled as buttons with all button variantscheckbox- Checkbox inputs with labelsinput- Text inputs with multiple types (Text, Email, Password, Multiline, etc.) and layoutsradio- Radio button groups with multiple layout options (Vertical, Horizontal, Compact, etc.)loader- Simple loading indicator
All core components from prefab-ui have been successfully ported! 🎉
Features
✨ Type-Safe - Leverages Gleam’s type system for compile-time safety
🎨 Themeable - Consistent color palette across all components
📦 Composable - Built with lustre_stylish’s declarative API
🚀 Zero CSS - All styles generated automatically
📖 Well Documented - Every component includes examples
Button Example
import lustre/prefab/button
import gleam/option.{Some}
// Basic button
button.new("Click me", Some(ButtonClicked))
|> button.view([])
// Styled button with options
button.new("Submit", Some(FormSubmitted))
|> button.with_style(button.Primary)
|> button.with_size(button.Large)
|> button.with_variant(button.Solid)
|> button.view([])
// Outline button
button.new("Cancel", Some(Cancelled))
|> button.with_style(button.Secondary)
|> button.with_variant(button.Outline)
|> button.view([])
// Disabled button
button.new("Loading...", option.None)
|> button.with_disabled()
|> button.view([])
Card Example
import lustre/prefab/card
import lustre/stylish as el
card.view(
[el.padding(30), el.width(el.px(400))],
el.column([el.spacing(10)], [
el.text("Card Title"),
el.text("Card content goes here"),
])
)
Theme Example
import lustre/prefab/theme
import lustre/stylish/background
import lustre/stylish/font
el.el([
background.color(theme.primary()),
font.color(theme.white()),
], el.text("Themed element"))
// Semantic colors
background.color(theme.success())
background.color(theme.danger())
background.color(theme.warning())
background.color(theme.info())
// With alpha transparency
background.color(theme.primary_alpha(0.5))
Text Example
import lustre/prefab/text
// Headers
text.h1([], "Main Title")
text.h2([], "Subtitle")
// Body text
text.body([], "This is body text")
text.label([], "Form Label")
text.help_text([], "Helper text goes here")
Alert Example
import lustre/prefab/alert
// Success alert with dismiss
alert.new("Operation completed successfully!")
|> alert.with_type(alert.Success)
|> alert.with_dismiss(DismissAlert)
|> alert.view([])
// Warning alert (compact)
alert.new("Please review your input")
|> alert.with_type(alert.Warning)
|> alert.with_size(alert.Compact)
|> alert.view([])
Input Example
import lustre/prefab/input
// Text input
input.new(
on_change: UpdateName,
value: model.name,
label: "Name",
)
|> input.with_placeholder("Enter your name")
|> input.view([])
// Email input with help text
input.new(
on_change: UpdateEmail,
value: model.email,
label: "Email",
)
|> input.with_input_type(input.Email)
|> input.with_help_text("We'll never share your email")
|> input.view([])
Radio Example
import lustre/prefab/radio
radio.new(
label: "Choose size",
on_change: UpdateSize,
selected: Some(model.size),
)
|> radio.with_options([Small, Medium, Large])
|> radio.with_serializer(size_to_string)
|> radio.with_layout(radio.Horizontal)
|> radio.view([])
// Semantic colors background.color(theme.success()) background.color(theme.danger()) background.color(theme.warning()) background.color(theme.info())
// With alpha transparency background.color(theme.primary_alpha(0.5))
## Philosophy
Lustre Prefab follows the same philosophy as lustre_stylish and prefab-ui:
1. **Pre-fabricated but flexible** - Sensible defaults with customization options
2. **Type-safe** - Impossible states are impossible
3. **Composable** - Build complex UIs from simple pieces
4. **Consistent** - Unified theming across all components
## Documentation
Full API documentation available at <https://hexdocs.pm/lustre_prefab>
Or build locally:
```sh
gleam docs build
Development
gleam build # Build the project
gleam test # Run the tests
gleam docs build # Generate documentation
Relationship to prefab-ui
This library is a Gleam/Lustre port of prefab-ui, maintaining API compatibility where possible while adapting to Gleam’s idioms and lustre_stylish’s architecture.
License
MIT License
Acknowledgments
- prefab-ui - The original Elm implementation
- Clarity Design System - Design inspiration
- lustre_stylish - The foundation layout library
- Lustre - The excellent Gleam web framework