PhoenixDuskmoon

CI Release Hex.pm Hex Docs npm

Duskmoon UI component library for Phoenix LiveView applications.

v9: Uses @duskmoon-dev/core CSS design system, HTML Custom Elements (@duskmoon-dev/elements), and Art Custom Elements (@duskmoon-dev/art-elements).

Requires tailwindcss >= 4.0

See the docs for more information.

Install

Add to mix.exs:

{:phoenix_duskmoon, "~> 9.0"},

Install frontend packages:

bun add @duskmoon-dev/core @duskmoon-dev/elements

Optionally, add CSS Art and Art Custom Elements support:

bun add @duskmoon-dev/css-art @duskmoon-dev/art-elements

View Helpers

Add to your Phoenix view helpers (e.g. lib/my_app_web.ex):

defp html_helpers do
quote do
# Standard UI components (buttons, cards, forms, navigation, etc.)
use PhoenixDuskmoon.Component
# CSS Art decorative components (snow, plasma ball, eclipse, etc.)
use PhoenixDuskmoon.ArtComponent
end
end

CSS Setup

In your CSS entry file (e.g. assets/css/app.css):

@import "tailwindcss";
@plugin "@duskmoon-dev/core/plugin";
@import "phoenix_duskmoon/components";

JavaScript Setup

Register the custom elements in assets/js/app.js:

import "@duskmoon-dev/elements/register";
// Optionally, register art custom elements
import "@duskmoon-dev/art-elements/register";

Hooks Setup

Some components require LiveView hooks. Add them when creating your LiveSocket:

import {LiveSocket} from "phoenix_live_view"
import * as DuskmoonHooks from "phoenix_duskmoon/hooks"
let liveSocket = new LiveSocket("/live", Socket, {
params: {_csrf_token: csrfToken},
hooks: DuskmoonHooks
})

Components that require hooks:

Usage

Buttons

<.dm_btn variant="primary">Click me</.dm_btn>
<.dm_btn variant="secondary" loading={@loading}>Loading</.dm_btn>
<.dm_btn variant="error" shape="circle">×</.dm_btn>
<.dm_btn native_submit variant="primary">Submit without JavaScript</.dm_btn>

Cards

<.dm_card class="p-6">
<:title><h3>Title</h3></:title>
<p>Content here</p>
<:footer><.dm_btn>Action</.dm_btn></:footer>
</.dm_card>

Icons

<.dm_mdi name="home" />
<.dm_bsi name="house" />

Forms

<.dm_form for={@form} phx-submit="save">
<.dmf_input field={@form[:email]} label="Email" />
<.dm_btn variant="primary" type="submit">Save</.dm_btn>
</.dm_form>

Common Attributes

Attribute Values
variant primary, secondary, accent, info, success, warning, error, ghost, link, outline
size xs, sm, md, lg
shape square, circle
loading boolean
disabled boolean
native_submit boolean; render a native no-JavaScript submit control
class additional CSS classes

Available Components

Upstream design alignment

The current frontend uses Core/CSS Art 1.19.9 and Elements/Art Elements 1.7.6. Individually published element dependencies are pinned to their current versions; see the contract audit for the exact set.

The new Core primitives render native HTML and use the packaged CSS. Applications own countdown timing, filter state, progress values and layout state. Carousel uses native scrolling, swap uses a checkbox, floating actions and megamenu use the browser Popover API. No element registration is needed for these primitives.

<.dm_indicator>
<:indicator><span class="badge badge-primary">3</span></:indicator>
<button type="button" class="btn">Inbox</button>
</.dm_indicator>
<.dm_sidebar_layout>
<:sidebar><nav aria-label="Workspace">Workspace links</nav></:sidebar>
<main>Page content</main>
</.dm_sidebar_layout>

Existing dm_menu, dm_drawer and dm_bottom_sheet retain their Elements methods and events. dm_loading_spinner now follows Core's reduced-motion behavior, and dm_stat uses its semantic stat layout. Chat scroll and chip event examples are available in Storybook. Browser File objects from chat events require the application's upload mechanism; they cannot be sent as LiveView JSON payloads.

Live Storybook

Live Storybook