Skip to content

teamon/headless

Repository files navigation

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.

Preview

Demo

See demo website

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 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
})

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.

See example app components.

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

// 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()

Development

# Install dependencies
mix deps.get
npm --prefix ./apps/demo/assets install

# Start development server with examples
mix phx.server

Inspirations

About

Headless UI Components for Phoenix

Resources

Stars

Watchers

Forks

Releases

No releases published