Changelog
v3.0.0 (2026-07-08)
Enhancements
- ClassMerge: Significantly improved
merge/1performance for component-heavy pages. (#143) - Calendar / DatePicker: New
todayattribute on<.calendar>,<.date_picker>,<.date_time_picker>, and<.date_range_picker>to control which day is treated as "today" (the highlighted current day and the default visible month). AcceptsDate,DateTime,NaiveDateTime, or ISO 8601 strings. When omitted, the client highlights the browser's local date, so the current day is correct for the user's time zone with no configuration (single-locale and multi-zone apps alike). Settodayto let the server control the value instead: for static calendars, a first-paint highlight, deterministic rendering (tests, screenshots), or anchoring to a non-clock date (for example a localized today derived from a timezone sent through connect params). Updatingtodayafter render re-syncs the highlight automatically. - Calendar / DatePicker: New
show_outside_daysattribute on<.calendar>,<.calendar_range>,<.date_picker>,<.date_time_picker>, and<.date_range_picker>to control whether the day grid pads its leading and trailing cells with days from the previous and next month. Defaults totrue, the existing fixed six-week grid with outside-month days dimmed and still selectable. Setshow_outside_days={false}to render only the current month: leading and trailing cells are left blank and full outside-month weeks are dropped, so the grid collapses to four to six rows and its height changes as you navigate. Only applies todaygranularity. - Design System: New surface system with auto-nesting elevation that fixes dark-mode overlay flatness. Overlay panels (Modal, Sheet, Popover, Dropdown, Select, Autocomplete, TagsInput, DatePicker, Toast) now read their context and render one tier above whatever they open over, so a dropdown inside a modal stays legible with nothing to configure. Derived from the theme's
--background-baseand tunable through the--surface-stepknob. Apply thesurfaceutility to your own panels to join the ladder. The ring color is exposed as--surface-ringso colored panels (like semantic toasts) can override it. Also softens dark-mode borders and surface edges.
New
Toast: New
<.toaster>component for server-driven notifications. Place it once in your layout, pass@flash, and fire toasts from anywhere withFluxon.put_toast/3(rides Phoenix flash, survivespush_navigate/2and controller redirects) orFluxon.send_toast/3(pushes into the current LiveView for HEEx content and callback actions). Toasts stack with a max, auto-dismiss with a paused-on-hover progress bar, support swipe-to-dismiss on touch, and survive WebSocket reconnects. Each toast can carry a single:actionor several:actions. Three types are supported::event(pushes a LiveView event),:link(uses<.link>semantics withhref/navigate/patch), and:dismiss(close-only). Actions inherit the toast color but can be individually styled with:variant(any Button variant) and:color. Loading toasts (Fluxon.send_toast_loading/3+Fluxon.resolve_toast/4) handle the "show pending → flip to success/error" flow without juggling ids.Fluxon.send_toast/2,Fluxon.send_toast_loading/2, andFluxon.dismiss_toast/1also returnPhoenix.LiveView.JScommands so you can fire (or pre-show a spinner for) toasts straight fromphx-clickwith no server round-trip.This component is available as a preview. Its API, behavior, and styling may change in future releases without prior deprecation.
# From a LiveView. Survives push_navigate. Fluxon.put_toast(socket, "Changes saved!", color: :success) # From a controller. Must pair with redirect. conn |> Fluxon.put_toast("Welcome aboard!", color: :success) |> redirect(to: ~p"/dashboard") # Stays in the current LiveView, with a callback action Fluxon.send_toast(socket, "Item deleted", color: :info, action: %{label: "Undo", type: :event, event: "undo", value: %{id: id}}) # Loading toast that flips to success on completion {socket, id} = Fluxon.send_toast_loading(socket, "Uploading...") # ...later... Fluxon.resolve_toast(socket, id, "Upload complete!", color: :success)<!-- Layout setup (once) --> <.toaster flash={@flash} /> <!-- Client-side fire, no server round-trip --> <.button phx-click={Fluxon.send_toast("Copied!", color: :success)}>Copy</.button>NumberInput: New
<.number_input>component for numeric entry. Mirrors<.input>for labels, descriptions, helper text, sizes, affix slots, and form-field binding, and adds flanking-/+stepper buttons with press-and-hold accelerating repeat, modifier-augmented keyboard stepping (Shiftforlarge_step,Altforsmall_step),ArrowUp/ArrowDown,PageUp/PageDown,Home/End, locale-aware display formatting viaIntl.NumberFormat, optionalallow_wheel_scrub(focused +Altheld), andsnap_on_stepto snap to step multiples. Internally renders a visible text field for formatted display plus a sibling hidden input that carries the canonical numeric value, so server-side code always receives a clean number regardless of locale.<!-- Simple quantity stepper --> <.number_input name="quantity" label="Quantity" value={1} min={0} max={99} /> <!-- Currency with locale formatting --> <.number_input field={@form[:price]} label="Price" min={0} step={0.01} locale="en-US" format={%{style: "currency", currency: "USD", minimum_fraction_digits: 2}} /> <!-- Wheel-scrubbable zoom level (focused + Alt) --> <.number_input name="zoom" value={1.0} min={0.25} max={4} step={0.25} small_step={0.05} large_step={0.5} allow_wheel_scrub format={%{maximum_fraction_digits: 2}} />A few things worth knowing:
step="any"disables snap-on-step but keyboard arrows still use the default step.controls="none"hides the buttons while keeping keyboard stepping.formataccepts a map ofIntl.NumberFormatoptions withsnake_casekeys.- Two DOM events:
fluxon:numberinput:changefires continuously (every tick during a press-and-hold);fluxon:numberinput:commitfires when the value settles (blur, pointerup, single keyboard step, single wheel tick). Usecommitto debounce server-side saves.
ScrollArea: New
<.scroll_area>component for custom-styled scrollbars that look the same in every browser. On mouse and trackpad, the custom scrollbar replaces the native one. Touch devices keep their native scroll, no JS in the way. Size the area withclasson the root, and put padding onviewport_classso it scrolls with the content. Tweak the bar itself viascrollbar_classandthumb_class. Thetypeattribute controls when the bar shows:"hover"(default),"scroll","always", or"auto"(matches the native scrollbar).This component is available as a preview. Its API, behavior, and styling may change in future releases without prior deprecation.
<.scroll_area class="h-72 w-64 rounded-base border border-base" viewport_class="p-4"> <p>Long content...</p> </.scroll_area> <.scroll_area type="always" thumb_class="bg-primary/60"> <pre>...</pre> </.scroll_area>TagsInput: New
<.tags_input>component for picking multiple values that render as dismissible tags. Two modes are available: toggle mode (the default), where the tags sit inside a combobox toggle, and typeable mode (typeable={true}), which gives you a regular<input>with tags rendered inline. Takes the same option shape as<.select>(strings, tuples, keyword lists, atoms, ranges, grouped and nested groups), plus the usual form-field attrs. Selection changes happen in the browser without a server roundtrip, and a hidden<select multiple>keeps form submission working.<!-- Toggle mode with listbox search --> <.tags_input field={f[:departments]} label="Departments" searchable clearable options={[{"Sales", "sales"}, {"Support", "support"}, {"Engineering", "engineering"}]} /> <!-- Typeable mode with inline tags --> <.tags_input field={f[:assignees]} label="Assignees" typeable placeholder="Pick assignees..." options={@users} /> <!-- Typeable + creatable (Enter commits a typed value not in the options list) --> <.tags_input field={f[:tags]} typeable creatable options={@tags} />A few things worth knowing:
maxquietly blocks further selection.minstops removals below the threshold in the browser.on_searchdoes server-side search for big datasets, using the same contract as<.select>.- The
:tagslot lets you swap in custom tag content (icons, avatars, colors). :option,:header,:footerslots are all there, plus the four affix slots.- Keyboard navigation in typeable mode follows React Aria conventions: ArrowLeft from an empty input drops you into the tag grid, Arrow keys move between tags, Delete/Backspace removes the focused tag, and Escape sends focus back to the input.
Calendar: New standalone inline calendar for date selection, no dropdown involved. Use
<.calendar>for single or multiple date selection, and<.calendar_range>for date ranges.<!-- Single date selection --> <.calendar name="appointment" label="Appointment Date" /> <!-- Multiple date selection --> <.calendar name="holidays[]" label="Company Holidays" multiple /> <!-- Date range selection --> <.calendar_range start_name="check_in" end_name="check_out" label="Stay Period" />Pass
staticfor a display-only calendar. No header, no JS hook, no hidden inputs. Selected dates still highlight. Useful for summary cards, confirmation screens, or any read-only view.<.calendar name="appointment" value={@appointment_date} static />DatePicker: Added a
monthsattribute (1..4, default 1) for rendering multiple month grids side-by-side. Useful for date range pickers where seeing several months at once helps users span a stay, trip, or pay period without paging. A single set of prev/next arrows shifts every visible grid by exactly one month. Range selection, keyboard navigation, presets, time picker, and confirm-mode apply/cancel all work across grids. Only takes effect whengranularityis"day"andnavigationis"default"or"extended"; other combinations emit a warning and collapse to a single grid.<!-- Two-month range picker (hotel-reservation style) --> <.date_range_picker start_name="check_in" end_name="check_out" months={2} /> <!-- Up to four months --> <.date_range_picker start_name="start" end_name="end" months={4} />DatePicker: Added a
presetsattribute that puts a sidebar of date shortcuts next to the calendar grid. Works for single dates ({"Today", Date.utc_today()}) and ranges ({"This week", start, end}). Presets follow the min/max limits and disabled dates, so anything out of range gets dimmed and turns off. Works with every close mode, confirm included.<.date_picker name="date" presets={[ {"Today", Date.utc_today()}, {"Tomorrow", Date.add(Date.utc_today(), 1)}, {"A week from now", Date.add(Date.utc_today(), 7)} ]} /> <.date_range_picker start_name="start" end_name="end" presets={[ {"This week", ~D[2026-02-23], ~D[2026-02-28]}, {"Next week", ~D[2026-03-02], ~D[2026-03-08]} ]} />DatePicker: Added a typeable mode via the
typeableattribute. Switch it on and the toggle button is replaced with a text input where users can type dates directly. Theinput_formatattribute takes any format string built fromdd,mm, andyyyysegments separated by a single character (/,.,-). Skip it and the format gets picked from thelocaleattribute.<.date_picker name="date" typeable /> <.date_picker name="date" typeable input_format="dd.mm.yyyy" /> <.date_picker name="date" typeable input_format="yyyy-mm-dd" /> <.date_picker name="date" typeable locale="de" /> <!-- uses dd.mm.yyyy -->DatePicker: New
hour_cycleattribute on<.date_time_picker>using CLDR values ("h12"or"h23"). Skip it and the value gets picked from thelocale. Most non-English locales default to"h23"(24-hour), and English locales default to"h12"(12-hour with AM/PM). Replaces the oldertime_formatattribute (see Deprecations).<.date_time_picker name="date" hour_cycle="h23" /> <.date_time_picker name="date" locale="fr" /> <!-- defaults to h23 -->Dropdown: Added submenu support through the
dropdown_submenu_triggercomponent and the:submenuslot, so you can build nested menus.<.dropdown> <.dropdown_link navigate={~p"/profile"}>Profile</.dropdown_link> <.dropdown_submenu_trigger submenu="more">More Options</.dropdown_submenu_trigger> <:submenu id="more"> <.dropdown_link navigate={~p"/settings"}>Settings</.dropdown_link> <.dropdown_link navigate={~p"/preferences"}>Preferences</.dropdown_link> </:submenu> </.dropdown>Select: Options can now be disabled. Pass a keyword list with
disabled: true(e.g.,[[key: "Label", value: "val", disabled: true]]). Disabled options look dimmed, can't be picked, and keyboard navigation skips over them.<.select name="status" options={[ [key: "Active", value: "active"], [key: "Pending", value: "pending", disabled: true], [key: "Archived", value: "archived"] ]} />Select: Added a
:toggleslot if you want to fully customize the toggle, plus a:toggle_labelslot for tweaking how selected options show up while keeping the default toggle styling (affixes, clear button, chevron).<!-- `:toggle` replaces the toggle's entire inner contents. No default affixes, clear button, or chevron. --> <.select name="tags" multiple options={@tags}> <:toggle :let={{label, value}}> <span class="chip"><.icon name="hero-tag" /> {label}</span> </:toggle> </.select> <!-- `:toggle_label` only customizes how each selected option is rendered. The default toggle (affixes, clear button, chevron) stays intact. --> <.select name="tags" multiple options={@tags}> <:toggle_label :let={{label, value}}> <span class="badge">{label}</span> </:toggle_label> </.select>Popover: Added an
openattribute so you can drive the panel state from a LiveView assign, pluson_openandon_closeJS callbacks that run after the enter and leave animations.<.popover id="filters" open={@show_filters} on_open={JS.push("filters_opened")}> <.button>Filters</.button> <:content>...</:content> </.popover>Overlay Components: Programmatic
open_*,close_*, andtoggle_*helpers are now available for all overlay components: Dialog, Popover, Select, Autocomplete, Dropdown, DatePicker, TagsInput, and Tooltip. Each helper comes in three forms: a bare%JS{}forphx-click, a%Socket{}form for server-side control, and a JS-chaining form for piping onto an existing%JS{}struct.on_openandon_closeJS callbacks were also added to Select, Autocomplete, Dropdown, and Tooltip, matching the existing Popover callbacks.# Client-side (phx-click, phx-mounted, etc.) Fluxon.open_popover("my-popover") Fluxon.close_select("country-select") Fluxon.toggle_dropdown("actions-menu") # Server-side (from a handle_event or handle_info) Fluxon.open_popover(socket, "my-popover") Fluxon.close_dialog(socket, "confirm-dialog") # Chained onto an existing JS pipeline JS.push("saved") |> Fluxon.close_popover("my-popover")Loading: Three new equalizer-style variants:
bars-fade,bars-scale, andbars-scale-fade.<.loading variant="bars-scale" class="size-6 text-primary" />Textarea: Added an
autogrowattribute that makes the textarea grow and shrink as the content changes, clamped betweenmin_rowsandmax_rows.<.textarea name="message" label="Message" autogrow min_rows={2} max_rows={8} placeholder="Type your message..." />Calendar & DatePicker: The
localeattribute now drives every locale-aware bit of behavior. It translates navigation labels, month names, weekday headers, time picker labels, and confirmation buttons. It also picks the defaultweek_start(Monday for most European locales, Saturday for Arabic, and so on), the defaultdisplay_format(%d.%m.%Yfor German,%Y-%m-%dfor Swedish), and the defaultinput_formatfor typeable mode. 37 locales are supported, including regional ones likeen-GB,en-AU,en-CA,es-MX,fr-CA, andzh-TW. If you setweek_start,display_format, orinput_formatdirectly, your value wins over the locale default.<.date_picker name="date" locale="en-GB" typeable /> <.date_picker name="date" locale="de" /> <.date_time_picker name="date" locale="fr" /> <.date_picker name="date" locale="de" week_start={0} /> <!-- override locale default -->
Enhancements
Autocomplete: Options can now be disabled, same way as Select. Pass a keyword list with
disabled: true(e.g.,[[key: "Label", value: "val", disabled: true]]). Disabled options look dimmed, can't be picked, and keyboard navigation skips over them.<.autocomplete name="status" options={[ [key: "Active", value: "active"], [key: "Archived", value: "archived", disabled: true] ]} />Theme: Colors were tuned for better contrast, calmer soft tones, and more uniform borders on Button, Badge, and Alert. Soft-foreground colors now come from the base semantic tokens, so overriding
--primary,--info,--danger,--success, or--warningcascades through the soft variants on its own. Nested soft components inside a colored alert or toast get an elevated surface tint so they don't blend into the parent. Disabled form controls now share the same opacity across the board.:root { --primary: oklch(0.55 0.18 250); /* soft, soft-foreground, and primary-border tokens follow automatically */ }Button & Tabs: Tweaked icon sizing and spacing so they line up better with typical design system proportions.
Checkbox & Radio: Default indicator size dropped from 18px to 16px (
size-4) so it pairs more naturally withtext-smlabels and matches typical form control sizes.Select: The listbox now scrolls to the selected option when it opens.
DatePicker:
<.date_range_picker>now supportsclose="auto", which closes the calendar once both dates are picked.Calendar & DatePicker: New
allow_deselectattribute (defaults totrue). Set it tofalseto stop users from clearing the selection by clicking an already-selected date. Useful when the field is required.<!-- Date must always be selected --> <.calendar name="required_date" value={Date.utc_today()} allow_deselect={false} /> <!-- At least one date must remain selected --> <.calendar name="dates[]" multiple allow_deselect={false} />Loading: Added a
labelattribute for an accessible name. When set, the component renders withrole="status"and anaria-label, giving screen readers something meaningful to announce.Accordion: A lot has changed here. The CSS-only expand/collapse animation is smoother now (no more flicker on rapid toggles). Open state is driven from the server and re-syncs from
expandedon every LiveView patch. There's a per-itemdisabledattribute. An optional:indicatorslot for swapping out the chevron. Attributes on the:headerslot now forward onto the trigger button (phx-click,phx-value-*, etc.).<.accordion multiple> <.accordion_item expanded> <:header phx-click={JS.push("section_opened")}>Profile</:header> <:panel>Profile content</:panel> </.accordion_item> <.accordion_item disabled> <:header>Coming soon</:header> <:panel>Locked content</:panel> </.accordion_item> <.accordion_item> <:header>Plus / Minus</:header> <:indicator> <.icon name="hero-plus" class="size-4 group-data-expanded/accordion-item:hidden" /> <.icon name="hero-minus" class="size-4 hidden group-data-expanded/accordion-item:block" /> </:indicator> <:panel>Custom indicator</:panel> </.accordion_item> </.accordion>
Bug Fixes
- Select: Fixed the clear button losing its event handlers after a LiveView DOM patch.
- Select: Fixed the highlight jumping to an invalid spot when you deselect in multiple mode.
- Select: Fixed highlight glitches with cascading or dependent selects when options change on the fly via LiveView.
Deprecations
- DatePicker:
time_formatis deprecated. Usehour_cycleinstead. The old"12"and"24"values still work but log a warning. - Select:
search_no_results_textis deprecated. Useno_results_textinstead. The old name still works but logs a warning. - Design System:
bg-accent/--background-accentis deprecated in favor ofhighlight,highlight-strong,bg-sunken, andbg-control. The token still works for backward compatibility and will be removed in a future major version.
Breaking Changes
Select / DatePicker: The toggle wrapper element used to render with
data-part="root". It's nowdata-part="field-root". If you've got custom CSS targeting[data-part=root]inside a Select or DatePicker, switch the selector to[data-part=field-root].Calendar & DatePicker:
week_startnow defaults to whatever the locale uses, instead of always defaulting to0(Sunday). This only affects components with a non-Englishlocaleand no explicitweek_start. Those will pick up the locale's natural week start day (so Monday for most European locales, for example). Components on the defaultlocale="en"or withweek_startset explicitly aren't affected. To get the old behavior, passweek_start={0}.Calendar & DatePicker:
display_formatnow defaults to the locale's typical date format instead of always"%b %-d, %Y". Same caveat as above: it only matters when you use a non-Englishlocalewithout settingdisplay_formatyourself. Passdisplay_format="%b %-d, %Y"to keep the old behavior.DatePicker: The
inlineattribute is gone. Use the new<.calendar>component for inline calendar rendering. To migrate: swap<.date_picker inline />for<.calendar />, and<.date_range_picker inline />for<.calendar_range />.Select: Enter only selects a highlighted option when the listbox is already open. Before, Enter would open it. This frees Enter up for native form submission. Use Space to open the listbox.
Tooltip: Default
delaywent from0(instant) to200(200ms) so tooltips don't flicker on quick hovers. Once a tooltip has been shown, subsequent tooltips on nearby elements open instantly until 500ms passes with no visible tooltip (a warmup effect). Setdelay={0}if you want them to fire instantly.Accordion: The
iconboolean attribute onaccordion_itemis gone. To hide the chevron, pass an empty:indicatorslot. To customize it, fill the slot with whatever you want.Accordion: The
animation_durationattribute onaccordionis gone. Animation duration is now CSS-controlled, so override it with a customclassif you need to.Accordion: The trigger element changed from
data-part="header"todata-part="trigger". If you've got custom CSS targeting[data-part=header]inside an Accordion, switch the selector to[data-part=trigger].Dropdown: The custom
:toggleslot is now a self-contained, accessible button instead of a wrapper around your own interactive element. The slot is rendered inside a focusablerole="button"element that owns the trigger wiring (tabindex,aria-haspopup,aria-controls,aria-expanded, and the disabled state), so the toggle stays a single focusable control. Put the trigger content directly in the slot and style it with the slot'sclass. The content must be non-interactive: a nested<button>or link now creates a second focusable control inside the toggle. To migrate, move the inner element's classes onto:toggle classand drop the wrapping element.<!-- Before --> <:toggle> <button class="flex items-center gap-2 rounded-lg px-3 py-2 hover:bg-accent"> <img src={@avatar} class="size-6 rounded-full" /> Account <.icon name="hero-chevron-down" /> </button> </:toggle> <!-- After --> <:toggle class="flex items-center gap-2 rounded-lg px-3 py-2 hover:bg-accent"> <img src={@avatar} class="size-6 rounded-full" /> Account <.icon name="hero-chevron-down" /> </:toggle>Dropdown: The toggle element changed from
data-part="button"todata-part="toggle". If you've got custom CSS or JS targeting[data-part=button]inside a Dropdown, switch the selector to[data-part=toggle].Modal: The
container_classattribute is gone. If you need to style the outer container, useclasson the root or target the relevantdata-partwith a selector.Modal, Sheet, Popover, Dropdown, Select, Autocomplete, TagsInput: The
animation,animation_enter, andanimation_leaveattributes are gone across the board. Animations are now driven internally (by Motion One for Modal and Sheet, and by the shared transition utility for the floating components), and for Modal and Sheet are picked from theplacement. Custom enter/leave animations are no longer supported on any of these components. Templates that still pass these attributes won't compile.Modal: The
full-left,full-right,full-top, andfull-bottomplacements are gone. They were edge-to-edge full panels, which is exactly what<.sheet>already does. Migrate by switching to<.sheet>with the matching placement:placement="full-left"becomes<.sheet placement="left">,full-rightbecomesright,full-topbecomestop,full-bottombecomesbottom.Sheet:
classandbackdrop_classdefaults are nownil(used to be""). Visible behavior doesn't change.
v2.3.1 (2025-11-14)
Bug Fixes
- Popover & Tabs: Fixed an issue where clicking links inside popovers containing tabs would trigger an aria-hidden accessibility warning.
- Modal & Sheet: Fixed an issue where nested modals would both close when clicking the "X (close)" button on the inner modal and body overflow would remain locked after closing all modals.
- Fixed an issue where dialog close events were being logged to the console.
v2.3.0 (2025-10-28)
New
DatePicker: Added
disabled_datesattribute for flexible date disabling beyond min/max constraints. Supports disabling specific dates, date ranges, and pattern-based matching including weekends, weekdays, day of month, ISO weeks, recurring annual dates, entire months, and years.<.date_picker name="availability" disabled_dates={[ :weekends, # No weekends {:weekday, 3}, # No Wednesdays {:day, 15}, # No 15th of any month {:month_day, 12, 25}, # No Christmas {:month, 4}, # No April dates {:week, 33} # No ISO week 33 ]} />
v2.2.1 (2025-10-26)
Bug Fixes
- Loading: Fixed an issue where multiple loading components on the same page caused duplicate ID errors in SVG animations. Each loading component instance now generates unique animation IDs.
v2.2.0 (2025-10-22)
Enhancements
- DatePicker: Added
granularityattribute with support forday,month, andyearmodes. The calendar now renders month or year grids when using non-day granularity, with automatic date normalization and display format adjustments. - Select & Autocomplete: Improved rendering of multi-level nested optgroups with proper visual indentation for deeply nested option groups.
- Checkbox & Switch: Added
checked_valueandunchecked_valueattributes to support custom form values. Components now allow specifying what values are submitted when checked or unchecked (e.g.,"1"/"0","yes"/"no"). Defaults to"true"/"false"for backward compatibility.
Bug Fixes
- Theme: Fixed an issue where semantic color backgrounds were semi-transparent, causing underlying UI elements to show through when used as positioned overlays. Alert and other semantic components now use solid backgrounds.
- Input: Fixed an issue where hidden inputs were visually rendering as text inputs. Hidden inputs now render without any additional markup or styling.
Breaking Changes
- Select: The native select now only renders a placeholder option when the
placeholderattribute is explicitly provided. Previously, an empty placeholder option was always included even when no placeholder was specified. To maintain the previous behavior of always showing an empty option, passplaceholder=""(empty string) to the native select component.
v2.1.0 (2025-08-31)
New
- Usage Rules: Added support for usage_rules.
Enhancements
- Button: Improved icon spacing consistency across all button sizes for better visual alignment.
Bug Fixes
- DatePicker: Fixed time input spinner arrows appearing in Firefox which caused broken state when interacting with them. The spinners are now hidden consistently across all browsers.
- Dropdown, Select, Tooltip, Popover, DatePicker, Autocomplete: Fixed an issue where floating elements would appear in the wrong position when used inside modals or sheets, especially after scrolling.
Breaking Changes
- DatePicker: The time input fields (
time-hour,time-minute,time-second) are no longer submitted with the form data. If you were relying on these separate time fields in your form submissions, you'll need to update your code to use the main datetime field instead.
v2.0.0 (2025-08-19)
Theming
This release introduces a theming system for Fluxon UI built on semantic colors and design tokens, replacing hardcoded color values with a token-based architecture that adapts to light and dark modes.
The Fluxon UI theming system is based on CSS custom properties (design tokens) that provide semantic meaning to colors. Instead of using specific TailwindCSS color names like blue-500 or red-600, Fluxon UI components now use semantic colors (primary, info, success, warning, danger) that convey intent and meaning. This approach utilizes meaningful color names that convey purpose instead of specific hues, backed by CSS custom properties for colors, backgrounds and borders. The design system integrates with TailwindCSS, utilizing its utility-first approach while providing semantic theming capabilities across all Fluxon UI components.
Theme Customization
The theming system supports customization through CSS custom properties. When you override theme tokens, all Fluxon UI components automatically adapt to use the new colors, borders, shadows, and other design elements:
:root {
/* Custom primary color - purple theme */
--primary: light-dark(#7c3aed, #a855f7);
/* Custom background colors */
--background-base: light-dark(#fafafa, #0a0a0a);
/* Custom semantic colors */
--success: #10b981;
--warning: #f59e0b;
}New
- Button: Added a new
surfacevariant, which provides a bordered, subtle background ideal for contained secondary actions. - Button: Added icon-only sizes (
icon-xs,icon-sm,icon-md,icon,icon-lg,icon-xl) for creating square buttons with centered icons. - Button: New
button_groupcomponent to visually group multiple buttons together. - Badge: Introduced a full set of variants:
solid,soft,surface(default),outline,dashed, andghost. - Badge: Added more sizing options with new
xs,sm(default),md,lg, andxlsizes. - Checkbox: Added support for the indeterminate state, which displays a dash icon to indicate that the checkbox is neither checked nor unchecked.
- Switch: Added support for the
restattribute, allowing additional HTML attributes to be passed directly to the underlying input element. - Select: Added support for multiple affix slots (
inner_prefix,inner_suffix,outer_prefix,outer_suffix). - Select: Added
xssize. - Autocomplete: Added support for multiple affix slots (
inner_prefix,inner_suffix,outer_prefix,outer_suffix). - Autocomplete: Added
xsandxlsizes. - Input: Added support for multiple affix slots (
inner_prefix,inner_suffix,outer_prefix,outer_suffix). - Input: Added
xssize. - Input: New
input_groupcomponent to visually group multiple inputs together. - DatePicker: Added support for multiple affix slots (
inner_prefix,inner_suffix,outer_prefix,outer_suffix). - DatePicker: Added
xssize. - Tabs: Added size support with
xs,sm, andmd(default) options. - Popover: Added programmatic control support with
Fluxon.open_popover/1andFluxon.close_popover/1functions for client-side popover management. - Form Components: Added support for the
formattribute on all form components (Autocomplete, Checkbox, Radio, Select, Switch), allowing form inputs to be associated with forms anywhere in the document.
Enhancements
- Form Components & Tabs: Adjusted default height sizes to be more compact. The default
mdsize is now 36px (previously 40px) while maintaining a 4px linear scale across all sizes. - Button: The component now automatically renders as a link (
<a>) ifhref,navigate, orpatchattributes are provided. - Button: Added support for the
disabledattribute on link buttons. When a button withhref,navigate, orpatchis disabled it becomes non-interactive, preventing navigation or patching actions. - Modal & Sheet: Fixed an issue where dialogs were pushing down page content instead of overlaying it. Dialogs now properly use fixed positioning to prevent layout shifts.
Breaking Changes
- Alert: The
variantattribute has been removed to standardize on thecolorattribute. Alerts now usecolorto define their appearance, acceptingprimary,danger,warning,success, andinfo. - Button: Variants have been updated for consistency.
variant="primary"is nowvariant="solid" color="primary", andvariant="secondary"is nowvariant="soft" color="primary". - Badge: The
pillvariant is replaced byclass="rounded-full", and theflatvariant is nowsoft. The default variant has been renamed tosurface. - Badge: Direct support for all TailwindCSS colors has been removed. Badges now use a semantic color palette:
primary,danger,warning,success, andinfo. For custom colors, you can use theclassattribute to apply custom background, text, and border styles. - Forms: The default size
basehas been renamed tomdacross all form components (Select,Switch,Autocomplete,Input,DatePicker) to ensure consistent sizing options. - Input: The
inner_prefixandinner_suffixslots no longer require manual padding adjustments. The component now handles this automatically. - Switch: The
colorattribute now only accepts semantic colors:primary,danger,success,warning, andinfo.
v1.2.0 (2025-07-03)
New
- Gettext: Added built-in support for translating validation errors across all form components. You can now configure a translation function to handle Phoenix validation error messages with Gettext or custom translation logic. See the Error Translation guide for setup instructions.
v1.1.4 (2025-06-13)
Bug Fixes
- Select: Fixed an issue where the search input would lose focus after making a selection in multiple selection mode with search enabled (#82)
v1.1.3 (2025-06-12)
Enhancements
- Select: Added server-side search support. The Select component now supports server-side filtering by setting the
on_searchattribute to a LiveView event name. - Dropdown: Added better dark mode support for highlighted dropdown items (#78)
- Accordion: Added support for additional HTML attributes to be applied to the accordion container and accordion item. (#72)
Bug Fixes
- DatePicker: Fixed an issue where datetime strings were not properly parsed when provided as values to the DatePicker component (#71)
- DatePicker: Fixed an issue in the DatePicker component where selecting a date in the datetime picker caused subtle visual jitter (#63)
v1.1.2 (2025-05-12)
Enhancements
- DatePicker: Prevent the time inputs from displaying spin buttons in Firefox (#70)
v1.1.1 (2025-04-17)
Bug Fixes
- DatePicker: Fixed an issue in the DatePicker component where calendar grid cells were expanding to an incorrect height in Safari. Fix #63.
v1.1.0 (2025-04-14)
Tailwind CSS v4
Components have been updated to support Tailwind CSS v4. This involved refactoring internal utility classes and state variant syntax to align with the latest version. As a result, this release is fully compatible with Phoenix 1.8. For more details on setup, see the installation guide.
Enhancements
- DatePicker: The toggle button now defaults to
w-full, ensuring it expands to the full width of its container for a more consistent layout. - Dropdown: Menu items (buttons and links) now correctly apply
cursor-pointerby default, enhancing visual feedback for interactivity. - Dropdown: Icons within menu items no longer apply a default text color. They now inherit color directly from the parent item, simplifying style customization and ensuring visual consistency.
- Autocomplete: Added a new
debounceattribute to the Autocomplete component. This integer attribute, defaulting to 200 milliseconds, controls the delay before triggering theon_searchevent for server-side searches.
Bug Fixes
- Autocomplete: Fixed an issue where the autocomplete's clear button did not properly clear the input value.
Deprecations
- The
skip_conflicts: trueoption for component imports is now deprecated. Please use the:onlyand:exceptoptions for more explicit control over imported components. Refer to the installation guide for updated usage.
v1.0.25 (2025-03-31)
Enhancements
- Select, Autocomplete, DatePicker: The positioning of the floating elements has been changed from
absolutetofixed. This prevents listbox from being clipped by parent elements withoverflow: hidden. - Modal, Sheet: The components now prevent unintended closure when dragging from inside to outside the dialog. This enhancement improves usability by allowing users to interact with dialog content, such as text selection, without accidentally closing the dialog when the mouse is released outside its boundaries.
v1.0.24 (2025-03-26)
Bug Fixes
- Select: Fixed an issue where the select component was emitting duplicate "change" events when in searchable mode.
v1.0.23 (2025-03-25)
Enhancements
- Autocomplete: Added support for clearing the autocomplete selection with a new clear button. The
clearableattribute can now be used to enable this feature. When enabled, a clear button appears next to the input field when a selection is made. Clicking the button clears the current selection. - Dropdown: Added support for disabled dropdown items. The Dropdown component now respects
disabled,data-disabled, andaria-disabledattributes on menu items. Keyboard navigation and mouse interactions will skip over disabled items. - Autocomplete, Select: Added support for custom header and footer content in the Select and Autocomplete components. Users can now include additional elements like action buttons or filters at the top and bottom of the listbox using the new
:headerand:footerslots. These slots accept aclassattribute for custom styling. - Select: The "Clear selection" button is now keyboard accessible with
tabindex="0", allowing users to interact with it using keyboard navigation.
v1.0.22 (2025-03-13)
Enhancements
- Autocomplete: Search event payload now includes the input element's ID. This enhancement allows developers to more easily identify which specific autocomplete instance triggered a search event in multi-input scenarios. The
idproperty is now available in the event payload alongside the existingqueryproperty when handling autocomplete search events. - Dropdown: Added automatic closing of the dropdown menu when a menu item is clicked. This behavior improves usability by closing the menu after a selection is made, particularly useful for button-type menu items that don't trigger page navigation.
Bug Fixes
- Autocomplete, DatePicker: Fixed an issue where the fields were triggering premature validations during phx-change events. It now prevents validation from occurring before user interaction with the field. Fix #51.
- Autocomplete: Fixed an issue where the component's selection state was not properly cleared when the input was emptied. Now, when the input value is cleared (e.g., using Cmd+Backspace), the component correctly resets its internal selection state. This ensures that the component's state remains consistent with the empty input, preventing potential conflicts between the displayed value and the internal selection.
- DatePicker: Fixed an issue where changing the field value via LiveView did not update the DatePicker selection. The component now synchronizes correctly with LiveView updates, ensuring accurate highlighting in the calendar. Fix #54.
- DatePicker: Fixed an issue where the AM/PM select was not correctly updating to "PM" when a time after 12:00 PM was set.