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
- PhiaEditor v2 JS engine: ~1,200 LOC vanilla JS, contenteditable-based
- OT engine for collaborative editing (
PhiaUi.Editor.OtEngine) - Collab server GenServer (
PhiaUi.Editor.CollabServer) - AI bridge module (
PhiaUi.Editor.AiBridge) - Citation helpers (
PhiaUi.Editor.CitationHelpers) - Export helpers (
PhiaUi.Editor.ExportHelpers)
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 topriv/templates/theme/theme.css prefers-reduced-motionguard added totheme.css(.phia-chart-animatedisables 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 (:video→aspect-video,:square→aspect-square,:wide→aspect-[2/1],:tall→aspect-[3/4]). Optional dark gradient overlay via CSSafter:pseudo-element (after:bg-gradient-to-t after:from-black/60). Badge slot for overlaid labels (top-left,absolute z-10). Inner block renders ascard_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 usesPhiaUi.Components.Avatarwith size:lg. Presence status dot overlaid on avatar::online→bg-emerald-500,:offline→bg-gray-400,:busy→bg-red-500,:away→bg-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 optionalhreflink), 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:ratingis 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=trueappliesring-2 ring-primary bg-primary/5. Optionalbadgelabel (rendered above plan name). Full-width CTA button withcta_href.disabledstate. Slots::header_extra,:footer. 17 tests.ProductCard (
product_card/1) — E-commerce product card. Product image (aspect-square), optionalbadgeoverlay (top-left, configurable variant). Price with optionaloriginal_price(line-through). Star rating from float (0.0–5.0, rounded and rendered as★/☆text). Review count.sold_out=truedisables CTA and shows "Sold Out" badge. Default CTA "Add to cart" withon_add_to_cartevent, overridable via:actionsslot. Optionalhreflink 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=falsehides the percentage label.labelattr 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=trueappliesopacity-60.dismissible=trueshows an × button in the top-right corner withphx-click={@on_dismiss}. Timestamp row intext-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 viafile_type/1pattern-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).hrefrenders filename as<a download>. Slot::actions. 22 tests.EventCard (
event_card/1) — Calendar event card with prominent date badge. Left-panel: colored bycategory_color(:primary,:blue,:emerald,:amber,:rose,:violet), shows 3-letter month abbrev + day number (3xl bold). Right panel: title, time row, location row (map-pinorvideo-cameraicon based onvirtual), stacked attendee avatars with+Noverflow.max_attendeescontrols 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 fromPhiaUi.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 viaURI.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:defaultand:compact. 16 tests.ColorSwatchCard (
color_swatch_card/1) — Color palette swatch card. Color block at top withstyle="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=truerenders<.copy_button>using existingPhiaCopyButtonhook. Optionalrgbandhslsecondary 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 tests — 0 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-selectedon selected month. FormField outputs"YYYY-MM". 18 tests.YearPicker (
year_picker/1,form_year_picker/1) — Scrollable year grid ±10 years from current,min/maxbounds.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">withinputmode="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 witharia-pressed. Abbreviated labels (Mo,Tu,We…). Hiddenname[]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 combinedDate+Timevia separate hidden inputs.calendar_time_picker_nav/1sub-component handles month navigation. 20 tests.DateRangePresets (
date_range_presets/1) —DateRangePickeraugmented with a preset sidebar: Today, Yesterday, This Week, Last 7 Days, Last 30 Days, This Month, Last Month, This Year, Custom. Preset buttons callon_changewith start/end dates. Fully composable via:presetsslot 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:viewattr +on_view_changeevent. MON-first grid. Events rendered as colored pills truncated at 3-per-day with+N more.big_calendar_event/1sub-component. Today highlighted.phx-clickon 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 bytop: #{start_px}px; height: #{duration_px}pxcomputed from start time and duration. Overlapping events share column width.calendar_week_event/1sub-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 ofDateCardcomponents. Acceptsdateslist +selecteddate. 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_clickevent. 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_changeevent 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_selectevent 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 CSSoverflow: hidden+scroll-snap-type: y mandatoryscroll wheel. Inline JS to sync scroll position →pushEventon 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 withbg-primary. Hiddenname[]inputs submit all selected dates.on_changeevent pushes updated selected list. 18 tests.BadgeCalendar (
badge_calendar/1) — Monthly calendar with numeric badge overlays. Acceptsdatamap%{~D[2026-03-05] => integer}. Badge renders asabsolute 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 CSStop+heightcomputed 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 targetDateTime. 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 viapush_eventor 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_bookevent. 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_changeevent. 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 triggerson_bookevent with%{date: date, slot: time}. 26 tests.StreakCalendar (
streak_calendar/1) — Habit tracker / contribution heatmap. Acceptsentrieslist 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/1sub-component: time, title, location, attendee avatars, color dot. 20 tests.MultiMonthCalendar (
multi_month_calendar/1) — Side-by-side display of 2–4 months (:countattr). 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. Acceptseventslist%{date, title, color, id}. Max 3 pills per day ++N moreoverflow. Day click triggerson_day_clickwith date + event list. 24 tests.UptimeBar (
uptime_bar/1) — Segmented uptime visualization. Acceptssegmentslist%{status: :up | :down | :degraded, label}. Green/red/yellow colored segments. Uptime percentage badge. Tooltip per segment on hover.rounding/2helper appliesrounded-fullfor 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. Acceptsdatalist of numbers. Normalizes to SVG viewBox. Trend badge (▲/▼ + %). Color inherited fromtext-*class. 20 tests.GaugeChart (
gauge_chart/1) — SVG semicircle gauge. Needle rotates from -90° (min) to +90° (max) based onvalue. 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. Acceptstaskslist%{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.openboolean attr toggles visibility with CSS transition. Auto-dismiss viaphx-clickor 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.+Noverflow badge whenmaxexceeded. 3 sizes (:sm,:default,:lg). Acceptsavatarslist%{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_selectevent. 18 tests.InputAddon (
input_addon/1) — Prefix and suffix addon wrapper forphia_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
:variantattr totabs/1::underline(default, bottom border),:solid(filled background),:pill(rounded). No registry count change.
Media, Communication & Navigation (5 components)
AudioPlayer (
audio_player/1) +PhiaAudioPlayerhook — HTML5<audio>element controlled by a custom UI. Play/pause toggle, scrubber (time slider), current/total time display, volume slider, mute button. Hook uses nativeaudioevents (timeupdate,loadedmetadata,ended).destroyed()removes all listeners. 22 tests.Sonner (
sonner/1) +PhiaSonnerhook — Rich toast notification system (Sonner-inspired). Icon variants (success✓,error✗,warning⚠,infoℹ,loadingspinner). Action button slot. Promise toast mode (pending → success/error). Stacking with configurableposition(6 positions).push_event(socket, "phia-sonner", %{...})API. 24 tests.QrCode (
qr_code/1) — SVG QR code generator usingeqrcode ~> 0.2.EQRCode.svg/2wrapped in a<div>. Attrs:value(string),size(integer, default 200),error_correction_level(:l,:m,:q,:h).titleattr 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-clickon each item. 16 tests.Toolbar (
toolbar/1,toolbar_button/1,toolbar_separator/1) — Horizontalrole="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 viaaria-keyshortcuts. 18 tests.
New JS Hooks
priv/templates/js/hooks/audio_player.js—PhiaAudioPlayerpriv/templates/js/hooks/sonner.js—PhiaSonner
Test Coverage
- 1098 new tests across 44 new components — 0 failures
- 4043 total tests — 0 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 (:xsh-3,:smh-4,:defaulth-6,:lgh-8,:xlh-12). Usesanimate-spinandcurrentColor— 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">withmin,max,step. Optionalprefixandsuffixslots.aria-valuemin/max/now. FormField integration for Ecto changesets. 28 tests.PasswordInput (
password_input/1,form_password_input/1) — Password field with toggle button. UsesPhoenix.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 whendisabled. FormField integration. 20 tests.CopyButton (
copy_button/1) +PhiaCopyButtonhook — Copy-to-clipboard button.navigator.clipboard.writeTextwithexecCommandfallback. Copy icon → check icon feedback fortimeoutms.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-clickon labels foron_changeevent.role="group"on container. 29 tests.Chip (
chip/1,chip_group/1) — Interactive pill component. Whenon_clickpresent, renders as<button>witharia-pressed={to_string(@selected)}. Whendismissible, shows × button witharia-label="Remove". 3 variants (:default,:outline,:filled), 3 sizes.chip_group/1wraps in flex-wrap container. 20 tests.Editable (
editable/1) +PhiaEditablehook — Inline edit field with preview/edit state. Renders previewdiv(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. AcceptsPhoenix.LiveView.UploadConfigor plain map.phx-drop-target={upload.ref}for drag-and-drop.:emptyslot for drop zone content.:fileslot with:let={entry}for file list.file_upload_entry/1: filename, progress bar (width: #{progress}%), error messages, cancel button withphx-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/1supportsshortcutattr for keyboard shortcut display,disabledstate. 31 tests.
Wave 3 — Lower Priority: Utility & Navigation
ColorPicker (
color_picker/1) +PhiaColorPickerhook — Color selector built on native<input type="color">. Swatch buttons update the input; hook syncs value display span and pusheson_changeevent.data-color-input,data-color-value,data-swatch-valuedata 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 (withon_click) or speed-dial (with:main+:itemslots 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 havephx-value-deselectfor individual removal.name="field[]"for multi-value form submission.aria-labelon 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-expandedon each<li>. 25 tests.BackTop (
back_top/1) +PhiaBackTophook — Scroll-to-top button. Fixed positioned, startsopacity-0. Hook listens toscrollevent (passive), togglesopacity-100beyond threshold. Click:window.scrollTo({top:0, behavior: "smooth"}). Cleanup indestroyed(). 15 tests.
New JS Hooks
priv/templates/js/hooks/copy_button.js—PhiaCopyButtonpriv/templates/js/hooks/editable.js—PhiaEditablepriv/templates/js/hooks/color_picker.js—PhiaColorPickerpriv/templates/js/hooks/back_top.js—PhiaBackTop
Test Coverage
- 336 new tests for 15 new components — 0 failures
- 2945 total tests — 0 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:avatarslot,data-activity-typeattribute,role="log"container,:footerslot. 41 tests.HeatmapCalendar (
heatmap_calendar/1) — GitHub-style contribution heatmap. Accepts rawdatamap%{{col, row} => integer},max_value, configurablerows/cols, axis labels, and optional legend. Intensity classesheatmap-0throughheatmap-4.role="grid"+role="gridcell"+aria-labelper cell. 21 tests.KanbanBoard (
kanban_board/1,kanban_column/1,kanban_card/1) — Multi-column project board. Cards supportpriority(critical,high,medium,low) with color-coded left border. Slots::avatar,:tags,:footer.data-priorityattribute 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:attachmentsslot andmax_charscounter. 49 tests.MentionInput (
mention_input/1,mention_dropdown/1,mention_chip/1) —@mentiontextarea withPhiaMentionInputJS hook.role="combobox"+aria-expandedon textarea. Dropdown usesrole="listbox"/role="option". Hidden_idsCSV input for form submission. Server-side suggestions driven bypushEvent.mention_chip/1for 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 whencount == 0(two function heads). Shows "N label" + clear button + action slot.role="toolbar"+aria-label.bulk_action/1hasdefaultanddestructivevariants, 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 usearia-current="page"when active. Trigger button hasaria-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.decorativeattr removes from accessibility tree. 16 tests. - Toggle (
toggle/1) —aria-pressedtoggle button. Variants:default,outline. Sizes:default,sm,lg. 19 tests. - Switch (
switch/1,form_switch/1) — CSS-animated toggle switch.role="switch".form_switch/1integrates withPhoenix.HTML.FormField. 22 tests. - ToggleGroup (
toggle_group/1,toggle_group_item/1) — Single/multiple selection group.:letcontext 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.:letcontext. FormField integration. 23 tests. - Tabs (
tabs/1,tabs_list/1,tabs_trigger/1,tabs_content/1) — Server-rendered tabbed interface.:letcontext passesactiveto triggers and content panels.aria-selectedon 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. ReusesPhiaDialoghook. 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">usingaccent-primary. WAI-ARIArole="slider". FormField integration. 45 tests. - Resizable (
resizable/1,resizable_panel/1,resizable_handle/1) — Drag-to-resize panel pairs.PhiaResizableJS 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 +checkedboolean 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 nudgePhiaMentionInput—@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/0undefined
Test Coverage
- 2564 tests total — 0 failures
- All 25 new components: 0 failures
mix credo --strict— 0 issuesmix 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-themeattribute on<html>element - Dispatches
phia:color-theme-changedCustomEvent
Updated: PhiaDarkMode JS Hook
- Now writes
phia-mode(new canonical key) andphia-theme(retained for backward compatibility) phia:theme-changedevent detail now includesmodefield alongside existingthemefield- 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 witharia-current, keyboard support. No JS hooks.
localStorage keys (updated)
| Key | Written by | Value |
|---|---|---|
phia-mode | PhiaDarkMode | "dark" | "light" (new canonical key) |
phia-theme | PhiaDarkMode | same as phia-mode (legacy, retained for compat) |
phia-color-theme | PhiaTheme | preset 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-themeattribute on<html>element - Dispatches
phia:color-theme-changedCustomEvent
Updated: PhiaDarkMode JS Hook
- Now writes
phia-mode(new canonical key) andphia-theme(retained for backward compatibility) phia:theme-changedevent detail now includesmodefield alongside existingthemefield- 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 witharia-current, keyboard support. No JS hooks.
localStorage keys (updated)
| Key | Written by | Value |
|---|---|---|
phia-mode | PhiaDarkMode | "dark" | "light" (new canonical key) |
phia-theme | PhiaDarkMode | same as phia-mode (legacy, retained for compat) |
phia-color-theme | PhiaTheme | preset 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:ratioaccepts any float. - Direction (
direction/1) — Minimal LTR/RTL wrapper. Setsdirattribute 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 requirePhoenix.HTML.FormField. Accept:errorstring 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/1integrates withPhoenix.HTML.FormFieldand 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 viaphx-click. Range highlight withbg-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 onlyPhoenix.LiveView.JS. Zero external hooks. State controlled by:openboolean.aria-expanded,aria-controlswired 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. Usesrole="alertdialog"and reusesPhiaDialoghook for focus trap. Destructive action variant appliesbg-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/Escapekeyboard 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 (inlineonerrorJS, no external hook). 4 sizes (sm,default,lg,xl).avatar_group/1stacks 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/1integrates withPhoenix.HTML.FormFieldvia hidden input. ARIA:aria-haspopup="listbox",role="option". - DatePicker (
date_picker/1,form_date_picker/1) — Composingcalendar/1inside a popover dropdown. Calendar SVG icon trigger, formatted date display viaCalendar.strftime/2.:formatattr customises display (default"%d/%m/%Y").form_date_picker/1emits ISO 8601 via hidden input. Integrates withPhoenix.HTML.FormField.
New JS Hooks
PhiaCalendar— keyboard navigation for calendar gridsPhiaCarousel— CSS transform slides, touch swipe, keyboard navigationPhiaContextMenu— right-click positioning, smart flip, keyboard menu navigationPhiaDrawer— 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/0is the source of truth formix phia.addandmix phia.list - TemplateLinter — compile-time EEx template validation
- TailwindCSS v4 Theme —
priv/static/theme.csswith@themesemantic 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); accessiblerole="alert" - Skeleton — loading placeholder with animated pulse
Form Integration
- Input (
phia_input/1) — label + input + description + error messages;Phoenix.HTML.FormFieldintegration;phx-debouncesupport - Textarea (
phia_textarea/1) — multi-line form-integrated input with the same label/error anatomy - Select (
phia_select/1) — native<select>withPhoenix.HTML.FormFieldand error display - Form —
form_field/1,form_label/1,form_message/1; thin wrappers overPhoenix.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-ARIArole="dialog"witharia-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.JSonly (no external hook); single and multiple open modes; WAI-ARIArole="region"+aria-expanded - Tooltip — PhiaTooltip JS hook;
getBoundingClientRect()positioning with smart flip; WAI-ARIArole="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-ARIArole="combobox"+role="listbox" - DateRangePicker — PhieDateRangePicker JS hook; dual-month calendar; range highlight; keyboard navigation;
phx-changeintegration
Navigation & Feedback
- Breadcrumb — accessible
<nav aria-label="Breadcrumb">landmark; separator slot; truncation support - Pagination — WAI-ARIA compliant
<nav>; previous/next/page controls;phx-clickintegration - Toast — PhiaToast JS hook;
push_event(socket, "show-toast", …)→handleEventin hook; 4 variants (default,success,error,warning); auto-dismiss with progress bar - DarkMode Toggle — PhiaDarkMode JS hook; toggles
.darkclass on<html>; persists choice inlocalStorage; respectsprefers-color-schemeon first load
Dashboard Shell
- Shell — CSS Grid
grid-cols-[240px_1fr] h-screen overflow-hiddenon desktop; Flexbox drawer layout on mobile; toggled viaPhoenix.LiveView.JS - Sidebar — brand slot, nav slot, footer slot; active link highlighting
- Topbar — full-width header slot; mobile hamburger trigger
- MobileSidebarToggle —
md:hiddenbutton that opens/closes the mobile sidebar drawer viaJS.toggle()
Dashboard Widgets
- StatCard — trend indicator (
up/down/neutral); icon slot; footer slot; coloured trend badge - MetricGrid — responsive 1–4 column grid; wraps any
StatCardchildren - ChartShell — titled card wrapper for any chart library (ECharts, Chart.js, VegaLite)
- Chart — PhiaChart JS hook;
build_config/2generates ECharts JSON from:type+:labels;Jason.encode!/1fordata-config/data-seriesattributes;push_event(socket, "update-chart-#{id}", …)for live updates; dark mode viaphia:theme-changedCustomEvent; falls back to Chart.js if ECharts is absent
DataGrid
- DataGrid — server-side sortable columns; streams-compatible; sort direction cycling (
asc → desc → none);phx-clicksort headers; WAI-ARIAaria-sort