View Source Headless UI Components for Phoenix
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.
Demo
Goals & Rules
- 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.)
Components
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 |
Installation
The package can be installed by adding headless
to your list of dependencies in mix.exs
:
def deps do
[
{:headless, "~> 0.1"}
]
end
Include JavaScript package in your app.js
:
// assets/js/app.js
// import and start headless
import headless from "headless"
headless.start()
// ...
// configure LiveSocket
let liveSocket = new LiveSocket('/live', Socket, {
// ...
// configure dom hook
dom: headless.dom
})
Usage
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
Adding your own Alpine components
If you want to add your own Alpine components you can import the bundled Alpine like this:
// assets/js/app.js
import headless, { Alpine } from "headless"
Alpine.data("my_custom_component", () => ...)
headless.start()
Development
# Start development server with examples
mix phx.server
# Update bundled Alpine
curl -L https://unpkg.com/@alpinejs/csp/dist/module.cjs.js > ./apps/headless/assets/vendor/alpine.js