PhoenixDuskmoon
Duskmoon UI component library for Phoenix LiveView applications.
v10: Keeps the @duskmoon-dev/core design system and DuskMoon custom elements,
with the build toolchain maintained and released independently in
duskmoon-bundler.
Requires Elixir >= 1.18 and tailwindcss >= 4.0.
See the docs for more information.
Applications using the removed dm_git_* helpers or the Git clipboard runtime
must migrate to application-owned components before upgrading; see the
Git component migration guide.
Install
Add to mix.exs:
{:phoenix_duskmoon, "~> 10.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:
<.dm_theme_switcher>— theme switching with localStorage<.dmf_spotlight>— keyboard shortcut handling (Cmd/Ctrl+K)<.dm_page_header>— scroll-based intersection observer
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
- Action: buttons, dropdowns, floating actions, links, menus, swaps, toggles
- Data Display: accordion, avatar, badge, card, carousel, chat, chat scroll, chip, collapse, countdown, datetime, diff, flash, list, markdown, markdown body, pagination, popover, progress, radial progress, skeleton, stat, table, timeline, tooltip
- Data Entry: autocomplete, cascader, checkbox, compact input, file upload, filter group, form, input, multi-select, OTP input, PIN input, radio, rating, segment control, select, slider, switch, textarea, time input, tree select
- Feedback: dialog, loading, snackbar, toast
- Navigation: actionbar, appbar, bottom nav, breadcrumb, left menu, megamenu, navbar, page footer, page header, stepper, tabs
- Layout: bottom sheet, divider, drawer, sidebar layout, theme switcher
- CSS Art: button noise, eclipse, plasma ball, signature, snow, spotlight search
Upstream design alignment
The current frontend uses Core/CSS Art 1.19.10 and Elements/Art Elements 1.8.0. 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.
<div class="indicator">
<span class="indicator-item badge badge-primary" aria-label="3 unread messages">3</span>
<button type="button" class="btn">Inbox</button>
</div>
<.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.
Repository development
This checkout contains the UI and Storybook. It consumes the published toolchain
cohort pinned in BUNDLER_VERSION and mix.lock; ordinary UI builds use verified
precompiled Duskmoon native artifacts. The toolchain source and its own releases
live in duskmoon-bundler.
See the migration and development guide for setup,
candidate integration and independent release order.
Live Storybook