Fluxon 3 is here
This is the biggest Fluxon release so far. Five new components, localization, a reworked dark mode, and a good amount of new features and bug fixes. It ended up being 277 commits on the v3 branch. That is a lot, but about 200 of them were just small tweaks. Spacing, colors, little UX things you probably would not notice on their own.
You'll also notice the Fluxon website got a full refresh. I went back through all the examples, added a bunch of new ones, and there are a few new dashboard and layout templates too.
I will focus on the big stuff here. The new components are Scroll Area, Calendar, Number Input, Tags Input, and Toast. There is also a typeable Date Picker now, plus dates and times that follow the user's locale.
New components
Scroll Area
Scroll Area swaps the native scrollbar for a custom one that looks the same in every browser, on both mouse and trackpad. On touch devices it leaves the native scroll alone, so momentum scrolling still feels right.
The type
attribute controls when the bar shows up: hover
(the default), scroll, always, or auto. Put padding on
viewport_class
so it scrolls with the content, and width and height on the root.
type="hover"
type="scroll"
type="always"
Calendar
The Calendar is a standalone, always-visible component for picking dates. <.calendar>
handles single and multiple dates, and <.calendar_range>
handles ranges. There's also a static
attribute that makes it read-only (no header, no inputs, but the selected days still highlight).
Number Input
Number Input is a new component for numeric values. It has plus and minus buttons on the sides, keyboard arrows, modifier keys for bigger or smaller steps (Shift, Alt), Home/End, PageUp/PageDown, and an optional
Alt
+ mouse wheel scrubbing mode.
Formatting goes through Intl.NumberFormat, so locale-aware display (currency, percent, fraction digits) works out of the box. Behind the scenes it shows a formatted text field and keeps a hidden input with the raw number next to it, so the server always gets a clean value no matter the locale.
Tags Input
Tags Input is a multi-value field where the selected values show up as tags you can dismiss. It sits somewhere between Select and Autocomplete. The goal is the same, pick from a set of options, mostly what changes is the UX. It has two modes: toggle mode (the default), where the tags sit inside a Select-style toggle, and typeable mode, where they render inline next to a normal text input.
It takes the same option shape as <.select>: strings, tuples, keyword lists, atoms, ranges, and nested groups all work.
Toast
This is probably the most exciting addition in this release. It's still experimental, so it ships in preview. I haven't had the time to really stress-test it yet, so expect some bugs, and the API, the styling, and a few behaviors can still change a fair bit before it settles.
Semantic colors
Each color tints the background and adds a leading icon. Pick the one that matches what the message means.
Action buttons
A toast can carry one or more action buttons. Each one's position:
says where it goes. The default is :below
(stacked under the title), and :inline
puts it on the same row as the title. Clicking an action pushes a named event back to the LiveView and dismisses the toast (unless you pass dismiss: false).
Bob Smith
ActiveEditor at Acme
Multi-step progress
For longer-running work like uploads or background jobs, you can start a toast with
Fluxon.send_toast_loading/3
and update it as things move along with Fluxon.resolve_toast/4. It reuses the same toast id, so the user sees one notification that changes its title, content, and color instead of a stack of separate ones.
You can also pass content:
with any HEEx fragment to render your own markup inside the toast (a progress bar, a step counter, an avatar, whatever you need).
New features
Plenty also landed on the components you already use. The ones I think are worth calling out:
Typeable Date Picker
Setting typeable
on <.date_picker>
swaps the toggle button for a text input where you type the date directly. The input_format
attribute takes any format built from dd, mm, and yyyy
segments, separated by /, ., or -. Skip it and the format comes from the
locale
attribute.
Localization
The Calendar and the Date Picker now ship with more than 35 locales, including regional ones like en-GB, en-AU, en-CA, es-MX, fr-CA, and zh-TW. Set the
locale
attribute and it translates the month names, the weekday headers, the navigation labels, the time picker labels, and the confirmation buttons.
It also picks sensible defaults for each locale: the week start (Monday for most European locales, Saturday for Arabic), the display format (%d.%m.%Y
for German, %Y-%m-%d
for Swedish), the hour cycle on the date time picker (the new hour_cycle
attribute, 12h for English, 24h for most others), and the typeable input format. Set any of these yourself and your value wins over the locale default.
German (de)
French (fr)
Date Picker presets
The Date Picker now has a presets
attribute that adds a sidebar of date shortcuts next to the calendar grid. Pass
{label, date}
tuples for single dates, or {label, start, end}
tuples for ranges. Presets respect min/max
and disabled dates, so anything out of range gets dimmed and ignored.
Multi-month date range picker
The Date Range Picker can now show several months next to each other through the new months
attribute (1 to 4, default 1). It helps with longer ranges like hotel stays or travel windows, where seeing two or three months at once means less flipping back and forth.
One set of previous and next arrows shifts every visible grid by a single month. The layout also adapts to the screen: one grid on phones, up to two on tablets, three on smaller desktops, and four on wide displays. So even with months=4 set, you still get a usable picker on a small screen.
Custom toggle for Select
Two new slots landed on <.select>: :toggle, if you want to replace the default toggle completely, and :toggle_label, if you want to keep the default toggle styling (affixes, chevron, clear button) and only change how the selected values render.
Paired with the existing :option
slot, you can keep the list and the toggle in sync. A common case is a status or priority picker, where each option shows a colored dot next to its name, both in the dropdown and after you select it.
Dropdown submenus
Dropdowns can nest now. The new dropdown_submenu_trigger
opens a sibling menu through a :submenu
slot, matched by id, and submenus can nest as deep as you need. Keyboard navigation, focus, and outside-click handling all work the way you'd expect from a nested menu.
Programmatic control for every overlay
Popover got server-side control in v2, and in v3 that spread to the whole family. Every
overlay now has open_*, close_*, and toggle_*
helpers: Dialog, Popover, Select, Autocomplete, Dropdown, Date Picker, Tags Input, and
Tooltip. Each helper comes in three shapes, so you use the same function whether you're
wiring a phx-click, driving state from the server, or chaining onto an existing JS
pipeline.
# Bare %JS{} for phx-click
<.button phx-click={Fluxon.open_popover("filters")}>Filters</.button>
# From a LiveView event handler, straight on the socket
def handle_event("apply_filters", _, socket) do
{:noreply, Fluxon.close_popover(socket, "filters")}
end
# Chained onto an existing JS command
JS.push("saved") |> Fluxon.close_popover("filters")
The Popover itself also picked up an open
attribute so you can drive its state from an assign, plus on_open
and on_close
JS callbacks that run after the enter and leave animations. Those same callbacks now live on
Select, Autocomplete, Dropdown, and Tooltip too.
Theme refinements
The theme tokens got a solid round of tuning. Borders are calmer and more consistent across Button, Badge, and Alert. The semantic colors (primary, info, success, warning, danger) were redone with raw OKLCH values for better contrast, and disabled form controls now use the same opacity everywhere.
Dark mode got the most work this release, mostly around depth. When panels stack, a dropdown inside a modal, a popover inside a sheet, a listbox over a dark page, they used to land on nearly the same flat gray and blur together. v3 fixes that with a new system: every panel sits on an elevation ladder, and each layer you stack sits one visible step lighter than the one beneath it. It's automatic, nothing to set up, and the borders and edges got softer along the way.
Every built-in overlay rides the ladder now, and you can add the surface
utility to put your own panels on it too. It shows the most when panels nest, like a
select opened inside a modal:
Before, the listbox blends into the modal
After, the listbox lifts above it
Move file to
That's the bigger stuff. There's more I didn't give its own section: textarea autogrow, an allow_deselect
option on Calendar and Date Picker, close="auto"
on the range picker, disabled options in <.select>
and <.autocomplete>, three new equalizer-style loading variants, smoother
animations all around, and a bunch of bug fixes across the components.
The full changelog has the complete list, including the deprecations and breaking changes you'll want to know about before upgrading.