alexbruf/elm-daisyui/1.0.0

Daisy.Tree

The closed view tree.

A page is composed of exactly four nested levels — Page > Section > Block

Leaf — plus Overlay, which lives only in Page.overlays. No constructor accepts a child of its own level or above, so "a card inside a card", "a section inside a block", "six sections" and "two primary buttons" are all unrepresentable rather than merely discouraged.

Every XConfig is a record of Maybe <Group> values taken straight from Daisy.Schema.<Component> plus, where the component declares one, modifiers : List <Component>.Modifier. There is no String class field anywhere and no Raw Html escape hatch, so Daisy.Render is the only module that can emit a class.

import Daisy.Tree exposing (..)


savePage : Page Msg
savePage =
    Page
        { shell = Plain
        , sections = Sections1 (Stack defaultStackConfig [ Prose [ Text "Hello" ] ])
        , cta = cta "Save" Save
        , overlays = []
        , theme = Light
        , dock = Nothing
        , fab = Nothing
        }

Page

type Page msg
= Page
{ shell : Shell msg
, sections : Sections msg
, cta : Cta msg
, overlays : List (Overlay msg)
, theme : Theme
, dock : Maybe (Dock msg)
, fab : Maybe (Fab msg)
}

A whole page.

sections is a fixed-arity type, so a page has between one and five sections. cta is mandatory and is the page's only btn-primary; the shell decides where it goes. overlays is the only place a modal, drawer or toast can appear. dock and fab are viewport-fixed chrome rendered in the same layer.

type Sections msg
= Sections1 (Section msg)
| Sections2 (Section msg) (Section msg)
| Sections3 (Section msg) (Section msg) (Section msg)
| Sections4
(Section msg)
(Section msg)
(Section msg)
(Section msg)
| Sections5
(Section msg)
(Section msg)
(Section msg)
(Section msg)
(Section msg)

One to five sections. There is no constructor for zero or six, so the page content budget is a type error rather than a runtime check.

type Shell msg
= Plain
| Dashboard
{ sidebar : MenuSpec msg
, navbar : NavbarParts msg
}

The page frame.

Plain is a single column of sections. Dashboard renders as a daisyUI drawer that is open from lg: up, with the sidebar menu in drawer-side and the navbar on top of drawer-content.

type alias Cta msg =
{ label : String
, onClick : msg
, size : Maybe Size
, style : Maybe Style
, modifiers : List Modifier
, behaviors : List Behavior
, tooltip : Maybe Tooltip
, aura : Maybe AuraConfig
, indicator : Maybe Indicator
}

The page's single primary call to action. Rendered as btn btn-primary.

cta : String -> msg -> Cta msg

A Cta with default styling.

cta "Save" Save

Theme

type Theme
= Light
| Dark
| Cupcake
| Bumblebee
| Emerald
| Corporate
| Synthwave
| Retro
| Cyberpunk
| Valentine
| Halloween
| Garden
| Forest
| Aqua
| Lofi
| Pastel
| Fantasy
| Wireframe
| Black
| Luxury
| Dracula
| Cmyk
| Autumn
| Business
| Acid
| Lemonade
| Night
| Coffee
| Winter
| Dim
| Nord
| Sunset
| Caramellatte
| Abyss
| Silk

Every theme daisyUI 5 ships. Daisy.Render.page writes the chosen one to data-theme on the page root.

All 35 themes, in daisyUI's own order.

themeToString : Theme -> String

The data-theme value for a Theme.

themeToString Caramellatte --> "caramellatte"

Sections

type Section msg
= Hero HeroConfig (List (Block msg))
| Navbar (NavbarParts msg)
| Footer FooterConfig (List (Block msg))
| Grid GridConfig (List (Block msg))
| Stack StackConfig (List (Block msg))

A top-level band of the page.

Navbar holds leaves in three named part lists; the others hold blocks.

type alias HeroConfig =
{ overlay : Bool }

hero has no class groups; overlay decides whether the renderer emits the hero-overlay part.

defaultHeroConfig : HeroConfig

A hero with no overlay.

emptyNavbarParts : NavbarParts msg

An empty navbar.

type alias FooterConfig =
{ direction : Maybe Direction
, placement : Maybe Placement
}

Groups of the daisyUI footer component.

defaultFooterConfig : FooterConfig

A footer with no direction or placement class.

type alias GridConfig =
{ columns : GridColumns }

Configuration of a Grid section.

defaultGridConfig : GridConfig

A four-column grid.

= Cols1
| Cols2
| Cols3
| Cols4

How many columns a Grid section has. Spacing is fixed by Daisy.Render.tokens; only the column count is authorable.

type alias StackConfig =
{ align : Align }

Configuration of a Stack section. This is a fixed-gap vertical band, not the daisyUI stack component — that one is Stacked.

defaultStackConfig : StackConfig

A stack whose blocks sit at the start edge.

The default is deliberately not AlignStretch, even though stretching is what most bands want: under Shell.Plain the renderer appends Page.cta to the last section's container, so a stretched last Stack would stretch the page's single primary button across the whole page. Ask for AlignStretch where you want it instead.

type Align
= AlignStart
| AlignCenter
| AlignEnd
| AlignStretch

Cross-axis alignment of a Stack section.

AlignStretch (items-stretch) is the one that lets a Table, Alert or Card fill the band; the other three shrink every block to its content width.

Blocks

type Block msg
= Accordion AccordionConfig (List (AccordionItem msg))
| Alert AlertConfig (List (Leaf msg))
| Breadcrumbs (List (Leaf msg))
| Card CardConfig (CardParts msg)
| Carousel CarouselConfig (List (CarouselItem msg))
| Chart ChartConfig ChartData
| Chat (List (ChatMessage msg))
| Collapse CollapseConfig (CollapseParts msg)
| Diff (DiffParts msg)
| Form (List (Fieldset msg))
| ListBlock (List (ListRow msg))
| Menu MenuConfig (List (MenuItem msg))
| MockupBrowser (MockupBrowserParts msg)
| MockupCode (List CodeLine)
| MockupPhone (MockupPhoneParts msg)
| MockupWindow (MockupWindowParts msg)
| Nav NavConfig (List (Leaf msg))
| Pagination PaginationConfig PaginationData
| Prose (List (Leaf msg))
| Stacked StackedConfig (List (Leaf msg))
| Stat StatConfig (List (StatItem msg))
| Steps StepsConfig (List Step)
| Table TableConfig (List (Row msg))
| Tabs TabsConfig (List (Tab msg))
| Timeline TimelineConfig (List (TimelineItem msg))

A self-contained content container inside a section. A block never contains another block.

type alias AccordionConfig =
{ modifiers : List Modifier
, name : String
}

Groups of the daisyUI collapse component, plus the radio group name that turns a set of collapses into an accordion.

defaultAccordionConfig : AccordionConfig

An accordion whose items share the group name "accordion".

type alias AccordionItem msg =
{ title : String
, content : List (Leaf msg)
}

One collapse inside an Accordion.

type alias AlertConfig =
{ color : Maybe Color
, style : Maybe Style
, direction : Maybe Direction
}

Groups of the daisyUI alert component.

defaultAlertConfig : AlertConfig

An alert with no colour, style or direction class.

type alias CardConfig =
{ style : Maybe Style
, size : Maybe Size
, modifiers : List Modifier
, aura : Maybe AuraConfig
, hover3d : Bool
}

Groups of the daisyUI card component plus the aura and hover-3d decoration properties.

defaultCardConfig : CardConfig

A plain card.

type alias CardParts msg =
{ figure : Maybe (Leaf msg)
, title : Maybe String
, body : List (CardChild msg)
, actions : List (Leaf msg)
}

The card-* parts. A part record makes card-body outside a card unrepresentable.

emptyCardParts : CardParts msg

A card with nothing in it.

type CardChild msg
= CardLeaf (Leaf msg)
| CardChart ChartConfig ChartData
| CardTable TableConfig (List (Row msg))
| CardStat StatConfig (List (StatItem msg))
| CardForm (List (Fieldset msg))

What a card-body may hold: leaves, plus the four block shapes a dashboard card is actually made of.

There is deliberately no CardCard: a card can never contain a card, which is what tools/should-not-compile/Reject/CardInCard.elm and Reject/CardInCardBody.elm pin down. Every constructor here takes exactly the arguments its Block counterpart takes, and Daisy.Render renders it through the same helper, so a chart in a card and a bare chart are the same markup.

type alias CarouselConfig =
{ direction : Maybe Direction
, modifiers : List Modifier
, snap : Maybe CarouselSnap
}

Groups of the daisyUI carousel component.

defaultCarouselConfig : CarouselConfig

A carousel with no direction or snap class.

type alias CarouselItem msg =
{ content : List (Leaf msg) }

One carousel-item.

= SnapStart
| SnapCenter
| SnapEnd

Where a carousel snaps its items. daisyUI declares these under modifier but they are mutually exclusive, so the tree offers one field and the renderer expands it into a single modifier class.

type alias ChatMessage msg =
{ placement : Placement
, color : Maybe Color
, image : Maybe ImageSrc
, header : Maybe String
, footer : Maybe String
, bubble : List (Leaf msg)
}

One chat message. The colour applies to the chat-bubble part, which is where daisyUI puts it.

type alias CollapseConfig =
{ modifiers : List Modifier }

Groups of the daisyUI collapse component.

defaultCollapseConfig : CollapseConfig

A closed collapse with no arrow or plus icon.

type alias CollapseParts msg =
{ title : String
, content : List (Leaf msg)
}

The collapse-title and collapse-content parts.

type alias DiffParts msg =
{ item1 : Leaf msg
, item2 : Leaf msg
}

The diff-item-1 and diff-item-2 parts. diff-resizer is emitted by the renderer.

type alias Fieldset msg =
{ legend : Maybe String
, fields : List (Field msg)
}

A fieldset inside a Form block. fieldset-legend cannot exist without its fieldset.

type alias Field msg =
{ label : Maybe String
, labelPlacement : LabelPlacement
, control : Leaf msg
, validate : Bool
, hint : Maybe String
}

One labelled, optionally validated control.

label and validator-hint are held here rather than as leaves, so a stray legend, label or hint is unrepresentable and the hint is always the sibling immediately after its input.

= LabelStart
| LabelEnd
| LabelFloating

Where a field's label sits: before the control, after it, or floating over it (floating-label).

field : String -> Leaf msg -> Field msg

A labelled field with no validation.

field "Email" (Input defaultInputConfig)
type alias ListRow msg =
{ cells : List (ListCell msg) }

One list-row.

type alias ListCell msg =
{ content : Leaf msg
, grow : Bool
, wrap : Bool
}

One cell of a list-row.

list-col-grow and list-col-wrap mark a single cell, not the whole list, so they are flags here rather than modifiers on the block. A cell with neither flag is rendered as its bare leaf.

listCell : Leaf msg -> ListCell msg

A plain cell that neither grows nor wraps.

listCell (Text "Cy Ganderton")
defaultMenuConfig : MenuConfig

A vertical menu at the default size.

type alias MockupBrowserParts msg =
{ toolbar : Maybe String
, content : List (Leaf msg)
}

The mockup-browser-toolbar part plus the framed content.

type alias MockupPhoneParts msg =
{ content : List (Leaf msg) }

The framed content. mockup-phone-camera and mockup-phone-display are emitted by the renderer.

type alias MockupWindowParts msg =
{ title : Maybe String
, content : List (Leaf msg)
}

A window title bar plus the framed content.

type alias CodeLine =
{ prefix : Maybe String
, text : String
}

One line of a MockupCode block.

defaultNavConfig : NavConfig

An untitled navigation column.

type alias PaginationConfig =
{ direction : Maybe Direction }

Groups of the daisyUI pagination component, which reuses join.

defaultPaginationConfig : PaginationConfig

A pagination bar with no direction class.

type alias PaginationData =
{ pages : List String
, active : Int
}

The pages of a pagination bar and the index of the active one.

type alias StackedConfig =
{ modifiers : List Modifier
, align : Maybe StackedAlign
}

Groups of the daisyUI stack component.

defaultStackedConfig : StackedConfig

A stack with no alignment class.

= StackedTop
| StackedBottom
| StackedStart
| StackedEnd

Where a daisyUI stack aligns its overlapping children. Declared under modifier but mutually exclusive; see snap on CarouselConfig.

type alias StatConfig =
{ direction : StatDirection }

Groups of the daisyUI stat component. The container class is stats.

defaultStatConfig : StatConfig

A stats container with no direction class.

= Fixed (Maybe Direction)
| Responsive

How a stats container lays its tiles out.

Fixed is the schema direction group: one class, or none. Responsive is daisyUI's own stats-vertical lg:stats-horizontal idiom — a column on a phone, a row from lg up. It is a separate constructor rather than a flag beside direction so there is no combination where one silently wins over the other.

type alias StatItem msg =
{ figure : Maybe (Leaf msg)
, title : String
, value : String
, desc : Maybe String
, actions : List (Leaf msg)
}

One tile: the stat, stat-figure, stat-title, stat-value, stat-desc and stat-actions parts.

emptyStatItem : String -> String -> StatItem msg

A titled tile with a value and nothing else.

type alias StepsConfig =
{ direction : Maybe Direction }

Groups of the daisyUI steps component. The colour classes are step-* and belong on a Step, not here.

defaultStepsConfig : StepsConfig

Steps with no direction class.

type alias Step =
{ label : String
, color : Maybe Color
, icon : Maybe String
}

One step, optionally coloured and with a step-icon.

type alias TableConfig =
{ size : Maybe Size
, modifiers : List Modifier
}

Groups of the daisyUI table component.

defaultTableConfig : TableConfig

A table with no size or zebra class.

type alias Row msg =
{ header : Bool
, cells : List (Leaf msg)
}

One table row. header = True renders its cells as <th> inside <thead>.

type alias TabsConfig =
{ style : Maybe Style
, size : Maybe Size
, placement : Maybe Placement
}

Groups of the daisyUI tab component. tab-active and tab-disabled belong on a Tab, not here.

defaultTabsConfig : TabsConfig

Tabs with no style, size or placement class.

type alias Tab msg =
{ label : String
, active : Bool
, disabled : Bool
, content : List (Leaf msg)
}

One tab and the panel it owns.

type alias TimelineConfig =
{ direction : Maybe Direction
, modifiers : List TimelineModifier
}

Groups of the daisyUI timeline component.

defaultTimelineConfig : TimelineConfig

A timeline with no direction class.

= TimelineSnapIcon
| TimelineCompact

The container-level modifiers of the daisyUI timeline component.

This deliberately omits timeline-box, the way ButtonColor omits btn-primary: daisyUI puts that class on one side of one item, so it is startBox / endBox on TimelineItem and cannot be listed here.

Widen a TimelineModifier to the generated schema type.

type alias TimelineItem msg =
{ start : Maybe String
, startBox : Bool
, middle : Maybe (Leaf msg)
, end : Maybe String
, endBox : Bool
}

The timeline-start, timeline-middle and timeline-end parts of one entry.

startBox / endBox put timeline-box on that side of this item, which is where daisyUI puts it.

Leaves

type Leaf msg
= Avatar (AvatarConfig msg) ImageSrc
| AvatarGroup (List (AvatarItem msg))
| Badge BadgeConfig String
| Button (ButtonConfig msg) String
| Calendar (CalendarConfig msg) CalendarState
| Checkbox (CheckboxConfig msg)
| Countdown Float
| Divider DividerConfig (Maybe String)
| FileInput (FileInputConfig msg)
| Filter (FilterData msg)
| HoverGallery (List ImageSrc)
| Heading HeadingLevel String
| Image (ImageConfig msg) ImageSrc
| Input (InputConfig msg)
| Join JoinConfig (List (JoinItem msg))
| Kbd KbdConfig String
| Link (LinkConfig msg) String
| Loading LoadingConfig
| Megamenu MegamenuConfig (List (MegamenuItem msg))
| Otp (OtpConfig msg) OtpData
| Progress ProgressConfig ProgressData
| RadialProgress RadialProgressData
| Radio (RadioConfig msg) RadioData
| Range (RangeConfig msg) RangeData
| Rating (RatingConfig msg) RatingData
| Select (SelectConfig msg) SelectData
| Skeleton SkeletonConfig
| Status StatusConfig
| Swap (SwapConfig msg) SwapFaces
| Text String
| TextRotate (List String)
| Textarea (TextareaConfig msg)
| ThemeSelect (ThemeSelectData msg)
| Toggle (ToggleConfig msg) ToggleData

A terminal control or piece of content. A leaf holds only data, never another node.

type alias ImageSrc =
String

The src of an image. Leaf.Image is not a daisyUI component; it exists because card, carousel, diff, stack, avatar and hover-gallery all need one.

= H1
| H2
| H3

The rank of a Leaf.Heading.

Heading is not a daisyUI component and emits no daisyUI class: it renders a bare <h1> / <h2> / <h3>, which Tailwind typography styles when the heading sits inside a Block.Prose. It exists because a page otherwise has no document outline at all — Leaf.Text is a text node and Prose is a <div>.

type alias AvatarConfig msg =
{ modifiers : List Modifier
, mask : Maybe MaskConfig
, dropdown : Maybe (Dropdown msg)
, indicator : Maybe Indicator
, tooltip : Maybe Tooltip
}

Groups of the daisyUI avatar component plus the mask, dropdown, indicator and tooltip properties.

defaultAvatarConfig : AvatarConfig msg

An avatar with no status dot or mask.

type alias AvatarItem msg =
{ config : AvatarConfig msg
, src : ImageSrc
}

One member of an avatar-group.

type alias BadgeConfig =
{ color : Maybe Color
, style : Maybe Style
, size : Maybe Size
, tooltip : Maybe Tooltip
}

Groups of the daisyUI badge component.

defaultBadgeConfig : BadgeConfig

A badge with no colour, style or size class.

type alias ButtonConfig msg =
{ color : Maybe ButtonColor
, style : Maybe Style
, size : Maybe Size
, modifiers : List Modifier
, behaviors : List Behavior
, tooltip : Maybe Tooltip
, dropdown : Maybe (Dropdown msg)
, indicator : Maybe Indicator
, aura : Maybe AuraConfig
, onClick : Maybe msg
}

Groups of the daisyUI button component, with the tree's narrowed colour type, plus the tooltip, dropdown, indicator and aura properties and the click handler.

defaultButtonConfig : ButtonConfig msg

A plain button.

Button defaultButtonConfig "Save"
= Neutral
| Secondary
| Accent
| Info
| Success
| Warning
| Error

The colour of a Button leaf.

This deliberately omits Primary: the only btn-primary on a page is Page.cta, which uses the schema type directly.

Widen a ButtonColor to the generated schema type.

type alias CalendarConfig msg =
{ id : String
, today : Date
, locale : CalendarLocale
, months : CalendarMonths
, toMsg : CalendarMsg -> msg
, onChange : CalendarValue -> msg
}

Everything the calendar picker needs that is not its own state.

The leaf is a typed front for the pure-Elm package alexbruf/elm-cally, a port of the Cally web component that renders the same markup and the same part attributes in the light DOM — which is exactly what daisyUI's calendar.css styles through its cally class. No ports, no custom element registration, no shadow DOM.

Daisy.Render builds elm-cally's own Config record from this one; it is never exposed raw, the same way Daisy.Chart hides terezka/elm-charts.

The update flow. A calendar is the second stateful leaf after ThemeSelect, and the only one whose state the application must store, because a date picker remembers which day holds the roving tabindex and which month is on screen:

  1. Keep a CalendarState in your Model, built once with Daisy.Render.initCalendarRange (or initCalendarDate / initCalendarMulti).
  2. Give toMsg a constructor of your own Msg that carries a CalendarMsg, and forward it in update to Daisy.Render.updateCalendar, storing the state it returns and running the Cmd it returns (that command carries the picker's own Browser.Dom.focus call, so keyboard navigation needs it).
  3. onChange fires with a CalendarValue whenever the selection changes; store that too if you want to show it.
  4. Rebuild Leaf.Calendar config state from the model on every view. The leaf is data, so nothing is retained between renders.

id prefixes every DOM id the picker renders (day buttons, the two paging buttons), so it must be unique on the page and stable across renders.

{ id : String
, today : Date
, toMsg : CalendarMsg -> msg
, onChange : CalendarValue -> msg
}
-> CalendarConfig msg

A calendar in EnGB showing one month.

Unlike every other defaultXConfig this is a function, not a value: a picker cannot exist without an id, a today and somewhere to send its messages, and elm-cally's own defaultConfig takes the same four.

= EnGB
| EnUS

The two locales alexbruf/elm-cally bundles. Elm has no Intl, so a locale is a table of formatting functions rather than a language tag, and the package ships exactly these two; a closed type keeps an unbuildable one from being asked for.

= OneMonth
| TwoMonths

How many month grids the picker shows, and therefore how far its previous and next buttons page.

This is a closed pair rather than an Int for the usual reason: months = 13 is not a calendar anyone means, and the renderer would have to decide what to do with it. TwoMonths puts the two grids side by side from sm up and in one column below it: elm-cally's [part~="months"] is a bare <div> and daisyUI's calendar.css has no months rule, so the layout comes from Daisy.Render's own token table (see Daisy.Render.calendarMonths).

= SelectDate Value Model
| SelectRange Value Model
| SelectMulti Value Model

What the picker selects, and everything it remembers for itself.

The three constructors are the three pickers elm-cally provides, and each one carries that picker's Value and Model as opaque data — the same way Leaf.ThemeSelect carries the current Theme. Build one with Daisy.Render.initCalendarDate / initCalendarRange / initCalendarMulti and hand it back to Daisy.Render.updateCalendar; nothing else can construct the Model inside, so the picker's invariants stay elm-cally's business.

= PickedDate (Maybe Date)
| PickedRange (Maybe ( Date, Date ))
| PickedDates (List Date)

The selection CalendarConfig.onChange reports, one constructor per CalendarState constructor. A range is always sorted.

= CalendarDateMsg Msg
| CalendarRangeMsg Msg
| CalendarMultiMsg Msg

One of the picker's own messages, on its way back to Daisy.Render.updateCalendar. The payloads are elm-cally's opaque Msg types, so an application can route one but cannot invent one.

Write the selection CalendarConfig.onChange reported back into the state, so the next render draws it.

Daisy.Render.updateCalendar advances everything the picker remembers for itself (the focused day and the page on screen); the value is the application's, which is why it comes back as its own message and goes back in through this function. A value of a different kind than the state is a no-op: one Leaf.Calendar only ever produces one kind.

type alias CheckboxConfig msg =
{ color : Maybe Color
, size : Maybe Size
, checked : Bool
, ariaLabel : Maybe String
, tooltip : Maybe Tooltip
, onCheck : Maybe (Bool -> msg)
}

Groups of the daisyUI checkbox component.

defaultCheckboxConfig : CheckboxConfig msg

An unchecked checkbox with no colour or size class.

type alias DividerConfig =
{ color : Maybe Color
, direction : Maybe Direction
, placement : Maybe Placement
, tooltip : Maybe Tooltip
}

Groups of the daisyUI divider component.

defaultDividerConfig : DividerConfig

A divider with no colour, direction or placement class.

type alias FileInputConfig msg =
{ color : Maybe Color
, style : Maybe Style
, size : Maybe Size
, ariaLabel : Maybe String
, tooltip : Maybe Tooltip
, onInput : Maybe (String -> msg)
}

Groups of the daisyUI file-input component.

defaultFileInputConfig : FileInputConfig msg

A file input with no colour, style or size class.

type alias FilterData msg =
{ name : String
, options : List String
, selected : Maybe String
, reset : Maybe FilterReset
, onSelect : Maybe (String -> msg)
}

A filter: a radio group styled as buttons, plus an optional reset control. daisyUI's filter declares no class groups, so this is all data.

= ResetPart
| ResetButton (List Modifier)

How a filter's reset control is drawn.

daisyUI has two idioms and the class set differs between them. ResetPart carries the filter-reset part, which is what a filter outside a <form> needs. ResetButton is the plain btn a filter inside a real <form> uses (daisyUI's own examples make it btn-square), where the browser's form reset does the work and no part class is involved.

type alias ImageConfig msg =
{ alt : String
, mask : Maybe MaskConfig
, hover3d : Bool
, tooltip : Maybe Tooltip
, onClick : Maybe msg
}

The mask and hover-3d properties of an image, plus its alt text.

defaultImageConfig : ImageConfig msg

A plain image with empty alt text.

type alias InputConfig msg =
{ color : Maybe Color
, style : Maybe Style
, size : Maybe Size
, placeholder : String
, value : String
, inputType : InputType
, required : Bool
, pattern : Maybe String
, minLength : Maybe Int
, maxLength : Maybe Int
, ariaLabel : Maybe String
, indicator : Maybe Indicator
, tooltip : Maybe Tooltip
, onInput : Maybe (String -> msg)
}

Groups of the daisyUI input component, plus the HTML validation constraints daisyUI's validator / validator-hint pair needs.

inputType, required, pattern, minLength and maxLength are rendered as the matching HTML attributes. Without at least one of them a Field marked validate = True can never become :user-invalid, so its hint would never show.

pattern is a regular expression (the HTML pattern attribute), never a class.

defaultInputConfig : InputConfig msg

An empty, unconstrained text input with no colour, style or size class.

= InputText
| InputEmail
| InputPassword
| InputNumber
| InputUrl
| InputTel
| InputSearch
| InputDate

What an input accepts. Rendered as the type attribute, which is half of what makes daisyUI's validator class do anything: the styling hangs off :user-invalid, and only a real constraint can make a control invalid.

type alias JoinConfig =
{ direction : Maybe Direction
, tooltip : Maybe Tooltip
}

Groups of the daisyUI join component.

defaultJoinConfig : JoinConfig

A join with no direction class.

type JoinItem msg
= JoinButton (ButtonConfig msg) String
| JoinInput (InputConfig msg)
| JoinSelect (SelectConfig msg) SelectData
| JoinText String

What a join may group. A closed list, so Leaf stays non-recursive.

type alias KbdConfig =
{ size : Maybe Size
, tooltip : Maybe Tooltip
}

Groups of the daisyUI kbd component.

defaultKbdConfig : KbdConfig

A kbd with no size class.

type alias LinkConfig msg =
{ color : Maybe Color
, style : Maybe Style
, href : String
, dropdown : Maybe (Dropdown msg)
, indicator : Maybe Indicator
, tooltip : Maybe Tooltip
, onClick : Maybe msg
}

Groups of the daisyUI link component.

defaultLinkConfig : LinkConfig msg

A link to "#" with no colour or style class.

type alias LoadingConfig =
{ style : Maybe Style
, size : Maybe Size
, tooltip : Maybe Tooltip
}

Groups of the daisyUI loading component.

defaultLoadingConfig : LoadingConfig

A loading indicator with no style or size class.

type alias MegamenuConfig =
{ size : Maybe Size
, direction : Maybe Direction
, modifiers : List Modifier
, tooltip : Maybe Tooltip
}

Groups of the daisyUI megamenu component.

defaultMegamenuConfig : MegamenuConfig

A megamenu with no size, direction or width class.

type alias MegamenuItem msg =
{ label : String
, active : Bool
, menu : MenuSpec msg
}

One labelled panel of a megamenu. active = True emits the megamenu-active part.

type alias OtpConfig msg =
{ color : Maybe Color
, size : Maybe Size
, modifiers : List Modifier
, tooltip : Maybe Tooltip
, onInput : Maybe (String -> msg)
}

Groups of the daisyUI otp component.

defaultOtpConfig : OtpConfig msg

A one-time-code input with no colour or size class.

type alias OtpData =
{ digits : Int }

How many boxes an otp has.

type alias ProgressConfig =
{ color : Maybe Color
, tooltip : Maybe Tooltip
}

Groups of the daisyUI progress component.

defaultProgressConfig : ProgressConfig

A progress bar with no colour class.

type alias ProgressData =
{ value : Maybe Float
, max : Float
}

The value of a progress bar. Nothing renders the indeterminate state.

type alias RadialProgressData =
{ value : Float
, label : String
}

The value and centre label of a radial-progress. Its size and thickness are CSS variables, not classes, so there is no config.

type alias RadioConfig msg =
{ color : Maybe Color
, size : Maybe Size
, ariaLabel : Maybe String
, tooltip : Maybe Tooltip
, onCheck : Maybe (Bool -> msg)
}

Groups of the daisyUI radio component.

defaultRadioConfig : RadioConfig msg

A radio with no colour or size class.

type alias RadioData =
{ name : String
, checked : Bool
}

The group name of a radio and whether it is selected.

type alias RangeConfig msg =
{ color : Maybe Color
, size : Maybe Size
, direction : Maybe Direction
, ariaLabel : Maybe String
, tooltip : Maybe Tooltip
, onInput : Maybe (String -> msg)
}

Groups of the daisyUI range component.

defaultRangeConfig : RangeConfig msg

A range with no colour, size or direction class.

type alias RangeData =
{ min : Float
, max : Float
, value : Float
}

The bounds and value of a range.

type alias RatingConfig msg =
{ size : Maybe Size
, modifiers : List RatingModifier
, shape : Maybe Style
, ariaLabel : Maybe String
, tooltip : Maybe Tooltip
, onRate : Maybe (Int -> msg)
}

Groups of the daisyUI rating component.

shape is the mask-* clip-path each radio wears. Nothing keeps the renderer's default (mask-star-2), which is what daisyUI's own rating examples use most.

defaultRatingConfig : RatingConfig msg

A rating of default-shaped stars with no size class.

= RatingHalf

The container-level modifiers of the daisyUI rating component.

This omits rating-hidden the way TimelineModifier omits timeline-box: daisyUI puts it on the rating's first, blank radio, so it is clearable on RatingData.

RatingHalf also drives the item masks: with it the renderer alternates mask-half-1 / mask-half-2 across the radios, which is the only way daisyUI's half-star rating works.

Widen a RatingModifier to the generated schema type.

type alias RatingData =
{ name : String
, count : Int
, value : Int
, clearable : Bool
}

The group name, number of stars and current value of a rating.

clearable = True puts daisyUI's blank rating-hidden radio first, so the rating can be set back to "no stars".

type alias SelectConfig msg =
{ color : Maybe Color
, style : Maybe Style
, size : Maybe Size
, ariaLabel : Maybe String
, tooltip : Maybe Tooltip
, onSelect : Maybe (String -> msg)
}

Groups of the daisyUI select component.

defaultSelectConfig : SelectConfig msg

A select with no colour, style or size class.

type alias SelectData =
{ options : List String
, selected : Maybe String
}

The options of a select and which one is chosen.

type alias SkeletonConfig =
{ modifiers : List Modifier
, tooltip : Maybe Tooltip
}

Groups of the daisyUI skeleton component.

defaultSkeletonConfig : SkeletonConfig

A block skeleton.

type alias StatusConfig =
{ color : Maybe Color
, size : Maybe Size
, tooltip : Maybe Tooltip
}

Groups of the daisyUI status component.

defaultStatusConfig : StatusConfig

A status dot with no colour or size class.

type alias SwapConfig msg =
{ style : Maybe Style
, modifiers : List Modifier
, tooltip : Maybe Tooltip
, onCheck : Maybe (Bool -> msg)
}

Groups of the daisyUI swap component.

defaultSwapConfig : SwapConfig msg

A swap with no rotate or flip class.

type alias SwapFaces =
{ on : String
, off : String
, indeterminate : Maybe String
}

The swap-on, swap-off and swap-indeterminate faces.

type alias TextareaConfig msg =
{ color : Maybe Color
, style : Maybe Style
, size : Maybe Size
, placeholder : String
, value : String
, required : Bool
, ariaLabel : Maybe String
, tooltip : Maybe Tooltip
, onInput : Maybe (String -> msg)
}

Groups of the daisyUI textarea component.

defaultTextareaConfig : TextareaConfig msg

An empty, optional textarea with no colour, style or size class.

type alias ThemeSelectData msg =
{ themes : List Theme
, current : Theme
, presentation : ThemePresentation
, onSelect : Maybe (Theme -> msg)
}

A theme switcher. theme-controller declares no class groups, so this is all data. Page.theme supplies the initial data-theme; this control changes it.

= ThemeAsSelect
| ThemeAsRadios
| ThemeAsToggle
| ThemeAsCheckbox
| ThemeAsSwap
| ThemeAsDropdown

How a theme-controller is presented. daisyUI's docs examples (toggle, checkbox, radio group, select, swap, dropdown) are presentations of one control, not separate components.

ThemeAsDropdown is the only compact one: every other presentation renders one sibling control per theme, which is 35 controls wide with allThemes. It renders daisyUI's documented "Using a dropdown" markup — a btn trigger and a dropdown-content list of theme-controller radios.

type alias ToggleConfig msg =
{ color : Maybe Color
, size : Maybe Size
, ariaLabel : Maybe String
, tooltip : Maybe Tooltip
, onCheck : Maybe (Bool -> msg)
}

Groups of the daisyUI toggle component.

defaultToggleConfig : ToggleConfig msg

A toggle with no colour or size class.

type alias ToggleData =
{ checked : Bool }

Whether a toggle is on.

Leaf properties

These are never nodes. They are fields on a leaf's config, so the renderer always owns the wrapper element and the anchor can never go missing.

type alias Tooltip =
{ text : String
, config : TooltipConfig
}

A tooltip attached to one leaf.

type alias TooltipConfig =
{ color : Maybe Color
, placement : Maybe Placement
, modifiers : List Modifier
}

Groups of the daisyUI tooltip component.

defaultTooltipConfig : TooltipConfig

A tooltip with no colour or placement class.

tooltip : String -> Tooltip

A Tooltip with default styling.

tooltip "Delete this row"
defaultDropdownConfig : DropdownConfig

A dropdown with no placement class.

type alias Indicator =
{ config : IndicatorConfig
, payload : IndicatorPayload
}

An indicator attached to one leaf.

type alias IndicatorConfig =
{ placement : Maybe Placement }

Groups of the daisyUI indicator component.

defaultIndicatorConfig : IndicatorConfig

An indicator with no placement class.

= IndicatorBadge BadgeConfig String
| IndicatorStatus StatusConfig

What sits in the indicator-item.

type alias MaskConfig =
{ style : Maybe Style
, modifiers : List Modifier
}

Groups of the daisyUI mask component. A clip-path shape applied to one existing element.

defaultMaskConfig : MaskConfig

A mask with no shape class.

type alias AuraConfig =
{ style : Maybe Style
, size : Maybe Size
}

Groups of the daisyUI aura component. A decorative border light around one existing element.

defaultAuraConfig : AuraConfig

An aura with no style or size class.

Overlays

type Overlay msg
= Modal (ModalConfig msg) (List (Block msg))
| Drawer DrawerConfig (List (Section msg))
| Toast ToastConfig (List (Block msg))

The only three components that may float over the page. They live in Page.overlays and nowhere else, and the renderer draws them after every section in one fixed wrapper, in the order drawer, modal, toast.

type alias ModalConfig msg =
{ placement : Maybe Placement
, modifiers : List Modifier
, id : String
, title : Maybe String
, actions : List (Leaf msg)
, onClose : Maybe msg
}

Groups of the daisyUI modal component. actions is rendered into the modal-action part, so a modal's buttons cannot drift out of it.

onClose is fired when the browser closes the dialog: pressing Escape, or the native close event. The renderer draws the modal with daisyUI's recommended dialog method (<dialog class="modal">), which is what makes Escape and the focus trap work at all; the application still owns visibility through SModal.Open, and onClose is how it learns to drop it.

defaultModalConfig : ModalConfig msg

A closed, untitled modal with the id "daisy-modal" that reports nothing when it closes.

type alias DrawerConfig =
{ placement : Maybe Placement
, modifiers : List Modifier
, id : String
, toggleLabel : String
}

Groups of the daisyUI drawer component. The variant group (is-drawer-open: / is-drawer-close:) is a pair of selector prefixes, not classes an element can carry, so it has no field here.

defaultDrawerConfig : DrawerConfig

A closed drawer with the id "daisy-drawer".

type alias ToastConfig =
{ placement : Maybe Placement }

Groups of the daisyUI toast component.

defaultToastConfig : ToastConfig

A toast in daisyUI's default corner.

Fixed page chrome

type alias Dock msg =
{ config : DockConfig
, items : List (DockItem msg)
}

A viewport-fixed bottom navigation bar. It is a field on Page rather than a section, because in a section it would overlap the content it sits on.

type alias DockConfig =
{ size : Maybe Size }

Groups of the daisyUI dock component. Its single modifier (dock-active) belongs on an item, so it is a flag on DockItem.

defaultDockConfig : DockConfig

A dock with no size class.

type alias DockItem msg =
{ icon : Maybe String
, label : String
, active : Bool
, onClick : Maybe msg
}

One dock button. Its label becomes the dock-label part.

type alias Fab msg =
{ config : FabConfig
, main : Leaf msg
, mainAction : Maybe (Leaf msg)
, actions : List (Leaf msg)
, close : Maybe (Leaf msg)
}

A viewport-fixed floating action button, with the fab-main-action and fab-close parts.

main is the trigger the user sees when the fab is closed. mainAction is the separate button daisyUI marks fab-main-action, which stays in place once the speed dial is open; the part class goes on that leaf itself, which is where every daisyUI example puts it.

type alias FabConfig =
{ modifiers : List Modifier }

Groups of the daisyUI fab component.

defaultFabConfig : FabConfig

A fab with no flower class.