Unstyled, accessible UI components for Phoenix and Phoenix LiveView. To be styled with the CSS framework of your choice.
Warning
This project is in a very early stage - see Components list below.
- Provide unstyled Phoenix components as building blocks for your own UI components
- If something can be achieved with HTML and CSS only, it should be done with HTML and CSS only (no-JS)
- Where JS is required, use Alpine.js
- Use
Alpine.data()
instead of inline markup - Components must work with standard Phoenix controllers (dead views)
- Components must work with Phoenix LiveView
- Components must work with standard Phoenix forms
- Components must be accessible (aria attributes, keyboard navigation, focus, etc.)
Component | Functions | Status |
---|---|---|
Avatar | use_avatar/1 |
✅ Done |
Checkbox | input/1 |
✅ Done |
Clipboard | use_clipboard/1 |
✅ Done |
Combobox | use_combobox/1 |
🏗️ In progress |
Command | 🏗️ In progress | |
Dialog | 🗺️ Planned | |
File Preview | 🗺️ Planned | |
Input OTP | 🗺️ Planned | |
Popover | use_popover/1 |
✅ Done |
Radio button | 🗺️ Planned | |
Tabs | 🗺️ Planned | |
Text input | input/1 |
✅ Done |
Textarea | 🗺️ Planned | |
Toggle | use_toggle/1 |
✅ Done |
The package can be installed by adding headless
to your list of dependencies in mix.exs
:
def deps do
[
{:headless, "~> 0.1"}
]
end
Include Alpine and JavaScript package in your app.js
:
// assets/js/app.js
import Alpine from "alpinejs"
import headless from "headless"
headless.configure(Alpine)
Alpine.start()
// ...
// configure LiveSocket
let liveSocket = new LiveSocket('/live', Socket, {
// ...
// configure dom hook
dom: headless.dom
})
Headless components are meant to be used as building blocks for your own components.
Most components are built using use_*
functions that expose the necessary HTML attributes
to provide the functionality leaving all tag rendering to the user.
This way every element can be 100% customized.
defmodule MyAppWeb.Components do
use Phoenix.Component
import Headless
attr :src, :any
attr :alt, :any
attr :initials, :string
def avatar(assigns) do
~H"""
<.use_avatar :let={a} src={@src}>
<div {a.root}>
<img {a.image} alt={@alt} />
<div {a.fallback}><%= @initials %></div>
</div>
</.use_avatar>
"""
end
end
// assets/js/app.js
import Alpine from "alpinejs"
import headless from "headless"
headless.configure(Alpine)
// add your components
Alpine.data("my_custom_component", () => ...)
Alpine.start()
# Install dependencies
mix deps.get
npm --prefix ./apps/demo/assets install
# Start development server with examples
mix phx.server