All notable changes to PhiaUI are documented here.

0.1.17 — 2026-03-19

Added — 179 new components (650 → 829)

Rich Editor v2 Suite — 34 components

Content Blocks (14): toggle_list, toggle_list_item, tab_block, tab_block_item, video_block, audio_block, bookmark_card, math_block, social_embed, pdf_viewer, map_embed, file_attachment, divider_block, table_of_contents_block. Block Controls (4): block_add_button, block_conversion_menu, block_toolbar, block_drag_indicator. Advanced Blocks (5): synced_block, columns_block, code_sandbox, a4_page, page_header_footer. Text Direction (2): text_direction_toggle, bidi_text_block. Language Tools (4): grammar_panel, grammar_suggestion, spell_check_toggle, dictionary_panel. New Presets (5): notion_editor, google_docs_editor, medium_editor_v2, code_notes_editor, collaborative_editor. PhiaEditor v2 engine (~1,200 LOC JS). 10 new JS hooks: PhiaRichEditor, PhiaEditorV2, PhiaEditorBundle, PhiaCodeHighlight, PhiaImageResize, PhiaTableEditor, PhiaEquationRenderer, PhiaDiagramRenderer, PhiaDrawingCanvas, PhiaDragHandle, PhiaEmojiPickerBlock, PhiaFormatPainter, PhiaTrackChanges, PhiaRibbonToolbar.

Collab Suite — 35 components

Presence (4), Cursors (4), Comments (6), Threads (5), Composer (3), Notifications (6), Version History (6), Collab Editor (1). Infrastructure: CollabRoom, CollabPresence, RoomManager, Supervisor. 4 new JS hooks: PhiaCollab, PhiaCollabCursors, PhiaCollabPresence, PhiaCollabComments.

Advanced Chart Suite — 19 chart types

Candlestick, box_plot, violin, sunburst, sankey, pareto, lollipop, dumbbell, waffle, stream, ridgeline, icicle, circle_packing, chord, dot_plot, arc_diagram, pictogram, parliament, word_cloud. New helper modules: ChartForceLayout, ChartHierarchy, ChartSankey.

Activity & Presence — 6 components

Activity timeline, connection status, presence avatars, editor highlight picker, document outline, word count bar.

Formatting & Extensions — 91 components across internal waves

Rich editor shell (6), editor blocks (9), media blocks (8), formatting controls (16), formatting toolbar (1), extensions (10), academic (8), writing tools (6), search nav (4), track changes (5), export (4), AI assistant (4), document shell (4), editor content (6).

Changed

  • Editor component count: 19 → ~170 (12 new editor modules)
  • JS hooks count: 81 → 95+
  • Test count: 8045+ → 9510+

Infrastructure


0.1.7 — 2026-03-07

Added — 189 new components across 9 waves (154 → 343 total)

Menu Suite — 36 navigation components

ActionSheet, AppShell, ChipNav, Dock, DotNavigation, FloatingNav, MegaMenu, NavLink, SpeedDial, VerticalNav, WizardNav plus MobileSidebarToggle improvements. Full breakdown → docs/components/navigation.md.

Editor Suite — 19 components

Full rich-text editor toolkit: EditorToolbar, ToolbarButton, ToolbarGroup, ToolbarSeparator, BubbleMenu, FloatingMenu, SlashCommandMenu, InlineEdit, InlineEditGroup, EditorColorPicker, EditorToolbarDropdown, EditorLinkDialog, EditorCodeBlock, EditorCharacterCount, MarkdownEditor, RichTextViewer, EditorFindReplace, EditorWordCount, AdvancedEditor. 8 new JS hooks: PhiaBubbleMenu, PhiaFloatingMenu, PhiaSlashCommand, PhiaEditorColorPicker, PhiaEditorDropdown, PhiaMarkdownEditor, PhiaEditorFindReplace, PhiaAdvancedEditor.

DnD Suite — 14 interaction components

DragHandle, DropIndicator, SortableList, SortableItem, SortableGrid, SortableGridItem, KanbanBoard (DnD), KanbanColumn, KanbanCard, DropZone, DragTransferList, MultiDragList, DraggableTree, DraggableTreeNode. 6 new JS hooks: PhiaSortable, PhiaSortableGrid, PhiaKanban, PhiaDropZone, PhiaDragTransferList, PhiaMultiDrag, PhiaDraggableTree.

Chart Suite — 16 native SVG charts (zero JS)

BarChart, LineChart, AreaChart, PieChart, DonutChart, RadarChart, ScatterChart, BubbleChart, RadialBarChart, HistogramChart, WaterfallChart, HeatmapChart, BulletChart, SlopeChart, TreemapChart, TimelineChart. Shared helpers: chart_helpers.ex (normalize_series, pie_slices, donut_slices, histogram_bins, squarify, polyline_length, chart_color, stagger_delay) and chart_axis_helpers.ex (nice_ticks, format_tick). 6 chart @keyframes added to theme.css: phia-bar-grow, phia-bar-grow-x, phia-line-draw, phia-dot-pop, phia-fade-in, phia-gauge-fill.

Animation Suite — 22 components

Marquee, Orbit, Aurora, MeteorShower, DotPattern, GridPattern, RippleBg, ShimmerText, Typewriter, WordRotate, TextScramble, FadeIn, Float, Spotlight, TiltCard, NumberTicker, AnimatedBorder, PulseRing, TypingIndicator, WaveLoader, ConfettiBurst, ParticleBg. 10 new JS hooks: PhiaMarquee, PhiaTypewriter, PhiaWordRotate, PhiaTextScramble, PhiaScrollReveal, PhiaSpotlight, PhiaTiltCard, PhiaNumberTicker, PhiaConfetti, PhiaParticleBg. All hooks respect prefers-reduced-motion; canvas hooks resize+cleanup on destroyed().

Widget Wave — 12 analytics widgets

BadgeDelta, BarList, CategoryBar, MeterGroup, FunnelChart, NpsWidget, ComparisonTable, Leaderboard, Watermark, ImageComparison, ResultState, Popconfirm. stat_card enhanced: delta, delta_type, sparkline_data, href attrs. gauge_chart enhanced: zones, threshold attrs + center_label slot. 1 new JS hook: PhiaImageComparison.

Input & Upload Wave — 18 components

SearchInput, ClearableInput, TextareaCounter, CopyInput, UrlInput, PhoneInput, InputGroup, InlineSearch, UnitInput, AutocompleteInput, AvatarUpload, UploadButton, ImageGalleryUpload, DocumentUpload, UploadProgress, UploadCard, UploadQueue, FullscreenDrop. 1 new JS hook: PhiaFullscreenDrop.

Typography Suite — 18 components

Heading, DisplayText, Text, Paragraph, Lead, Blockquote, InlineCode, CodeBlock, Mark, TextLink, Overline, Caption, Abbr, ProseList, OrderedList, GradientText, TruncatedText, Prose.

Forms Suite — 34 components

FormLayout (FormSection, FormFieldset, FormGrid, FormRow, FormActions, FormSummary), FormSelects (CheckboxGroup, CheckboxGroupItem, FormCheckboxGroup, RadioCard, RadioCardGroup, FormRadioCardGroup, Cascader, FormCascader, ButtonTransferList), SpecialInputs (CurrencyInput, FormCurrencyInput, MaskedInput, FormMaskedInput, RangeSlider, FormRangeSlider, SignaturePad, ColorSwatchPicker, FormColorSwatchPicker, FloatInput, FormFloatInput, FloatTextarea, FormFloatTextarea, FormFeedback, InputStatus, FormStepper, FormStepperItem, CountrySelect, FormCountrySelect). 4 new JS hooks: PhiaMaskedInput, PhiaRangeSlider, PhiaSignaturePad, PhiaCascader.

Infrastructure

  • Added @keyframes + --animate-* CSS tokens for Animation Suite and DnD Suite to priv/templates/theme/theme.css
  • prefers-reduced-motion guard added to theme.css (.phia-chart-animate disables all chart animations)
  • Registry grew from 154 → 343 entries (all implemented)
  • Tests: 6183 total, 0 new failures

0.1.6 — 2026-03-06

Added — 15 new card components (Card Suite)

Full-spectrum card library covering content, marketing, dashboard, e-commerce, and utility patterns. Every component is zero-JS, pure Elixir/HEEx + TailwindCSS v4, composing existing PhiaUI primitives (Card, Badge, Avatar, Icon, Progress, Button, CopyButton). Registry grew from 139 to 154 entries — all implemented.

Content Cards (7 components)

  • ImageCard (image_card/1) — Hero cover-image card. Full-bleed <img> with 4 aspect ratio options (:videoaspect-video, :squareaspect-square, :wideaspect-[2/1], :tallaspect-[3/4]). Optional dark gradient overlay via CSS after: pseudo-element (after:bg-gradient-to-t after:from-black/60). Badge slot for overlaid labels (top-left, absolute z-10). Inner block renders as card_content. 12 tests.

  • ProfileCard (profile_card/1) — User profile card with two layout variants. :vertical (default): centered avatar + name + role + bio + tags + actions. :horizontal: flex-row with avatar left and content right. Avatar uses PhiaUi.Components.Avatar with size :lg. Presence status dot overlaid on avatar: :onlinebg-emerald-500, :offlinebg-gray-400, :busybg-red-500, :awaybg-amber-500. Slots: :bio, :tags, :actions. 16 tests.

  • FeatureCard (feature_card/1) — Landing-page feature block: icon + title + description. Three card style variants: :default (border + shadow), :bordered (border-2, no shadow), :ghost (no border, no shadow — renders plain <div>). Two icon positions: :top (flex-col, icon above title) and :left (flex-row, icon beside text block). Slots: :icon, :inner_block. 14 tests.

  • ArticleCard (article_card/1) — Blog/news article card. Optional cover image (aspect-video), category badge, meta row (date · read_time), title (with optional href link), excerpt (line-clamp-3), and author row (avatar + name). All fields are optional except :title. 19 tests.

  • TestimonialCard (testimonial_card/1) — Customer testimonial card. Star rating 1–5 (Unicode /), rendered only when :rating is set. Large decorative quotation mark (text-6xl text-muted-foreground/20). Italic quote body. Author row with optional avatar, name, role, and company. Three variants: :default (card + shadow), :bordered (card + border-2), :minimal (plain div, no card). 17 tests.

  • PricingCard (pricing_card/1) — SaaS pricing plan card. Attrs: plan, price, period (/month), description, features (list of strings; prefix marks unavailable items). Feature list rendered with check icons (text-emerald-500) for available and for unavailable items. highlighted=true applies ring-2 ring-primary bg-primary/5. Optional badge label (rendered above plan name). Full-width CTA button with cta_href. disabled state. Slots: :header_extra, :footer. 17 tests.

  • ProductCard (product_card/1) — E-commerce product card. Product image (aspect-square), optional badge overlay (top-left, configurable variant). Price with optional original_price (line-through). Star rating from float (0.0–5.0, rounded and rendered as / text). Review count. sold_out=true disables CTA and shows "Sold Out" badge. Default CTA "Add to cart" with on_add_to_cart event, overridable via :actions slot. Optional href link on image/title. 15 tests.

Dashboard & Operational Cards (5 components)

  • ProgressCard (progress_card/1) — Goal / task progress card. Uses existing <.progress> component internally. Four color variants: :default (primary bar), :success ([&>div]:bg-emerald-500), :warning ([&>div]:bg-amber-500), :destructive ([&>div]:bg-destructive). Three progress bar sizes: :sm (h-1), :md (h-2), :lg (h-3). show_value=false hides the percentage label. label attr overrides the default "N%" display. Slots: :icon (in header), :footer. 18 tests.

  • NotificationCard (notification_card/1) — Notification / alert card. Left accent border (border-l-4) colored by type: :info (blue), :success (emerald), :warning (amber), :error (red). Type icon from Lucide sprite beside content. read=true applies opacity-60. dismissible=true shows an × button in the top-right corner with phx-click={@on_dismiss}. Timestamp row in text-xs text-muted-foreground. Slots: :icon (override default type icon), :actions. 20 tests.

  • FileCard (file_card/1) — File attachment card. Extension-based icon color coding via file_type/1 pattern-matching: PDF → bg-red-100 text-red-600; DOC/DOCX → bg-blue-100 text-blue-600; XLS/XLSX → bg-emerald-100 text-emerald-600; PPT/PPTX → bg-orange-100 text-orange-600; images → bg-violet-100 text-violet-600; archives → bg-yellow-100 text-yellow-600; media → bg-pink-100 text-pink-600. Uppercase extension badge. Two variants: :default (stacked, larger icon) and :compact (single-row). href renders filename as <a download>. Slot: :actions. 22 tests.

  • EventCard (event_card/1) — Calendar event card with prominent date badge. Left-panel: colored by category_color (:primary, :blue, :emerald, :amber, :rose, :violet), shows 3-letter month abbrev + day number (3xl bold). Right panel: title, time row, location row (map-pin or video-camera icon based on virtual), stacked attendee avatars with +N overflow. max_attendees controls visible count. Slot: :actions. 20 tests.

  • TeamCard (team_card/1) — Team member directory card. Three layout variants: :default (centered avatar top, content below), :compact (smaller avatar, denser spacing), :horizontal (flex-row, avatar left, content right). Avatar from PhiaUi.Components.Avatar. Optional department badge, email link (mailto:). Slots: :badges, :actions. 15 tests.

Utility & Specialty Cards (3 components)

  • LinkPreviewCard (link_preview_card/1) — URL link-unfurl embed card (Slack/Twitter style). Domain extracted server-side via URI.parse/1. Three variants: :default (full card with optional og-image, favicon, site name, title, description, domain), :compact (single row: favicon + title + domain, no image), :minimal (plain title + domain, no border). External link icon (external-link) shown in :default and :compact. 16 tests.

  • ColorSwatchCard (color_swatch_card/1) — Color palette swatch card. Color block at top with style="background-color: #{hex}". Three sizes: :sm (h-16), :md (h-24), :lg (h-32). Color name (text-sm font-medium) below block. Hex value in monospace (text-xs text-muted-foreground). copyable=true renders <.copy_button> using existing PhiaCopyButton hook. Optional rgb and hsl secondary rows. Slot: :tags. 14 tests.

  • CtaCard (cta_card/1) — Call-to-action / empty-state / onboarding card. Four variants: :default (border + shadow), :bordered (border-2), :filled (bg-muted), :minimal (plain <div>, no card chrome). Two alignment modes: :center (text-center items-center) and :start (text-start items-start). Slots: :illustration (icon, SVG, or image above title), :actions (primary + secondary buttons), :footer (fine print). 16 tests.

Test Coverage

  • 344 new tests across 15 new components — 0 failures
  • 4604+ total tests0 new failures (2 pre-existing failures in unrelated tests)
  • Component registry: 154 entries (139 → 154, all implemented)
  • mix credo --strict — 0 issues

0.1.5 — 2026-03-05

Added — 44 new components (Calendar Suite + Advanced Widgets + Media)

Largest release to date. Multi-session image-analysis, gap analysis vs Full Calendar, Eleken design system, Ant Design, and Mantine. Registry grew from 75 to 119 entries — all implemented.

Calendar & Scheduling Suite — Wave 8: Standard Date/Time Pickers (6 components)

  • TimePicker (time_picker/1, form_time_picker/1) — Clock-face or scroll-wheel time selector. 12h/24h mode, configurable minute step (1/5/15/30), AM/PM toggle. role="group" with labelled hour/minute/period spinbuttons. FormField integration. 24 tests.

  • DateTimePicker (date_time_picker/1, form_date_time_picker/1) — Combined calendar + time picker rendered in a popover. Outputs ISO 8601 ("2026-03-05T14:30:00"). TimePicker embedded below calendar grid. FormField integration. 22 tests.

  • MonthPicker (month_picker/1, form_month_picker/1) — Grid of 12 abbreviated month names, year navigation arrows. aria-selected on selected month. FormField outputs "YYYY-MM". 18 tests.

  • YearPicker (year_picker/1, form_year_picker/1) — Scrollable year grid ±10 years from current, min/max bounds. aria-selected. FormField outputs "YYYY". 16 tests.

  • WeekPicker (week_picker/1, form_week_picker/1) — ISO 8601 week selector. Calendar grid highlights entire selected week on hover/selection. FormField outputs "YYYY-Www". 20 tests.

  • DateField (date_field/1, form_date_field/1) — Segmented DD / MM / YYYY input. Each segment is an independent <input type="number"> with inputmode="numeric". Arrow keys increment/decrement, Tab advances to next segment. aria-label="Day", aria-label="Month", aria-label="Year". FormField integration. 26 tests.

Calendar & Scheduling Suite — Wave 8 additional: WeekDayPicker

  • WeekDayPicker (week_day_picker/1) — Mon–Sun pill toggles for recurrence rule UIs. Multi-select with aria-pressed. Abbreviated labels (Mo, Tu, We…). Hidden name[] inputs for form submission. 14 tests.

Calendar & Scheduling Suite — Wave 9: Calendar Compositions (2 components)

  • CalendarTimePicker (calendar_time_picker/1) — Full-month calendar grid + inline time picker rendered as a single coherent widget. Outputs combined Date + Time via separate hidden inputs. calendar_time_picker_nav/1 sub-component handles month navigation. 20 tests.

  • DateRangePresets (date_range_presets/1) — DateRangePicker augmented with a preset sidebar: Today, Yesterday, This Week, Last 7 Days, Last 30 Days, This Month, Last Month, This Year, Custom. Preset buttons call on_change with start/end dates. Fully composable via :presets slot for custom entries. 22 tests.

Calendar & Scheduling Suite — Wave 10: Full-Page Calendar (1 component)

  • BigCalendar (big_calendar/1) — Full-page month view inspired by Google Calendar. View switcher (month / week / day) via :view attr + on_view_change event. MON-first grid. Events rendered as colored pills truncated at 3-per-day with +N more. big_calendar_event/1 sub-component. Today highlighted. phx-click on days and events. 28 tests.

Calendar & Scheduling Suite — Wave 11: Week Grid (1 component)

  • CalendarWeekView (calendar_week_view/1) — Week grid with 24-hour time axis on the left. Each event is absolutely positioned by top: #{start_px}px; height: #{duration_px}px computed from start time and duration. Overlapping events share column width. calendar_week_event/1 sub-component with color, title, time label. 25 tests.

Calendar & Scheduling Suite — Wave 12: Day Cards (2 components)

  • DateCard (date_card/1) — Individual day card with 4 visual states: default, today (ring), selected (filled background), disabled (muted, pointer-events-none). Attrs: date, state, on_click. 16 tests.

  • DateStrip (date_strip/1) — Horizontal scrollable row of DateCard components. Accepts dates list + selected date. Auto-scrolls to keep selected card visible (inline JS). aria-label="Date strip". 14 tests.

Calendar & Scheduling Suite — Wave 13: Compact Week Navigator (1 component)

  • WeekCalendar (week_calendar/1) — Compact week navigator widget. Header: current month/year title + prev/next arrows. 7-day strip below: each day shows abbreviated weekday label + date number. Selected day renders as a filled pill. on_day_click event. 18 tests.

Calendar & Scheduling Suite — Wave 14: Range Calendar (1 component)

  • RangeCalendar (range_calendar/1) — SUN-first single-month grid with rich range band visualization. Start/end dates render as filled blue circles with half-band; intermediate days render as full-band. Circular blue navigation buttons. on_range_change event with {start, end} map. 20 tests.

Calendar & Scheduling Suite — Wave 15: Scheduling Components (9 components)

  • TimeSlotGrid (time_slot_grid/1) — Grid of bookable time slots. Each slot is a button with 3 states: available, booked, selected. Configurable columns and slot duration. on_select event pushes %{slot: time_string}. 20 tests.

  • WheelPicker (wheel_picker/1) — iOS-style scroll-wheel picker. Configurable number of columns, each with a list of items and a selected index. Pure CSS overflow: hidden + scroll-snap-type: y mandatory scroll wheel. Inline JS to sync scroll position → pushEvent on snap. 22 tests.

  • MultiSelectCalendar (multi_select_calendar/1) — Calendar with multi-day toggle. Each day button toggles in/out of a selected set. Selected days rendered with bg-primary. Hidden name[] inputs submit all selected dates. on_change event pushes updated selected list. 18 tests.

  • BadgeCalendar (badge_calendar/1) — Monthly calendar with numeric badge overlays. Accepts data map %{~D[2026-03-05] => integer}. Badge renders as absolute top-1 right-1 text-xs. aria-label="N events on date". 16 tests.

  • DailyAgenda (daily_agenda/1) — Single-day 24-hour timeline. Hour rows divided into 15-min gridlines. Events rendered as absolutely-positioned cards with CSS top + height computed from time values. Overlap detection: side-by-side columns. 24 tests.

  • ScheduleEventCard (schedule_event_card/1) — Rich event detail card. Slots: title, time range, location, attendees (avatar stack), status badge, action buttons. Color accent bar on left border matches event category color. 18 tests.

  • CountdownTimer (countdown_timer/1) — Live countdown to a target DateTime. Displays DD : HH : MM : SS flip tiles. Counts down to zero (shows "00:00:00:00"). Configurable label and expired state. Pure server-rendered — no JS hook; update via push_event or LiveView timer. 16 tests.

  • TimeSlotList (time_slot_list/1) — Vertical list of time slots with availability indicator. Each slot shows time, duration, availability label, and a "Book" button. Available/booked/pending states with colored dot. on_book event. 16 tests.

  • TimeSliderPicker (time_slider_picker/1) — Dual-handle slider for selecting a start + end time within a day. Renders two <input type="range"> with CSS overlap. Outputs start/end as "HH:MM" strings. on_change event. 20 tests.

Calendar & Scheduling Suite — Wave 16: Booking & Schedule Views (4 components)

  • BookingCalendar (booking_calendar/1) — Full appointment booking flow. Month calendar shows available/booked/closed days. Clicking an available day reveals time slot list. Confirm button triggers on_book event with %{date: date, slot: time}. 26 tests.

  • StreakCalendar (streak_calendar/1) — Habit tracker / contribution heatmap. Accepts entries list of %{date, completed}. Shows current streak, longest streak, completion percentage. Intensity coloring per week. Legend below grid. 22 tests.

  • ScheduleView (schedule_view/1) — Agenda-style event list grouped by date. Events sorted chronologically. Date group headers highlight today. schedule_view_event/1 sub-component: time, title, location, attendee avatars, color dot. 20 tests.

  • MultiMonthCalendar (multi_month_calendar/1) — Side-by-side display of 2–4 months (:count attr). Navigation arrows advance all months together. Range selection spans across months. Used for extended booking windows. 24 tests.

Advanced Dashboard Widgets — Wave 6 (4 components)

  • CircularProgress (circular_progress/1) — Radial SVG progress ring. Attrs: value (0–100), size (px), stroke_width, color (semantic token). role="progressbar" + aria-valuenow + aria-valuemax. Inner label slot for value/text. 22 tests.

  • EventCalendar (event_calendar/1) — Monthly calendar grid with event pills per day. Accepts events list %{date, title, color, id}. Max 3 pills per day + +N more overflow. Day click triggers on_day_click with date + event list. 24 tests.

  • UptimeBar (uptime_bar/1) — Segmented uptime visualization. Accepts segments list %{status: :up | :down | :degraded, label}. Green/red/yellow colored segments. Uptime percentage badge. Tooltip per segment on hover. rounding/2 helper applies rounded-full for single-segment edge case. 20 tests.

  • ReceiptCard (receipt_card/1) — Transaction/purchase receipt layout. Line items table with description + amount. Subtotal, tax, total rows. Merchant header with logo slot. QR code slot at bottom. Print-friendly CSS. 20 tests.

Advanced Dashboard Widgets — Wave 7 (4 components)

  • SparklineCard (sparkline_card/1) — Inline SVG sparkline polyline + metric value card. Accepts data list of numbers. Normalizes to SVG viewBox. Trend badge (▲/▼ + %). Color inherited from text-* class. 20 tests.

  • GaugeChart (gauge_chart/1) — SVG semicircle gauge. Needle rotates from -90° (min) to +90° (max) based on value. Color zones (green/yellow/red arcs). Min/max labels at edges. Center displays value + unit. 22 tests.

  • GanttChart (gantt_chart/1) — Horizontal timeline/project planning. Accepts tasks list %{label, start_date, end_date, color, progress}. Date axis auto-scales to task range. Today indicator vertical line. Progress bar within each task bar. 26 tests.

  • Snackbar (snackbar/1) — Temporary notification banner appearing at the bottom center of the screen. Variants: default, success, error, warning. open boolean attr toggles visibility with CSS transition. Auto-dismiss via phx-click or timer. Action slot for link/button. 18 tests.

Display & Interaction Additions — Wave 5 (3 components)

  • AvatarGroup (avatar_group/1) — Standalone stacked avatars registry entry. Negative-margin overlap. +N overflow badge when max exceeded. 3 sizes (:sm, :default, :lg). Accepts avatars list %{src, name, fallback}. 16 tests.

  • SelectableCard (selectable_card/1) — Card with selection state. Renders a hidden <input type="checkbox"> or <input type="radio"> underneath. Selected state: ring-2 ring-primary. Checkmark icon appears in top-right corner when selected. on_select event. 18 tests.

  • InputAddon (input_addon/1) — Prefix and suffix addon wrapper for phia_input/1. Merges borders and removes duplicate rounded corners at the join. Addon can be text, icon, or button. Zero JS. 16 tests.

Tabs Enhancement — Wave 5 (update, not new entry)

  • Tabs variants — Added :variant attr to tabs/1: :underline (default, bottom border), :solid (filled background), :pill (rounded). No registry count change.

Media, Communication & Navigation (5 components)

  • AudioPlayer (audio_player/1) + PhiaAudioPlayer hook — HTML5 <audio> element controlled by a custom UI. Play/pause toggle, scrubber (time slider), current/total time display, volume slider, mute button. Hook uses native audio events (timeupdate, loadedmetadata, ended). destroyed() removes all listeners. 22 tests.

  • Sonner (sonner/1) + PhiaSonner hook — Rich toast notification system (Sonner-inspired). Icon variants (success ✓, error ✗, warning ⚠, info ℹ, loading spinner). Action button slot. Promise toast mode (pending → success/error). Stacking with configurable position (6 positions). push_event(socket, "phia-sonner", %{...}) API. 24 tests.

  • QrCode (qr_code/1) — SVG QR code generator using eqrcode ~> 0.2. EQRCode.svg/2 wrapped in a <div>. Attrs: value (string), size (integer, default 200), error_correction_level (:l, :m, :q, :h). title attr for <title> inside SVG for accessibility. 16 tests.

  • BottomNavigation (bottom_navigation/1, bottom_navigation_item/1) — Mobile bottom tab bar. Fixed at bottom, full width, 3–5 items. Each item: icon + label + optional badge. aria-current="page" on active item. phx-click on each item. 16 tests.

  • Toolbar (toolbar/1, toolbar_button/1, toolbar_separator/1) — Horizontal role="toolbar" bar. toolbar_button/1: icon button with tooltip, aria-label, disabled state, active/pressed state. toolbar_separator/1: role="separator", aria-orientation="vertical". Arrow key navigation via aria-keyshortcuts. 18 tests.

New JS Hooks

  • priv/templates/js/hooks/audio_player.jsPhiaAudioPlayer
  • priv/templates/js/hooks/sonner.jsPhiaSonner

Test Coverage

  • 1098 new tests across 44 new components — 0 failures
  • 4043 total tests0 failures
  • Component registry: 119 entries (75 → 119, all implemented — zero planned-only entries)
  • mix credo --strict — 0 issues

0.1.4 — 2026-03-04

Added — 15 gap-analysis components (vs shadcn/ui, Mantine, Ant Design, Chakra UI, MUI)

Gap analysis identified 15 high-demand components present in major UI libraries but missing from PhiaUI. All components follow TDD (tests first), use semantic Tailwind v4 tokens, WAI-ARIA, and zero npm dependencies.

Wave 1 — High Priority: Input Primitives

  • InputOTP (input_otp/1, input_otp_group/1, input_otp_slot/1, input_otp_separator/1) — Multi-slot OTP/PIN field. Each slot is <input type="text" maxlength="1" inputmode="numeric">. Auto-advances focus on input; Backspace returns to previous slot. autocomplete="one-time-code" on slot 0. aria-label="Digit N". Inline JS (no hook) for focus traversal. Supports separator between slot groups. 25 tests.

  • Spinner (spinner/1) — Animated SVG loading indicator. 5 sizes (:xs h-3, :sm h-4, :default h-6, :lg h-8, :xl h-12). Uses animate-spin and currentColor — inherits text color. role="status" + aria-label + aria-live="polite" + <span class="sr-only">. 15 tests.

  • NumberInput (number_input/1, form_number_input/1) — Stepper input with [−] [value] [+] layout. Native <input type="number"> with min, max, step. Optional prefix and suffix slots. aria-valuemin/max/now. FormField integration for Ecto changesets. 28 tests.

  • PasswordInput (password_input/1, form_password_input/1) — Password field with toggle button. Uses Phoenix.LiveView.JS.toggle_attribute({"type", "password", "text"}) — zero JS hook needed. autocomplete="current-password" by default. Eye SVG icon inline. aria-label="Show password". Disables toggle button when disabled. FormField integration. 20 tests.

  • CopyButton (copy_button/1) + PhiaCopyButton hook — Copy-to-clipboard button. navigator.clipboard.writeText with execCommand fallback. Copy icon → check icon feedback for timeout ms. aria-live="polite" on hidden span for screen reader announcement. 18 tests.

Wave 2 — Medium Priority: Selection & Interaction

  • SegmentedControl (segmented_control/1) — Horizontal selector using hidden radio inputs + styled labels. Active state applied server-side (bg-background shadow-sm). 3 sizes (:sm, :default, :lg). phx-click on labels for on_change event. role="group" on container. 29 tests.

  • Chip (chip/1, chip_group/1) — Interactive pill component. When on_click present, renders as <button> with aria-pressed={to_string(@selected)}. When dismissible, shows × button with aria-label="Remove". 3 variants (:default, :outline, :filled), 3 sizes. chip_group/1 wraps in flex-wrap container. 20 tests.

  • Editable (editable/1) + PhiaEditable hook — Inline edit field with preview/edit state. Renders preview div (role=button, tabindex=0) and hidden input wrapper. Hook: click/Enter/Space → startEdit (focus+select), Enter → submit (pushEvent), Escape/click-outside → cancel. 25 tests.

  • FileUpload (file_upload/1, file_upload_entry/1) — Generic file drop zone. Accepts Phoenix.LiveView.UploadConfig or plain map. phx-drop-target={upload.ref} for drag-and-drop. :empty slot for drop zone content. :file slot with :let={entry} for file list. file_upload_entry/1: filename, progress bar (width: #{progress}%), error messages, cancel button with phx-value-ref. 22 tests.

  • Menubar (menubar/1, menubar_menu/1, menubar_trigger/1, menubar_content/1, menubar_item/1, menubar_separator/1) — Desktop app-style horizontal menu bar. role="menubar" on container, role="menubutton" + aria-haspopup="menu" on triggers, role="menu" on content panels (hidden by default, JS toggles). menubar_item/1 supports shortcut attr for keyboard shortcut display, disabled state. 31 tests.

Wave 3 — Lower Priority: Utility & Navigation

  • ColorPicker (color_picker/1) + PhiaColorPicker hook — Color selector built on native <input type="color">. Swatch buttons update the input; hook syncs value display span and pushes on_change event. data-color-input, data-color-value, data-swatch-value data attributes for hook targeting. 20 tests.

  • FloatButton (float_button/1) — Fixed circular action button (FAB). Position variants: :bottom_right, :bottom_left, :top_right, :top_left. Two function heads: simple button (with on_click) or speed-dial (with :main + :item slots showing expandable action items). h-14 w-14 rounded-full bg-primary. 18 tests.

  • MultiSelect (multi_select/1, form_multi_select/1) — Multiple-value select with <select multiple>. Selected values shown as chip row above the select. Chips have phx-value-deselect for individual removal. name="field[]" for multi-value form submission. aria-label on select for accessibility. FormField integration. 25 tests.

  • Tree (tree/1, tree_item/1) — Hierarchical tree view using native <details>/<summary> (zero JavaScript). role="tree" on root <ul>. Expandable items: <details open={@expanded}> + <summary> with chevron SVG + <ul role="group" class="ml-4"> for nesting. Leaf items: phx-click + phx-value-value. aria-expanded on each <li>. 25 tests.

  • BackTop (back_top/1) + PhiaBackTop hook — Scroll-to-top button. Fixed positioned, starts opacity-0. Hook listens to scroll event (passive), toggles opacity-100 beyond threshold. Click: window.scrollTo({top:0, behavior: "smooth"}). Cleanup in destroyed(). 15 tests.

New JS Hooks

  • priv/templates/js/hooks/copy_button.jsPhiaCopyButton
  • priv/templates/js/hooks/editable.jsPhiaEditable
  • priv/templates/js/hooks/color_picker.jsPhiaColorPicker
  • priv/templates/js/hooks/back_top.jsPhiaBackTop

Test Coverage

  • 336 new tests for 15 new components — 0 failures
  • 2945 total tests0 failures
  • Component registry: 75 entries (62 → 75, replacing 2 planned entries with implemented)

0.1.3 — 2026-03-03

Added — 25 new components across 3 sessions (image-analysis driven gap analysis)

Enterprise Components — 10 components

  • ActivityFeed (activity_feed/1, activity_group/1, activity_item/1) — Chronological event log with 6 activity types (mention, file, call, task, reaction, system), optional :avatar slot, data-activity-type attribute, role="log" container, :footer slot. 41 tests.

  • HeatmapCalendar (heatmap_calendar/1) — GitHub-style contribution heatmap. Accepts raw data map %{{col, row} => integer}, max_value, configurable rows/cols, axis labels, and optional legend. Intensity classes heatmap-0 through heatmap-4. role="grid" + role="gridcell" + aria-label per cell. 21 tests.

  • KanbanBoard (kanban_board/1, kanban_column/1, kanban_card/1) — Multi-column project board. Cards support priority (critical, high, medium, low) with color-coded left border. Slots: :avatar, :tags, :footer. data-priority attribute on each card. 38 tests.

  • ChatMessage (chat_container/1, chat_message/1, chat_bubble/1, chat_suggestions/1, chat_input/1) — Full AI/human chat UI. role="log" + aria-live="polite" on container. Roles: user (right, bg-primary), assistant (left, bg-muted), system (centered). Avatar slot, thumbs up/down feedback buttons (phx-value-message-id), timestamp, suggestion chips, compose form with :attachments slot and max_chars counter. 49 tests.

  • MentionInput (mention_input/1, mention_dropdown/1, mention_chip/1) — @mention textarea with PhiaMentionInput JS hook. role="combobox" + aria-expanded on textarea. Dropdown uses role="listbox" / role="option". Hidden _ids CSV input for form submission. Server-side suggestions driven by pushEvent. mention_chip/1 for static server-rendered previews. 35 tests + JS hook.

  • FilterBar (filter_bar/1, filter_search/1, filter_select/1, filter_toggle/1, filter_reset/1) — Horizontal filter toolbar for tables. Search input with magnifier icon (phx-change), labelled native select (phx-change), checkbox toggle (phx-change), reset button (phx-click). CSS-only, no JS hook. 38 tests.

  • FilterBuilder (filter_builder/1, filter_rule/1) — Dynamic query builder. Each rule row: field selector + operator selector + value input + remove button. Operators and value input type adapt automatically to field type (text, select, date, number). Entirely server-driven — no JS hook. 26 tests.

  • BulkActionBar (bulk_action_bar/1, bulk_action/1) — Contextual action toolbar for table row selection. Hidden when count == 0 (two function heads). Shows "N label" + clear button + action slot. role="toolbar" + aria-label. bulk_action/1 has default and destructive variants, optional icon. 25 tests.

  • StepTracker (step_tracker/1, step/1) — Multi-step wizard progress indicator. Status variants: complete (bg-primary + check icon), active (bg-primary + ring + aria-current="step"), upcoming (outlined border, muted text). Horizontal and vertical orientations. Optional step number, description. CSS-only. 26 tests.

  • NavigationMenu (navigation_menu/1, navigation_menu_list/1, navigation_menu_item/1, navigation_menu_link/1, navigation_menu_trigger/1, navigation_menu_content/1) — Horizontal nav bar. Links use aria-current="page" when active. Trigger button has aria-haspopup="true" + chevron icon. Content is an absolute-positioned dropdown panel. CSS-only layout. 32 tests.

Form Primitives — 8 components

  • Progress (progress/1) — role="progressbar", aria-valuenow, aria-valuemin, aria-valuemax. Indeterminate mode (no value). CSS-only. 22 tests.
  • Separator (separator/1) — Horizontal / vertical <hr> divider. role="separator", aria-orientation. decorative attr removes from accessibility tree. 16 tests.
  • Toggle (toggle/1) — aria-pressed toggle button. Variants: default, outline. Sizes: default, sm, lg. 19 tests.
  • Switch (switch/1, form_switch/1) — CSS-animated toggle switch. role="switch". form_switch/1 integrates with Phoenix.HTML.FormField. 22 tests.
  • ToggleGroup (toggle_group/1, toggle_group_item/1) — Single/multiple selection group. :let context passes {group} to items for spread. 17 tests.
  • RadioGroup (radio_group/1, radio_group_item/1, form_radio_group/1) — Native radio inputs with label. :let context. FormField integration. 23 tests.
  • Tabs (tabs/1, tabs_list/1, tabs_trigger/1, tabs_content/1) — Server-rendered tabbed interface. :let context passes active to triggers and content panels. aria-selected on active trigger. 24 tests.
  • Sheet (sheet/1, sheet_trigger/1, sheet_content/1, sheet_header/1, sheet_footer/1, sheet_close/1) — Modal panel with 4 directions (top, bottom, left, right) and 5 sizes. Reuses PhiaDialog hook. 56 tests.
  • HoverCard (hover_card/1, hover_card_trigger/1, hover_card_content/1) — role="tooltip" preview card on hover/focus. CSS-only positioning. 22 tests.
  • ScrollArea (scroll_area/1) — Custom scrollbar overlay. Three orientations: vertical, horizontal, both. CSS-only. 18 tests.

Visual Primitives — 5 components

  • Slider (slider/1, form_slider/1) — CSS-styled <input type="range"> using accent-primary. WAI-ARIA role="slider". FormField integration. 45 tests.
  • Resizable (resizable/1, resizable_panel/1, resizable_handle/1) — Drag-to-resize panel pairs. PhiaResizable JS hook (drag, touch, keyboard ← →). Horizontal/vertical split. 35 tests.
  • Timeline (timeline/1, timeline_item/1) — Vertical activity timeline with CSS connector line. Status variants: complete, active, upcoming. Icon slot. 32 tests.
  • Rating (rating/1, form_rating/1) — CSS-only star rating using hidden radio inputs + checked boolean attr. role="radiogroup". FormField integration. 40 tests.
  • Kbd (kbd/1) — Semantic <kbd> element for keyboard shortcut display. 9 tests.

New JS Hooks

  • PhiaResizable — drag-to-resize panel handles, touch support, keyboard nudge
  • PhiaMentionInput@ detection, pushEvent(onMention, {query}), insertMention(id, name)

Bug Fixes

  • Fixed 3 pre-existing test failures: version test (0.1.0 → current), package files (assets → lib), PhiaUi.hello/0 undefined

Test Coverage

  • 2564 tests total — 0 failures
  • All 25 new components: 0 failures
  • mix credo --strict — 0 issues
  • mix format --check-formatted

Theme System v2 — CSS-first Architecture (also 0.1.3)

Complete architectural refactoring of the theme system inspired by DaisyUI's data-attribute pattern, eliminating runtime <style> injection in favour of a static pre-generated CSS file.

New: mix phia.theme install

Generates assets/css/phia-themes.css with all 8 built-in themes, each under its own [data-phia-theme="name"] CSS attribute selector. Automatically injects @import "./phia-themes.css" into assets/css/app.css (idempotent). Options:

  • --output PATH — custom output path (default: assets/css/phia-themes.css)
  • --themes a,b,c — generate only a subset of presets

Improved: mix phia.theme list

Added PRIMARY (light) column showing the OKLCH primary color value for each preset.

Improved: mix phia.theme export

New --format css option: exports a theme as [data-phia-theme="name"] CSS selectors instead of JSON.

New: ThemeCSS.generate/2 with opts

Extended generate/2 with keyword options:

  • selector: — override :root (default)
  • dark_selector: — override .dark (default)
  • include_theme_block: — include/exclude @theme {} block (default: true)

Backward-compatible: generate(theme) still works identically.

New: ThemeCSS.generate_for_selector/1

Generates CSS using [data-phia-theme="name"] and .dark [data-phia-theme="name"] selectors. No @theme block — designed for the multi-theme file.

New: ThemeCSS.generate_all/1

Generates a complete CSS file with all themes as attribute selectors. Accepts a list of atoms (:zinc, :blue), %Theme{} structs, or nil (defaults to all presets).

Refactored: ThemeProvider component

Breaking change (minor): <.theme_provider theme={:blue}> no longer injects a <style> tag. Instead, it sets data-phia-theme="blue" on the wrapper div. CSS custom properties cascade automatically from phia-themes.css.

Migration: Run mix phia.theme install to generate the CSS file, then import it in app.css. Existing templates using <.theme_provider theme={:blue}> work without modification.

New: PhiaTheme JS Hook

New hook in priv/templates/js/hooks/theme.js for runtime color preset switching.

  • Supports <button phx-hook="PhiaTheme" data-theme="blue"> (click event)
  • Supports <select phx-hook="PhiaTheme"> (change event)
  • Persists preference in localStorage['phia-color-theme']
  • Sets data-phia-theme attribute on <html> element
  • Dispatches phia:color-theme-changed CustomEvent

Updated: PhiaDarkMode JS Hook

  • Now writes phia-mode (new canonical key) and phia-theme (retained for backward compatibility)
  • phia:theme-changed event detail now includes mode field alongside existing theme field
  • Anti-FOUC snippet updated to restore both dark mode and color preset on page load

New components

  • TabsNav (tabs_nav/1, tabs_nav_item/1) — Navigation tabs with 3 visual variants: underline (default, bottom border), pills (filled background), segment (segmented control). Fully accessible with aria-current, keyboard support. No JS hooks.

localStorage keys (updated)

KeyWritten byValue
phia-modePhiaDarkMode"dark" | "light" (new canonical key)
phia-themePhiaDarkModesame as phia-mode (legacy, retained for compat)
phia-color-themePhiaThemepreset name (e.g., "blue", "zinc")

Test coverage (theme)

  • 113 new tests for theme system (ThemeCSS, ThemeProvider, mix phia.theme)

0.1.2 — 2026-03-03

Theme System v2 — CSS-first Architecture

Complete architectural refactoring of the theme system inspired by DaisyUI's data-attribute pattern, eliminating runtime <style> injection in favour of a static pre-generated CSS file.

New: mix phia.theme install

Generates assets/css/phia-themes.css with all 8 built-in themes, each under its own [data-phia-theme="name"] CSS attribute selector. Automatically injects @import "./phia-themes.css" into assets/css/app.css (idempotent). Options:

  • --output PATH — custom output path (default: assets/css/phia-themes.css)
  • --themes a,b,c — generate only a subset of presets

Improved: mix phia.theme list

Added PRIMARY (light) column showing the OKLCH primary color value for each preset.

Improved: mix phia.theme export

New --format css option: exports a theme as [data-phia-theme="name"] CSS selectors instead of JSON.

New: ThemeCSS.generate/2 with opts

Extended generate/2 with keyword options:

  • selector: — override :root (default)
  • dark_selector: — override .dark (default)
  • include_theme_block: — include/exclude @theme {} block (default: true)

Backward-compatible: generate(theme) still works identically.

New: ThemeCSS.generate_for_selector/1

Generates CSS using [data-phia-theme="name"] and .dark [data-phia-theme="name"] selectors. No @theme block — designed for the multi-theme file.

New: ThemeCSS.generate_all/1

Generates a complete CSS file with all themes as attribute selectors. Accepts a list of atoms (:zinc, :blue), %Theme{} structs, or nil (defaults to all presets).

Refactored: ThemeProvider component

Breaking change (minor): <.theme_provider theme={:blue}> no longer injects a <style> tag. Instead, it sets data-phia-theme="blue" on the wrapper div. CSS custom properties cascade automatically from phia-themes.css.

Migration: Run mix phia.theme install to generate the CSS file, then import it in app.css. Existing templates using <.theme_provider theme={:blue}> work without modification.

New: PhiaTheme JS Hook

New hook in priv/templates/js/hooks/theme.js for runtime color preset switching.

  • Supports <button phx-hook="PhiaTheme" data-theme="blue"> (click event)
  • Supports <select phx-hook="PhiaTheme"> (change event)
  • Persists preference in localStorage['phia-color-theme']
  • Sets data-phia-theme attribute on <html> element
  • Dispatches phia:color-theme-changed CustomEvent

Updated: PhiaDarkMode JS Hook

  • Now writes phia-mode (new canonical key) and phia-theme (retained for backward compatibility)
  • phia:theme-changed event detail now includes mode field alongside existing theme field
  • Anti-FOUC snippet updated to restore both dark mode and color preset on page load

New components

  • TabsNav (tabs_nav/1, tabs_nav_item/1) — Navigation tabs with 3 visual variants: underline (default, bottom border), pills (filled background), segment (segmented control). Fully accessible with aria-current, keyboard support. No JS hooks.

localStorage keys (updated)

KeyWritten byValue
phia-modePhiaDarkMode"dark" | "light" (new canonical key)
phia-themePhiaDarkModesame as phia-mode (legacy, retained for compat)
phia-color-themePhiaThemepreset name (e.g., "blue", "zinc")

Test coverage

  • 113 new tests for theme system (ThemeCSS, ThemeProvider, mix phia.theme)
  • All tests pass: mix test
  • mix format --check-formatted
  • mix credo --strict — no new issues

0.1.2 — 2026-03-03

Added — 15 new components (5 agents × 3 parallel cycles)

Utilities & Layout — 5 components

  • AspectRatio (aspect_ratio/1) — CSS padding-top trick maintains any aspect ratio (16:9, 4:3, 1:1, 21:9, 9:16) for images, videos, and arbitrary HTML. Zero JS. Attr :ratio accepts any float.
  • Direction (direction/1) — Minimal LTR/RTL wrapper. Sets dir attribute on a <div> for multilingual applications. Useful for Arabic, Hebrew, and RTL content.
  • EmptyState (empty/1) — Centered empty state with 4 optional named slots: :icon, :title, :description, :action. Works inside <td colspan> in tables.
  • Field (field/1, field_label/1, field_description/1, field_message/1) — Standalone form field layout components that do NOT require Phoenix.HTML.FormField. Accept :error string directly. Ideal wrapper for Checkbox, Radio, Switch.
  • ButtonGroup (button_group/1) — Groups multiple Button components into a unified toolbar bar. Orientation :horizontal (default) or :vertical. Uses CSS [&>*] selectors to remove duplicate borders and manage border-radius on first/last children.

Form Integration — 2 components

  • Checkbox (checkbox/1, form_checkbox/1) — Native HTML <input type="checkbox"> styled with Tailwind. Supports :checked, :indeterminate (data-state + aria-checked="mixed"), :disabled. form_checkbox/1 integrates with Phoenix.HTML.FormField and displays Ecto errors. No custom JS hook.
  • Calendar (calendar/1) — Server-rendered monthly grid with 7-column layout. Attrs: :value (Date.t), :mode ("single" | "range"), :min, :max, :disabled_dates. Navigation via phx-click. Range highlight with bg-accent. PhiaCalendar JS hook for keyboard navigation only (Arrow keys, Home, End, Enter). WAI-ARIA: role="grid", role="gridcell", aria-selected.

Interactive Components — 5 components

  • Collapsible (collapsible/1, collapsible_trigger/1, collapsible_content/1) — Expand/collapse section using only Phoenix.LiveView.JS. Zero external hooks. State controlled by :open boolean. aria-expanded, aria-controls wired between trigger and content.
  • AlertDialog (alert_dialog/1, alert_dialog_header/1, alert_dialog_title/1, alert_dialog_description/1, alert_dialog_footer/1, alert_dialog_action/1, alert_dialog_cancel/1) — Critical action confirmation modal. Uses role="alertdialog" and reuses PhiaDialog hook for focus trap. Destructive action variant applies bg-destructive.
  • Carousel (carousel/1, carousel_content/1, carousel_item/1, carousel_previous/1, carousel_next/1) — CSS transform-based slide carousel with touch swipe, keyboard (ArrowLeft/ArrowRight), and loop mode. PhiaCarousel JS hook. WAI-ARIA: role="region", aria-roledescription="slide".
  • ContextMenu (context_menu/1, context_menu_trigger/1, context_menu_content/1, context_menu_item/1, context_menu_separator/1, context_menu_checkbox_item/1, context_menu_label/1) — Right-click contextmenu event menu. PhiaContextMenu JS hook: smart viewport-aware positioning, click-outside close, ArrowUp/Down/Enter/Escape keyboard navigation. WAI-ARIA: role="menu", role="menuitem".
  • Drawer (drawer/1, drawer_trigger/1, drawer_content/1, drawer_header/1, drawer_footer/1, drawer_close/1) — Slide-in modal panel from any edge. Directions: "bottom" (default, mobile sheet), "top", "left", "right". PhiaDrawer JS hook: CSS transform animation, complete focus trap, Escape to close, backdrop click to close. WAI-ARIA: role="dialog", aria-modal="true".

Composed Components — 3 components

  • Avatar (avatar/1, avatar_image/1, avatar_fallback/1, avatar_group/1) — Circular profile image with automatic fallback to initials on image load error (inline onerror JS, no external hook). 4 sizes (sm, default, lg, xl). avatar_group/1 stacks avatars with negative spacing.
  • Combobox (combobox/1, form_combobox/1) — Search-filtered select dropdown. Server-rendered options list filtered in real-time by search query. Check icon (✓) on selected item. form_combobox/1 integrates with Phoenix.HTML.FormField via hidden input. ARIA: aria-haspopup="listbox", role="option".
  • DatePicker (date_picker/1, form_date_picker/1) — Composing calendar/1 inside a popover dropdown. Calendar SVG icon trigger, formatted date display via Calendar.strftime/2. :format attr customises display (default "%d/%m/%Y"). form_date_picker/1 emits ISO 8601 via hidden input. Integrates with Phoenix.HTML.FormField.

New JS Hooks

  • PhiaCalendar — keyboard navigation for calendar grids
  • PhiaCarousel — CSS transform slides, touch swipe, keyboard navigation
  • PhiaContextMenu — right-click positioning, smart flip, keyboard menu navigation
  • PhiaDrawer — slide animation, focus trap, Escape/backdrop handlers

Documentation

  • Added docs/components/utilities.md — Aspect Ratio, Direction, Empty State, Field, Button Group, Avatar
  • Added docs/guides/tutorial-dashboard.md — Step-by-step tutorial: build a complete dashboard with PhiaUI

Test Coverage

  • 1574 tests total (+358 new tests from 15 components)
  • All 15 new components: 0 failures
  • mix credo --strict — 0 issues on all new components

0.1.1 — 2026-03-03

Added

Infrastructure

  • ClassMerger (cn/1) — native Tailwind class merger with ETS-backed GenServer cache; no external tw_merge dependency
  • ComponentRegistry — central registry with 59 entries; ComponentRegistry.all/0 is the source of truth for mix phia.add and mix phia.list
  • TemplateLinter — compile-time EEx template validation
  • TailwindCSS v4 Themepriv/static/theme.css with @theme semantic tokens: OKLCH colour palette, radius scale, shadow scale, and @custom-variant dark (&:where(.dark, .dark *)) for automatic dark mode
  • Mix tasks: phia.install (copies JS hooks + CSS), phia.add <component> (ejects component files), phia.list (catalogue), phia.icons (copies Lucide sprite)

Primitive Components

  • Button — 6 variants (default, destructive, outline, secondary, ghost, link), 4 sizes (default, sm, lg, icon)
  • Card — composable anatomy: card/1, card_header/1, card_title/1, card_description/1, card_content/1, card_footer/1
  • Badge — 4 variants (default, secondary, destructive, outline)
  • Table — streams-compatible; 8 sub-components: table/1, table_header/1, table_body/1, table_footer/1, table_row/1, table_head/1, table_cell/1, table_caption/1
  • Icon — Lucide SVG sprite integration; 4 sizes (xs, sm, md, lg)
  • Alert — 2 variants (default, destructive); accessible role="alert"
  • Skeleton — loading placeholder with animated pulse

Form Integration

  • Input (phia_input/1) — label + input + description + error messages; Phoenix.HTML.FormField integration; phx-debounce support
  • Textarea (phia_textarea/1) — multi-line form-integrated input with the same label/error anatomy
  • Select (phia_select/1) — native <select> with Phoenix.HTML.FormField and error display
  • Formform_field/1, form_label/1, form_message/1; thin wrappers over Phoenix.HTML.Form
  • TagsInput — PhiaTagsInput JS hook; CSV hidden input for form submission; keyboard-driven tag management
  • ImageUpload — native Phoenix LiveView uploads API; drag-and-drop zone; preview thumbnails; no custom hook
  • RichTextEditor — PhiaRichTextEditor JS hook; contenteditable + document.execCommand + Selection API; 14 toolbar commands; zero npm dependencies

Interactive Components

  • Dialog — PhiaDialog JS hook; focus trap via _focusable() query; Escape key dismissal; scroll lock; auto-focus on open; WAI-ARIA role="dialog" with aria-modal
  • DropdownMenu — PhiaDropdownMenu JS hook; smart viewport-aware positioning (flip top/bottom, left/right); click-outside dismissal; full arrow-key navigation; WAI-ARIA role="menu"
  • Accordion — powered by Phoenix.LiveView.JS only (no external hook); single and multiple open modes; WAI-ARIA role="region" + aria-expanded
  • Tooltip — PhiaTooltip JS hook; getBoundingClientRect() positioning with smart flip; WAI-ARIA role="tooltip"
  • Popover — PhiaPopover JS hook; focus trap; smart flip positioning; click-outside close; WAI-ARIA aria-expanded / aria-haspopup
  • Command (Ctrl+K global search) — PhiaCommand JS hook; fuzzy-search filtering; keyboard navigation (↑↓ Enter Escape); WAI-ARIA role="combobox" + role="listbox"
  • DateRangePicker — PhieDateRangePicker JS hook; dual-month calendar; range highlight; keyboard navigation; phx-change integration

Navigation & Feedback

  • Breadcrumb — accessible <nav aria-label="Breadcrumb"> landmark; separator slot; truncation support
  • Pagination — WAI-ARIA compliant <nav>; previous/next/page controls; phx-click integration
  • Toast — PhiaToast JS hook; push_event(socket, "show-toast", …)handleEvent in hook; 4 variants (default, success, error, warning); auto-dismiss with progress bar
  • DarkMode Toggle — PhiaDarkMode JS hook; toggles .dark class on <html>; persists choice in localStorage; respects prefers-color-scheme on first load

Dashboard Shell

  • Shell — CSS Grid grid-cols-[240px_1fr] h-screen overflow-hidden on desktop; Flexbox drawer layout on mobile; toggled via Phoenix.LiveView.JS
  • Sidebar — brand slot, nav slot, footer slot; active link highlighting
  • Topbar — full-width header slot; mobile hamburger trigger
  • MobileSidebarTogglemd:hidden button that opens/closes the mobile sidebar drawer via JS.toggle()

Dashboard Widgets

  • StatCard — trend indicator (up / down / neutral); icon slot; footer slot; coloured trend badge
  • MetricGrid — responsive 1–4 column grid; wraps any StatCard children
  • ChartShell — titled card wrapper for any chart library (ECharts, Chart.js, VegaLite)
  • Chart — PhiaChart JS hook; build_config/2 generates ECharts JSON from :type + :labels; Jason.encode!/1 for data-config/data-series attributes; push_event(socket, "update-chart-#{id}", …) for live updates; dark mode via phia:theme-changed CustomEvent; falls back to Chart.js if ECharts is absent

DataGrid

  • DataGrid — server-side sortable columns; streams-compatible; sort direction cycling (asc → desc → none); phx-click sort headers; WAI-ARIA aria-sort