# Fluxon Documentation ## Fluxon.Components.Accordion A flexible and accessible accordion component for organizing content into collapsible sections. Built with progressive disclosure in mind, it provides an interactive way to manage content density while maintaining full keyboard navigation and screen reader support. The accordion system consists of two main components working together: - `accordion`: The main container that manages state, accessibility, and animations - `accordion_item`: Individual sections containing headers and expandable panels The accordion follows a structured hierarchical organization: ``` accordion ├── accordion_item │ ├── header (slot) │ └── panel (slot) ├── accordion_item │ ├── header (slot) │ └── panel (slot) └── accordion_item ├── header (slot) └── panel (slot) ``` Each `accordion_item` consists of two required slots: - `header`: The always-visible clickable area that toggles the panel - `panel`: The expandable content area that shows/hides on interaction This structure ensures proper state management, accessibility, and visual organization while maintaining flexibility for various content patterns, from simple text to complex interactive components. ## Usage The accordion component consists of two main parts: the container (`accordion`) and individual sections (`accordion_item`). Each section has a header that toggles visibility and a panel that contains the expandable content: ```heex <.accordion> <.accordion_item> <:header>What is Fluxon? <:panel> Fluxon is a powerful UI component library for Phoenix LiveView applications. <.accordion_item> <:header>How do I get started? <:panel> Add Fluxon to your dependencies and follow the installation guide. ``` ## Expansion Behavior The accordion supports two primary modes of operation: single-section and multi-section expansion. You can also control whether all sections can be collapsed simultaneously. ### Single Section Expansion (Default) By default, only one section can be expanded at a time. Opening a new section automatically closes the previously expanded one: ```heex <.accordion> <.accordion_item> <:header>Section 1 <:panel>Content for section 1 <.accordion_item> <:header>Section 2 <:panel>Content for section 2 ``` ### Multiple Section Expansion Enable multiple section expansion by setting the `multiple` attribute: ```heex <.accordion multiple> <.accordion_item> <:header>Section 1 <:panel>Can be open while other sections are expanded <.accordion_item> <:header>Section 2 <:panel>Also can remain open with other sections ``` ### Preventing All Closed State For cases where at least one section should always remain expanded, use `prevent_all_closed`: ```heex <.accordion prevent_all_closed> <.accordion_item expanded> <:header>Always One Open <:panel>This or another section will always be expanded <.accordion_item> <:header>Another Section <:panel>More content here ``` ## Rich Headers Headers can contain complex content including icons, badges, or additional text. This is useful for creating more informative and visually appealing accordions: ```heex <.accordion> <.accordion_item> <:header class="flex items-center gap-3"> <.icon name="document" class="size-5 text-zinc-400" />

Documentation

View the complete documentation

<.badge class="ml-auto">New <:panel> Detailed documentation content... ``` ## Keyboard Support The accordion component implements the WAI-ARIA Accordion Pattern with comprehensive keyboard navigation: | Key | Element Focus | Description | |-----|---------------|-------------| | `Tab`/`Shift+Tab` | Header | Moves focus between accordion headers and other focusable elements | | `Space`/`Enter` | Header | Toggles the expansion state of the focused section | | `↑` | Header | Moves focus to the previous accordion header | | `↓` | Header | Moves focus to the next accordion header | | `Home` | Header | Moves focus to the first accordion header | | `End` | Header | Moves focus to the last accordion header | | `Tab` | Panel | When panel is expanded, allows navigation through focusable elements within | ### function accordion/1 **Signatures:** - `accordion(assigns)` Renders an accordion component with customizable attributes and slots. The accordion component serves as a container for collapsible sections, managing their state, interactions, and accessibility. It provides a foundation for building expandable content areas with proper keyboard navigation, ARIA support, and animation capabilities. ## Attributes * `id` (`:string`) - Unique identifier for the accordion container. When not provided, a random ID will be generated. This ID is used to establish ARIA relationships between components and manage focus state. * `class` (`:any`) - Additional CSS classes to apply to the accordion container. These classes will be merged with the default styles. Useful for controlling spacing, width, borders, and other visual properties of the entire accordion. Defaults to `nil`. * `multiple` (`:boolean`) - When true, allows multiple accordion items to be expanded simultaneously. When false (default), expanding one item will automatically collapse any other expanded items, maintaining a single-section view. Defaults to `false`. * `prevent_all_closed` (`:boolean`) - When true, prevents all accordion items from being closed simultaneously. This ensures that at least one item remains expanded at all times, useful for maintaining content visibility in critical interfaces. Defaults to `false`. * `animation_duration` (`:integer`) - Duration of the expand/collapse animation in milliseconds. This value controls the transition speed of panels opening and closing. Adjust this to match your application's animation preferences or accessibility requirements. Defaults to `300`. ## Slots * `inner_block` (required) - Content to be rendered inside the accordion. This should contain one or more accordion_item components that define the collapsible sections. Each item consists of a header and panel slot. ### function accordion_item/1 **Signatures:** - `accordion_item(assigns)` Renders an individual accordion item with a header and expandable panel. Each accordion item consists of a clickable header that toggles the visibility of its associated panel. The component handles all necessary ARIA attributes, state management, and animations to ensure proper accessibility and user interaction. ## Attributes * `id` (`:string`) - Unique identifier for the accordion item. When not provided, a random ID will be generated. This ID is used to establish ARIA relationships between the header button and its associated panel, ensuring proper accessibility. * `class` (`:any`) - Additional CSS classes to apply to the accordion item container. These classes will be merged with the default styles. Useful for customizing the appearance of individual sections, such as borders, backgrounds, or spacing. Defaults to `nil`. * `expanded` (`:boolean`) - Controls the initial expanded state of the accordion item. When true, the item will be expanded when first rendered. This is useful for pre-expanding important content or maintaining state across renders. Defaults to `false`. * `icon` (`:boolean`) - Controls the visibility of the chevron icon that indicates expand/collapse state. Set to false to hide the icon for a more minimal appearance or when using custom indicators in the header slot. Defaults to `true`. ## Slots * `panel` (required) - Content to be displayed in the expandable panel. This content is hidden when the accordion item is collapsed and visible when expanded. The panel supports any HTML content, including other Phoenix components and LiveView features. Accepts attributes: * `class` (`:any`) - Additional CSS classes to apply to the panel content container. Useful for styling the expanded content area with custom padding, typography, or other visual properties. * `header` (required) - Content to be displayed in the clickable header. This is always visible and toggles the expansion state when clicked. The header can contain complex content including icons, text, or other interactive elements. Accepts attributes: * `class` (`:any`) - Additional CSS classes to apply to the header button. Useful for customizing the appearance of the clickable area, including layout, spacing, and hover states. ## Fluxon.Components.Alert A versatile alert component for displaying status messages, notifications, and interactive feedback. Built with accessibility and flexibility in mind, it provides a comprehensive solution for communicating important information through visually distinct and accessible alerts. > #### Flash Messages {: .neutral} > > The alert component is not intended to replace Phoenix's flash messages. For a similar aesthetic > in flash messages, it's recommended to apply the alert component's styles to the original > `<.flash />` component. ## Usage The component can be used with simple text content for straightforward messages: ```heex <.alert>Simple alert message ``` ![Alert Message](images/alert/alert-message.png) ## Visual Variants The component supports different visual styles through the `variant` attribute, each designed for specific types of messages: ```heex <.alert variant="info" title="Update Available"> A new version of the application is ready to install. <.alert variant="success" title="Order Confirmed"> Your order has been successfully processed. <.alert variant="warning" title="Session Expiring"> Your session will expire in 5 minutes. <.alert variant="error" title="Connection Lost"> Unable to connect to the server. ``` ![Alert Variants](images/alert/variants.png) Each variant comes with its own color scheme and icon, optimized for both light and dark modes: - `default`: Neutral styling for general messages - `info`: Blue accents for informational messages - `success`: Green accents for success messages - `warning`: Amber accents for warning messages - `error`: Red accents for error messages - `neutral`: Gray styling for system messages ## Content Structure Alerts can display content in multiple ways to match your messaging needs: #### Simple Text For basic messages without additional context: ```heex <.alert>Your changes have been saved. ``` #### With Title For messages that need a clear heading: ```heex <.alert title="Profile Updated"> Your profile changes have been saved successfully. ``` #### With Title and Subtitle For complex messages that need additional context: ```heex <.alert title="Scheduled Maintenance" subtitle="System Update" variant="info"> The system will be unavailable on Saturday from 2 AM to 4 AM. ``` ## Interactive Features ### Dismissible Alerts By default, alerts include a close button. This behavior can be customized: ```heex <.alert hide_close> This alert cannot be dismissed <.alert on_close={JS.push("handle_alert_close", value: %{id: @alert_id})}> This alert triggers a custom event when closed ``` ### Custom Actions Alerts can include interactive elements for user actions: ```heex <.alert variant="warning" title="Unsaved Changes" on_close={JS.push("dismiss_warning")}> You have unsaved changes that will be lost.
<.button size="xs">Save Changes <.button size="xs" variant="ghost">Discard
``` ![Rich Content Alert](images/alert/rich-content.png) ## Icon Customization The component provides flexibility in how icons are displayed: ```heex <.alert hide_icon> Message without icon <.alert> <:icon> <.icon name="hero-bell" class="size-5" /> Custom notification icon ``` ![Alert With Custom Icon](images/alert/custom-icon.png) ### function alert/1 **Signatures:** - `alert(assigns)` Renders an alert component with support for various visual styles and interactive elements. ## Attributes * `id` (`:string`) - The unique identifier for the alert element. If not provided, a random ID will be generated. * `class` (`:any`) - Additional CSS classes to apply to the alert element. These are merged with the component's base classes and variant-specific styles. Defaults to `nil`. * `title` (`:string`) - The main heading text of the alert. When provided, creates a title section styled according to the chosen variant's color scheme. Defaults to `nil`. * `subtitle` (`:string`) - Secondary text displayed alongside the title. Only rendered when either title or subtitle is present. Defaults to `nil`. * `variant` (`:string`) - The visual style variant of the alert. Affects the entire component's appearance: - `default`: White background with zinc accents - `neutral`: Light gray background with zinc accents - `error`: Light red background with red accents - `success`: Light green background with green accents - `info`: Light blue background with sky blue accents - `warning`: Light amber background with amber accents Defaults to `"default"`. * `hide_icon` (`:boolean`) - When true, hides the alert's status icon. Defaults to `false`. * `hide_close` (`:boolean`) - When true, hides the alert's close button. Defaults to `false`. * `on_close` (`Phoenix.LiveView.JS`) - LiveView JS commands to execute when the alert is closed. Defaults to `%Phoenix.LiveView.JS{ops: []}`. ## Slots * `inner_block` - The main content to be displayed in the alert body. Renders with variant-specific text colors. * `icon` - Optional custom icon to replace the default status icon. If not provided and `hide_icon` is false, a default icon based on the variant will be shown. ## Fluxon.Components.Autocomplete A modern, accessible autocomplete component with rich search capabilities. The autocomplete component provides a text input that filters a list of options as the user types, with keyboard navigation and accessibility features. It supports both client-side and server-side search capabilities, making it suitable for both small and large datasets. > #### Select vs Autocomplete {: .info} > > While both components enable users to choose from a list of options, they offer different interaction patterns > that may better suit certain use cases. > > **Select Component** > Best suited for browsing through predefined options, especially when users benefit from seeing > all choices at once. Supports multiple selection. > > **Autocomplete Component** > Optimized for searching through large datasets, with both client and server-side filtering. > Features a type-to-search interface with custom empty states and loading indicators. > > **Key Differences:** > > | Feature | Select | Autocomplete | > |---------|---------|--------------| > | Primary Interaction | Click to browse | Type to search | > | Data Size | Small to medium lists | Any size dataset | > | Filtering | Client-side only | Client or server-side | > | Multiple Selection | Supported | Not supported | > | Clearing Selection | Supported | Supported | ## Usage Basic usage with a list of options: ```heex <.autocomplete name="country" options={[{"United States", "us"}, {"Canada", "ca"}]} placeholder="Search countries..." /> ``` The autocomplete component follows the same options API as [`Phoenix.HTML.Form.options_for_select/2`](https://hexdocs.pm/phoenix_html/Phoenix.HTML.Form.html#options_for_select/2), supporting: - List of strings: `["Option 1", "Option 2"]` - List of tuples: `[{"Label 1", "value1"}, {"Label 2", "value2"}]` - List of keyword pairs: `[key: "value"]` - Grouped options: `[{"Group", ["Option 1", "Option 2"]}]` A full-feature example would look like this: ```heex <.autocomplete name="user" label="Select User" sublabel="Search by name or email" description="Choose a user to assign the task to" help_text="Type to search through all registered users" placeholder="Search users..." search_threshold={3} options={@users} /> ``` ## Form Integration The autocomplete component integrates with Phoenix forms in two ways: using the `field` attribute for form integration or using the `name` attribute for standalone inputs. ### Using with Phoenix Forms (Recommended) Use the `field` attribute to bind the autocomplete to a form field: ```heex <.form :let={f} for={@changeset} phx-change="validate" phx-submit="save"> <.autocomplete field={f[:user_id]} label="Assigned To" options={@users} /> ``` Using the `field` attribute provides: - Automatic value handling from form data - Error handling and validation messages - Form submission with correct field names - Integration with changesets - Nested form data handling Example with a complete changeset implementation: ```elixir defmodule MyApp.Task do use Ecto.Schema import Ecto.Changeset schema "tasks" do field :title, :string belongs_to :assigned_to, MyApp.User timestamps() end def changeset(task, attrs) do task |> cast(attrs, [:assigned_to_id, :title]) |> validate_required([:assigned_to_id]) end end # In your LiveView def mount(_params, _session, socket) do users = MyApp.Accounts.list_active_users() |> Enum.map(&{&1.name, &1.id}) changeset = Task.changeset(%Task{}, %{}) {:ok, assign(socket, users: users, form: to_form(changeset))} end def render(assigns) do ~H""" <.form :let={f} for={@form} phx-change="validate"> <.autocomplete field={f[:assigned_to_id]} options={@users} label="Assigned To" placeholder="Search users..." /> """ end def handle_event("validate", %{"task" => params}, socket) do changeset = %Task{} |> Task.changeset(params) |> Map.put(:action, :validate) {:noreply, assign(socket, form: to_form(changeset))} end ``` ### Using Standalone Autocomplete For simpler cases or when not using Phoenix forms, use the `name` attribute: ```heex <.autocomplete name="search_user" options={@users} value={@user_id} placeholder="Search users..." /> ``` When using standalone autocomplete: - The `name` attribute determines the form field name - Values are managed through the `value` attribute - Errors are passed via the `errors` attribute ## Search Behavior The autocomplete component offers two distinct search strategies: client-side and server-side filtering. This flexibility allows the component to efficiently handle both small, static datasets and large, dynamic data sources that require server-side processing. ### Client-side Search Client-side search provides immediate feedback as users type, filtering the provided options directly in the browser. This approach is ideal for small to medium datasets that do not require server-side processing, such as language selections, predefined categories, list of countries, etc. ```heex <.autocomplete name="language" search_mode="contains" search_threshold={2} no_results_text="No languages matching '%{query}'" options={[ {"English", "en"}, {"Spanish", "es"}, {"French", "fr"}, {"German", "de"} ]} /> ``` The component offers three search modes through the `search_mode` attribute, each providing different matching behavior: - `"contains"` (default): Matches if the option label contains the search query anywhere - `"starts-with"`: Matches only if the option label begins with the search query - `"exact"`: Matches only if the option label exactly matches the search query The `search_threshold` attribute determines how many characters must be typed before filtering begins, helping to prevent unnecessary filtering operations for very short queries. ### Server-side Search For large datasets, dynamic data sources, or when complex search logic is required, the component supports server-side search through LiveView integration. This is particularly useful when dealing with database queries, API calls, or when implementing features like debounced search or typeahead suggestions. Server-side search is activated by providing the `on_search` attribute with a LiveView event name. When users type, the component sends this event with the search query as a parameter: ```heex <.autocomplete name="movie" options={@movies} on_search="search_movies" search_threshold={2} placeholder="Type to search movies..." /> ``` In your LiveView, handle the search event to fetch and update the options: ```elixir def mount(_params, _session, socket) do {:ok, assign(socket, movies: [])} end def handle_event("search_movies", %{"query" => query}, socket) when byte_size(query) >= 2 do case MyApp.Movies.search(query) do {:ok, movies} -> {:noreply, assign(socket, movies: movies)} {:error, _reason} -> {:noreply, assign(socket, movies: [])} end end ``` The component automatically manages the search state, including: - Debouncing requests to prevent excessive server calls - Displaying a loading indicator during searches - Maintaining the selected value while searching - Handling empty states and error conditions #### Initial Options While server-side search is primarily focused on dynamic filtering, you can optionally provide an initial set of options that will be available when the component loads: ```elixir def mount(_params, _session, socket) do {:ok, assign(socket, movies: MyApp.Movies.featured_movies())} end ``` ```heex <.autocomplete name="movie" options={@movies} on_search="search_movies" search_threshold={2} placeholder="Search movies..." /> ``` These initial options are accessible as soon as the user interacts with the component, whether by clicking the input field, using arrow keys (↑/↓), or focusing the input when `open_on_focus` is enabled. The choice between providing initial options or starting with an empty list depends on your use case: - **Initial Options**: Ideal when you want to showcase popular or recommended choices upfront, reducing the need for typing and improving discoverability. This works well for scenarios like movie recommendations, frequently used items, or recently accessed content. - **Empty Initial State**: Better suited when the dataset is too large to meaningfully preload options, when you want to encourage specific search terms, or when options are highly contextual to the user's input. This is common in scenarios like user search in large organizations or product search in extensive catalogs. #### ⚠️ Selected Value and Initial Options When the component is initialized with a value, it attempts to find the corresponding label from the provided options to display in the input. For example, if the component is initialized with `value={2}` and the options include `{"Alice", 2}`, the input will display "Alice" as the selected value. ```elixir def mount(_params, _session, socket) do # Bad: Selected user (id: 2) is not included in initial options {:ok, assign(socket, selected_user_id: 2, users: [] # Empty initial options )} end ``` ```elixir def mount(_params, _session, socket) do featured_users = MyApp.Accounts.featured_users() |> Enum.map(&{&1.name, &1.id}) selected_user = MyApp.Accounts.get_user!(2) # Good: Include the selected user in initial options {:ok, assign(socket, selected_user_id: selected_user.id, users: [{selected_user.name, selected_user.id} | featured_users] )} end ``` When using server-side search with a selected value, it's crucial to ensure that the selected option is included in the initial options list, even if you're starting with an otherwise empty list. If the selected value's option is not found in the list, the raw value will be displayed in the input, resulting in a poor user experience. ## Custom Option Rendering The autocomplete component supports custom option rendering through its `:option` slot. For each option in the list, the component passes a tuple `{label, value}` to the slot: ```heex <.autocomplete name="user" options={@users} placeholder="Search users..." > <:option :let={{label, value}}>
{label}
{user_email(value)}
``` ## Header and Footer Content The autocomplete component allows you to add custom content at the top and bottom of the listbox using the `:header` and `:footer` slots. This is useful for adding actions like buttons or links or additional information to the dropdown. ```heex <.autocomplete field={f[:product]} options={@products}> <:header class="p-2 border-b">
<.button size="xs" class="rounded-full" phx-click="filter" phx-value-type="all">All <.button size="xs" class="rounded-full" phx-click="filter" phx-value-type="active">Active
<:footer class="p-2 border-t"> <.button type="button" size="sm" class="w-full" as="link" navigate={~p"/products/new"}> <.icon name="u-plus" class="size-4" /> Create new ``` Both slots support a `class` attribute for custom styling and maintain proper borders with the options list. ### Empty State The autocomplete component also supports a custom empty state through the `:empty_state` slot: ```heex <.autocomplete options={@users}> <:empty_state>
<.icon name="u-user-x" class="size-8 mx-auto mb-2" />

No users found

Try a different search term

``` ## Clearable Selection By default, once a selection is made in the autocomplete component, users need to manually clear the input field to change their selection. The `clearable` attribute adds an "✕" button that appears when a value is selected, making it easy to reset the selection with a single click. ```heex <.autocomplete name="language" clearable options={[ {"English", "en"}, {"Spanish", "es"}, {"French", "fr"}, {"German", "de"} ]} /> ``` This feature is particularly useful in forms where users might want to change their selection or when the autocomplete is used for optional fields that can be left blank. ## Keyboard Support The autocomplete component provides comprehensive keyboard navigation: | Key | Element Focus | Description | |-----|---------------|-------------| | `Tab`/`Shift+Tab` | Input | Moves focus to and from the input | | `↑` | Input | Opens listbox and highlights last option | | `↓` | Input | Opens listbox and highlights first option | | `↑` | Option | Moves highlight to previous visible option | | `↓` | Option | Moves highlight to next visible option | | `Enter` | Option | Selects the highlighted option | | `Escape` | Any | Closes the listbox | | Type characters | Input | Filters options based on input | ## Common Use Cases ### User Search with Avatar ```elixir defmodule MyApp.UsersLive do use FluxlandWeb, :live_view def mount(_params, _session, socket) do {:ok, socket |> assign(users: fetch_users()) |> assign(form: to_form(%{}, as: :search))} end def render(assigns) do ~H""" <.form :let={f} for={@form} phx-change="search"> <.autocomplete field={f[:user_id]} options={user_options(@users)} on_search="search_users" clearable> <:option :let={{label, value}}>
{label}
{user_by_id(value, @users)["email"]}
<:empty_state>

No matching users found

Try searching by name or email

""" end def handle_event("search_users", %{"query" => query}, socket) do {:noreply, assign(socket, users: fetch_users(query))} end def handle_event("search", _params, socket), do: {:noreply, socket} defp fetch_users(query \\ "") do case Req.get("https://dummyjson.com/users/search", params: [limit: 10, q: query]) do {:ok, %{body: %{"users" => users}}} -> users _ -> [] end end defp user_options(users), do: Enum.map(users, &{&1["firstName"] <> " " <> &1["lastName"], &1["id"]}) defp user_by_id(id, users), do: Enum.find(users, &(&1["id"] == id)) end ``` ### function autocomplete/1 **Signatures:** - `autocomplete(assigns)` Renders an autocomplete component with rich search capabilities and full keyboard navigation support. This component provides a flexible way to build search interfaces with real-time filtering, server-side search capabilities, and rich option rendering. It includes built-in form integration, error handling, and accessibility features. ## Attributes * `id` (`:any`) - The unique identifier for the autocomplete component. Defaults to `nil`. * `name` (`:any`) - The form name for the autocomplete. Required when not using the `field` attribute. * `field` (`Phoenix.HTML.FormField`) - The form field to bind to. When provided, the component automatically handles value tracking, errors, and form submission. * `class` (`:any`) - Additional CSS classes to apply to the autocomplete component. These classes are applied to the listbox container. Defaults to `nil`. * `label` (`:string`) - The primary label for the autocomplete. This text is displayed above the input and is used for accessibility purposes. Defaults to `nil`. * `sublabel` (`:string`) - Additional context displayed to the side of the main label. Useful for providing extra information without cluttering the main label. Defaults to `nil`. * `help_text` (`:string`) - Help text to display below the autocomplete. This can provide additional context or instructions for using the input. Defaults to `nil`. * `description` (`:string`) - A longer description to provide more context about the autocomplete. This appears below the label but above the input element. Defaults to `nil`. * `placeholder` (`:string`) - Text to display in the input when empty. This text appears in the search input and helps guide users to start typing. Defaults to `nil`. * `autofocus` (`:boolean`) - Whether the input should have the autofocus attribute. Defaults to `false`. * `disabled` (`:boolean`) - When true, disables the autocomplete component. Disabled inputs cannot be interacted with and appear visually muted. Defaults to `false`. * `size` (`:string`) - Controls the size of the autocomplete component: - `"sm"`: Small size, suitable for compact UIs - `"base"`: Default size, suitable for most use cases - `"lg"`: Large size, suitable for prominent inputs - `"xl"`: Extra large size, suitable for hero sections Defaults to `"base"`. * `search_threshold` (`:integer`) - The minimum number of characters required before showing suggestions. This helps prevent unnecessary searches and improves performance. Defaults to `0`. * `no_results_text` (`:string`) - Text to display when no options match the search query. Use `%{query}` as a placeholder for the actual search term. This is only shown when no custom empty state is provided. Defaults to `"No results found for \"%{query}\"."`. * `on_search` (`:string`) - Name of the LiveView event to be triggered when searching. If provided, filtering will be handled server-side. The event receives `%{"query" => query}` as parameters. Defaults to `nil`. * `debounce` (`:integer`) - The debounce time in milliseconds for server-side searches. This delays the `on_search` event until the user stops typing for the specified duration. Defaults to `200`. * `search_mode` (`:string`) - The mode of the client-side search to use for the autocomplete: - `"contains"`: Match if option contains the search query (default) - `"starts-with"`: Match if option starts with the search query - `"exact"`: Match only if option exactly matches the search query Defaults to `"contains"`. * `open_on_focus` (`:boolean`) - When true, the listbox opens when the input is focused, even if no search query has been entered yet. Defaults to `false`. * `value` (`:any`) - The current selected value of the autocomplete. When using forms, this is automatically handled by the `field` attribute. * `errors` (`:list`) - List of error messages to display below the autocomplete. These are automatically handled when using the `field` attribute with form validation. Defaults to `[]`. * `options` (`:list`) (required) - A list of options for the autocomplete. Can be provided in multiple formats: - List of strings: `["Option 1", "Option 2"]` - List of tuples: `[{"Label 1", "value1"}, {"Label 2", "value2"}]` - List of keyword pairs: `[key: "value"]` * `animation` (`:string`) - The animation style for the listbox. This controls how the listbox appears and disappears when opening/closing. Defaults to `"transition duration-150 ease-in-out"`. * `animation_enter` (`:string`) - CSS classes applied to the listbox when it enters (opens). Defaults to `"opacity-100 scale-100"`. * `animation_leave` (`:string`) - CSS classes applied to the listbox when it leaves (closes). Defaults to `"opacity-0 scale-95"`. * `clearable` (`:boolean`) - When true, displays a clear button to remove the current selection. This allows users to easily reset the input value without having to delete it manually. Defaults to `false`. ## Slots * `option` - Optional slot for custom option rendering. When provided, each option can be fully customized with rich content. The slot receives a tuple `{label, value}` for each option. * `empty_state` - Optional slot for custom empty state rendering. When provided, this content is shown instead of the default "no results" message when no options match the search query. Accepts attributes: * `class` (`:any`) - Additional CSS classes to apply to the empty state container. * `header` - Optional slot for custom header rendering. When provided, this content is shown in the top of the listbox. Accepts attributes: * `class` (`:any`) - Additional CSS classes to apply to the header container. * `footer` - Optional slot for custom footer rendering. When provided, this content is shown in the bottom of the listbox. Accepts attributes: * `class` (`:any`) - Additional CSS classes to apply to the footer container. ## Fluxon.Components.Badge A versatile badge component for displaying status indicators, categories, and counts. Badges are compact visual elements that help highlight information, categorize content, or show counts. They are designed to be highly visible while maintaining readability and can adapt their appearance for both light and dark modes. ## Usage Badges can be used to highlight status, categorize content, or display counts: ```heex <.badge>Default <.badge color="blue">In Progress <.badge color="green">Completed <.badge color="red">Failed ``` ![Basic Badges](images/badge/basic-badges.png) ## Colors and Theming The badge component offers an extensive color palette optimized for both light and dark modes: ```heex <.badge color="blue">Blue <.badge color="green">Green <.badge color="red">Red <.badge color="yellow">Yellow <.badge color="purple">Purple <.badge color="pink">Pink <.badge color="indigo">Indigo <.badge color="teal">Teal ``` ![Badge Colors](images/badge/badge-colors.png) Each color includes carefully designed variations: - Light mode: Semi-transparent background with matching ring - Dark mode: Darker background with adjusted contrast Available color spectrums: - Base colors: `zinc` (default) - Red spectrum: `red`, `rose`, `pink` - Orange spectrum: `orange`, `amber` - Yellow spectrum: `yellow` - Green spectrum: `green`, `emerald`, `lime` - Blue spectrum: `blue`, `sky`, `cyan` - Purple spectrum: `purple`, `violet`, `indigo` - Special colors: `fuchsia`, `teal` ## Visual Variants The component offers three distinct visual styles: ```heex <.badge variant="default">Default Badge <.badge variant="pill">Pill Badge <.badge variant="flat">Flat Badge ``` ![Badge Variants](images/badge/badge-variants.png) ## Working with Icons Badges work seamlessly with icons for enhanced visual communication. The component automatically handles icon sizing and alignment through the `icon` class: ```heex <.badge color="green"> <.icon name="hero-check-circle" class="icon" /> Verified <.badge color="amber"> <.icon name="hero-clock" class="icon" /> Pending <.badge color="red"> <.icon name="hero-x-circle" class="icon" /> Failed ``` ![Badges with Icons](images/badge/badges-with-icons.png) > #### Icon Class Required {: .info} > > The `icon` class is required for proper icon sizing and alignment within badges: > > ```heex > <.badge> > <.icon name="hero-check" class="icon" /> > <.icon name="hero-check" /> > > ``` ## Real-World Examples ### Status Indicators ```heex <.badge color="green" variant="pill">Active <.badge color="amber" variant="pill">Pending <.badge color="red" variant="pill">Inactive ``` ![Status Badges](images/badge/status-badges.png) ### Category Labels ```heex <.badge color="blue" variant="flat">Documentation <.badge color="purple" variant="flat">Feature <.badge color="orange" variant="flat">Bug Fix ``` ![Category Badges](images/badge/category-badges.png) ### Notification Counts ```heex <.badge color="red" variant="pill">99+ <.badge color="blue" variant="pill">New <.badge color="green" variant="pill">4 ``` ![Count Badges](images/badge/count-badges.png) ### function badge/1 **Signatures:** - `badge(assigns)` Renders a badge component with the given attributes and content. The badge component provides a flexible way to highlight information through visual indicators. It supports various styles, colors, and can contain both text and icons. ## Attributes * `class` (`:any`) - Additional CSS classes to apply to the badge element. These are merged with the component's base classes, variant styles, and color styles. Defaults to `nil`. * `color` (`:string`) - The color scheme of the badge. Each color includes light and dark mode variants that affect the background, text, and ring colors. Defaults to `"zinc"`. * `variant` (`:string`) - The visual style variant of the badge: - `default`: Standard rounded corners with ring - `pill`: Fully rounded edges for a softer look - `flat`: Similar to default but without ring/border Defaults to `"default"`. * Global attributes are accepted. Additional HTML attributes to apply to the badge element. ## Slots * `inner_block` (required) - The content to be displayed within the badge. Supports text and icons with automatic spacing and alignment. ## Fluxon.Components.Button A versatile button component that provides consistent, accessible, and visually appealing interactive elements. This component offers a comprehensive solution for building interactive elements across your application, from simple actions to complex workflows. It seamlessly integrates with Phoenix LiveView and provides built-in support for both button and anchor tag rendering, making it suitable for navigation, form submissions, and general user interactions. ## Usage Buttons can be used in their simplest form for actions and interactions: ```heex <.button>Default Button <.button variant="solid">Solid Button <.button variant="ghost">Ghost Button ``` ![Basic Buttons](images/button/basic-buttons.png) ## Visual Variants The component supports three distinct visual styles: ```heex <.button variant="default">Default <.button variant="solid">Solid <.button variant="ghost">Ghost ``` ![Button Variants](images/button/button-variants.png) Each variant is designed for specific use cases: - `default`: Standard button with subtle gradient and border, ideal for secondary actions - `solid`: Filled button with stronger visual weight, perfect for primary actions - `ghost`: Borderless button with hover state, great for tertiary actions ## Colors and Theming The button supports multiple color schemes, each carefully designed for both light and dark modes: ```heex <.button color="blue" variant="solid">Primary <.button color="green" variant="solid">Success <.button color="red" variant="solid">Danger <.button color="yellow" variant="solid">Warning ``` ![Button Colors](images/button/button-colors.png) Available colors and their common use cases: - `default`: Neutral gray tones for general actions - `red`: Error and destructive actions - `yellow`: Warning or attention actions - `green`: Success or confirmation actions - `blue`: Primary or call-to-action buttons Each color includes specific styling for all variants: - Default: Semi-transparent with matching border - Solid: Full color with white text - Ghost: Colored text with transparent background ## Size Options The component offers five size variants to accommodate different use cases: ```heex <.button size="xs">Extra Small <.button size="sm">Small <.button size="md">Medium <.button size="lg">Large <.button size="xl">Extra Large ``` ![Button Sizes](images/button/button-sizes.png) Size specifications: | Size | Height | Text | Icon Size | Use Case | |------|--------|------|-----------|-----------| | `xs` | 32px | xs | 14px | Compact UI elements | | `sm` | 36px | sm | 16px | Secondary actions | | `md` | 40px | sm | 16px | Default size | | `lg` | 44px | base | 18px | Primary actions | | `xl` | 48px | base/lg | 20px | Hero sections | ## Working with Icons The button component automatically handles icon sizing and spacing: ```heex <.button> <.icon name="hero-plus" class="icon" /> Add Item <.button variant="solid" color="green"> <.icon name="hero-check" class="icon" /> Confirm ``` ![Buttons with Icons](images/button/buttons-with-icons.png) > #### Icon Class Required {: .info} > > The `icon` class is required for proper icon sizing and alignment: > > ```heex > <.button> > <.icon name="hero-check" class="icon" /> > <.icon name="hero-check" /> > > ``` ## Link Mode The button can be rendered as a link while maintaining consistent styling: ```heex <.button as="link" navigate={~p"/dashboard"}> Go to Dashboard ``` When used as a link, it supports all LiveView link attributes: - `navigate`: For live navigation - `patch`: For live patches - `href`: For regular navigation - Standard anchor attributes (`target`, `rel`, etc.) ## Real-World Examples ### Primary Action ```heex <.button variant="solid" color="blue" size="lg"> <.icon name="hero-arrow-right" class="icon" /> Get Started ``` ![Primary Action Button](images/button/primary-action.png) ### Destructive Action ```heex <.button variant="solid" color="red" phx-click="delete_account" phx-value-id={@account_id}> <.icon name="hero-trash" class="icon" /> Delete Account ``` ![Destructive Action Button](images/button/destructive-action.png) ### Navigation Link ```heex <.button as="link" navigate={~p"/settings"} variant="ghost"> <.icon name="hero-cog-6-tooth" class="icon" /> Settings ``` ![Navigation Link Button](images/button/navigation-link.png) ### function button/1 **Signatures:** - `button(assigns)` Renders a button or link with customizable styles and attributes. This component provides a flexible way to create interactive elements with consistent styling across your application. It supports various sizes, colors, and visual variants while maintaining proper accessibility and user experience standards. ## Attributes * `color` (`:string`) - The color scheme of the button. Each color includes specific styles for all variants and maintains proper contrast in both light and dark modes. Defaults to `"default"`. * `size` (`:string`) - The size variant of the button. Affects height, padding, font size, and icon sizing. Defaults to `"md"`. * `type` (`:string`) - The type attribute for button elements. Common values: `button`, `submit`, `reset`. Only applies when `as` is set to `button`. Defaults to `nil`. * `variant` (`:string`) - The visual style variant of the button: - `default`: Standard button with subtle gradient and border - `solid`: Filled button with stronger visual weight - `ghost`: Borderless button with hover state Defaults to `"default"`. * `as` (`:string`) - Determines whether the component renders as a button or link element. When `link` is used, all Phoenix LiveView link attributes are supported. Defaults to `"button"`. * `class` (`:any`) - Additional CSS classes to be applied to the button. These are merged with the component's base classes, variant styles, and size styles. Defaults to `nil`. * Global attributes are accepted. Additional HTML attributes to apply to the button element. Supports both standard button attributes and anchor/link attributes. Supports all globals plus: `["target", "download", "rel", "hreflang", "type", "referrerpolicy", "navigate", "patch", "href", "replace", "method", "csrf_token", "autofocus", "disabled", "form", "formaction", "formenctype", "formmethod", "formnovalidate", "formtarget", "name", "type", "value"]`. ## Slots * `inner_block` (required) - The content to be displayed within the button. Supports text and icons with automatic spacing and sizing based on the selected size variant. ## Fluxon.Components.Checkbox A versatile checkbox component for capturing single and multiple selections. This component provides a comprehensive solution for building accessible form inputs, selection interfaces, and rich interactive content. It seamlessly integrates with Phoenix forms and offers both standard and card variants to accommodate various design patterns, from simple boolean toggles to visually rich selection interfaces. ## Usage The checkbox component can be used in its simplest form for single selections: ```heex <.checkbox name="terms" label="I agree to the terms and conditions" value="accepted" /> ``` ![Basic Checkbox](images/checkbox/basic-usage.png) The checkbox value will be `"true"` when checked and `"false"` when unchecked. ```elixir %{"_target" => ["terms"], "terms" => "true"} %{"_target" => ["terms"], "terms" => "false"} ``` For more context, you can add sublabels and descriptions: ```heex <.checkbox name="notifications" label="Enable notifications" sublabel="Receive updates about your account" description="We'll send you important updates about your account status and security." /> ``` ![Checkbox with Sublabel and Description](images/checkbox/basic-sublabel-description.png) ## Form Integration The checkbox component offers two ways to handle form data: using the `field` attribute for Phoenix form integration or using the `name` attribute for standalone checkboxes. Each approach has its own benefits and use cases. ### Using with Phoenix Forms (Recommended) When working with Phoenix forms, use the `field` attribute to bind the checkbox to a form field: ```heex <.form :let={f} for={@form} phx-change="validate" phx-submit="save"> <.checkbox field={f[:marketing_emails]} label="Marketing emails" sublabel="Receive updates about new features and promotions" /> <.checkbox field={f[:terms_accepted]} label="Terms and Conditions" description="I agree to the terms of service and privacy policy" value="accepted" /> <.checkbox field={f[:newsletter_frequency]} label="Weekly newsletter" value="weekly" checked={@user.newsletter_frequency == "weekly"} /> ``` Using the `field` attribute provides several advantages: - Automatic value handling from the form data - Built-in error handling and validation messages - Proper form submission with correct field names - Integration with changesets for data validation - Automatic ID generation for accessibility - Proper handling of nested form data The component will automatically: - Set the checkbox field's name based on the form structure - Display the current value from the form data - Show validation errors when present - Handle nested form data with proper input naming ### Using Standalone Checkboxes For simpler cases or when not using Phoenix forms, use the `name` attribute: ```heex <.checkbox name="show_archived" checked={@show_archived} label="Show archived items" /> <.checkbox name="user[preferences][dark_mode]" checked={@user_preferences.dark_mode} errors={@errors["dark_mode"]} label="Dark mode" sublabel="Use dark theme" /> ``` When using standalone checkboxes: - You must provide the `name` attribute - Values must be managed manually via the `checked` attribute - Errors must be passed explicitly via the `errors` attribute - Form submission handling needs to be implemented manually - Nested data requires manual name formatting (e.g., `user[preferences][dark_mode]`) > #### When to use each approach {: .tip} > > Use the `field` attribute when: > - Working with changesets and data validation > - Handling complex form data structures > - Need automatic error handling > - Building CRUD interfaces > > Use the `name` attribute when: > - Building simple toggle controls > - Creating standalone filters > - Handling one-off form controls > - Need more direct control over the checkbox behavior ## Card Variant The component offers a card variant that transforms checkboxes into rich, interactive selection cards: ```heex <.checkbox control="left" field={f[:notifications]} variant="card" label="Push Notifications" sublabel="Stay informed" description="Get real-time updates for messages and activity" value="enabled" /> ``` ![Checkbox Card Variant](images/checkbox/card.png) ## Checkbox Group Checkbox groups are used to map a list of options to a single form field: ```heex <.checkbox_group name="preferences" label="Notification Preferences" description="Choose when you want to receive notifications" > <:checkbox value="email" label="Email notifications" /> <:checkbox value="push" label="Push notifications" /> <:checkbox value="sms" label="SMS notifications" /> ``` ![Checkbox Group](images/checkbox/basic-group.png) ### Form Integration Like the single checkbox component, checkbox groups seamlessly integrate with Phoenix forms. See the form integration section in the [Form Integration](#module-form-integration) section for a detailed guide on form handling. Here's a simple example using the `field` attribute: ```heex <.form :let={f} for={@form} phx-change="validate" phx-submit="save"> <.checkbox_group field={f[:notification_preferences]} label="Notification Preferences" description="Choose how you want to be notified" > <:checkbox value="email" label="Email" sublabel="Get notified via email" /> <:checkbox value="push" label="Push" sublabel="Receive push notifications" /> <:checkbox value="sms" label="SMS" sublabel="Get SMS alerts" /> ``` Different from the single checkbox, the group will send a list of selected values in the form submission: ```elixir %{"_target" => ["preferences"], "preferences" => ["", "email", "push"]} ``` > #### Empty Values in Checkbox Groups {: .info} > > When working with checkbox groups, it's important to understand how browsers handle unselected checkboxes: > > - By HTML specification, browsers only submit values for checked checkboxes > - If no checkboxes are selected, the field will be completely absent from the form data > > To ensure consistent form handling, this component includes a hidden input with an empty value: > > ```elixir > > ``` > > This means your form submissions will always include the field, with these possible values: > > ```elixir > # No checkboxes selected > %{"group" => [""]} > > # One or more selected > %{"group" => ["", "option1", "option2"]} > ``` > > When processing the form data, you'll want to: > 1. Filter out the empty string value > 2. Handle an empty list as "no selection" > > ```elixir > # Example processing > selected = Enum.reject(params["group"] || [], &(&1 == "")) > ``` ### Card Variant The card variant transforms checkboxes into rich, interactive selection cards: ```heex <.checkbox_group label="Weekdays" description="Select the days of the week you want to work" field={f[:weekdays]} variant="card" class="flex gap-x-2" > <:checkbox :for={{label, value} <- [{"S", "sun"}, {"M", "mon"}, {"T", "tue"}, {"W", "wed"}, {"T", "thu"}, {"F", "fri"}, {"S", "sat"}]} value={value} class="flex items-center justify-center rounded-full has-checked:bg-zinc-800 text-zinc-700 has-checked:text-white size-10" > {label} ``` ![Checkbox Card Variant](images/checkbox/group-card.png) ### function checkbox/1 **Signatures:** - `checkbox(assigns)` Renders a single checkbox input for capturing boolean or single-value selections. This component provides a flexible way to build form inputs with support for labels, descriptions, and rich styling options. It includes built-in form integration, error handling, and accessibility features. ## Attributes * `id` (`:any`) - The unique identifier for the checkbox. When not provided, a random ID will be generated. Defaults to `nil`. * `name` (`:any`) - The form name for the checkbox. Required when not using the `field` attribute. * `checked` (`:boolean`) - Whether the checkbox is checked. When using forms, this is automatically handled by the `field` attribute. * `value` (`:any`) - The value associated with the checkbox. This value is submitted when the checkbox is checked. * `errors` (`:list`) - List of error messages to display below the checkbox. These are automatically handled when using the `field` attribute with form validation. Defaults to `[]`. * `label` (`:string`) - The primary label for the checkbox. This text is displayed next to the checkbox and is used for accessibility purposes. Defaults to `nil`. * `sublabel` (`:string`) - Additional context displayed to the side of the main label. Useful for providing extra information without cluttering the main label. Defaults to `nil`. * `description` (`:string`) - Detailed description of the checkbox option. This text appears below the label and can contain longer explanatory text. Defaults to `nil`. * `class` (`:any`) - Additional CSS classes to apply to the checkbox. Useful for controlling the appearance of the checkbox. Defaults to `nil`. * `field` (`Phoenix.HTML.FormField`) - The form field to bind to. When provided, the component automatically handles value tracking, errors, and form submission. * `variant` (`:string`) - The visual variant of the checkbox. Currently supports: - `nil` (default): Standard checkbox with label - `"card"`: Rich selection card with support for custom content Defaults to `nil`. * `control` (`:string`) - Controls the position of the checkbox input in card variants. It's only available when `variant="card"`. - `"left"`: Places the checkbox on the left side of the card - `"right"`: Places the checkbox on the right side of the card Must be one of `"left"`, or `"right"`. * Global attributes are accepted. Additional HTML attributes to apply to the checkbox input. Currently supports the `disabled` attribute. Supports all globals plus: `["disabled"]`. ## Slots * `inner_block` - Optional custom content for the checkbox. When provided in card variants, this content replaces the standard label/sublabel/description structure. ### function checkbox_group/1 **Signatures:** - `checkbox_group(assigns)` Renders a checkbox group for managing multiple related selections. This component provides a flexible way to handle multiple choice selections, with support for both standard checkbox lists and rich card-based interfaces. It includes built-in form integration, error handling, and accessibility features. ## Attributes * `id` (`:any`) - The unique identifier for the checkbox group. When not provided, a random ID will be generated. Defaults to `nil`. * `name` (`:string`) - The form name for the checkbox group. For groups, this will be suffixed with `[]` to support multiple selections. Required when not using the `field` attribute. * `value` (`:any`) - The current value(s) of the checkbox group. For groups, this should be a list of selected values. When using forms, this is automatically handled by the `field` attribute. * `label` (`:string`) - The primary label for the checkbox group. This text is displayed above the checkboxes and is used for accessibility purposes. Defaults to `nil`. * `sublabel` (`:string`) - Additional context displayed on the side of the main label. Useful for providing extra information about the checkbox group without cluttering the main label. Defaults to `nil`. * `description` (`:string`) - Detailed description of the checkbox group. This text appears below the label and can contain longer explanatory text about the available options. Defaults to `nil`. * `errors` (`:list`) - List of error messages to display below the checkbox group. These are automatically handled when using the `field` attribute with form validation. Defaults to `[]`. * `class` (`:any`) - Additional CSS classes to apply to the checkbox group container. Useful for controlling layout, spacing, and visual styling of the group. Defaults to `nil`. * `field` (`Phoenix.HTML.FormField`) - The form field to bind to. When provided, the component automatically handles value tracking, errors, and form submission. * `disabled` (`:boolean`) - When true, disables all checkboxes in the group. Disabled checkboxes cannot be interacted with and appear visually muted. Defaults to `false`. * `variant` (`:string`) - The visual variant of the checkbox group. Currently supports: - `nil` (default): Standard stacked checkboxes - `"card"`: Rich selection cards with support for custom content Defaults to `nil`. * `control` (`:string`) - Controls the position of the checkbox input in card variants. It's only available when `variant="card"`. - `"left"`: Places the checkbox on the left side of the card - `"right"`: Places the checkbox on the right side of the card Must be one of `"left"`, or `"right"`. ## Slots * `checkbox` (required) - Defines the individual checkboxes within the group. Each checkbox can have: - `value`: The value associated with this checkbox - `label`: The checkbox label - `sublabel`: Additional context on the side of the label - `description`: Detailed description of the option - `disabled`: Whether this specific checkbox is disabled - `class`: Additional CSS classes for this checkbox - `checked`: Whether this checkbox should be checked by default Accepts attributes: * `value` (`:any`) (required) * `label` (`:string`) * `sublabel` (`:string`) * `description` (`:string`) * `disabled` (`:boolean`) * `class` (`:any`) * `checked` (`:boolean`) ## Fluxon.Components.DatePicker A date picker component that provides calendar-based date selection with support for time picking and date ranges. ## Usage The component provides three specialized functions to handle different date selection needs. Here are examples of each use case: ```heex <.date_picker name="appointment" label="Appointment Date" /> <.date_time_picker name="meeting" label="Meeting Time" time_format="12" # or "24" for 24-hour format /> <.date_range_picker start_name="check_in" end_name="check_out" label="Stay Period" /> ``` Like all other form components, the date picker supports various labeling options to provide context and guidance to users: ```heex <.date_picker name="appointment" label="Appointment Date" sublabel="Required" description="Choose when you'd like to schedule your consultation" help_text="Our office is open Monday through Friday, 9 AM to 5 PM" /> ``` ## Date Range Constraints The date picker supports limiting the selectable dates through the `min` and `max` attributes. Both attributes expect an Elixir `Date` struct and provide client-side validation only. For security purposes, you should always implement corresponding backend validations, typically through Ecto changesets. Here's an example that limits date selection to the next 30 days: ```heex <.date_picker field={f[:deadline]} label="Project Deadline" min={Date.utc_today()} max={Date.add(Date.utc_today(), 30)} /> ``` You can also use date literals with the `~D` sigil for fixed dates: ```heex <.date_picker name="birth_date" label="Birth Date" min={~D[1900-01-01]} max={Date.utc_today()} /> ``` When date constraints are set, the component: - Disables and visually styles dates outside the allowed range - Prevents keyboard navigation to disabled dates - Automatically disables month/year navigation buttons when the visible month would not show any selectable dates - Ensures the calendar opens to a month containing selectable dates, even if the current month is outside the allowed range - Maintains the constraints when switching between months or years - Clears the selection if a previously selected date becomes invalid due to dynamically changed constraints ## Multiple Date Selection The date picker supports selecting multiple dates through the `multiple` attribute. This mode is particularly useful for scenarios like scheduling recurring events, selecting holiday dates, or planning multiple appointments: ```heex <.date_picker field={f[:holidays]} label="Company Holidays" multiple description="Select all company holidays for the year" help_text="Click dates to toggle selection" /> ``` When multiple date selection is enabled: - The calendar remains open after each selection to facilitate choosing multiple dates - Each selected date is visually highlighted in the calendar - Clicking a selected date deselects it - The toggle button displays "X dates selected" when more than one date is chosen - Time picker integration is not supported (see [Time Picker Integration](#module-time-picker-integration)) - Auto-close mode is not supported (see [Closing Strategies](#module-closing-strategies)) > #### Browser Behavior with Multiple Fields {: .info} > > When using multiple selection fields in HTML forms (e.g., `name="dates[]"`), browsers have a > specific behavior that can affect form submissions: > > - When options are selected, each value is included in the form data > - However, when all options are deselected, the browser omits the field entirely from the form submission > - This means the server cannot distinguish between "no form submitted" and "user deselected all dates" > > To work around this browser limitation, the component automatically includes a hidden input with an > empty value. As a result, when all dates are deselected, an empty string is sent to the backend > instead of omitting the field entirely. This results in consistent form submissions: > > ```elixir > # When dates are selected > %{ > "date_form" => %{ > "holidays" => ["2025-05-15", "2025-05-14", "2025-05-22"] > } > } > > # When all dates are deselected (hidden input provides the empty value) > %{ > "date_form" => %{ > "holidays" => [""] # Instead of field being omitted entirely > } > } > ``` ## Date Formatting The date picker uses Elixir's [strftime](https://hexdocs.pm/calendar/Calendar.Strftime.html#strftime/3) under the hood to format dates. Control how dates are displayed using the `display_format` attribute: ```heex <.date_picker field={f[:date]} label="Date" display_format="%B %-d, %Y" # Displays as "January 1, 2024" /> ``` Common date format patterns: - `"%Y-%m-%d"`: ISO format (2024-01-01) - `"%b %-d, %Y"`: Short month (Jan 1, 2024) - `"%B %-d, %Y"`: Full month (January 1, 2024) - `"%d/%m/%Y"`: European format (01/01/2024) - `"%m/%d/%Y"`: US format (01/01/2024) When using the `date_time_picker/1` component, you should include time format patterns in your display format. Here are some common datetime patterns: ```heex <.date_time_picker field={f[:appointment]} label="Appointment" time_format="12" display_format="%B %-d, %Y at %I:%M %p" # January 1, 2024 at 02:30 PM /> <.date_time_picker field={f[:meeting]} label="Meeting" time_format="24" display_format="%Y-%m-%d %H:%M" # 2024-01-01 14:30 /> ``` Common datetime format patterns: - `"%Y-%m-%d %H:%M:%S"`: ISO format with 24h time (2024-01-01 14:30:00) - `"%B %-d, %Y at %I:%M %p"`: Full month with 12h time (January 1, 2024 at 02:30 PM) - `"%d/%m/%Y %H:%M"`: European format with 24h time (01/01/2024 14:30) - `"%m/%d/%Y %I:%M %p"`: US format with 12h time (01/01/2024 02:30 PM) - `"%a, %b %-d at %I:%M %p"`: Short format (Mon, Jan 1 at 02:30 PM) Time format specifiers: - `%H`: 24-hour format (00-23) - `%I`: 12-hour format (01-12) - `%M`: Minutes (00-59) - `%S`: Seconds (00-59) - `%p`: AM/PM indicator > #### Format Specifier Compatibility {: .info} > > Time-related format specifiers (`%H`, `%M`, `%S`, `%I`, `%p`) should only be used with the > `date_time_picker/1` component. Using these specifiers with `date_picker/1` or `date_range_picker/1` > will raise formatting errors since these components do not handle time values. ## Week Start Configuration The date picker allows customizing which day of the week appears in the first column through the `week_start` attribute. This is particularly useful for adapting to different cultural preferences, as some regions start their weeks on Sunday while others prefer Monday: ```heex <.date_picker field={f[:date]} label="Date" week_start={1} # Week starts on Monday /> ``` The `week_start` attribute accepts a number from 0 to 6, where each number maps to a day: | Integer | Weekday | Notes | |---------|----------|--------| | 0 | Sunday | Default | | 1 | Monday | Common in Europe | | 2 | Tuesday | | | 3 | Wednesday| | | 4 | Thursday | | | 5 | Friday | Common in Islamic countries | | 6 | Saturday | Common in Nepal | When you change the week start day: - The calendar grid adjusts to show the specified day in the first column - All other days shift accordingly while maintaining their order - Week-based keyboard navigation (e.g., up/down arrows) adapts to the new week structure - The calendar maintains the new week start even when navigating between months ## Date Time Picker The `date_time_picker/1` function combines date selection with precise time input, supporting both 12-hour and 24-hour time formats. This is particularly useful for scheduling appointments, meetings, or any event that requires specific timing: ```heex <.date_time_picker field={f[:appointment]} label="Appointment Time" time_format="12" display_format="%B %-d, %Y at %I:%M %p" /> ``` The time input interface appears below the calendar and includes hours and minutes fields. When using 12-hour format (`time_format="12"`), an AM/PM selector is also displayed. The component handles time entry through both keyboard input and increment/decrement controls: ```heex <.date_time_picker field={f[:meeting_start]} label="Meeting Start" time_format="24" display_format="%d/%m/%Y %H:%M" /> <.form :let={f} for={@changeset} phx-change="validate"> <.date_time_picker field={f[:scheduled_at]} label="Schedule For" time_format="12" min={~D[2025-02-01]} max={~D[2025-03-31]} /> ``` When working with the date time picker, keep in mind: The field value must be a `NaiveDateTime` or `DateTime` struct. Using a `Date` struct will raise runtime errors since it cannot store time information. For example, in your schema: ```elixir schema "appointments" do field :scheduled_at, :naive_datetime # ... end ``` The component provides a natural interface for time selection: - Direct keyboard input for quick value entry - Up/down arrow keys to increment/decrement values - Automatic value constraints (hours: 0-23 or 1-12, minutes: 0-59) - Tab navigation between hour, minute, and AM/PM fields - AM/PM toggle with 'a' and 'p' keys in 12-hour mode - Enter key to confirm and close the date time picker > #### Timezone Handling {: .warning} > > The DatePicker component currently does not support timezone handling. All dates and times are treated as UTC. Timezone support is planned for future versions. ## Date Range Picker The `date_range_picker/1` function provides a specialized interface for selecting date ranges, making it ideal for booking systems, reporting tools, or any feature requiring start and end dates. The component offers both form-integrated and standalone usage: ```heex <.form :let={f} for={@changeset} phx-change="validate"> <.date_range_picker start_field={f[:start_date]} end_field={f[:end_date]} label="Booking Period" min={Date.utc_today()} max={Date.add(Date.utc_today(), 90)} /> ``` Unlike the single date picker, the range picker handles two distinct fields (start and end dates) individually. This means each date has its own field in your schema and form, providing more flexibility for validation and data handling. The component provides visual feedback during selection, highlighting the range as users make their choices. When a date is selected, it becomes either the start or end date based on its position relative to any existing selection. The calendar remains open until both dates are chosen, allowing users to adjust their selection with immediate visual feedback. The component supports several intuitive interaction patterns: - Click two different dates to select a range - Click the same date twice to create a single-day range - Click a date within an existing range to shrink the range - Click outside an existing range to expand it - Click a selected date to clear the selection and start over For standalone usage without form integration, use the name-based attributes: ```heex <.date_range_picker start_name="check_in" end_name="check_out" start_value={@check_in} end_value={@check_out} label="Stay Period" description="Select your check-in and check-out dates" /> ``` The component handles various selection patterns intuitively: ```heex <.date_range_picker start_field={f[:period_start]} end_field={f[:period_end]} label="Report Period" display_format="%B %-d, %Y" # January 1, 2024 min={Date.utc_today()} max={Date.add(Date.utc_today(), 365)} help_text="Select dates within the current year" /> ``` Form submissions include both start and end dates as separate fields, making it straightforward to handle in your LiveView: ```elixir def handle_event("validate", %{"booking" => params}, socket) do changeset = %Booking{} |> Booking.changeset(params) |> Map.put(:action, :validate) {:noreply, assign(socket, form: to_form(changeset))} end # In your schema schema "bookings" do field :start_date, :date field :end_date, :date timestamps() end def changeset(booking, attrs) do booking |> cast(attrs, [:start_date, :end_date]) |> validate_required([:start_date, :end_date]) |> validate_start_before_end() end defp validate_start_before_end(changeset) do case {get_field(changeset, :start_date), get_field(changeset, :end_date)} do {start_date, end_date} when not is_nil(start_date) and not is_nil(end_date) -> if Date.compare(end_date, start_date) == :lt do add_error(changeset, :end_date, "must be after start date") else changeset end _ -> changeset end end ``` The component automatically sorts the selected dates, ensuring that the earlier date becomes the start date regardless of selection order. This behavior, combined with the visual feedback and intuitive interaction patterns, creates a natural and error-resistant date range selection experience. ## Closing Strategies The date picker provides three distinct modes for handling when the calendar closes and when changes are confirmed. Each mode serves different use cases and can be controlled through the `close` attribute. ### Auto Mode (default) The default `"auto"` mode provides the most streamlined experience for single date selection. In this mode, the calendar closes immediately after a date is selected, and change events are emitted as soon as the selection is made. This is ideal for simple date picking scenarios where immediate feedback is desired: ```heex <.date_picker field={f[:date]} close="auto" /> ``` The component automatically falls back to manual mode when using features that require multiple interactions, such as time picker integration, range selection, or multiple date selection. ### Manual Mode The `"manual"` mode keeps the calendar open after selection, offering more flexibility for users who need to compare dates or make multiple adjustments. While the calendar stays open, change events are still emitted immediately as selections change: ```heex <.date_picker field={f[:date]} close="manual" /> ``` Users can explicitly close the calendar through standard interactions: pressing the Escape key, clicking outside the calendar, or clicking the toggle button. ### Confirm Mode The `"confirm"` mode adds an explicit confirmation step, making it ideal for scenarios where accuracy is crucial. This mode introduces Cancel and Confirm buttons at the bottom of the calendar and treats changes as "pending" until explicitly confirmed: ```heex <.date_picker field={f[:date]} close="confirm" /> ``` In confirm mode, the calendar stays open until explicitly confirmed or cancelled, and change events are only emitted after clicking the confirm button. If the user cancels or closes the calendar, the previous selection is restored, ensuring data integrity. > #### Mode Selection Tips {: .tip} > > Choose the mode that best fits your use case: > - Use `"auto"` for simple, single date selections where immediate feedback is appropriate > - Use `"manual"` when users need to compare or review dates before finalizing > - Use `"confirm"` when accuracy is crucial and changes need explicit confirmation > - The component will automatically adjust to `"manual"` mode when using time picker, range selection, or multiple selection features for better user experience ## Navigation Modes The date picker provides three navigation modes that determine how users can move between months and years. Each mode is configured through the `navigation` attribute. ### Default Mode The default mode offers a simple and clean interface focused on month-to-month navigation. It displays the current month and year as text, with arrow buttons on either side for moving to the previous or next month. ```heex <.date_picker field={f[:date]} navigation="default" /> ``` ### Extended Mode Extended mode enhances the default navigation by adding year navigation arrows alongside the month arrows. This creates a more efficient way to navigate through larger time spans while maintaining the familiar arrow-based interaction. ```heex <.date_picker field={f[:date]} navigation="extended" /> ``` ### Select Mode Select mode transforms the navigation interface by combining month arrows with dropdown menus for both month and year selection. The dropdowns provide direct access to any month or year within the allowed range. ```heex <.date_picker field={f[:date]} navigation="select" /> ``` > #### Navigation and Constraints {: .info} > > The date picker intelligently handles navigation when date constraints are set: > - Navigation buttons and dropdowns automatically disable when reaching min/max limits > - The calendar ensures the visible month always contains selectable dates > - Year dropdown options are limited to the years within the allowed range ## Form Integration The date picker component provides robust form integration through two approaches: using Phoenix form fields (recommended) or using standalone name attributes. Each approach supports single dates, multiple dates, and date ranges. ### Using with Phoenix Forms (Recommended) Use the `field` attribute to bind the date picker to a form field: ```heex <.form :let={f} for={@changeset} phx-change="validate" phx-submit="save"> <.date_picker field={f[:appointment_date]} label="Appointment Date" min={Date.utc_today()} max={Date.add(Date.utc_today(), 30)} /> ``` Using the `field` attribute provides: - Automatic value handling from form data - Error handling and validation messages - Form submission with correct field names - Integration with changesets - ID generation for accessibility - Proper type conversion between form data and Elixir date types - Nested form data handling Here's a complete example showing different date field types and validations: ```elixir defmodule MyApp.Booking do use Ecto.Schema import Ecto.Changeset schema "bookings" do # Single date field field :appointment_date, :date # Date with time field :meeting_datetime, :naive_datetime # Multiple dates field :blocked_dates, {:array, :date} # Date range field :start_date, :date field :end_date, :date timestamps() end def changeset(booking, attrs) do booking |> cast(attrs, [:appointment_date, :meeting_datetime, :blocked_dates, :start_date, :end_date]) |> validate_required([:appointment_date]) |> validate_future_date(:appointment_date) |> validate_date_range() end # Custom validation for future dates defp validate_future_date(changeset, field) do validate_change(changeset, field, fn _, date -> if Date.compare(date, Date.utc_today()) == :lt do [{field, "must be in the future"}] else [] end end) end # Validate that end_date comes after start_date defp validate_date_range(changeset) do case {get_field(changeset, :start_date), get_field(changeset, :end_date)} do {start_date, end_date} when not is_nil(start_date) and not is_nil(end_date) -> if Date.compare(end_date, start_date) == :lt do add_error(changeset, :end_date, "must be after start date") else changeset end _ -> changeset end end end # In your LiveView def mount(_params, _session, socket) do changeset = Booking.changeset(%Booking{}, %{}) {:ok, assign(socket, form: to_form(changeset))} end def render(assigns) do ~H""" <.form :let={f} for={@form} phx-change="validate"> <.date_picker field={f[:appointment_date]} label="Appointment Date" min={Date.utc_today()} /> <.date_time_picker field={f[:meeting_datetime]} label="Meeting Time" time_format="12" /> <.date_picker field={f[:blocked_dates]} label="Blocked Dates" multiple help_text="Select multiple dates that should be unavailable" /> <.date_range_picker start_field={f[:start_date]} end_field={f[:end_date]} label="Booking Period" /> """ end def handle_event("validate", %{"booking" => params}, socket) do changeset = %Booking{} |> Booking.changeset(params) |> Map.put(:action, :validate) {:noreply, assign(socket, form: to_form(changeset))} end ``` ### Using Standalone Date Pickers For simpler cases or when not using Phoenix forms, use the `name` attribute: ```heex <.date_picker name="filter_date" label="Filter By Date" value={@selected_date} /> <.date_picker name="holiday_dates[]" label="Holiday Dates" multiple value={@selected_dates} /> <.date_range_picker start_name="check_in" end_name="check_out" start_value={@check_in} end_value={@check_out} label="Stay Period" /> <.date_time_picker name="event_time" label="Event Time" time_format="24" value={@event_datetime} /> ``` When using standalone date pickers: - The `name` attribute determines the form field name - Values are managed through the `value` attribute (or `start_value`/`end_value` for ranges) - For multiple selection, append `[]` to the name attribute - Errors are passed via the `errors` attribute - Values are submitted in ISO 8601 format (YYYY-MM-DD or YYYY-MM-DD HH:mm:ss) - For date ranges, use `start_name` and `end_name` to specify field names > #### Type Handling {: .info} > > The date picker automatically handles conversion between string values and Elixir date types: > - `:date` fields expect and return `Date` structs > - `:naive_datetime` fields expect and return `NaiveDateTime` structs > - `:datetime` fields expect and return `DateTime` structs > - Multiple selection fields work with lists of these types > - When using standalone mode, values are always in ISO 8601 string format ## Keyboard Support The component provides comprehensive keyboard navigation: | Key | Element Focus | Description | |-----|---------------|-------------| | `Tab`/`Shift+Tab` | Toggle button | Moves focus to and from the date picker | | `Space`/`Enter` | Toggle button | Opens/closes the date picker | | `↑` | Calendar | Moves to the same day in the previous week | | `↓` | Calendar | Moves to the same day in the next week | | `←` | Calendar | Moves to the previous day | | `→` | Calendar | Moves to the next day | | `Home` | Calendar | Moves to the first day of the current week | | `End` | Calendar | Moves to the last day of the current week | | `PageUp` | Calendar | Moves to the same day in the previous month | | `PageDown` | Calendar | Moves to the same day in the next month | | `Enter`/`Space` | Calendar | Selects the focused date | | `Escape` | Any | Closes the date picker | | `Backspace` | Toggle button | Clears selection (when `clearable={true}`) | When time picker is enabled: | Key | Element Focus | Description | |-----|---------------|-------------| | `↑`/`↓` | Time input | Increments/decrements the value | | `0-9` | Time input | Sets the value directly | | `a`/`p` | AM/PM select | Switches between AM/PM | The component implements a focus trap when open, ensuring keyboard navigation stays within the calendar. ### function date_picker/1 **Signatures:** - `date_picker(assigns)` Renders a date picker for single or multiple date selection. The date picker provides calendar-based date selection with support for both single and multiple date picking. It includes form integration, validation, and comprehensive keyboard navigation. ## Attributes * `field` (`Phoenix.HTML.FormField`) - The form field to bind to. When provided, the component automatically handles value tracking, errors, and form submission. * `name` (`:any`) - The form name for the date picker. Required when not using the `field` attribute. For multiple selections, this will be automatically suffixed with `[]`. * `value` (`:any`) - The current selected value(s). For multiple selections, this should be a list. When using forms, this is automatically handled by the `field` attribute. * `id` (`:any`) - The unique identifier for the date picker component. When not provided, a random ID will be generated. Defaults to `nil`. * `min` (`Date`) - The earliest date that can be selected. Dates before this will be disabled. Defaults to `nil`. * `max` (`Date`) - The latest date that can be selected. Dates after this will be disabled. Defaults to `nil`. * `week_start` (`:integer`) - The day of the week that should appear in the first column. - `0`: Sunday (default) - `1`: Monday - `2`: Tuesday - `3`: Wednesday - `4`: Thursday - `5`: Friday - `6`: Saturday Defaults to `0`. * `size` (`:string`) - Controls the size of the date picker component: - `"sm"`: Small size, suitable for compact UIs - `"base"`: Default size, suitable for most use cases - `"lg"`: Large size, suitable for prominent selections - `"xl"`: Extra large size, suitable for hero sections Defaults to `"base"`. * `class` (`:any`) - Additional CSS classes to be applied to the date picker calendar container. These classes will be merged with the default styles. Defaults to `nil`. * `close` (`:string`) - Controls how the date picker closes after selection: - `"auto"`: Closes immediately after selection (default) - `"manual"`: Stays open after selection - `"confirm"`: Requires explicit confirmation via button Defaults to `"auto"`. * `navigation` (`:string`) - Controls the calendar navigation interface: - `"default"`: Month arrows only - `"extended"`: Month and year arrows - `"select"`: Month arrows + year/month dropdowns Defaults to `"default"`. * `inline` (`:boolean`) - When true, renders the calendar inline instead of in a dropdown. Defaults to `false`. * `disabled` (`:boolean`) - When true, disables the date picker component. Disabled date pickers cannot be interacted with and appear visually muted. Defaults to `false`. * `label` (`:string`) - The primary label for the date picker. This text is displayed above the date picker and is used for accessibility purposes. Defaults to `nil`. * `sublabel` (`:string`) - Additional context displayed to the side of the main label. Useful for providing extra information without cluttering the main label. Defaults to `nil`. * `description` (`:string`) - A longer description to provide more context about the date picker. This appears below the label but above the date picker element. Defaults to `nil`. * `help_text` (`:string`) - Help text to display below the date picker. This can provide additional context or instructions for using the date picker. Defaults to `nil`. * `placeholder` (`:string`) - Text to display when no date is selected. This text appears in the date picker toggle and helps guide users to make a selection. Defaults to `nil`. * `errors` (`:list`) - List of error messages to display below the date picker. These are automatically handled when using the `field` attribute with form validation. Defaults to `[]`. * `multiple` (`:boolean`) - When true, allows selecting multiple dates. This submits an array of dates. Defaults to `false`. * `display_format` (`:string`) - The format string used to display the selected date(s) in the toggle button. Uses strftime format. Common patterns: - `"%Y-%m-%d"`: ISO format (2024-01-01) - `"%b %-d, %Y"`: Short month (Jan 1, 2024) - `"%B %-d, %Y"`: Full month (January 1, 2024) - `"%d/%m/%Y"`: European format (01/01/2024) - `"%m/%d/%Y"`: US format (01/01/2024) Defaults to `"%b %-d, %Y"`. ### function date_range_picker/1 **Signatures:** - `date_range_picker(assigns)` Renders a date picker configured for selecting date ranges. The date range picker enables selection of start and end dates with visual feedback for the selected range. It supports both form-integrated and standalone usage with proper validation and error handling. ## Attributes * `start_field` (`Phoenix.HTML.FormField`) - The form field for the start date when using range selection with forms. Required when `range={true}` and using form integration. * `end_field` (`Phoenix.HTML.FormField`) - The form field for the end date when using range selection with forms. Required when `range={true}` and using form integration. * `start_name` (`:any`) - The form name for the start date when using range selection without forms. Required when `range={true}` and not using form integration. * `end_name` (`:any`) - The form name for the end date when using range selection without forms. Required when `range={true}` and not using form integration. * `start_value` (`:any`) - The current start date value when using range selection without forms. * `end_value` (`:any`) - The current end date value when using range selection without forms. * `id` (`:any`) - The unique identifier for the date picker component. When not provided, a random ID will be generated. Defaults to `nil`. * `min` (`Date`) - The earliest date that can be selected. Dates before this will be disabled. Defaults to `nil`. * `max` (`Date`) - The latest date that can be selected. Dates after this will be disabled. Defaults to `nil`. * `week_start` (`:integer`) - The day of the week that should appear in the first column. - `0`: Sunday (default) - `1`: Monday - `2`: Tuesday - `3`: Wednesday - `4`: Thursday - `5`: Friday - `6`: Saturday Defaults to `0`. * `size` (`:string`) - Controls the size of the date picker component: - `"sm"`: Small size, suitable for compact UIs - `"base"`: Default size, suitable for most use cases - `"lg"`: Large size, suitable for prominent selections - `"xl"`: Extra large size, suitable for hero sections Defaults to `"base"`. * `class` (`:any`) - Additional CSS classes to be applied to the date picker calendar container. These classes will be merged with the default styles. Defaults to `nil`. * `close` (`:string`) - Controls how the date picker closes after selection: - `"auto"`: Closes immediately after selection (default) - `"manual"`: Stays open after selection - `"confirm"`: Requires explicit confirmation via button Defaults to `"auto"`. * `navigation` (`:string`) - Controls the calendar navigation interface: - `"default"`: Month arrows only - `"extended"`: Month and year arrows - `"select"`: Month arrows + year/month dropdowns Defaults to `"default"`. * `inline` (`:boolean`) - When true, renders the calendar inline instead of in a dropdown. Defaults to `false`. * `disabled` (`:boolean`) - When true, disables the date picker component. Disabled date pickers cannot be interacted with and appear visually muted. Defaults to `false`. * `label` (`:string`) - The primary label for the date picker. This text is displayed above the date picker and is used for accessibility purposes. Defaults to `nil`. * `sublabel` (`:string`) - Additional context displayed to the side of the main label. Useful for providing extra information without cluttering the main label. Defaults to `nil`. * `description` (`:string`) - A longer description to provide more context about the date picker. This appears below the label but above the date picker element. Defaults to `nil`. * `help_text` (`:string`) - Help text to display below the date picker. This can provide additional context or instructions for using the date picker. Defaults to `nil`. * `placeholder` (`:string`) - Text to display when no date is selected. This text appears in the date picker toggle and helps guide users to make a selection. Defaults to `nil`. * `errors` (`:list`) - List of error messages to display below the date picker. These are automatically handled when using the `field` attribute with form validation. Defaults to `[]`. * `display_format` (`:string`) - The format string used to display the selected date(s) in the toggle button. Uses strftime format. Common patterns: - `"%Y-%m-%d"`: ISO format (2024-01-01) - `"%b %-d, %Y"`: Short month (Jan 1, 2024) - `"%B %-d, %Y"`: Full month (January 1, 2024) - `"%d/%m/%Y"`: European format (01/01/2024) - `"%m/%d/%Y"`: US format (01/01/2024) Defaults to `"%b %-d, %Y"`. ### function date_time_picker/1 **Signatures:** - `date_time_picker(assigns)` Renders a date picker with integrated time selection capabilities. The date time picker combines date selection with time input fields, supporting both 12-hour and 24-hour time formats. It maintains all core date picker features while adding precise time selection controls. ## Attributes * `field` (`Phoenix.HTML.FormField`) - The form field to bind to. When provided, the component automatically handles value tracking, errors, and form submission. * `name` (`:any`) - The form name for the date picker. Required when not using the `field` attribute. For multiple selections, this will be automatically suffixed with `[]`. * `value` (`:any`) - The current selected value(s). For multiple selections, this should be a list. When using forms, this is automatically handled by the `field` attribute. * `id` (`:any`) - The unique identifier for the date picker component. When not provided, a random ID will be generated. Defaults to `nil`. * `min` (`Date`) - The earliest date that can be selected. Dates before this will be disabled. Defaults to `nil`. * `max` (`Date`) - The latest date that can be selected. Dates after this will be disabled. Defaults to `nil`. * `week_start` (`:integer`) - The day of the week that should appear in the first column. - `0`: Sunday (default) - `1`: Monday - `2`: Tuesday - `3`: Wednesday - `4`: Thursday - `5`: Friday - `6`: Saturday Defaults to `0`. * `size` (`:string`) - Controls the size of the date picker component: - `"sm"`: Small size, suitable for compact UIs - `"base"`: Default size, suitable for most use cases - `"lg"`: Large size, suitable for prominent selections - `"xl"`: Extra large size, suitable for hero sections Defaults to `"base"`. * `class` (`:any`) - Additional CSS classes to be applied to the date picker calendar container. These classes will be merged with the default styles. Defaults to `nil`. * `close` (`:string`) - Controls how the date picker closes after selection: - `"auto"`: Closes immediately after selection (default) - `"manual"`: Stays open after selection - `"confirm"`: Requires explicit confirmation via button Defaults to `"auto"`. * `navigation` (`:string`) - Controls the calendar navigation interface: - `"default"`: Month arrows only - `"extended"`: Month and year arrows - `"select"`: Month arrows + year/month dropdowns Defaults to `"default"`. * `inline` (`:boolean`) - When true, renders the calendar inline instead of in a dropdown. Defaults to `false`. * `disabled` (`:boolean`) - When true, disables the date picker component. Disabled date pickers cannot be interacted with and appear visually muted. Defaults to `false`. * `label` (`:string`) - The primary label for the date picker. This text is displayed above the date picker and is used for accessibility purposes. Defaults to `nil`. * `sublabel` (`:string`) - Additional context displayed to the side of the main label. Useful for providing extra information without cluttering the main label. Defaults to `nil`. * `description` (`:string`) - A longer description to provide more context about the date picker. This appears below the label but above the date picker element. Defaults to `nil`. * `help_text` (`:string`) - Help text to display below the date picker. This can provide additional context or instructions for using the date picker. Defaults to `nil`. * `placeholder` (`:string`) - Text to display when no date is selected. This text appears in the date picker toggle and helps guide users to make a selection. Defaults to `nil`. * `errors` (`:list`) - List of error messages to display below the date picker. These are automatically handled when using the `field` attribute with form validation. Defaults to `[]`. * `time_format` (`:string`) - The time format to use: - `"12"`: 12-hour format with AM/PM selection - `"24"`: 24-hour format Defaults to `"12"`. * `display_format` (`:string`) - The format string used to display the selected date in the toggle button. Uses strftime format. Common patterns: - `"%Y-%m-%d %H:%M:%S"`: ISO format with 24h time (2024-01-01 14:30:00) - `"%B %-d, %Y at %I:%M %p"`: Full month with 12h time (January 1, 2024 at 02:30 PM) - `"%d/%m/%Y %H:%M"`: European format with 24h time (01/01/2024 14:30) - `"%m/%d/%Y %I:%M %p"`: US format with 12h time (01/01/2024 02:30 PM) - `"%a, %b %-d at %I:%M %p"`: Short format (Mon, Jan 1 at 02:30 PM) Defaults to `"%b %-d %I:%M %p"`. ## Fluxon.Components.Dropdown A comprehensive dropdown system for creating accessible, interactive menus and selection interfaces. This component provides a flexible solution for building dropdown menus across your application. It offers a fully accessible implementation with keyboard navigation, automatic positioning, and proper focus management. The component is designed to work seamlessly with LiveView while maintaining proper accessibility standards. ## Usage Create a simple dropdown menu with default styling: ```heex <.dropdown> <.dropdown_link navigate={~p"/profile"}>Profile <.dropdown_link navigate={~p"/settings"}>Settings <.dropdown_separator /> <.dropdown_link href={~p"/logout"} method="delete">Sign Out ``` ![Basic Dropdown](images/dropdown/basic-dropdown.png) ## Custom Toggle Replace the default button with a custom toggle element: ```heex <.dropdown> <:toggle> <.dropdown_button>Profile <.dropdown_button>Billing <.dropdown_button>Settings ``` ![Custom Toggle](images/dropdown/custom-toggle.png) ## Disabled Items The dropdown supports disabled menu items that are automatically skipped during keyboard navigation and cannot be selected or activated: ```heex <.dropdown> <.dropdown_button>Account <.dropdown_button disabled>Upgrade Plan <.dropdown_separator /> <.dropdown_link navigate={~p"/settings"}>Settings <.dropdown_link navigate={~p"/restricted"} data-disabled>Admin Panel ``` For button items, use the standard `disabled` attribute. For link items, use the `data-disabled` attribute since HTML links don't support the native `disabled` attribute. Disabled items are visually dimmed and are completely skipped during keyboard navigation. ## Rich Content Create complex dropdown interfaces with headers, separators, and custom content: ```heex <.dropdown class="w-64"> <.dropdown_custom class="flex items-center p-2"> Avatar
Emma Johnson emma@acme.com
<.dropdown_separator /> <.dropdown_header>Account <.dropdown_link navigate={~p"/profile"}>Profile <.dropdown_link navigate={~p"/billing"}>Billing <.dropdown_header>Support <.dropdown_link navigate={~p"/help"}>Documentation <.dropdown_link navigate={~p"/contact"}>Contact Us <.dropdown_separator /> <.dropdown_link href={~p"/logout"} method="delete" class="text-red-600"> Sign Out ``` ![Rich Content](images/dropdown/rich-content.png) ## Hover Interaction Enable hover-based opening with custom delays: ```heex <.dropdown open_on_hover hover_open_delay={200} hover_close_delay={300}> <.dropdown_link navigate={~p"/profile"}>Profile <.dropdown_link navigate={~p"/settings"}>Settings ``` ## Menu Positioning Control the dropdown's placement relative to its toggle: ```heex <.dropdown placement="bottom-end"> <.dropdown_link>Bottom End Aligned <.dropdown placement="right-start"> <.dropdown_link>Right Side Menu ``` ## Custom Animations Customize the dropdown's enter/leave animations: ```heex <.dropdown animation="transition-all duration-300" animation_enter="opacity-100 translate-y-0" animation_leave="opacity-0 -translate-y-2" > <.dropdown_link>Smooth Slide Animation ``` ## Keyboard Navigation The component provides comprehensive keyboard support following ARIA best practices: | Key | Element Focus | Description | |-----|--------------|-------------| | `Tab`/`Shift+Tab` | Toggle button | Moves focus to and from the dropdown toggle | | `Space`/`Enter` | Toggle button | Opens/closes the dropdown when focused | | `↑` | Toggle button | Opens dropdown and highlights last item | | `↓` | Toggle button | Opens dropdown and highlights first item | | `↑` | Menu item | Moves highlight to previous item | | `↓` | Menu item | Moves highlight to next item | | `Enter`/`Space` | Menu item | Activates the highlighted item | | `Escape` | Any | Closes the dropdown | ## Focus Management The dropdown implements sophisticated focus management to ensure a seamless user experience. Focus remains on the toggle button while users navigate through menu items using arrow keys. Menu items are not focusable through tab navigation, maintaining a streamlined keyboard interaction model. The component manages proper ARIA attributes to communicate the current selection to assistive technologies. ## Positioning System The dropdown menu intelligently positions itself relative to its toggle button. It automatically adjusts its placement based on available viewport space, ensuring optimal visibility regardless of the toggle button's position. The positioning system handles window resizing and scrolling, maintaining proper alignment in dynamic layouts. ### function dropdown/1 **Signatures:** - `dropdown(assigns)` Renders a fully accessible dropdown menu with rich interaction support. This component provides a flexible way to create dropdown menus with proper keyboard navigation, focus management, and positioning. It supports both click and hover interactions, custom toggle elements, and various animation options. ## Attributes * `id` (`:string`) - The unique identifier for the dropdown component. If not provided, one will be automatically generated. * `label` (`:string`) - The text label for the default dropdown toggle button. Only used when no custom toggle is provided via the `:toggle` slot. Defaults to `"Menu"`. * `class` (`:any`) - Additional CSS classes for the dropdown menu panel. Useful for controlling width, max-height, and other menu-specific styles. Defaults to `nil`. * `container_class` (`:string`) - Additional CSS classes for the dropdown's outer container. Affects the positioning wrapper element. Defaults to `nil`. * `toggle_class` (`:string`) - Additional CSS classes for the dropdown toggle button. Only applies to the default toggle button, not custom toggles. Defaults to `nil`. * `disabled` (`:boolean`) - When true, disables the dropdown toggle and prevents the menu from opening. Defaults to `false`. * `placement` (`:string`) - Controls the placement of the dropdown menu relative to its toggle button. Supports different positions with automatic repositioning when needed. The possible values are: `top`, `top-start`, `top-end`, `right`, `right-start`, `right-end`, `bottom`, `bottom-start`, `bottom-end`, `left`, `left-start`, `left-end` Defaults to `"bottom-start"`. * `animation` (`:string`) - Base animation classes applied to the dropdown menu. Controls the transition timing and easing function. Defaults to `"transition ease-in-out duration-150"`. * `animation_enter` (`:string`) - Classes applied when the dropdown menu enters. Usually defines the final state of the animation. Defaults to `"opacity-100 scale-100"`. * `animation_leave` (`:string`) - Classes applied when the dropdown menu leaves. Usually defines the initial state of the exit animation. Defaults to `"opacity-0 scale-95"`. * `open_on_hover` (`:boolean`) - When true, opens the dropdown menu on mouse hover instead of click. Can be combined with hover delays for better user experience. Defaults to `false`. * `hover_open_delay` (`:integer`) - Delay in milliseconds before opening the menu when hovering. Only applies when `open_on_hover` is true. Defaults to `0`. * `hover_close_delay` (`:integer`) - Delay in milliseconds before closing the menu when mouse leaves. Only applies when `open_on_hover` is true. Defaults to `0`. ## Slots * `inner_block` (required) - The content of the dropdown menu. Usually contains `dropdown_link`, `dropdown_button`, or other dropdown components. * `toggle` - Optional custom toggle element. When provided, replaces the default button toggle while maintaining proper accessibility attributes. Accepts attributes: * `class` (`:any`) - Additional CSS classes for the wrapper of the custom toggle element. ### function dropdown_button/1 **Signatures:** - `dropdown_button(assigns)` Renders a dropdown button item. A dropdown button is an interactive item within the dropdown menu that triggers an action rather than navigating to a new page. It renders as a ` ``` In this example, there are a few important things to notice: 1. The `Fluxon.open_dialog/1` function will be called to open the modal. This will happen in the client side so the modal will open instantly. 2. The `JS.push/2` function will be called to push a new event to the server to update the `@user_details` assign with the new details of the user. 3. When the `@user_details` assign is present (updated), it will be displayed in the modal. 4. When the modal is closed, the `reset-user-details` event will be pushed to the server to reset the `@user_details` assign to `nil` so we don't see old details when opening the modal again. It's worth mentioning that this is a simple example and it's not optimized for a good UX. In a real scenario, you would want to display a loading state, have a fixed size modal to avoid content shifting, maybe an animation when the content is loaded, etc. Here's some ideas: ```heex <.modal id="user-details-modal" class="w-[400px]" on_close={JS.push("reset-user-details")}>
<.loading />

ID: {@user_details.user_id}

Name: {@user_details.user_name}

``` ## Placement and Positioning The modal component provides flexible positioning options to accommodate different UI patterns. By default, modals are centered on the screen, but there are times when you might want different placements - like a side panel for filters, a bottom sheet for mobile interfaces, or a top banner for important announcements. ### Standard Placements The most common placement options position the modal relative to the viewport while maintaining some padding from the edges: ```heex <.modal id="centered-modal"> This modal is centered both horizontally and vertically <.modal id="top-modal" placement="top"> This appears at the top of the viewport <.modal id="right-modal" placement="right" class="h-full max-w-md"> This creates a side panel on the right ``` All standard placement options: - `center` (default): Centers the modal both horizontally and vertically - `top`: Aligns to the viewport top with horizontal centering - `bottom`: Aligns to the viewport bottom with horizontal centering - `left`: Aligns to the viewport left with vertical centering - `right`: Aligns to the viewport right with vertical centering ### Full-Size Placements When you need edge-to-edge modals that span the full width or height of the viewport, use the full-size placement options. These are particularly useful for responsive designs and mobile interfaces: ```heex <.modal id="side-drawer" placement="full-left" class="w-80"> <.modal id="bottom-sheet" placement="full-bottom" class="rounded-t-xl">
``` Full-size placement options: - `full-left`: Creates a full-height panel aligned to the left edge - `full-right`: Creates a full-height panel aligned to the right edge - `full-top`: Creates a full-width panel aligned to the top edge - `full-bottom`: Creates a full-width panel aligned to the bottom edge ## Size Control and Scrolling By default, the modal will center itself both horizontally and vertically, adapting its width to fit the content. When the content grows beyond the viewport height, the modal's wrapper will scroll, allowing the content to extend beyond the screen. However, this default behavior might not always provide the best user experience, especially when dealing with dynamic content or long lists. Here's how you can control the modal's dimensions and scrolling behavior: ```heex <.modal id="modal-with-sections" class="w-[600px]">

Users List

{user.name}
{user.email}
``` In this example, we create a modal with: - A fixed width using `w-[600px]` to maintain consistent sizing - A non-scrolling header that stays in view - A scrollable content area with `max-h-[400px]` and `overflow-y-auto` - A fixed footer for actions ## Modal Stacking The modal component supports stacking multiple modals on top of each other, which is essential for complex workflows like confirmation dialogs, multi-step forms, or nested detail views. The stacking system automatically manages focus, z-index, and backdrop behavior. Here's an example of a workflow that uses stacked modals: ```heex <.modal id="user-details">

User Details

Name: {@user.name}

Email: {@user.email}

<.button phx-click={Fluxon.close_dialog("user-details")}> Close <.button phx-click={Fluxon.open_dialog("confirm-delete")} color="red"> Delete User
<.modal id="confirm-delete">

Confirm Deletion

Are you sure you want to delete this user? This action cannot be undone.

<.button phx-click={Fluxon.close_dialog("confirm-delete")}> Cancel <.button phx-click={ Fluxon.close_dialog("confirm-delete") |> Fluxon.close_dialog("user-details") |> JS.push("delete_user", value: %{user_id: @user.id}) } color="red" > Confirm Delete
``` When working with stacked modals: 1. Each modal maintains its own focus trap, but only the topmost modal is interactive 2. Background modals are visually dimmed but remain visible for context 3. Closing a modal automatically restores focus to the previous modal 4. You can chain multiple modal actions (open/close) with the `|>` operator ## Forms Forms in modals work just like regular LiveView forms. The modal component doesn't interfere with form handling, making it straightforward to implement create/edit workflows: ```heex <.modal id="new-user-modal" class="w-[400px]"> <.form for={@form} phx-submit="save_user">

New User

Create a new user account.

<.input field={@form[:name]} label="Name" /> <.input field={@form[:email]} type="email" label="Email" />
<.button phx-click={Fluxon.close_dialog("new-user-modal")}> Cancel <.button type="submit" phx-disable-with="Creating..."> Create User
``` For a better user experience, we can automatically close the modal after successful form submission using `Fluxon.close_dialog/2` in the LiveView callback: ```elixir def handle_event("save_user", %{"user" => user_params}, socket) do case Accounts.create_user(user_params) do {:ok, _user} -> {:noreply, socket |> put_flash(:info, "User created successfully") |> Fluxon.close_dialog("new-user-modal")} {:error, changeset} -> {:noreply, assign(socket, form: to_form(changeset))} end end ``` ### function modal/1 **Signatures:** - `modal(assigns)` Renders a modal component. The modal component provides a flexible and customizable way to display content in an overlay that focuses the user's attention. It includes built-in accessibility features, keyboard navigation support, and customizable animations. ## Features - Fully accessible with proper ARIA attributes and keyboard navigation - Customizable placement and animations - Backdrop overlay with click-to-close functionality - Focus management and trapping - Flexible content area supporting any HTML or components - Customizable close behavior ## Attributes * `id` (`:string`) (required) - The unique identifier for the modal component. This ID is used to target the modal for opening, closing, and managing focus. Must be unique across all modals on the page. * `open` (`:boolean`) - Whether the modal is initially open. When true, the modal will be displayed immediately when mounted. Useful for showing modals based on server-side conditions. Defaults to `false`. * `on_close` (`Phoenix.LiveView.JS`) - JavaScript commands to execute when the modal is closed. Can be used to trigger additional actions or animations when the modal closes. Accepts a Phoenix.LiveView.JS command chain. Defaults to `%Phoenix.LiveView.JS{ops: []}`. * `on_open` (`Phoenix.LiveView.JS`) - JavaScript commands to execute when the modal is opened. Can be used to trigger additional actions or animations when the modal opens. Accepts a Phoenix.LiveView.JS command chain. Defaults to `%Phoenix.LiveView.JS{ops: []}`. * `class` (`:any`) - Additional CSS classes to be applied to the modal content container. These classes will be merged with the default styles. Useful for customizing the modal's appearance or dimensions. Defaults to `nil`. * `container_class` (`:any`) - Additional CSS classes for the modal's outer container. Affects the positioning wrapper element. Useful for adjusting the modal's overall layout or stacking context. Defaults to `nil`. * `close_on_esc` (`:boolean`) - Whether to close the modal when the Escape key is pressed. When true, provides a standard keyboard shortcut for dismissing the modal, improving accessibility. Defaults to `true`. * `close_on_outside_click` (`:boolean`) - Whether to close the modal when clicking outside of its content area. When true, allows users to dismiss the modal by clicking on the backdrop overlay. Defaults to `true`. * `prevent_closing` (`:boolean`) - When true, prevents the modal from being closed through standard interactions (Escape key, backdrop click, close button). Useful for critical dialogs that require explicit user action. Defaults to `false`. * `hide_close_button` (`:boolean`) - Whether to hide the close button in the top-right corner. When true, removes the standard close button, useful when providing custom close controls or when the modal should only be closed through specific actions. Defaults to `false`. * `animation` (`:string`) - Base animation classes applied to the modal. Controls the transition timing and easing function. Can be customized to match your application's animation style. Defaults to `"transition duration-200 ease-in-out"`. * `animation_enter` (`:string`) - Classes applied when the modal enters. Defines the final state of the animation when the modal becomes visible. Typically controls opacity and transform properties. * `animation_leave` (`:string`) - Classes applied when the modal leaves. Defines the state of the exit animation when the modal is being hidden. Typically controls opacity and transform properties. * `backdrop_class` (`:string`) - Additional CSS classes for the modal backdrop overlay. These classes will be merged with the default backdrop styles. Useful for customizing the overlay's appearance. Defaults to `nil`. * `placement` (`:string`) - Controls the placement of the modal relative to the viewport. Supports different positions with automatic repositioning when needed. Available options: - `center`: Centers the modal both horizontally and vertically - `top`: Aligns to the top of the viewport - `bottom`: Aligns to the bottom of the viewport - `left`: Aligns to the left of the viewport - `right`: Aligns to the right of the viewport - `full-left`: Full-height modal aligned to the left - `full-right`: Full-height modal aligned to the right - `full-top`: Full-width modal aligned to the top - `full-bottom`: Full-width modal aligned to the bottom Defaults to `"center"`. ## Slots * `inner_block` (required) - The content of the modal. Can contain any HTML or components to create complex modal interfaces. Common patterns include headers, content sections, and footer areas with action buttons. ## Fluxon.Components.Navlist A comprehensive navigation system for building structured, accessible navigation menus. This component provides a flexible solution for creating navigation interfaces across your application. It offers a hierarchical structure with support for sections, headings, and interactive links, making it suitable for sidebars, settings pages, and other navigation-heavy interfaces. The navigation system consists of three main components working together: - `navlist`: The main container that provides structure and spacing - `navheading`: Optional section headers for organizing navigation groups - `navlink`: Interactive navigation items with LiveView integration The navigation system follows a structured hierarchical organization: ``` navlist ├── navheading (optional) ├── navlink ├── navlink └── navlink ``` This structure ensures proper spacing, accessibility, and visual organization while maintaining flexibility for various navigation patterns, including nested and expandable navigation. ## Usage The navlist component provides a structured way to build navigation menus: ```heex <.navlist heading="Main Navigation"> <.navlink navigate={~p"/dashboard"} active> <.icon name="hero-home" class="size-5" /> Dashboard <.navlink navigate={~p"/projects"}> <.icon name="hero-folder" class="size-5" /> Projects <.navlink navigate={~p"/settings"}> <.icon name="hero-cog-6-tooth" class="size-5" /> Settings ``` ![Basic Navlist](images/navlist/basic-navlist.png) ## Multiple Sections Create structured navigation with multiple sections: ```heex <.navlist heading="Main"> <.navlink navigate={~p"/dashboard"} active> <.icon name="hero-home" class="size-5" /> Dashboard <.navlink navigate={~p"/projects"}> <.icon name="hero-folder" class="size-5" /> Projects <.navlist heading="Settings"> <.navlink navigate={~p"/profile"}> <.icon name="hero-user" class="size-5" /> Profile <.navlink navigate={~p"/preferences"}> <.icon name="hero-cog-6-tooth" class="size-5" /> Preferences ``` ![Multiple Sections](images/navlist/multiple-sections.png) ## Badges and Counters Enhance navigation items with badges and counters: ```heex <.navlist heading="Inbox"> <.navlink href="/inbox/unread"> Unread <.badge variant="pill" color="red" class="ml-auto">23 <.navlink href="/inbox/starred"> Starred <.badge variant="pill" class="ml-auto">5 ``` ![Navigation with Badges](images/navlist/navigation-with-badges.png) ## Expandable Navigation Create hierarchical navigation with expandable sections using LiveView's JS commands: ```heex <.navlist heading="Sales"> <.navlink phx-click={JS.toggle_attribute({"data-expanded", ""})}> <.icon name="hero-users" class="size-5" /> Customers <.icon name="hero-chevron-right" class="size-3 ml-auto text-zinc-500 in-data-expanded:rotate-90 transition-transform duration-200" />
<.navlist> <.navlink phx-click={JS.toggle_attribute({"data-expanded", ""})}> Orders <.icon name="hero-chevron-right" class="size-3 ml-auto text-zinc-500 in-data-expanded:rotate-90 transition-transform duration-200" />
<.navlist> <.navlink navigate="/invoices">Invoices <.navlink navigate="/orders">Orders
<.navlink navigate="/customer-groups">Customer Groups <.navlink phx-click={JS.toggle_attribute({"data-expanded", ""})}> Segments <.icon name="hero-chevron-right" class="size-3 ml-auto text-zinc-500 in-data-expanded:rotate-90 transition-transform duration-200" />
<.navlist> <.navlink navigate="/segments/active">Active <.navlink navigate="/segments/at-risk">At Risk
<.navlink navigate="/subscriptions"> <.icon name="hero-arrow-path" class="size-5" /> Subscriptions ``` ![Expandable Navigation](images/navlist/expandable-navigation.png) The expandable navigation pattern uses several key techniques: - `JS.toggle_attribute/1` for client-side toggling of expanded state - Grid-based height animation for smooth transitions - Nested navlists for hierarchical structure - Visual indicators with rotating chevron icons - Left border and padding for visual hierarchy ## Rich Navigation Examples Create visually rich navigation interfaces with custom styling: ```heex <.navlist> <.navheading class="text-xs uppercase font-medium text-zinc-400 dark:text-zinc-500"> Customers <.navlink :for={ {icon, label, badge, path, active} <- [ {"hero-users", "Customers", nil, ~p"/customers", false}, {"hero-shopping-bag", "Subscriptions", "23", ~p"/subscriptions", true}, {"hero-cube", "Products", nil, ~p"/products", false}, {"hero-tag", "Coupons", nil, ~p"/coupons", false} ] } navigate={path} active={active} class={[ "group py-2 relative", "hover:text-blue-600 hover:bg-white hover:shadow-sm", "dark:hover:bg-zinc-800", "hover:ring-1 ring-zinc-200", "dark:ring-zinc-800", "hover:after:absolute hover:after:inset-y-0 hover:after:left-0", "hover:after:my-1.5 hover:after:w-1 hover:after:bg-blue-600", "hover:after:rounded-r-md" ]} > <.icon class="size-5 text-zinc-500 dark:text-zinc-400 group-hover:text-blue-600" name={icon} /> {label} <.badge :if={badge} color="blue">{badge} ``` ![Customized Navigation](images/navlist/customized-navigation.png) ### function navheading/1 **Signatures:** - `navheading(assigns)` Renders a navigation section heading with proper styling and spacing. This component helps organize navigation sections by providing visual hierarchy through styled headings. It's typically used within a `navlist` component to label groups of navigation items. ## Attributes * `class` (`:any`) - Additional CSS classes for the heading element. Defaults to `nil`. ## Slots * `inner_block` (required) - The text content of the heading element. ## Basic Usage ```heex <.navheading>Main Navigation ``` ## Custom Styling ```heex <.navheading class="text-xs uppercase tracking-wider"> Account Settings ``` ### function navlink/1 **Signatures:** - `navlink(assigns)` Renders an interactive navigation link with support for active states and LiveView integration. This component provides a flexible way to create navigation items with consistent styling, proper spacing, and full LiveView integration. It supports icons, badges, and custom content while maintaining accessibility and interactive states. ## Attributes * `class` (`:any`) - Additional CSS classes for the link element. These are merged with the component's base styles for hover and active states. Defaults to `nil`. * `active` (`:boolean`) - When true, applies active styling to the link including background color and enhanced text contrast. Defaults to `false`. * Global attributes are accepted. Additional HTML attributes supported by LiveView links including navigation attributes (patch, navigate) and standard link attributes. Supports all globals plus: `["target", "download", "rel", "hreflang", "type", "referrerpolicy", "navigate", "patch", "href", "replace", "method", "csrf_token", "autofocus", "disabled", "form", "formaction", "formenctype", "formmethod", "formnovalidate", "formtarget", "name", "type", "value"]`. ## Slots * `inner_block` (required) ## Basic Usage ```heex <.navlink navigate={~p"/dashboard"} active>Dashboard ``` ## With Icons ```heex <.navlink navigate={~p"/inbox"}> <.icon name="hero-envelope" class="size-5" /> Inbox <.badge class="ml-auto">99+ <.navlink navigate={~p"/archive"}> <.icon name="hero-archive-box" class="size-5" /> Archive <.navlink navigate={~p"/trash"} class="text-red-600 dark:text-red-400"> <.icon name="hero-trash" class="size-5" /> Trash ``` ![Navlink with Icons](images/navlist/navlist-with-icons.png) ## LiveView Navigation The component supports all LiveView link attributes: ```heex <.navlink patch={~p"/messages"} replace={true}> Messages <.navlink navigate={~p"/settings"}> Settings ``` ## Active State Navigation items can be marked as active using the `active` attribute: ```heex <.navlink active={@current_path == "/dashboard"}> Dashboard ``` ### function navlist/1 **Signatures:** - `navlist(assigns)` Renders a navigation list container with optional heading and structured content. This component serves as the foundation for building navigation menus, providing proper spacing, structure, and accessibility features. It works in conjunction with `navheading` and `navlink` components to create comprehensive navigation interfaces. ## Attributes * `heading` (`:string`) - Optional heading text for the navigation section. When provided, renders a heading element above the navigation items. Defaults to `nil`. * `class` (`:any`) - Additional CSS classes for the nav container. Defaults to `nil`. * Global attributes are accepted. Additional attributes for the nav container. ## Slots * `inner_block` (required) - The content of the navigation section. Usually a list of navlinks. ## Fluxon.Components.Popover A powerful and accessible popover component that displays floating content anchored to a trigger element. This component provides a flexible solution for building tooltips, contextual menus, and interactive content that needs to be anchored to specific elements on the page. It offers a fully accessible implementation with keyboard navigation, automatic positioning, and proper focus management. ## Usage Create a simple informational tooltip: ```heex <.popover open_on_hover> <.icon name="hero-information-circle" class="text-zinc-400" /> <:content>

The invoice will be generated at the end of the month.

``` ![Basic Tooltip](images/popover/basic-tooltip.png) ## Interactive Content Build rich interactive menus with forms and actions: ```heex <.popover placement="bottom-end" class="w-64"> <.button variant="ghost"> <.icon name="hero-cog-6-tooth" /> Settings <:content>
Dark Mode <.switch name="dark_mode" checked />
Notifications <.switch name="notifications" />
<.button size="sm" class="w-full"> <.icon name="hero-arrow-path" class="icon" /> Reset Preferences
``` ![Interactive Menu](images/popover/interactive-menu.png) ## Search Suggestions Create dynamic search suggestions with focus interaction: ```heex <.popover open_on_focus placement="bottom-start" class="w-80"> <.input type="search" placeholder="Search users..." phx-debounce="300" /> <:content>
<.loading />
{user.name}
{user.email}
``` ![Search Suggestions](images/popover/search-suggestions.png) ## Form Field Help Provide contextual help for form fields: ```heex <.input name="api-key" label="API Key" value="sk_test_..." class="font-mono"> <:inner_suffix> <.popover open_on_hover placement="right"> <.icon name="hero-question-mark-circle" class="text-zinc-400" /> <:content>

About API Keys

Your API key is used to authenticate requests. Keep it secure and never share it publicly.

<.link class="text-sm text-blue-600 hover:underline" href="/docs/api-keys"> Learn more about API keys →
``` ![Form Help](images/popover/input-help.png) ## Filters Create filter panels: ```heex <.popover placement="bottom-end" class="w-64"> <.button variant="ghost"> <.icon name="hero-adjustments-horizontal" class="icon" /> Table settings <:content>

Table settings

<.icon name="hero-arrows-up-down" class="text-zinc-700 dark:text-zinc-300 size-4" /> Sort by
<.select native value="Name" options={["Name", "Date", "Size", "Type", "Modified"]} name="sort_by" size="sm" class="py-1 shadow-none" />
<.icon name="hero-view-columns" class="text-zinc-700 dark:text-zinc-300 size-4" /> View
<.select native value="List" options={["List", "Board", "Calendar", "Timeline"]} name="view" size="sm" class="py-1 shadow-none" />
<.separator class="my-4" />

Columns

<.label for="name" class="text-zinc-700 dark:text-zinc-300">Name <.switch name="name" checked id="name" />
<.label for="date" class="text-zinc-700 dark:text-zinc-300">Date <.switch name="date" checked id="date" />
<.label for="size" class="text-zinc-700 dark:text-zinc-300">Size <.switch name="size" checked id="size" />
<.label for="type" class="text-zinc-700 dark:text-zinc-300">Type <.switch name="type" id="type" />
<.label for="modified" class="text-zinc-700 dark:text-zinc-300">Modified <.switch name="modified" id="modified" />
``` ![Filters](images/popover/filters.png) ### function popover/1 **Signatures:** - `popover(assigns)` Renders a popover component with rich interaction support and automatic positioning. This component provides a flexible way to create tooltips, contextual menus, and other floating content that needs to be anchored to specific elements. It supports multiple interaction modes and intelligent positioning while maintaining accessibility. ## Attributes * `id` (`:string`) - Optional unique identifier for the popover. If not provided, a random ID will be generated. Useful when you need to programmatically control the popover. * `class` (`:any`) - Additional CSS classes to be applied to the popover content container. Useful for controlling width, padding, and other visual styles. Defaults to `nil`. * `open_on_hover` (`:boolean`) - When true, the popover will open when hovering over the trigger element. Perfect for tooltip-like behavior and quick information display. Defaults to `false`. * `open_on_focus` (`:boolean`) - When true, the popover will open when the trigger element receives focus. Ideal for form helpers, search suggestions, and accessibility improvements. Defaults to `false`. * `placement` (`:string`) - Controls the preferred placement of the popover relative to its trigger element. The actual placement may adjust automatically if there isn't enough space. Available options: - `top`, `top-start`, `top-end`: Above the trigger - `bottom`, `bottom-start`, `bottom-end`: Below the trigger - `left`, `left-start`, `left-end`: To the left of the trigger - `right`, `right-start`, `right-end`: To the right of the trigger The `-start` and `-end` variants control alignment along the cross axis. Defaults to `"top"`. ## Slots * `inner_block` (required) - The trigger element that will open the popover. This can be any HTML element or component, such as a button, input, or custom element. * `content` (required) - The content to display in the popover. Can contain any HTML or components, from simple text to complex interactive elements like forms or menus. ## Fluxon.Components.Radio A versatile radio component for building single-selection interfaces with rich styling options. This component provides a comprehensive solution for creating accessible radio button groups with support for both standard and card-based layouts. It seamlessly integrates with Phoenix forms and offers extensive customization options for building everything from simple option lists to visually rich selection interfaces. ## Usage The radio group component can be used in its simplest form for single selections: ```heex <.radio_group name="system" value="debian" label="Operating System"> <:radio value="ubuntu" label="Ubuntu" /> <:radio value="debian" label="Debian" /> <:radio value="fedora" label="Fedora" /> ``` ![Basic Radio Group](images/radio/basic-group.png) For more context, you can add sublabels and descriptions: ```heex <.radio_group name="system" label="Operating System" sublabel="Choose your preferred OS" description="Select the operating system that best suits your needs" > <:radio value="ubuntu" label="Ubuntu" sublabel="Popular and user-friendly" description="Ubuntu is a Debian-based Linux operating system" /> <:radio value="debian" label="Debian" sublabel="Stable and reliable" description="Debian is a Linux distribution composed of free and open-source software" /> <:radio value="fedora" label="Fedora" sublabel="Cutting-edge features" description="Fedora is a Linux distribution developed by the Fedora Project" /> ``` ![Radio Group with Sublabels and Descriptions](images/radio/basic-sublabel-description.png) ## Form Integration The radio group component offers two ways to handle form data: using the `field` attribute for Phoenix form integration or using the `name` attribute for standalone radio groups. Each approach has its own benefits and use cases. ### Using with Phoenix Forms (Recommended) When working with Phoenix forms, use the `field` attribute to bind the radio group to a form field: ```heex <.form :let={f} for={@form} phx-change="validate" phx-submit="save"> <.radio_group field={f[:subscription]} label="Subscription Plan" description="Choose your preferred subscription plan" > <:radio value="basic" label="Basic Plan" sublabel="$10/month" /> <:radio value="pro" label="Pro Plan" sublabel="$20/month" /> <:radio value="enterprise" label="Enterprise Plan" sublabel="$50/month" /> ``` Using the `field` attribute provides several advantages: - Automatic value handling from the form data - Built-in error handling and validation messages - Proper form submission with correct field names - Integration with changesets for data validation - Automatic ID generation for accessibility - Proper handling of nested form data The component will automatically: - Set the radio field's name based on the form structure - Display the current value from the form data - Show validation errors when present - Handle nested form data with proper input naming ### Using Standalone Radio Groups For simpler cases or when not using Phoenix forms, use the `name` attribute: ```heex <.radio_group name="theme" value={@current_theme} errors={@errors} label="Theme Selection" > <:radio value="light" label="Light Theme" /> <:radio value="dark" label="Dark Theme" /> <:radio value="system" label="System Theme" /> ``` When using standalone radio groups: - You must provide the `name` attribute - Values must be managed manually via the `value` attribute - Errors must be passed explicitly via the `errors` attribute - Form submission handling needs to be implemented manually - Nested data requires manual name formatting (e.g., `user[preferences][theme]`) > #### When to Use Each Approach {: .tip} > > Use the `field` attribute when: > - Working with changesets and data validation > - Handling complex form data structures > - Need automatic error handling > - Building CRUD interfaces > > Use the `name` attribute when: > - Building simple selection interfaces > - Creating standalone filters > - Handling one-off form controls > - Need more direct control over the radio group behavior ## Card Variant The component offers a card variant that transforms radio buttons into rich, interactive selection cards: ```heex <.radio_group name="system" label="Choose a plan" description="Choose the plan that best suits your needs." variant="card" control="left" class="gap-0" > <:radio value="basic" label="Basic" sublabel="Perfect for small projects" class="rounded-none -my-px rounded-t-lg" /> <:radio value="pro" label="Professional" checked sublabel="Most popular for growing teams" class="rounded-none -my-px" /> <:radio value="business" label="Business" sublabel="Advanced features for larger teams" class="rounded-none -my-px" /> <:radio value="enterprise" label="Enterprise" sublabel="Custom solutions for organizations" class="rounded-none -my-px" /> ``` ![Radio Card Variant](images/radio/card-plans.png) ## Rich Content The card variant supports custom content through the radio slot, enabling highly customized selection interfaces: ```heex <.radio_group name="system" label="Category" variant="card" class="grid grid-cols-3"> <:radio value="web-design" class="flex-1 group has-checked:border-blue-500 has-checked:bg-blue-50">
<.icon name="u-layout-alt-01-duotone" class="size-6 text-zinc-500 group-has-checked:text-blue-500" /> Web Design
<:radio value="ui-ux" class="flex-1 group has-checked:border-blue-500 has-checked:bg-blue-50">
<.icon name="u-pen-tool-01-duotone" class="size-6 text-zinc-500 group-has-checked:text-blue-500" /> UI/UX Design
<:radio value="development" class="flex-1 group has-checked:border-blue-500 has-checked:bg-blue-50">
<.icon name="u-laptop-02-duotone" class="size-6 text-zinc-500 group-has-checked:text-blue-500" /> Development
``` ![Radio Rich Content](images/radio/rich-content.png) ### function radio_group/1 **Signatures:** - `radio_group(assigns)` Renders a radio group for managing single-selection options. This component provides a flexible way to handle exclusive selections, with support for both standard radio lists and rich card-based interfaces. It includes built-in form integration, error handling, and accessibility features. ## Attributes * `id` (`:any`) - The unique identifier for the radio group. When not provided, a random ID will be generated. Defaults to `nil`. * `name` (`:string`) - The form name for the radio group. Required when not using the `field` attribute. * `value` (`:any`) - The current selected value of the radio group. When using forms, this is automatically handled by the `field` attribute. * `label` (`:string`) - The primary label for the radio group. This text is displayed above the radio buttons and is used for accessibility purposes. Defaults to `nil`. * `sublabel` (`:string`) - Additional context displayed on the side of the main label. Useful for providing extra information about the radio group without cluttering the main label. Defaults to `nil`. * `description` (`:string`) - Detailed description of the radio group. This text appears below the label and can contain longer explanatory text about the available options. Defaults to `nil`. * `errors` (`:list`) - List of error messages to display below the radio group. These are automatically handled when using the `field` attribute with form validation. Defaults to `[]`. * `class` (`:any`) - Additional CSS classes to apply to the radio group container. Useful for controlling layout, spacing, and visual styling of the group. Defaults to `nil`. * `field` (`Phoenix.HTML.FormField`) - The form field to bind to. When provided, the component automatically handles value tracking, errors, and form submission. * `disabled` (`:boolean`) - When true, disables all radio buttons in the group. Disabled radio buttons cannot be interacted with and appear visually muted. Defaults to `false`. * `variant` (`:string`) - The visual variant of the radio group. Currently supports: - `nil` (default): Standard stacked radio buttons - `"card"`: Rich selection cards with support for custom content Defaults to `nil`. * `control` (`:string`) - Controls the position of the radio input in card variants. It's only available when `variant="card"`. - `"left"`: Places the radio button on the left side of the card - `"right"`: Places the radio button on the right side of the card Must be one of `"left"`, or `"right"`. ## Slots * `radio` (required) - Defines the individual radio buttons within the group. Each radio button can have: - `value`: The value associated with this radio button - `label`: The radio button label - `sublabel`: Additional context on the side of the label - `description`: Detailed description of the option - `disabled`: Whether this specific radio button is disabled - `class`: Additional CSS classes for this radio button - `checked`: Whether this radio button should be checked by default Accepts attributes: * `value` (`:any`) (required) * `label` (`:string`) * `sublabel` (`:string`) * `description` (`:string`) * `disabled` (`:boolean`) * `class` (`:any`) * `checked` (`:boolean`) ## Fluxon.Components.Select A select component that implements a modern, accessible selection interface. This component can be used to build both simple and complex selection interfaces. It supports single and multiple selections, option searching, custom option rendering, and keyboard navigation. The component can be used either as a custom select or as a native select element. The component is built on top of the standard HTML ` > > ``` > > This results in consistent form submissions: > > ```elixir > # No options selected (hidden input provides the empty value) > %{"select" => [""]} > > # One or more options selected (hidden input value is included) > %{"select" => ["", "option1", "option2"]} > ``` > > When processing the form data: > 1. Filter out the empty string value > 2. Handle an empty list as "no selection" > > ```elixir > # Example processing > selected = Enum.reject(params["select"] || [], &(&1 == "")) > ``` By default, there is no limit on the number of selections. If no options are selected, the `[""]` array is sent. ### Maximum Selections Use the `max` attribute to limit the number of selections: ```heex <.select name="countries" multiple max={2} /> ``` ## Clearable By default, single selections cannot be unselected. The `clearable` attribute adds this ability and shows a clear button. Pressing backspace when the select is focused also clears the selection. For multiple selections, the clear button unselects all options. ```heex <.select name="country" clearable /> ``` When clearing a single selection, an empty option (`