Documentation
¶
Overview ¶
Package headless is the structure and accessibility half of a design system: the tags, the roles, the labelling relationships, the state attributes and the hooks a runtime binds to. It renders no classes and ships no CSS.
The split exists because structure and styling have different lifetimes and different reviewers. Whether a password field's reveal button announces what it will do next, whether a field's error is tied to its input by aria-describedby, whether a pager says which page is current — none of that changes when the palette does, and all of it is testable without rendering a pixel (a11y_test.go, harness_test.go). A class map is then free to be redrawn, or replaced entirely, without putting a single accessibility guarantee back at risk.
A component here is a pure function from its props and a Classes to HTML. The Classes decides what class each named Part carries; a nil Classes renders the same markup with no classes at all, which is what "headless" means and what the goldens pin. Seven things are named in a component's contract, and the harness checks each: its Parts, its runtime hooks (data-hui-*), what a caller may set on its Parts (Attrs, Slots, Binds), its Strings, and for a component that changes in-page state, an Island. See box.go, strings.go and island.go.
The package is SSR-first and hydrates incrementally, the same model as the rest of the framework (core-ui/ARCHITECTURE.md): first paint is the full markup, behaviour is armed by hook on arrival, and a state change is an island RPC on the element that keeps its href or action for a reader with no script. Its dependencies are core-ui/html, core/render and core-ui/interactive (the signal attribute allow-list a Bind is checked against), plus the agents inventory registration every framework subpackage carries.
The behaviour module exists: behavior.go registers it under the name "headless" through the same seam a stylesheet uses (registry.RegisterBehavior), the host serves it at /__gofastr/runtime/headless.js, and the kernel loads it when one of its markers is on the page. The styled layer's adoption has begun: framework/ui's Button family renders through this package dressed with the fui-button class map, and the remaining families follow in their own changes.
Index ¶
- Constants
- func Alert(p AlertProps, s Classes) render.HTML
- func Attrs(pairs map[string]string) html.Attrs
- func BackToTop(p BackToTopProps, s Classes) render.HTML
- func Badge(p BadgeProps, s Classes) render.HTML
- func Breadcrumbs(p BreadcrumbsProps, s Classes) render.HTML
- func Button(p ButtonProps, s Classes) render.HTML
- func Card(p CardProps, s Classes, body ...render.HTML) render.HTML
- func Carousel(p CarouselProps, s Classes) render.HTML
- func Choice(p ChoiceProps, s Classes) render.HTML
- func Cluster(p ClusterProps, s Classes, children ...render.HTML) render.HTML
- func Color(p ColorProps, s Classes) render.HTML
- func Combobox(p ComboboxProps, s Classes) render.HTML
- func ConditionalField(p ConditionalFieldProps, s Classes, children ...render.HTML) render.HTML
- func Container(p ContainerProps, s Classes, children ...render.HTML) render.HTML
- func Counter(p CounterProps, s Classes) render.HTML
- func Describe(id, hint, errText string) (describedBy, hintID, errID string)
- func DetailList(p DetailListProps, s Classes) render.HTML
- func Disclosure(p DisclosureProps, s Classes) render.HTML
- func Divider(p DividerProps, s Classes) render.HTML
- func El(tag string, s Classes, p Part, own html.Attrs, children ...render.HTML) render.HTML
- func EmptyState(p EmptyStateProps, s Classes) render.HTML
- func Field(p FieldProps, s Classes, build func(FieldControl) render.HTML) render.HTML
- func FieldRow(s Classes, fields ...render.HTML) render.HTML
- func Fieldset(p FieldsetProps, s Classes, fields ...render.HTML) render.HTML
- func FileUpload(p FileUploadProps, s Classes) render.HTML
- func Flag(a html.Attrs, name string, on bool) html.Attrs
- func Form(p FormProps, s Classes, fields ...render.HTML) render.HTML
- func Gallery(p GalleryProps, s Classes) render.HTML
- func Grid(p GridProps, s Classes, children ...render.HTML) render.HTML
- func Group(p GroupProps, s Classes, items ...render.HTML) render.HTML
- func Input(p InputProps, s Classes) render.HTML
- func InputGroup(p InputGroupProps, s Classes, children ...render.HTML) render.HTML
- func Internal(own html.Attrs) html.Attrs
- func JSONTree(p JSONTreeProps, s Classes) render.HTML
- func LightboxViewer(p LightboxViewerProps, s Classes) render.HTML
- func Mark(a html.Attrs, names ...string) html.Attrs
- func Menu(p MenuProps, s Classes) render.HTML
- func Merge(a, b html.Attrs) html.Attrs
- func MultiSelect(p MultiSelectProps, s Classes) render.HTML
- func NotificationBell(p NotificationBellProps, s Classes) render.HTML
- func NumberInput(p NumberInputProps, s Classes) render.HTML
- func OptimisticAction(p OptimisticActionProps, s Classes) render.HTML
- func Own(h render.HTML) render.HTML
- func PageHeader(p PageHeaderProps, s Classes) render.HTML
- func Pagination(p PaginationProps, s Classes) render.HTML
- func PaneHost(p PaneHostProps, s Classes) render.HTML
- func Password(p PasswordProps, s Classes) render.HTML
- func Progress(p ProgressProps, s Classes) render.HTML
- func Rail(p RailProps, s Classes) render.HTML
- func RangeSlider(p RangeSliderProps, s Classes) render.HTML
- func Rating(p RatingProps, s Classes) render.HTML
- func Register(sp Spec)
- func Repeater(p RepeaterProps, s Classes) render.HTML
- func Safe(extra html.Attrs, owned ...string) html.Attrs
- func Section(p SectionProps, s Classes, children ...render.HTML) render.HTML
- func Select(p SelectProps, s Classes) render.HTML
- func Sidebar(p SidebarProps, s Classes) render.HTML
- func SidebarDrawerTrigger(p SidebarProps, s Classes) render.HTML
- func SidebarRegion(p SidebarProps, s Classes) render.HTML
- func Skeleton(p SkeletonProps, s Classes) render.HTML
- func Slider(p SliderProps, s Classes) render.HTML
- func SortableItems(p SortableListProps, s Classes) render.HTML
- func SortableList(p SortableListProps, s Classes) render.HTML
- func Spacer(p SpacerProps, s Classes) render.HTML
- func Spinner(p SpinnerProps, s Classes) render.HTML
- func Stack(p StackProps, s Classes, children ...render.HTML) render.HTML
- func StatCard(p StatCardProps, s Classes) render.HTML
- func StepWizard(p StepWizardProps, s Classes) render.HTML
- func Steps(p StepsProps, s Classes) render.HTML
- func Switch(p SwitchProps, s Classes) render.HTML
- func SystemBanner(p SystemBannerProps, s Classes) render.HTML
- func Table(p TableProps, s Classes) render.HTML
- func TableOfContents(p TableOfContentsProps, s Classes) render.HTML
- func Tabs(p TabsProps, s Classes) render.HTML
- func TabsMaxPanels() int
- func Tag(p TagProps, s Classes) render.HTML
- func TagInput(p TagInputProps, s Classes) render.HTML
- func Textarea(p TextareaProps, s Classes) render.HTML
- func Timeline(p TimelineProps, s Classes) render.HTML
- func Toast(p ToastProps, s Classes) render.HTML
- func ToastStack(p ToastStackProps, s Classes) render.HTML
- func ToggleAction(p ToggleActionProps, s Classes) render.HTML
- func Toolbar(p ToolbarProps, s Classes, children ...render.HTML) render.HTML
- func ToolbarGroup(s Classes, label string, children ...render.HTML) render.HTML
- func ToolbarSearch(p ToolbarSearchProps, s Classes, child render.HTML) render.HTML
- func ToolbarSpacer(s Classes) render.HTML
- func Tree(p TreeProps, s Classes) render.HTML
- func ValidationSummary(p ValidationSummaryProps, s Classes) render.HTML
- type Action
- type AlertProps
- type BackToTopProps
- type BadgeProps
- type BadgeTone
- type Bind
- type Binds
- type Box
- type Breadcrumb
- type BreadcrumbsProps
- type ButtonProps
- type CardProps
- type CarouselProps
- type CarouselSlide
- type Case
- type ChoiceProps
- type Classes
- type ClusterProps
- type ColorProps
- type Column
- type ComboboxOption
- type ComboboxProps
- type ConditionalFieldProps
- type ContainerProps
- type CounterProps
- type DetailListProps
- type DetailRow
- type DisclosureProps
- type DividerProps
- type EmptyStateProps
- type Event
- type FieldControl
- type FieldError
- type FieldProps
- type FieldsetProps
- type FileUploadProps
- type FormProps
- type GalleryItem
- type GalleryLightbox
- type GalleryProps
- type GridProps
- type GroupProps
- type InputGroupProps
- type InputProps
- type Island
- type JSONTreeProps
- type Kit
- type LightboxViewerProps
- type LightboxWiring
- type Live
- type MenuAction
- type MenuItem
- type MenuProps
- type MultiSelectOption
- type MultiSelectProps
- type NotificationBellProps
- type NumberInputProps
- type OptimisticActionProps
- type Option
- type PageHeaderProps
- type PaginationProps
- type PaneHostProps
- type Part
- type PartAttrs
- type Parts
- type PasswordProps
- type ProgressProps
- type RailItem
- type RailProps
- type RangeSliderProps
- type RatingProps
- type RepeaterItem
- type RepeaterProps
- type Row
- type SectionProps
- type SelectProps
- type SidebarItem
- type SidebarProps
- type SkeletonProps
- type SliderProps
- type Slots
- type SortDir
- type SortableItem
- type SortableListProps
- type SpacerProps
- type Spec
- type SpinnerProps
- type StackProps
- type StatCardProps
- type Step
- type StepWizardProps
- type StepsProps
- type Strings
- type SwitchProps
- type SystemBannerProps
- type TOCItem
- type Tab
- type TableOfContentsProps
- type TableProps
- type TabsProps
- type TagInputProps
- type TagProps
- type TextareaProps
- type TimelineProps
- type ToastProps
- type ToastStackProps
- type ToggleActionProps
- type ToolbarProps
- type ToolbarSearchProps
- type TreeNode
- type TreeProps
- type ValidationSummaryProps
- type WizardStep
Constants ¶
const BehaviorName = "headless"
BehaviorName is the runtime module the hooks are bound by. The host serves it at /__gofastr/runtime/headless.js and the kernel loads it when one of its markers is on the page.
const CarouselBehaviorName = "headless-carousel"
CarouselBehaviorName is the runtime module that binds the carousel's data-hui-* hooks: the active slide, the controls, the status sentence, the auto-rotation with its pauses, and the keyboard. It replaces the retired core-ui/runtime carousel module.
const CollectionsBehaviorName = "headless-collections"
CollectionsBehaviorName is the runtime module that binds the tag input's and the repeater's data-hui-* hooks. It replaces the retired core-ui/runtime taginput and formrepeater modules.
const ComboboxBehaviorName = "headless-combobox"
ComboboxBehaviorName is the runtime module that binds the combobox's data-hui-* hooks and owns its keyboard contract. It replaces the retired core-ui/runtime combobox module; the RPC debouncing and the signal swap stay the kernel's data-fui-rpc contract.
const ControlsBehaviorName = "headless-controls"
ControlsBehaviorName is the runtime module that binds the stateful form controls' data-hui-* hooks. The host serves it at /__gofastr/runtime/headless-controls.js and the kernel loads it when one of its markers is on the page; it replaces the retired core-ui/runtime numberinput, slider, rangeslider and animatedcounter modules.
const DisclosureBehaviorName = "headless-disclosure"
DisclosureBehaviorName is the runtime module that binds the disclosure family's data-hui-* hooks (including the close-on-navigate for non-persistent disclosures). It replaces the retired core-ui/runtime disclosure module wholesale.
const FeedbackBehaviorName = "headless-feedback"
FeedbackBehaviorName is the runtime module that binds the feedback family's data-hui-* hooks and owns the toast stack runtime the kernel's response-header path dispatches into. It replaces the retired core-ui/runtime copy, toasts and networkretrybanner modules; the kernel's loadModule('headless-feedback') retarget is what keeps NS.toast, _initToasts and the X-Gofastr-Toast dispatch working.
const MenuBehaviorName = "headless-menu"
MenuBehaviorName is the runtime module that binds the menu's data-hui-* hooks and owns the menu keyboard contract. It replaces the retired core-ui/runtime menu module.
const MultiSelectBehaviorName = "headless-multiselect"
MultiSelectBehaviorName is the runtime module that binds the multiselect's data-hui-* hooks: the chips strip (rebuilt from the checkboxes' own state after every change), the chip remove buttons and the click-outside close. It replaces the retired core-ui/runtime multiselect module.
NavigationBehaviorName is the runtime module that binds the page-level controls' data-hui-* hooks: the back-to-top link, the theme (colour-scheme) control group, and the page's keyboard shortcuts. It replaces the retired core-ui/runtime backtotop, themeswitch and shortcut modules.
const PaneHostBehaviorName = "headless-panehost"
PaneHostBehaviorName is the runtime module that binds the pane host's data-hui-* hooks: the open/close/swap lifecycle, the focus handoff and restore, the responsive drawer (its Tab trap over the kernel's focus selector and the kernel's refcounted scroll lock), the programmatic API and events, and the query deep link. It replaces the retired core-ui/runtime panehost module.
const RailBehaviorName = "headless-rail"
RailBehaviorName is the runtime module that binds the rail's data-hui-* hooks and owns the shared IntersectionObserver the table of contents arms through. It replaces the retired core-ui/runtime scrollspy module.
const SidebarBehaviorName = "headless-sidebar"
SidebarBehaviorName is the runtime module that binds the sidebar's data-hui-* hooks: the collapse state (persisting only when a storage key rides the root — server-owned otherwise) and the toggle. The mobile drawer is the widget runtime's. It replaces the retired core-ui/runtime sidebar module.
const SortableListBehaviorName = "headless-sortablelist"
SortableListBehaviorName is the runtime module that binds the sortable list's data-hui-* hooks: the drag-and-drop and keyboard reorder, the polite announcements (from Strings that travel as attributes), and the commit/rollback/versioned-409 conflict path. It replaces the retired core-ui/runtime sortablelist module.
const SpecimenGlyph render.HTML = `<svg width="16" height="16" viewBox="0 0 16 16" fill="none" ` +
`stroke="currentColor" stroke-width="1.5" aria-hidden="true">` +
`<circle cx="8" cy="8" r="6.25"/><path d="M5.5 8.25 7.25 10l3.25-3.5"/></svg>`
SpecimenGlyph is the icon a fixture draws when a component takes one.
It is a real 16×16 svg, because "<svg/>" is not. An svg with no width, no height and no viewBox has no intrinsic size, so CSS falls back to the replaced-element default of 300×150 — and every fixture in this package once used the short form. A badge meant to be a pill drew 340px wide and an alert's header grew a 140px hole between its title and its text.
Nothing in the markup was wrong. The classes were right, the parts were right, the audit was clean, and the page still looked broken — which is the whole reason a fixture has to be something a caller would plausibly pass, not the shortest string that type-checks.
const TOCBehaviorName = "headless-toc"
TOCBehaviorName is the runtime module that binds the table of contents' data-hui-* hooks. It replaces the retired core-ui/runtime toc module: the list is server-rendered from explicit items now, so what the module owns is only the active-entry state.
const TabsBehaviorName = "headless-tabs"
TabsBehaviorName is the runtime module that binds the tab strips' data-hui-* hooks and owns their keyboard contract. It replaces the retired core-ui/runtime tabs module (loaded there only through the prefetch bridge; here it is a registered behaviour on the strip's own marker).
const TreeBehaviorName = "headless-tree"
TreeBehaviorName is the runtime module that binds the tree's data-hui-* hooks: the roving tabindex, the arrow/Home/End/type-ahead keyboard contract, and the expand/collapse that drives the same toggle button a click drives. It replaces the retired core-ui/runtime tree module.
const WhenBehaviorName = "headless-when"
WhenBehaviorName is the runtime module that binds ConditionalField's data-hui-when regions, split from the headless module to keep both under the byte budget. The when hooks it owns moved with it.
const WizardBehaviorName = "headless-wizard"
WizardBehaviorName is the runtime module that binds the step wizard's data-hui-* hooks. No old standalone module existed: the plain POST wizard needed none, and this one owns only the island path's focus restore and announcement.
Variables ¶
This section is empty.
Functions ¶
func Attrs ¶
Attrs is a small builder: it drops empty values, so a component can declare every attribute it might set in one place and let the zero value mean "absent" rather than "present and empty".
Boolean attributes are the exception — an empty string IS the value for disabled, required and friends — so those go through Flag.
func BackToTop ¶
func BackToTop(p BackToTopProps, s Classes) render.HTML
BackToTop renders the jump link.
The anchor is the whole contract: its href is the no-script destination, and the module that binds data-hui-back-to-top shows it past the threshold (through data-hui-back-to-top-visible, which no component renders — the module owns it), scrolls to the target, and returns focus to the link after the scroll. A stylesheet hides the link while the visible mark is absent, so the link appears when it is true and never flashes on a page still at its top.
func Breadcrumbs ¶
func Breadcrumbs(p BreadcrumbsProps, s Classes) render.HTML
Breadcrumbs renders the trail.
func Choice ¶
func Choice(p ChoiceProps, s Classes) render.HTML
Choice renders label > input + span(text). The label wraps the control, so clicking the text toggles it with no for/id pair to keep in sync — and the wrap itself is the accessible target, which is why the control's own small box already passes WCAG 2.5.8.
func Cluster ¶
Cluster renders a wrapping row.
A row of controls is not a Cluster: Toolbar aligns its children by construction, every child being control-height, and gives the search field the slack and the groups their labels. Cluster is for content that wraps — tags, badges, a byline's parts — where the row is a layout fact and nothing in it is a control.
func Color ¶
func Color(p ColorProps, s Classes) render.HTML
Color renders the colour control as an affix shell: the native picker reduced to a swatch beside a readonly hex readout, so the field reads as one control-height input instead of a bare OS widget. The swatch carries no name and never submits; the hex text is the value and the swatch is a picker bound to it, which is also why the two never swap roles. The hex readout's tabindex stays 0 (it IS the control); the swatch is taken out of the tab order (tabindex -1) so there is exactly one focus target and one submitted value. There is no Required notion here because type=color always has a value; a required field that cannot bite would be a lie.
func Combobox ¶
func Combobox(p ComboboxProps, s Classes) render.HTML
Combobox renders the search input with its listbox.
func ConditionalField ¶
ConditionalField renders the region — VISIBLE.
It carries no hidden attribute, because hiding it here would make the dependent field reachable only after script had run: a page with script disabled, a reader mode, a crawler and a first paint before script arms would all see a field that never arrived. The module that binds data-hui-when hides and shows it as the watched field changes; the hiding is the platform's own hidden attribute, restated by a stylesheet at a specificity nothing here can beat.
It is a div and adds no semantics: the fields inside arrive with their own labels, and a region name would be read before each one.
func Counter ¶
func Counter(p CounterProps, s Classes) render.HTML
Counter renders the value between its two buttons.
func Describe ¶
Describe wires an input to its error and its hint by id, returning the aria-describedby value. This is the whole reason a field is a component and not three elements in a row: the relationship has to be built from the same ids the elements are given, in one place, or it silently rots.
The error comes first, so the correction is read before the rule it violated; both ids ride in one attribute whenever both are set — the hint is the rule the value must obey, and dropping it from the description exactly when it was broken is dropping it when the reader needs it most.
func DetailList ¶
func DetailList(p DetailListProps, s Classes) render.HTML
DetailList renders the record as a <dl>.
The description list is the contract: a <dt> and the <dd> after it are one pair to assistive technology in a way a grid of divs never is, and the pair survives every restyling because the relationship is the element, not the layout. A row wrapper keeps each pair addressable for the class map without breaking that pairing — a div between dt and dd is valid HTML and keeps the pair's reading order intact.
func Disclosure ¶
func Disclosure(p DisclosureProps, s Classes) render.HTML
Disclosure renders the native details disclosure.
func Divider ¶
func Divider(p DividerProps, s Classes) render.HTML
Divider renders the line.
A meaningful one is an <hr>: the element already means "a thematic break", so no role has to be claimed. A decorative one is a div that says nothing, because the alternative — an <hr> with aria-hidden — is a semantic element being told to lie.
func El ¶
El builds one element: the part's class, then the caller's attrs, then children. Attrs the component owns always win over ExtraAttrs, which is why they are passed separately.
func EmptyState ¶
func EmptyState(p EmptyStateProps, s Classes) render.HTML
EmptyState renders the nothing-here.
The root is role="region", because an empty result is a place the reader arrives at and needs to recognise — "this is the empty state, its name is the reason" — and an unnamed div is a place nothing can name. An explicit ID names the heading `<ID>-title` and points the region's aria-labelledby at it, so the name and the heading cannot disagree; without one the region is named by an aria-label equal to the Title and the heading carries no id — a title-derived id is not unique, and two empty panels with one title on a page would collide.
func Field ¶
func Field(p FieldProps, s Classes, build func(FieldControl) render.HTML) render.HTML
Field renders the group. build receives the wiring and returns the control.
func FileUpload ¶
func FileUpload(p FileUploadProps, s Classes) render.HTML
FileUpload renders the control.
The input is a real <input type="file">, visually hidden and fully present: focusable, labelled, keyboard-operable, and submitting with the form. The drop zone is its <label>, so clicking anywhere in the zone opens the picker with no script at all.
Dragging is an ENHANCEMENT and never the only route. WCAG 2.5.7 (Dragging Movements, AA since 2.2) says any drag action needs a single-pointer alternative, and the population that cannot drag — tremor, switch access, head pointer, touch with a stylus — is larger than the population that finds dragging convenient. Here the alternative is the same control: the zone is a label, so it is a click target before any script runs.
The chosen files are announced through a polite live region, because picking a file otherwise changes nothing a screen reader notices: the input's value is not read back, and the list of names appears silently.
func Form ¶
Form renders the form.
The interesting part is what happens after a failed submit. The server re-renders with Errors set; the module that binds data-hui-form-errors then moves focus to the summary, which is role="alert" and tabindex="-1". Without that move, a screen reader user is left at the top of an unchanged-looking page with no indication anything happened — the single most common way an accessible-looking form is not one.
func Group ¶
Group renders the fieldset. The legend is a real <legend> inside a real <fieldset>: that pair is the native group semantic, naming every control inside without a single aria attribute.
func InputGroup ¶
InputGroup renders the joined row.
It is a div by default and deliberately adds no semantics: the controls inside are already labelled, and wrapping two labelled controls in a group with a third name means a screen reader reads the group name before each one. A name is added only when the caller says the group needs one.
func Internal ¶
Internal returns own with data-fui-internal set: the attribute an owned style's @scope stops at. A component puts it on each subtree that holds none of the caller's content (a header built from a Title string, a control's input, a dismiss button), and never on an element that holds a slot, or on any ancestor of one: content passed in stays in the owner's reach. The component's root is never marked; an owner may place it. A mark under another mark is inert. own is not modified; nil is fine.
func JSONTree ¶
func JSONTree(p JSONTreeProps, s Classes) render.HTML
JSONTree renders the value as a collapsible tree.
func LightboxViewer ¶
func LightboxViewer(p LightboxViewerProps, s Classes) render.HTML
LightboxViewer renders the open viewer's body.
The three rendered signals — alt on the visually-hidden title, src on the image's src attribute and (for the download anchor) its href, caption on the figcaption — are the lightbox widget contract's own names: the deeplink a trigger carries (src=…&alt=…&caption=…) lands in them, and a viewer that renamed them would render a widget that never updates. The group parameter is not rendered: the behaviour module reads it from the signal store, not from markup.
func Mark ¶
Mark sets attributes whose PRESENCE is the value: the data-hui-* hooks a runtime binds to, and the HTML attributes that work the same way — hidden, popover, open, inert.
It exists because Attrs drops empty values, which is right for "absent means unset" and catastrophic here: the component renders with every option set and the attribute missing, so it is styled, labelled, announced, and either wired to nothing or visible when it should not be. That shipped five times in the package this one grew from — a popover attribute, a copy hook, a drop list, repeater rows, and hidden on an empty message — every one of them built through Attrs, and the fifth AFTER this helper existed, because the helper was thought of as being for hooks. It is not: it is for any attribute whose empty string is meaningful.
func MultiSelect ¶
func MultiSelect(p MultiSelectProps, s Classes) render.HTML
MultiSelect renders the checkbox-group disclosure.
func NotificationBell ¶
func NotificationBell(p NotificationBellProps, s Classes) render.HTML
NotificationBell renders the trigger.
The trigger is an anchor with a real destination — the no-script page goes to the notifications page, the script-enhanced one opens the popover, and the same element is both. The count the anchor's name says is the count the badge shows, so the news and the number cannot disagree.
func NumberInput ¶
func NumberInput(p NumberInputProps, s Classes) render.HTML
NumberInput renders the number field between its steppers.
func OptimisticAction ¶
func OptimisticAction(p OptimisticActionProps, s Classes) render.HTML
OptimisticAction renders the button. The headless module binds it through the kernel's action primitive: endpoint, method and both label parts are the data-hui-action-* hooks below, and a non-2xx rolls everything back with the shake the class map's stylesheet may hang on data-state="error".
func Own ¶
Own marks every top-level element of h data-fui-internal. It is for markup a component builds from its own config and hands to another component as slot content: framework/ui's default banner glyph, a form's submit row, a field's control. The receiving component cannot tell that markup from a caller's, so the composer says it here, and a slot whose content is wholly Own'd counts as the component's own (see ownedSlot): the element holding it is marked too.
Top-level text cannot carry an attribute and is left as it is, which also leaves the slot reachable: a composer that wants its text internal wraps it in an element first. Elements already marked are left alone.
func PageHeader ¶
func PageHeader(p PageHeaderProps, s Classes) render.HTML
PageHeader renders the page top.
The element is a plain <header>: role="banner" is the top-level page header's to claim, and whether this header is that one is a decision the page makes, not the header — so the component claims no role and the browser's header semantics stand.
func Pagination ¶
func Pagination(p PaginationProps, s Classes) render.HTML
Pagination renders prev / numbered pages / next. The current page carries aria-current="page" and the stylesheet styles the attribute, so state and appearance cannot disagree. Prev and next at the ends are disabled anchors: visible, named, and out of the tab order rather than gone.
The nav landmark itself is PartRoot and carries no class; the list inside it is PartPagination, which is where a caller's Class has always landed.
func Password ¶
func Password(p PasswordProps, s Classes) render.HTML
Password renders the affix shell: a div carrying the runtime's data-hui-affix hook, with a borderless input and a reveal button inside. The shell owns the one border, so nothing stacks a border on a border.
The reveal button is complete, correct markup — type=button so it never submits, an aria-label — but it is INERT until a runtime module exists to toggle the input's type and the button's own label. Nothing is wired on purpose: no inline script, no dead onclick, and no pretending it works before it does.
func RangeSlider ¶
func RangeSlider(p RangeSliderProps, s Classes) render.HTML
RangeSlider renders the two-thumb range pair.
func Rating ¶
func Rating(p RatingProps, s Classes) render.HTML
Rating renders the radio group.
The fieldset/legend and the radio inputs ARE the contract: native arrows move between choices, the form POSTs the chosen value, and every choice is named ("3 out of 5") — which is why no behaviour module exists for it. A second state owner would add nothing the radios do not already guarantee.
The choices render in REVERSE order (Max..1): the sheet's sibling selector cascades the highlight backward from the checked or hovered choice to every earlier one, with no script at all.
func Register ¶
func Register(sp Spec)
Register adds a component to the harness. Called from each component's own file, so the fixture lives beside the thing it describes and moves when it moves.
func Repeater ¶
func Repeater(p RepeaterProps, s Classes) render.HTML
Repeater renders the repeated rows with their add and remove controls.
The rows are ordinary form fields and the controls are named submit buttons, so the no-script page is not a degraded page: add and remove submit the surrounding form with the operation in the request, and the server re-renders. With an Island the same buttons carry the framework's RPC contract beside their submit semantics, the region swaps in place, and the module restores focus to the row's first control (a removal) or the add control (an addition).
func Safe ¶
Safe copies caller-supplied extras, dropping the keys a component owns so no caller can break its structure or its labelling, and the keys refused wherever a caller's attributes come in (see refused). Keys are stored folded, the way the browser reads them: NAME and name are one attribute, and stored as written a caller's NAME sorted ahead of the component's name, so the browser kept the caller's. One key under two spellings is refused rather than left to map order.
func Select ¶
func Select(p SelectProps, s Classes) render.HTML
Select renders the native dropdown. The chevron is the stylesheet's (appearance: none plus a drawn arrow), so the markup stays a plain select — no wrapper div to align against its neighbours.
func Sidebar ¶
func Sidebar(p SidebarProps, s Classes) render.HTML
Sidebar renders the shell: the data-hui-sidebar root the module owns, the drawer trigger, the inline column with the collapse toggle, and the region (see SidebarRegion) inside it.
func SidebarDrawerTrigger ¶
func SidebarDrawerTrigger(p SidebarProps, s Classes) render.HTML
SidebarDrawerTrigger renders the drawer-opening hamburger button on its own, for hosts that place it in their own chrome (the page header) instead of above the sidebar's inline column — pair it with SidebarProps.HideDrawerTrigger so the shell does not draw a second one. Same button and widget contract as the shell's own trigger (data-fui-open names the drawer widget); the styled component's class map carries the variant class the sheet's >= md hiding keys on — the button IS the component's root, so root overrides and binds land on it. Empty DrawerName renders nothing.
func SidebarRegion ¶
func SidebarRegion(p SidebarProps, s Classes) render.HTML
sidebarDrawerTrigger is the one implementation of the hamburger: SidebarRegion renders the navigation content alone — the title, the prepend slot, the nav landmark with the items, the footer — with no data-hui-sidebar shell hooks: a host slotting the region into its own chrome (a drawer body, a pinned panel) calls this directly, and the module never treats it as a sidebar root.
func Skeleton ¶
func Skeleton(p SkeletonProps, s Classes) render.HTML
Skeleton renders the placeholder.
The bars are aria-hidden, every one of them. A skeleton is a picture of content that does not exist yet, and a screen reader reading out eight empty boxes — or worse, announcing each shimmer as it animates — is strictly worse than silence. What it does instead is say "Loading apps" once, politely, and then wait.
This is also why the bars are not <p> or <div> full of nbsp: there is no text to read, so there should be no text.
func Slider ¶
func Slider(p SliderProps, s Classes) render.HTML
Slider renders the labelled range control.
func SortableItems ¶
func SortableItems(p SortableListProps, s Classes) render.HTML
SortableItems renders just the row elements without the <ol> wrapper, the fragment a conflict-recovery endpoint returns to replace a list's contents with the server's own rows. Empty items render an empty fragment: authoritative reconciliation may empty a column.
func SortableList ¶
func SortableList(p SortableListProps, s Classes) render.HTML
SortableList renders the list.
func Spacer ¶
func Spacer(p SpacerProps, s Classes) render.HTML
Spacer renders the space.
It is a <span>, not a div, because a contents list is a paragraph ("Restarts … 263" is one sentence of a list) and a div inside a <p> is a parse error the browser repairs by closing the paragraph — which splits the list into pieces nobody styled. It is aria-hidden and empty: the space is the whole content, and a screen reader user gets the term and the value as neighbours, which is the same fact the leader line draws for the eye.
func Spinner ¶
func Spinner(p SpinnerProps, s Classes) render.HTML
Spinner renders the indicator.
role="status" rather than role="progressbar": a progressbar promises a value, and a spinner has none — that is what makes it a spinner
func StatCard ¶
func StatCard(p StatCardProps, s Classes) render.HTML
StatCard renders the metric.
Label, value and trend are read in that order and the label is first for the same reason a form label precedes its control: the name arrives before the number, so "MRR: 48,200" is one fact instead of a number the reader has to look up.
func StepWizard ¶
func StepWizard(p StepWizardProps, s Classes) render.HTML
StepWizard renders the form, its rail and its controls.
func Steps ¶
func Steps(p StepsProps, s Classes) render.HTML
Steps renders a progress rail — a list of states, not a set of controls. Each step's data-state drives both its marker and the connecting line the stylesheet draws between markers, so the rail cannot disagree with the states; the current step also carries aria-current="step" for AT. Exactly one step may be current: an explicit State "current" on a step other than Current's is refused, because two current steps tell assistive technology the flow is in two places at once.
func Switch ¶
func Switch(p SwitchProps, s Classes) render.HTML
Switch renders a checkbox that looks like a track-and-thumb. The input keeps type=checkbox — it still submits like one — and role= switch states the shape to assistive tech. The track, the thumb and the motion are the stylesheet's, keyed off :checked, so nothing in this markup can fall out of step with the state.
func SystemBanner ¶
func SystemBanner(p SystemBannerProps, s Classes) render.HTML
SystemBanner renders the message.
role="status" rather than alert: a system message is important and must not interrupt. It is on screen at the top of the shell, and a polite region is read at the next pause — announcing itself over whatever the reader was doing would make the top of every page a shout. The offline banner is the one exception, and it is the exception because losing the connection is the one system message worth interrupting for: everything the reader does next will fail until it is back. It carries role="alert" and aria-live="assertive" both, as the framework banner it replaces did, so either attribute alone still says how urgent it is.
func Table ¶
func Table(p TableProps, s Classes) render.HTML
Table renders the list: one wrapper div (PartRoot) holding a focusable scroll region (PartScroll) around the table, and the footer, when there is one, as the region's sibling. The scroll region is the element a class map makes the horizontal scroll surface — the one a wide table on a narrow screen scrolls inside — and it is markup, not styling, because a scroll region that cannot take focus cannot be scrolled by keyboard.
The explicit ARIA roles stay on every element. They look redundant on a displayed <table> and are not: a cards collapse sets display:block on the table's elements, and a table element displayed as a block loses its implicit table semantics in Chromium and WebKit. The roles are what keep a collapsed table a table for assistive technology.
aria-sort is the only sort indicator rendered — ascending and descending on the active column, none on every other sortable one — and the stylesheet draws from the attribute, so state and appearance cannot disagree.
func TableOfContents ¶
func TableOfContents(p TableOfContentsProps, s Classes) render.HTML
TableOfContents renders the contents navigation.
func TabsMaxPanels ¶
func TabsMaxPanels() int
TabsMaxPanels exposes the ceiling to the styled layer, whose generated CSS covers exactly this many indices.
func TagInput ¶
func TagInput(p TagInputProps, s Classes) render.HTML
TagInput renders the chips, the draft input and the add control.
The chip list is a real list (role="list" of items) rather than a strip of hidden inputs the runtime converts on arrival: the values are visible on the first paint, each with its own named remove control, and the hidden inputs beside them are what the form submits. Enter and comma commit the draft; Backspace on an empty draft removes the last chip; the add control commits it for a reader whose keyboard has no handy Enter (a tablet's on-screen one) — all bound by the module, none of it required for the values already committed to be real.
func Textarea ¶
func Textarea(p TextareaProps, s Classes) render.HTML
Textarea renders the multiline control. The value is the content, not an attribute: setting both is what makes some browsers show the stale attribute after a reset.
func Timeline ¶
func Timeline(p TimelineProps, s Classes) render.HTML
Timeline renders the events as an ordered list.
Ordered, because the order is the content: these things happened in this sequence, and <ol> is what says so — a screen reader announces the count and the position, so "3 of 7" locates you in the history without seeing the line down the left.
The dots and the connecting line are aria-hidden. They are a picture of the ordering that the list already states, and announcing them would mean hearing "bullet" before every entry.
func ToastStack ¶
func ToastStack(p ToastStackProps, s Classes) render.HTML
ToastStack renders the region the toasts live in.
The stack carries the framework's data-fui-toast-stack name beside its own: the kernel's response-header toast path and the runtime's auto-mount look for the framework's name, and the module that owns the component lifecycle looks for this package's. One region, two contracts, because the kernel's half is infrastructure this package does not own.
func ToggleAction ¶
func ToggleAction(p ToggleActionProps, s Classes) render.HTML
ToggleAction renders the button. The headless module binds it through the kernel's action primitive, ships nothing itself but the initial state below, and mirrors committed onto aria-pressed from then on.
func Toolbar ¶
Toolbar renders a row of controls that aligns by construction: every child is control-height, so nothing needs aligning to anything else. Build children from ToolbarGroup, ToolbarSpacer and ToolbarSearch.
func ToolbarGroup ¶
ToolbarGroup clusters related controls under a visible label. An empty label omits the label span; the cluster remains.
func ToolbarSearch ¶
ToolbarSearch wraps the search field, the one child allowed to take the row's slack, in the GET form that submits it.
func ToolbarSpacer ¶
ToolbarSpacer pushes everything after it to the far end of the row.
func ValidationSummary ¶
func ValidationSummary(p ValidationSummaryProps, s Classes) render.HTML
ValidationSummary renders the summary that goes above a form.
This is the single highest-value accessibility component in a form, and the reasoning is worth stating in full.
When a form fails validation, a sighted user sees red appear near the fields. A screen reader user, unless told, hears nothing: focus is wherever it was, the page looks the same to the accessibility tree except for text that changed somewhere below. So the summary:
- is role="alert", which interrupts — this DID just happen, it is the one case where interrupting is correct;
- is tabindex="-1", so the server can send focus to it after a failed submit. Not focusable-by-tab, focusable-by-script: it must never become a tab stop for someone filling in the form;
- lists each error as a LINK to the field, because the value of the summary is getting to the field, not reading the list. The link moves focus to the control itself, so the next thing the user types goes in the right box.
Rendering it with no errors renders nothing: an empty "there is a problem" box that announces itself is a lie that interrupts.
Types ¶
type Action ¶
Action is the wiring a component admits through its request seam: the same type Button's Action prop takes, named here so a form's Request reads as what it is. Every key is checked for what it deserves at render; see formRequestAttrs.
type AlertProps ¶
type AlertProps struct {
// Tone names the kind of message: the class map turns it into colour
// through the root's "<part>--<tone>" variant. It is passed
// through, not interpreted; the tone word is what carries it to a
// reader.
Tone string
// ToneWord is the tone in words — "Error", "Warning", "Success".
// It is rendered for assistive tech and hidden visually, and it is
// the reason this component satisfies WCAG 1.4.1: colour may not
// be the only thing carrying meaning, and a red box is exactly
// that to anyone who cannot see the red.
//
// Empty means the Title already says which kind it is — "Deploy
// failed" needs no "Error:" in front of it — so the word is
// skipped rather than duplicated.
ToneWord string
// Title is the headline. Required: an alert with no headline is a
// coloured paragraph.
Title string
// Text is the detail, in prose.
Text string
// Body is the detail as markup — a list, a code sample, nested
// content that is not an action. It renders after Text; prose
// belongs in Text, and actions in Actions.
Body render.HTML
// Icon is decorative. The tone word carries the meaning.
Icon render.HTML
// Actions are the controls: retry, view logs, dismiss.
Actions render.HTML
// Live says whether this interrupts. See Live.
Live Live
// Focus moves focus here when the page loads.
//
// It is how a message that is ALREADY THERE gets announced. A live
// region announces changes; content present when the document
// loads is not a change, and role="alert" at load time is reported
// inconsistently across screen readers. After a form posts and the
// server redirects — the shape of every action in a
// server-rendered app — the confirmation is present at load, so
// the only reliable way to say it is to put the reader on it.
Focus bool
// DismissHref makes the alert dismissable with a link that keeps a
// real href, so dismissing needs no script and survives the page
// being reloaded. The label names what is being dismissed, because
// "Dismiss" three times in a row tells a screen reader user
// nothing.
DismissHref string
DismissLabel string
// Island is where the dismiss goes with script: dismissing is an
// in-page state change, so the × carries the RPC contract beside
// its href. Required when DismissHref is set; ignored otherwise.
Island Island
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on every part. Nothing here is
// fillable — Actions already takes the page's own controls, and
// everything else an alert draws is what a screen reader is given
// to tell one alert from another.
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
}
AlertProps is a message about something that happened, or is true.
type BackToTopProps ¶
type BackToTopProps struct {
// Href is where the link goes: a same-origin anchor, usually the
// top of the page or the main content's id. Required — a jump
// control with no destination is a button pretending to be one,
// and the no-script page would carry a dead link.
Href string
// Target, when set, is the element id the module reads the scroll
// sentinel from and scrolls to. An id, not a selector: the module
// resolves it, and an id here cannot become a query the way a
// selector string can.
Target string
// Label is the accessible name. Empty takes Strings.BackToTop;
// the glyph alone names nothing.
Label string
// Icon is the glyph. The default arrow is the structure's own; a
// caller's SVG replaces it.
Icon render.HTML
// Threshold is the scroll offset in CSS pixels past which the
// module shows the link. Zero takes the module's default;
// negative is refused.
Threshold int
// Smooth asks for smooth scrolling. The module downgrades to an
// instant jump under reduced motion; the preference is honoured,
// not overridden.
Smooth bool
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on the root, the icon and the label.
// Strings are not read — the name is the caller's Label.
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
}
BackToTopProps configures the page's way back to its top.
type BadgeProps ¶
type BadgeProps struct {
// Label is the visible text, and the whole of what a screen reader
// hears. Required.
Label string
// Icon renders before the label, and is decorative: the label is
// the accessible name, so an icon that repeated it would be read
// twice. Anything the icon means that the label does not say
// belongs in the label.
Icon render.HTML
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on the root and the icon.
Parts Parts
}
BadgeProps is a badge: a small status chip, not a fill. A badge has no tone of its own and says none: its label IS its meaning ("running", "3 unread", "beta"), and the tone a class map variant paints it is decoration for the word already there. An Alert prefixes its tone because its title may not say it; a badge whose colour means something its label does not say has the wrong label.
type BadgeTone ¶
type BadgeTone string
BadgeTone selects a badge's colour. It is class-map vocabulary: the structure does not care, the class map looks it up.
type Bind ¶
type Bind struct {
// Signal is the signal's name. Required.
Signal string
// Mode is "text" (the default: the part's text is the value),
// "html" (the part's HTML is the value, the trusted path an island
// fragment uses) or "attr" (one attribute is the value).
Mode string
// Attr is the attribute for mode "attr", and must be one the
// framework lets a signal write: any aria-*, or its allow-list.
// Empty otherwise.
Attr string
}
Bind keeps a part in step with one of the host framework's client signals: its runtime rewrites the part's text, its HTML, or one attribute whenever the signal changes. It is the third thing a caller may set on a part, beside slots and attrs, because a binding is neither: an attribute may not carry a data-fui-* key, on purpose, so the only way a part can follow a signal is to say so here, where it is typed, reviewable, lands on exactly one element, and cannot reach an attribute the runtime would execute.
type Box ¶
type Box struct {
Classes Classes
Slots Slots
Over PartAttrs
Binds Binds
// contains filtered or unexported fields
}
Box carries the three layers through a component's render. A zero Box with only a Classes behaves exactly as El always did, which is why adopting it is a per-component change and not a rewrite.
func (Box) El ¶
El renders one element with the part's class, the caller's attrs for that part, then the component's own attrs — in that order, so the component wins.
func (Box) Fill ¶
Fill returns the caller's content for a part, or the component's own when there is none.
func (Box) FillableOn ¶
FillableOn names the parts whose content a caller may replace — the same parts the spec lists as Fillable — so a text or html Bind can be refused on every other part at render, where the mistake is a panic with a reason. A Bind that rewrites content is a Slot with a timer: allowed where Slots are, and nowhere else.
type Breadcrumb ¶
type Breadcrumb struct {
// Text is the step's visible label. Required.
Text string
// Href is the step's destination. Empty on the last step (the
// current page names itself, it does not link to itself); a value
// on the last step links it unless Current is also set.
Href string
// Current marks the step as the current page whatever its Href:
// rendered as text with aria-current="page" rather than a link,
// for a page that appears in its own trail with a link.
Current bool
}
Breadcrumb is one step in the trail.
type BreadcrumbsProps ¶
type BreadcrumbsProps struct {
// Label names the navigation landmark. Empty takes
// Strings.BreadcrumbsLabel.
Label string
// Items are the steps, shallowest first. Required and non-empty:
// a trail with no steps is a landmark that says nothing.
Items []Breadcrumb
ID string
ExtraAttrs html.Attrs
// Parts: attrs on the root and the list. No part is fillable: the
// trail is the contract.
Parts Parts
Strings *Strings
}
BreadcrumbsProps configures the trail.
type ButtonProps ¶
type ButtonProps struct {
// Label is the visible text. An icon-only button leaves it empty
// and sets AriaLabel; a button with neither has no accessible name
// and is refused.
Label string
AriaLabel string
Icon render.HTML
// Suffix renders after the label — a keyboard hint, a count. It is
// the caller's markup, so whether it is announced is the caller's
// decision: a keyboard hint hides its glyphs and supplies words, a
// badge announces itself.
Suffix render.HTML
// Variant and Size are class-map vocabulary, passed through so the class map
// can look up "<part>--<variant>". The structure does not care.
Variant string
Size string
// Disabled is a real state here. A disabled anchor is not a thing
// in HTML, so Href + Disabled drops the href and says so with
// aria-disabled rather than leaving a live link that looks dead.
Disabled bool
Type string
Href string
// External, with Href, opens the link in a new tab with
// rel="noopener noreferrer" and owns target and rel: a caller's
// spelling of either — folded or not — cannot clobber the noopener
// contract.
External bool
// PopoverTarget names a popover this button opens. It is also what
// gives that popover its invoker, which is how the runtime places
// the panel beside this button.
PopoverTarget string
// HasPopup, when set, is the aria-haspopup value ("menu", "dialog").
HasPopup string
// Action is what the button DOES when the host framework's runtime
// is on the page: the data-fui-rpc attributes of one of its
// actions, as its Attrs() returns them, one of its local signal
// mutations (set, increment, toggle), or one of the wiring keys a
// page can put on any clickable — opening a widget or pane, firing
// a toast, writing the URL, deep-linking an open, prefetching a
// runtime module. It is a seam of its own rather than a use of
// ExtraAttrs, because ExtraAttrs is for what a page knows and a
// component cannot — a test id, a title — and Safe drops every
// data-fui-* key from it so a decoration can never become a
// request. An action is not decoration. Naming it makes it
// reviewable: a button that fires a request says so in its props,
// in one place, and the type refuses anything that is not a
// request or a wiring key.
//
// The request family (data-fui-rpc*, data-fui-confirm, the signal
// mutations) needs a button: an anchor carrying one is refused at
// render, because a link navigates and a button acts. The wiring
// keys may ride either tag.
Action html.Attrs
ID string
ExtraAttrs html.Attrs
// Parts is the caller's reach into this component's named parts:
// attributes on the root (a class appends, never replaces) and on
// the icon. The root is not fillable; the icon is caller markup
// already.
Parts Parts
}
ButtonProps is a button, or an anchor that looks like one.
type CardProps ¶
type CardProps struct {
// Title renders as a heading. Empty omits it, along with the whole
// header when Desc is empty too — an empty header is a stripe of
// padding that looks like a mistake.
Title string
// TitleTag is the heading level, "h3" by default. A card does not
// know how deep in the outline it sits, so a page that nests cards
// under an h2 says so here rather than letting every card claim
// the same level and leave the document with no structure to
// navigate by.
TitleTag string
Desc string
// Href makes the whole card one focusable link — the surface is
// the affordance. The contents render inside a single inner part,
// so the anchor wraps exactly what the card showed as a div. A
// href the anchor policy refuses is refused at render, naming the
// prop, the package's posture for every configured href
// (Alert.DismissHref, Form.Action, Table.Path): a rejected href is
// the developer's mistake, not a link to render dead.
Href string
ID string
ExtraAttrs html.Attrs
// Parts. The header is the one fillable part, and the rule it
// comes from is worth stating: a slot exists only where the
// component COMPOSES something a prop cannot express. A card's
// header is built from a title string and a description string,
// so a header that needs a control in it has no prop to arrive
// through. The body and the footer already take caller content, so
// a slot there would be a second way to do one thing — which is
// worse than none, because half the call sites will use each.
//
// Attrs are the opposite: they apply to every part, on every
// component, because adding an attribute cannot break a structure.
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
}
CardProps configures a card.
A card is the one component here with almost no accessibility surface, and saying so is the point of the type: the heading level is the only decision in it that a screen reader can be hurt by, and it is a decision the card cannot make alone.
type CarouselProps ¶
type CarouselProps struct {
// Label names the region. Required.
Label string
// Slides, in order. Required, at least one.
Slides []CarouselSlide
// Loop makes Next on the last wrap to the first (and vice versa).
// Default: the ends disable.
Loop bool
// AutoRotateMS, when > 0, advances every N ms. Negative refused.
AutoRotateMS int
// VisiblePerView shows N slides side-by-side (default 1; 0 or
// negative refused — a viewport of nothing is not a viewport).
VisiblePerView int
// NoDots hides the dot anchors.
NoDots bool
// NoArrows hides the prev/next controls.
NoArrows bool
ID string
ExtraAttrs html.Attrs
// Parts: attrs on the root, the track, the slides and the
// controls.
Parts Parts
Strings *Strings
}
CarouselProps configures the carousel.
type CarouselSlide ¶
type CarouselSlide struct {
// Content is the slide body. Required.
Content render.HTML
// Label is the slide's accessible label. Defaults to
// Strings.CarouselSlide ("Slide <n> of <total>") at render.
Label string
// ID is the slide's stable id. Empty takes "<trackID>-slide-<n>".
ID string
}
CarouselSlide is one entry.
type Case ¶
Case is one rendering of a component, with a reason for existing. The reason is not documentation: a case with nothing to show is a case that will be updated to match whatever the code does next.
type ChoiceProps ¶
type ChoiceProps struct {
// Type is "checkbox" or "radio".
Type string
// Name groups the choice. For a radio it IS the group; items that
// must act as one group share it, which is why the group helpers
// stamp it on every item.
Name string
// Value is what the choice submits when checked. Required for
// Radio: without distinct values a group cannot tell its options
// apart. A checkbox may leave it empty and submit "on", the HTML
// default.
Value string
// Label is the visible text beside the control. Required: an
// unlabelled choice is a bug, not a variant.
Label string
// Hint is secondary text under the label, for the consequence of
// the choice rather than its meaning.
Hint string
Checked bool
Disabled bool
ID string
// Extra attrs land on the input, the control that submits.
Extra html.Attrs
}
ChoiceProps configures one checkbox or radio.
type Classes ¶
Classes maps parts to class names. Nil is valid and renders unstyled.
type ClusterProps ¶
type ClusterProps struct {
Gap string
// Align is cross-axis: "center" by default in the class map, because a
// row of controls of different heights should line up on their
// middles.
Align string
// Justify is main-axis: "start", "between", "end".
Justify string
// NoWrap keeps the row on one line. Use it sparingly: a row that
// cannot wrap is a row that overflows on a phone, and horizontal
// page scroll is the failure this whole layer exists to prevent.
NoWrap bool
Tag string
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on the root.
Parts Parts
}
ClusterProps is horizontal flow that wraps: a row of buttons, a row of tags, a toolbar.
type ColorProps ¶
type ColorProps struct {
Name string
// Value is the colour as text, usually but not always #rrggbb.
Value string
Disabled bool
Invalid bool
// ID and extra attrs land on the hex text input, the control that
// submits.
ID string
Extra html.Attrs
DescribedBy string
// Parts: attrs and binds on the shell, the hex input and the
// swatch. Strings carry the swatch's name.
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
}
ColorProps configures a colour control.
type Column ¶
type Column struct {
// Key identifies the column: the value under SortParam in the
// sort href, and the key a Row's Cells are matched by. Required.
// Anything a query can encode is a legal Key — that is the point
// of building the href through net/url.
Key string
// Header is the visible column header text. May be empty: an
// actions or icon column. A header-less column that cannot be
// sorted is hidden from assistive tech; one that can is named
// from Strings.TableSortBy, because an anchor with no text is a
// control with no name.
Header string
// Sortable makes the header a sort control: an anchor that
// re-submits the screen's query with this column's Key and the
// next direction.
Sortable bool
// HeaderAttrs and CellAttrs add attributes to this column's <th>
// and to every <td> under it, through the same sanitiser as
// ExtraAttrs (Safe): data-fui-* keys, style, id and class are
// dropped, names are stored folded, and one attribute under two
// spellings is refused.
HeaderAttrs html.Attrs
CellAttrs html.Attrs
// Variant is class-map vocabulary for the whole column: looked
// up as "<part>--<variant>" on this column's <th> (PartHeader)
// and each of its <td> (PartCell), so a class map can align a
// column's text or shade its column without the structure
// caring. Empty means none.
Variant string
}
Column describes one table column.
type ComboboxOption ¶
type ComboboxOption struct {
// ID is the option's stable id. Empty takes "<listboxID>-opt-<n>".
ID string
// Value is what a pick writes into the input. Empty takes Label.
Value string
// Label is the option's visible text. Required.
Label string
// Meta is secondary text beside the label (a path, a kind).
Meta string
// Href turns the option into an anchor: picking it navigates.
// Unsafe schemes drop the navigation affordance entirely (the
// pick still fills the input).
Href string
// Disabled removes the option from keyboard navigation.
Disabled bool
}
ComboboxOption is one row in the listbox.
type ComboboxProps ¶
type ComboboxProps struct {
// ID is the input's element id. Required; the listbox takes
// "<ID>-listbox".
ID string
// Name is the form-submit name on the input. Required.
Name string
// Label names the input. Required.
Label string
// Placeholder for the input.
Placeholder string
// Island is the typed in-page results contract: the endpoint that
// re-renders the listbox and the signal the region is bound to.
// Optional — a static Options list needs no island; the no-script
// path is the same-origin GET form below either way.
Island *Island
// NoScriptAction is the form's action URL, the no-script
// destination: same-origin, a GET that submits the query. Required
// when Island is set (a reader without script must still reach the
// results); refused when it is "#".
NoScriptAction string
// Options is a static list the module filters client-side. Takes
// precedence over the Island (no round-trip fires).
Options []ComboboxOption
// DebounceMS bounds the input debounce. Zero takes 250; negative
// is refused.
DebounceMS int
ExtraAttrs html.Attrs
// Parts: attrs on the root, the input and the listbox. The
// listbox's content is the Options' — not fillable.
Parts Parts
Strings *Strings
}
ComboboxProps configures the combobox.
type ConditionalFieldProps ¶
type ConditionalFieldProps struct {
// When is the NAME of the watched field. Required: a region that
// watches nothing is always shown, which is a div.
//
// The scope the runtime reads the name in: the region's own form
// first — two forms can each carry a "plan" control and the region
// follows the one it belongs to — and, when the region has no
// form or its form holds no control of that name, the document,
// preferring controls no form owns (a page-level switch) and
// otherwise the first in document order.
When string
// Value is the watched field's value that shows the region.
// Required: shown on every value is the same as always shown.
// The empty string is refused, so "show when unchecked" — a
// checkbox whose unchecked value is "" — is not expressible here;
// watch a select or a radio pair whose values are both stated
// instead.
Value string
ID string
ExtraAttrs html.Attrs
}
ConditionalFieldProps is a region shown when another field has a given value.
type ContainerProps ¶
type ContainerProps struct {
// Size names the measure — "sm", "md", "lg", "full".
Size string
Tag string
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on the root.
Parts Parts
}
ContainerProps is the page's measure: a maximum width and the gutters that keep content off the edge of the screen.
type CounterProps ¶
type CounterProps struct {
// Signal is the client signal the count lives in. Required: the
// buttons' whole contract is that they change a value the page
// already holds, and the display's contract is that the same
// signal writes it.
Signal string
// Name, when set, renders the value as a named number input the
// surrounding form submits — the no-script path. The input's
// value follows the signal the same way the span does, so the
// two variants are one control.
Name string
// Value is the count's first value, seeded into the markup.
Value int
// Step is the increment size. Default 1; must be positive.
Step int
// Label names the group for assistive technology. Empty takes
// Strings.CounterLabel: three controls with no group name is a
// label, a minus, a number and a plus to nobody, so the default
// names them.
Label string
// AnimateFrom, when set, is the value the count animates from on
// arrival; Value is where it lands, and Value stays the SSR text.
// Nil means no animation. The hooks it renders are bound by the
// headless-controls module, which respects reduced motion and
// never owns the number.
AnimateFrom *int
// DurationMS bounds the animation. Zero takes the module's
// default; negative is refused.
DurationMS int
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on the root and the value. Strings
// carry the group's name and the two buttons'.
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
}
CounterProps configures a client-side counter.
type DetailListProps ¶
type DetailListProps struct {
// Rows are the pairs, in reading order. At least one.
Rows []DetailRow
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on the list, its rows and their terms
// and values.
Parts Parts
}
DetailListProps is a record read as label/value pairs.
type DetailRow ¶
type DetailRow struct {
// Label is the term. Required: a value with no term is a fact
// nobody can look up.
Label string
// Value is the value, and it may be markup — a status badge, a
// link, an empty-value dash. Required: render the empty-value
// dash for a missing value, so the absence is deliberate.
Value render.HTML
}
DetailRow is one labelled value: the term in a <dt>, the value in the <dd> that follows it.
type DisclosureProps ¶
type DisclosureProps struct {
// Summary is the always-visible controller. Required and
// non-blank: a details whose summary says nothing is a button with
// no name.
Summary render.HTML
// Content is the revealed panel.
Content render.HTML
// Open renders the details expanded.
Open bool
// Trap opts the open disclosure into focus containment: Tab walks
// inside it and comes back, the drawer posture. The containment is
// the widget runtime's own (the kernel's focus selector), armed by
// the module while the disclosure is open.
Trap bool
// Name, when set, is the details element's name attribute: the
// browser groups disclosures that share it and opens one at a time
// (the native accordion) — opening one closes the others with no
// script at all. Control bytes are refused: the value is a group
// key the browser matches verbatim.
Name string
// PersistKey, when set, keeps the open state across client-side
// navigation AND restores it on arrival from the session store,
// namespaced and component-encoded so two disclosures never share
// one key. Empty means the ordinary dialect: closed by a
// navigation, whatever the reader left open.
PersistKey string
ID string
ExtraAttrs html.Attrs
// Parts: attrs on the root, the summary and the panel. The summary
// is fillable — its content is the caller's — and so is the panel.
Parts Parts
}
DisclosureProps configures one disclosure.
type DividerProps ¶
type DividerProps struct {
// Label puts text in the break ("or"). A labelled divider is
// always meaningful, so it is never decorative.
Label string
// Vertical draws it along the block axis, for a divider inside a
// row.
Vertical bool
// Decorative says this line groups nothing — it is a flourish, and
// is hidden from assistive tech. Without it a screen reader
// announces "separator" at every line on the page.
Decorative bool
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on the root, the lines and the label.
Parts Parts
}
DividerProps is a line between things.
type EmptyStateProps ¶
type EmptyStateProps struct {
// Title is the heading. Required: it is also the region's name.
Title string
// Level is the heading level, 3 by default. An empty state nests
// inside a section; one mounted as the whole page under the h1
// says 2 here.
Level int
// Description is the supporting line: what would be here, or what
// to do about it.
Description string
// Action is the way out — "New app", "Clear the filter". A dead
// end with no action is a page the reader can only leave with the
// back button.
Action render.HTML
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on every part the state draws.
Parts Parts
}
EmptyStateProps is the page a list with nothing in it shows instead of the list.
type Event ¶
type Event struct {
// Title is what happened. Required.
Title string
// Detail is the supporting line.
Detail string
// When is the human-readable time ("3 days ago", "18:22").
When string
// Machine is the machine-readable timestamp for <time datetime>,
// RFC 3339. Without it "3 days ago" is a string no assistive tech,
// translation layer or scraper can resolve to a moment.
Machine string
// Tone lets the class map colour the marker — "success", "danger".
Tone string
// Meta is the secondary line beside the title — an actor, a
// relative time ("by dom", "2h ago") — in the header row, read
// after the title it qualifies. When is the timestamp contract;
// Meta is a caption with no machine form.
Meta string
// Body is extra markup under the detail: a log excerpt, actions.
Body render.HTML
}
Event is one thing that happened.
type FieldControl ¶
type FieldControl struct {
// ID is the field's For: the id the label points at.
ID string
// DescribedBy is the error's and the hint's ids, error first, for
// the control's aria-describedby. Empty when the field has
// neither — unless ReserveError held an empty error node in place,
// whose id rides here too.
DescribedBy string
// Invalid is true when the field has an Error, so a control never
// has to be told twice.
Invalid bool
// Required mirrors the field's own flag.
Required bool
}
FieldControl is what a field tells its control about itself. The control is built from it rather than beside it, which is the whole point: the id scheme, the description wiring and the invalid state all originate in one place and reach the input by construction.
Passing a pre-built control instead is how a hint ends up rendered, given an id, and never referenced — visible on screen and absent to a screen reader. That was true of every field in this system until Field started handing these down.
type FieldError ¶
type FieldError struct {
// For is the id of the control at fault. With it the message
// becomes a link that moves focus to the field; without it the
// message is text, which is the right fallback and a worse
// experience.
For string
// Message is what is wrong, in words the person can act on.
// "Invalid" is not one of them.
Message string
}
FieldError is one thing that went wrong.
type FieldProps ¶
type FieldProps struct {
// Label is required. An input without a label is not a variant, it
// is a defect: nothing announces it and nothing clicks it into
// focus.
Label string
// For is the control's id. Without it the label is decorative — it
// neither names the control for assistive tech nor enlarges its hit
// area — so a Field with a Label and no For is refused.
For string
// Hint is help text: the rule the value must obey. It stays
// rendered — and stays in the description — when Error is set: the
// hint is the rule, the error is the violation, and dropping the
// rule exactly when it was broken is dropping it when the reader
// needs it most. The error is drawn first and read first, so the
// correction arrives before the reminder.
//
// The cost is paid in pixels and syllables: an errored row is
// taller, and its description is longer, than an error-only one.
// That is the deliberate trade of this primitive; a caller who
// wants the hint gone on error says so by not setting it.
Hint string
// Error is announced and drawn before the hint.
Error string
// ReserveError keeps an error paragraph rendered — empty and wired
// into the control's aria-describedby — when Error itself is
// empty. It exists for a script that fills the node without
// re-rendering the field (a live editor applying edits as the
// operator types). An empty described-by target announces nothing
// until it is filled, which is the point: the wiring ships, the
// words arrive when they are true.
//
// The node's id is the contract a filling script looks it up by:
// the control's id with "-error" appended, the same id that rides
// aria-describedby. It carries no hook of its own — a data-hui-*
// attribute is something this package's runtime module binds, and
// no module has behaviour for an empty paragraph.
//
// A caller that fills the node must also set aria-invalid on the
// control it describes; this component cannot know the script's
// verdict. The server-rendered path should pass Error instead —
// a reserved node is a scaffold, not an answer.
ReserveError bool
// Required marks the label and is mirrored onto the control by the
// caller (the control owns its own required attribute).
Required bool
// Parts is the caller's reach into the field's named parts:
// attributes on the root (a class appends, never replaces). No
// part is fillable — every element a field draws is half of a
// relationship built from the control's id, and replacement
// content would break the half it replaced.
Parts Parts
ID string
ExtraAttrs html.Attrs
}
FieldProps is the label / control / hint / error group.
type FieldsetProps ¶
type FieldsetProps struct {
// Legend is the group's name, rendered as a real <legend> inside
// a real <fieldset>: that pair is the native group semantic,
// naming every control inside without a single aria attribute.
//
// Empty renders the group as a plain div: an unlabelled fieldset
// is a landmark that names nothing, and a group with no name to
// give is a row of fields, not a section.
Legend string
// Description is the supporting line under the legend. It is
// wired to the group by aria-describedby beside any group error,
// read with the question it explains.
Description string
// Error is the error that belongs to the group as a whole — the
// question was answered wrong somewhere in it, not in any one
// field. It is wired to the group by aria-describedby, so the
// fields' own errors and the group's never compete for the same
// relationship.
Error string
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on the group and every part it draws.
Parts Parts
}
FieldsetProps is a titled group of fields: the section of a form that belongs together ("Notifications", "Access").
type FileUploadProps ¶
type FileUploadProps struct {
// Name is the field name. Required.
Name string
// ID is the input's id. Required: the zone is a <label for=…>, and
// without the pair the biggest click target on the control does
// nothing.
ID string
// Label is the instruction inside the zone. Required.
Label string
// CTA is the part of the instruction that reads as the action —
// "choose a file". It is NOT a button: a button inside a label
// swallows the label's click, so the whole zone stops opening the
// picker. It is styled text, and the real control is the input.
CTA string
// Hint is the accepted types and size, tied to the input by
// aria-describedby so it is read with the field rather than being
// small print beside it.
Hint string
// Accept is the accept attribute; Multiple allows several files.
Accept string
Multiple bool
Required bool
Disabled bool
Invalid bool
// DescribedBy is an extra id to reference, from a Field.
DescribedBy string
// Parts: attrs and binds on the root, the zone, the input, the
// list and the status. Strings carry the sentences the
// runtime says when files are chosen.
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
ExtraAttrs html.Attrs
}
FileUploadProps is a file picker with a drop target.
type FormProps ¶
type FormProps struct {
// Action and Method are the submission target. Method defaults to
// post.
Action string
Method string
// Label names the form for assistive tech when it is one of
// several on a page. A single form on a page needs no name; two
// unnamed ones are two identical entries in a landmark list.
Label string
// Errors renders above the fields. When non-empty the form asks
// the runtime to move focus there on load, which is what makes a
// failed submit noticed at all — see ValidationSummary.
Errors render.HTML
// Actions are the submit and cancel controls.
Actions render.HTML
// Multipart sets the encoding a file upload needs. Without it the
// browser submits file inputs as names with no contents, which
// looks like a server bug and is not one.
Multipart bool
// NoValidate turns off the browser's own validation bubbles, for a
// form that validates on the server and reports through Errors.
// The bubbles are not a substitute: they show one message at a
// time, vanish on blur, and cannot be styled or read back.
NoValidate bool
// Island is where the form's answer is rendered again: when set,
// the form carries the RPC contract beside its action and the
// arrival pass focuses the summary. The HTTP convention the
// runtime's RPC lands in the signal: a validation failure is
// answered 200 with the region's HTML — the errors ARE the
// answer, the island swaps them in, and the summary takes focus.
// A non-2xx is a transport or server error, which the runtime
// delivers as {ok:false, status, text} in the signal, never as
// markup: an island form that answers 422 to a failed validation
// renders nothing at all. Nil is right for a page that IS the
// form — sign-in, the auth flow the architecture keeps native —
// where the plain POST to the page is the whole design.
Island Island
// Request is what the form DOES when the host framework's runtime
// is on the page: its data-fui-rpc contract — the endpoint the
// submit posts to, a method that may differ from the native one
// (a form that natively POSTs for no-script may PUT over RPC),
// the success effects (a signal to land in, a page to navigate
// to, a reset, a widget to open or close) — plus the mount hook a
// generated form carries (data-action-mount, the compiled action
// that populates its relation selects). It is a seam of its own
// rather than a use of ExtraAttrs for the same reason Button's
// Action is: Safe drops every data-fui-* and data-action-* key, so
// wiring through extras would render a plain form that posts
// natively. A key outside the request vocabulary panics at render,
// naming the key and the seam.
//
// Island and Request are two ways of saying "the submit is an
// RPC"; carrying both on one form is refused rather than resolved
// by precedence.
Request Action
// Parts is the caller's reach into the form's named parts:
// attributes on the root and on the body and actions rows (a
// class appends, never replaces). Nothing is fillable — the
// fields and the actions are the caller's own children.
Parts Parts
ID string
ExtraAttrs html.Attrs
}
FormProps is a form and the things around it.
type GalleryItem ¶
type GalleryItem struct {
// Src is the full-resolution image URL. Required; refused when
// unsafe (a javascript: URL in an image is a payload, not a
// picture) — it degrades to nothing the day the caller hands one
// in, so the refusal is loud.
Src string
// Thumb is the thumbnail URL. Defaults to Src.
Thumb string
// Alt is the image's description. Required: an image with no
// description is decoration lying about being content.
Alt string
// Caption is optional descriptive text under the image.
Caption string
// Width / Height for the thumbnail (CLS-safe). Default 200×150.
Width int
Height int
}
GalleryItem is one entry.
type GalleryLightbox ¶
type GalleryLightbox struct {
// Name is the lightbox to open: the data-fui-open value, the Name
// of a mounted framework/ui.Lightbox. Required when the wiring is
// set; a zero GalleryLightbox renders plain links.
Name string
// Group is the data-fui-lightbox-group value: the id the lightbox's
// prev/next nav walks across this gallery's items. Empty derives
// "<Name>-gallery".
Group string
}
GalleryLightbox names the lightbox a gallery's items open. It is a typed prop rather than per-item extra attrs because the data-fui-* keys it renders are the widget runtime's open contract, which the extra-attrs surface refuses on purpose — a caller's decoration can never become a request, but a lightbox trigger is a first-class intent, so it is named here where it is reviewable.
type GalleryProps ¶
type GalleryProps struct {
// Items are the entries, in order. Required non-empty.
Items []GalleryItem
// Label names the list. Required: an unnamed image list is a
// landmark a screen reader cannot jump to.
Label string
// HrefFn, when set, returns a per-item destination. Empty for an
// item makes that item's link the full image, so every tile stays
// a working link.
HrefFn func(i int, it GalleryItem) string
// ExtraAttrsPerItem adds attributes to item N's anchor (a lightbox
// group id, a deeplink): index → attrs.
ExtraAttrsPerItem map[int]html.Attrs
// Lightbox, when set, wires every item's anchor to a framework
// lightbox: the click opens the named overlay instead of
// navigating, through the widget runtime's open contract. The
// no-script path stays the full-image href the anchor carries.
Lightbox GalleryLightbox
ID string
ExtraAttrs html.Attrs
// Parts: attrs on the list, items, figures, links, images,
// captions.
Parts Parts
}
GalleryProps configures the gallery.
type GridProps ¶
type GridProps struct {
// Min is the narrowest a column may get before the grid drops one,
// as a name from the scale ("sm", "md", "lg"), not a length.
//
// A length is what the framework's Grid takes, and it silently did
// nothing for every value: the component wrote a data attribute
// and no stylesheet ever read it. A named step cannot rot that way
// — the class map either has a rule for the name or the name is a typo
// that shows up the first time anyone looks.
Min string
Gap string
Tag string
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on the root.
Parts Parts
}
GridProps is an auto-fitting grid.
type GroupProps ¶
type GroupProps struct {
// Legend is the group's shared label. Required: a set of choices
// with no question above them is as broken as an unlabelled input.
Legend string
// Required marks the legend with data-required, the same state
// attribute a Field puts on its label, so a class map can draw
// the mark a sighted reader looks for. It is a cue, not a
// constraint: what the browser and the parser enforce is the
// required attribute on the leaves, which the caller sets there.
Required bool
ID string
Extra html.Attrs
}
GroupProps configures a fieldset of choices under one legend. The items arrive already rendered (each wrapped by its own styled component) because the wrapper owns the per-item style handle.
type InputGroupProps ¶
type InputGroupProps struct {
// Label names the group when it holds more than one focusable
// thing and no single label covers them. It becomes a group role
// with that name; without it the group is a plain div, which is
// correct for the common case of one labelled input plus a button
// that already says what it does.
Label string
ID string
ExtraAttrs html.Attrs
}
InputGroupProps joins controls into one visual control: an input with a button, a select with a field.
type InputProps ¶
type InputProps struct {
Type string
// DescribedBy is the aria-describedby a Field hands down. It is
// the whole reason a hint or an error reaches assistive tech: the
// text is on screen either way, but without this attribute a
// screen reader user hears the label and nothing else — no
// format hint, and no reason the control is red.
DescribedBy string
Name string
Value string
Placeholder string
Required bool
Disabled bool
// Invalid states aria-invalid for assistive tech; the class map
// colours the border off the same attribute.
Invalid bool
// AriaLabel names the control where a visible label cannot go — a
// search box in a toolbar, a field inside a table's own controls.
// Everywhere else the label belongs to a Field, on screen where
// everyone can read it. A placeholder is not a label: it goes away
// on the first keystroke, its contrast is deliberately low, and
// not every screen reader treats it as a name.
AriaLabel string
ID string
Extra html.Attrs
// Owned are the type-specific attrs — min, max and step, and only
// those — applied after the common set and after Extra so a caller
// cannot widen a numeric input's bounds through extra attrs behind
// the config's back. Any other key is refused: this is a seam for
// bounds, not a second ExtraAttrs. Empty values are skipped,
// leaving Extra's say if it has one.
Owned html.Attrs
}
InputProps is the single-line control every Input flavour renders: one void input, the same state attrs assembled the same way. The flavours differ only in Type and the typed attributes they add (min/max/step), which is why none of them can drift in structure from a plain Input.
type Island ¶
type Island struct {
// Endpoint is the RPC path the region's next rendering comes
// from: same-origin, starting with "/".
Endpoint string
// Signal is the data-fui-signal the region is bound to; the
// response replaces it.
Signal string
}
Island is where a state change goes: the endpoint that renders the region again, and the signal that region is bound to.
It is the sibling of Button's Action, and it exists for the same reason: the host framework attaches a request to markup by splicing attributes into the rendered string, which works on anything and therefore says nothing. Here the request is a prop on the component that fires it, so a table that turns its own pages says so in its props, in one place, and the attributes cannot be forged through ExtraAttrs — Safe drops every data-fui-* key on purpose.
The framework's first hard rule is that an in-page state change is never a route: no link that merely navigates for a new page of rows, a new sort, a filter. The component renders the RPC contract (see attrs, in box.go) on the SAME element that keeps the href or action for no script, so the progressive shape is one element — an anchor that is the page without script and the island update with it.
type JSONTreeProps ¶
type JSONTreeProps struct {
// Value is the data to render. Required non-nil; values that do
// not marshal to JSON are refused (a channel, a func, a cycle).
Value any
// OpenDepth is the recursion depth that renders open by default.
// 0 means only the root is open; -1 means everything is open.
OpenDepth int
// MaxStringLen truncates long strings with the truncation mark.
// 0 means no limit.
MaxStringLen int
ID string
ExtraAttrs html.Attrs
// Strings overrides the words (object, array, null, empty,
// truncation). Nil takes the defaults.
Strings *Strings
// Parts: attrs on the root, nodes, summaries, lists, keys.
Parts Parts
}
JSONTreeProps configures the tree.
type Kit ¶
type Kit struct {
// Classes is this component's own classes.
Classes Classes
// contains filtered or unexported fields
}
Kit is what a fixture is handed: this component's class map, and a way to reach any other component's.
It exists because a fixture composes. A Form fixture needs a Button and an Input inside it, and before this existed there was only one class map in scope — the Form's — so every fixture either passed the parent's class map to the child, which dresses an <input> in .ds-form and leaves it otherwise naked, or gave up and wrote the child as a raw HTML string, which no part check, no golden and no audit can see. Thirty-one components did one or the other.
The lookup is a function rather than a map because the class maps live in the styled layer, which imports this one. Inverting that would put class names in the headless half, and the whole split is that they are not there.
func NewKit ¶
NewKit builds a Kit with a resolver. The package that owns the class maps calls this to render the fixtures dressed; the contract suite passes nil and gets an unstyled system.
func (Kit) For ¶
For is the class map a child component should wear. The name is the component's, exactly as it is registered.
func (Kit) Variant ¶
Variant is For, for a component whose class map depends on a tone or kind: an alert is danger or info, a badge neutral or warning. The catalogue drew every alert in the same blue until this existed, because one component mapped to one class map and a tone could not be asked for.
type LightboxViewerProps ¶
type LightboxViewerProps struct {
// Name is the lightbox's identity (required): the value its hooks
// carry, and the source of the title span's id (<Name>-title),
// which the surrounding modal's aria-labelledby points at.
Name string
// Label is the accessible name of the open viewer. Empty means
// Strings.LightboxViewerLabel.
Label string
Nav bool
// Caption renders a <figcaption> bound to the viewer's caption
// signal.
Caption bool
// Download renders an anchor that saves the image being viewed,
// its href bound to the viewer's src signal.
Download bool
// PrevIcon, NextIcon and DownloadIcon are the buttons' glyphs.
// Decorative; the accessible names come from Strings.
PrevIcon render.HTML
NextIcon render.HTML
DownloadIcon render.HTML
// Wiring renders the framework module's data-fui-lightbox*
// attributes IN PLACE OF the hooks. See LightboxWiring.
Wiring LightboxWiring
ID string
ExtraAttrs html.Attrs
// Parts: attrs on every part. Nothing here is fillable — the
// caption and the image are signal-bound, and the buttons are the
// nav contract; a slot would fight the binding it replaced.
Parts Parts
// Strings are the strings this component says. Nil means the
// English defaults; a layer above sets them from the request's
// language.
Strings *Strings
}
LightboxViewerProps configure the viewer.
type LightboxWiring ¶
type LightboxWiring struct {
// Viewer is the data-fui-lightbox value: the lightbox widget's
// name, carried by the root and the nav buttons, and (as a bare
// marker) by the image the module's pinch-zoom owns.
Viewer string
// states the same fact: the opt-in that makes prev/next and the
// arrow keys step the gallery group.
Nav bool
}
LightboxWiring is the framework binder's spelling of the viewer's own facts. The data-hui-* hooks are this package's contract with any runtime a host chooses, and they render exactly when Wiring is zero: a host shipping its own viewer module against the hooks leaves Wiring zero and none of the framework's attributes render. A set Wiring renders the data-fui-lightbox* family instead — for framework/ui's lightbox module, which binds data-fui-* hooks only — and suppresses the hui twins: the two vocabularies name the same facts, and a viewer that rendered both would invite a host module to double-bind the gallery the framework module steps.
type Live ¶
type Live string
Live says how — and whether — an alert interrupts.
This is the decision the component exists to force, because getting it wrong is not a small mistake in either direction.
- LiveOff is the default and the right answer for anything the server rendered as part of the page. An alert that was already on screen when the page loaded has not "happened"; announcing it as an event means a screen reader reads page furniture over the top of whatever the user was doing, on every single page load.
- LivePolite queues the message until the user pauses. It is for something that arrived after load and can wait: a background job finished, a value saved.
- LiveAssertive interrupts immediately. It is for something the user must hear before they do anything else: the deploy failed, the form did not submit, the connection dropped. Nothing routine belongs here — an assertive region that fires often is one a user learns to resent and cannot turn off.
role="alert" already implies assertive and role="status" already implies polite, so only the role is written. Stating both is how a message ends up announced twice.
type MenuAction ¶
type MenuAction struct {
// Path is the form's action URL.
Path string
// Method defaults to POST.
Method string
// Fields are the hidden inputs, first use: the CSRF token.
Fields map[string]string
// Unsafe acknowledges the no-Fields case deliberately.
Unsafe bool
}
MenuAction is the row's form-POST shape.
CSRF contract: the framework never mints or verifies tokens — the caller's form middleware owns that. But a state-changing POST with no hidden inputs is almost certainly a forgotten token, so the default refuses it: an Action with no Fields panics unless Unsafe explicitly acknowledges the endpoint carries its own protection.
type MenuItem ¶
type MenuItem struct {
// Label is the row's visible text. Required unless Separator.
Label string
// Href turns the row into an <a> link. Mutually exclusive with the
// custom action attrs; if both are supplied, Href wins.
Href string
// RPC and RPCMethod wire the row to a server-side handler via the
// kernel's data-fui-rpc contract. Use for "Delete this row" items.
RPC, RPCMethod string
// Confirm asks the reader to confirm before the RPC fires; the
// runtime honours it on RPC dispatch and on any form submit.
Confirm string
// Icon is rendered before the Label. Inline HTML.
Icon render.HTML
// Danger tints destructive rows; a visual hint only.
Danger bool
// Disabled removes the row from keyboard navigation and pointer
// interaction while keeping it in the panel.
Disabled bool
// Separator renders a horizontal divider instead of a row.
Separator bool
// ID becomes the rendered row's id attribute. Uniqueness is
// caller-owned, like any HTML id — the menu refuses the duplicates
// it can see.
ID string
// Radio, when non-empty, renders the row as a radio option:
// role="menuitemradio" plus aria-checked (see Checked) and the
// group attr the module arbitrates client-side. Exactly one row of
// a group should carry Checked. Mutually exclusive with Children —
// both set is refused at render.
Radio string
// Checked sets aria-checked on a Radio row.
Checked bool
// Action renders the row as a form submission instead of a link or
// RPC, for hosts whose command rows hit PRG endpoints. Nil (the
// zero value) renders nothing. Mutually exclusive with Href, RPC,
// Radio and Children: incoherent combos are refused at render.
Action *MenuAction
// Children nests a submenu behind this row. The row renders as a
// disclosure summary; setting Href, RPC, Action or Radio on it is
// refused at render.
Children []MenuItem
// ExtraAttrs forwards additional attributes onto the row. Keys the
// row owns are dropped, as everywhere in this package.
ExtraAttrs html.Attrs
}
MenuItem is one row: an actionable item (Label required, Href / RPC / Action as supplied) or a separator. The framework owns the role attributes; callers only describe semantics.
type MenuProps ¶
type MenuProps struct {
// ID pairs the trigger with the panel. Empty derives a stable id
// from the menu's content.
ID string
// Label is the trigger's visible text. Mutually exclusive with
// TriggerHTML and TriggerElement.
Label string
// TriggerHTML overrides Label with custom inline HTML.
TriggerHTML render.HTML
// TriggerElement replaces the framework summary with a
// caller-owned interactive element: the menu renders a
// summary-less disclosure beside it and the module makes the
// element the controller. Use for host-styled triggers — an
// interactive element inside a summary is axe nested-interactive.
TriggerElement render.HTML
// Items is the menu's contents. Required; an empty menu panics —
// it signals a bug, not a runtime state.
Items []MenuItem
// Position names the panel's anchoring variant (bottom-start, …);
// the class map resolves it. Empty takes bottom-start.
Position string
// LazyPanel ships the panel's rows inside an inert template the
// module mounts on first open, for page-scoped consumers that must
// not see closed-menu rows in the live DOM.
LazyPanel bool
ExtraAttrs html.Attrs
// Parts: attrs on the root. Rows own their guarantees.
Parts Parts
}
MenuProps configures a dropdown menu.
type MultiSelectOption ¶
type MultiSelectOption struct {
// Value is the form-submit value. Required.
Value string
// Label is the option's visible text. Required.
Label string
// Selected checks the option on first paint.
Selected bool
// Disabled greys the option out and keeps it unsubmitting.
Disabled bool
}
MultiSelectOption is one checkbox option.
type MultiSelectProps ¶
type MultiSelectProps struct {
// Name is the form-field name every checkbox shares; the form
// receives the repeated key for each checked option. Required.
Name string
// Label is the group's accessible name and the disclosure's
// summary. Required.
Label string
// Options are the choices, in order. Required and non-empty.
Options []MultiSelectOption
// Open renders the disclosure expanded.
Open bool
// Placeholder is what the chips strip says when nothing is
// picked. Empty takes Strings.MultiSelectPlaceholder.
Placeholder string
ID string
ExtraAttrs html.Attrs
// Parts: attrs on the root, the chips strip, the summary, the
// panel, the group and the rows. No part is fillable: the
// checkbox group is the contract.
Parts Parts
Strings *Strings
}
MultiSelectProps configures one multiselect.
type NotificationBellProps ¶
type NotificationBellProps struct {
// Href is where the link goes: the notifications page,
// same-origin. Required — a bell that rings to nowhere is a dead
// link on the no-script page, and "#" is not a destination.
Href string
// Label is the trigger's visible name. Required.
Label string
// UnreadCount is the count the badge shows and the accessible
// name says. Negative is refused; zero hides the badge (nothing
// unread is no news) unless a Bind raises it.
UnreadCount int
// UnreadBind, when set, keeps the count following a client
// signal: the badge the server rendered at zero appears when the
// signal changes it.
UnreadBind *Bind
// Opens, when set, is the widget name the anchor opens with
// script: the same element is the no-script link (Href) and the
// widget's trigger, rendered as the kernel's data-fui-open and a
// bottom-anchored popover. A name carrying control bytes or
// whitespace is refused — it is a widget key, not free text.
Opens string
// Icon is the glyph. The default bell is the structure's own; a
// caller's SVG replaces it.
Icon render.HTML
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on the root, the icon, the badge and the
// count. Strings carry the spoken count.
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
}
NotificationBellProps configures the unread-count trigger.
type NumberInputProps ¶
type NumberInputProps struct {
// Name is the form-field name. Required.
Name string
// Label is the visible label. Required: it names the control and
// the two buttons (through NumberDecrement / NumberIncrement).
Label string
// Value is the initial value as text, so a decimal step's value
// travels unchanged. Empty means no value. A value that is not a
// number, or violates a supplied bound, is refused.
Value string
// Min and Max bound the value. Nil leaves the bound to the
// server; a Min above a Max is refused.
Min *int
Max *int
// Step is the stepper granularity. Default 1; positive only.
Step int
// Required and Disabled are the input's own states; Disabled also
// takes the buttons out.
Required bool
Disabled bool
// Help is the rule the value obeys; Error is the violation. Both
// reach the input's description, the error first.
Help string
Error string
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on every part. Strings carry the two
// buttons' names.
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
}
NumberInputProps configures a number field with explicit −/+ buttons.
type OptimisticActionProps ¶
type OptimisticActionProps struct {
// Endpoint is the URL the click fires against. Required, and
// same-origin (it must start with "/").
Endpoint string
// Method defaults to POST and may be PUT, PATCH or DELETE.
Method string
// IdleLabel is the text at rest. Required.
IdleLabel string
// SuccessLabel is the text painted the moment the button is
// clicked. Required — and it must say something the idle label
// does not, because the label flip IS the state change; colour
// alone is never allowed to carry it.
SuccessLabel string
// IdleIcon and DoneIcon are decoration beside each label. Each
// span carries its own so the flip swaps glyph and word together.
IdleIcon render.HTML
DoneIcon render.HTML
// Variant and Size are class-map vocabulary, passed through so the
// class map can look up "<part>--<variant>". The structure does not
// care.
Variant string
Size string
// Disabled is the state at render time. The runtime manages it
// from the first click: pending disables, settlement re-enables.
Disabled bool
// FailedText is what the status span announces when the server
// refuses. Defaults to "Could not save. Try again."
FailedText string
ID string
ExtraAttrs html.Attrs
// Parts: attrs only. Nothing is fillable — the two labels are
// the state, and a slot that replaced one could make the button
// say it did something it did not.
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
}
OptimisticActionProps is a button that commits once: the success label is painted on click, the endpoint fired, and a non-2xx rolls everything back with a shake.
type Option ¶
type Option struct {
// Value is what the option submits; Label is what it shows. They
// are separate so the submitted key stays stable while the visible
// text is edited.
Value string
Label string
}
Option is one entry in a Select's list.
type PageHeaderProps ¶
type PageHeaderProps struct {
// Title is the page's heading. Required: the header exists to
// name the page, and a header with no heading is padding.
Title string
// Level is the heading level, 1 by default. The page's own header
// is the h1; a header for a sub-page inside a page says 2 here
// rather than leaving the outline to guess.
Level int
// Eyebrow is a short kicker above the title ("Customers"). It is
// aria-hidden: it repeats what the title or the navigation
// already says, in fewer words, and hearing both is hearing the
// page's name twice.
Eyebrow string
// Subtitle is the supporting line under the title.
Subtitle string
// Badge is status content beside the heading, outside its accessible name.
Badge render.HTML
// Actions are the page-level controls — New, Import, Filter — in
// the trailing slot. They apply to the page, not to an item in
// it; an action about one row belongs on that row.
Actions render.HTML
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on every part the header draws.
Parts Parts
}
PageHeaderProps is the top of a page: a heading, the words that qualify it, and the actions that apply to the whole page.
type PaginationProps ¶
type PaginationProps struct {
// AriaLabel names the nav landmark for AT. Required: pagination
// announced as "pagination" is how AT users find it at all.
AriaLabel string
// Page is the current page, 1-based. Must be within 1..Pages.
Page int
// Pages is the total number of pages. At least 1.
Pages int
// Path is the screen's own path: each page href is it plus the
// carried query, the page parameter replaced. Empty means the
// current document — a relative "?query" href. When set it must
// be same-origin and carry no query or fragment of its own: the
// carry belongs in Query, where it survives the page turn, and a
// Path query is silently replaced — a value lost with no error is
// the defect this component exists to make structural.
Path string
// Query is the query the screen's URL already carries — the
// search, the filters, the sort — and survives a page turn
// beside the page number.
Query url.Values
// PageParam names the page query parameter. It defaults to "p".
PageParam string
// Window is the number of pages shown each side of the current
// one, the first and last always shown. Default 1; a Window
// large enough shows every page.
Window int
// OmitPrevNext drops the Previous and Next anchors entirely.
OmitPrevNext bool
// PrevLabel and NextLabel default to "Previous" and "Next".
PrevLabel string
NextLabel string
// Island is where a page change goes when the pager sits inside
// a region rather than being the page: the page anchors then
// carry the RPC contract beside their hrefs — the page without
// script, the region update with it, the URL written after the
// swap. Optional, the Table posture: the URL is the truth for a
// list, so a list screen's page anchors are plain navigations
// the client router intercepts. An Island that looks wired and
// is not is refused, whichever shape the pager renders.
Island Island
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on the root, the list and the gaps.
// Strings carry the two end links.
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
}
PaginationProps configures a pagination bar.
type PaneHostProps ¶
type PaneHostProps struct {
// Primary is the always-visible pane. Required.
Primary render.HTML
// Secondary is the first optional side pane.
Secondary render.HTML
// Tertiary is the second optional side pane.
Tertiary render.HTML
// SecondaryOpen / TertiaryOpen set the SSR initial open state.
SecondaryOpen bool
TertiaryOpen bool
// SecondaryLabel / TertiaryLabel label each side pane's region.
// Empty takes "Secondary" / "Tertiary".
SecondaryLabel string
TertiaryLabel string
// DeepLinkParam names the query parameter that carries pane state
// for refresh/share/Back parity. Empty leaves the URL alone. A
// non-token value (control bytes, markup, whitespace) is refused.
DeepLinkParam string
ID string
ExtraAttrs html.Attrs
// Parts: attrs on the root and each pane.
Parts Parts
}
PaneHostProps configures the host.
type Part ¶
type Part string
Part names an element inside a component. A class map styles parts; the structure names them. Adding a part is a change to both layers, which is the point: a class map cannot invent a hook the markup does not offer, and the markup cannot quietly drop one a class map is using.
Action parts. The idle and done labels are parts of their own because a class map may want to weigh one differently from the other — a committed toggle that reads heavier than its idle sibling. The status span is PartVisuallyHidden because it must be read and must not be seen, the same rule as every other off-screen sentence in this package.
const ( PartBreadcrumbList Part = "breadcrumb-list" PartBreadcrumbItem Part = "breadcrumb-item" PartBreadcrumbLink Part = "breadcrumb-link" PartBreadcrumbSeparator Part = "breadcrumb-separator" )
Breadcrumb parts.
const ( PartCarouselStage Part = "carousel-stage" PartCarouselTrack Part = "carousel-track" PartCarouselSlide Part = "carousel-slide" PartCarouselDot Part = "carousel-dot" PartCarouselPrev Part = "carousel-prev" PartCarouselNext Part = "carousel-next" )
Carousel parts.
const ( PartTagInputList Part = "tag-input-list" PartTagInputTag Part = "tag-input-tag" PartTagInputZone Part = "tag-input-zone" PartTagInputField Part = "tag-input-field" PartTagInputAdd Part = "tag-input-add" )
TagInput parts.
const ( PartRepeaterItems Part = "repeater-items" PartRepeaterItem Part = "repeater-item" PartRepeaterFields Part = "repeater-fields" PartRepeaterAdd Part = "repeater-add" )
Repeater parts.
const ( PartComboboxForm Part = "combobox-form" PartComboboxInput Part = "combobox-input" PartComboboxListbox Part = "combobox-listbox" PartComboboxOption Part = "combobox-option" PartComboboxStatus Part = "combobox-status" )
Combobox parts.
const ( PartOption Part = "option" PartAffixButton Part = "affix-button" PartAffixSwatch Part = "affix-swatch" )
Control parts. The single-line controls and the affix shells are their own root; the input inside an affix shell is PartControl, and the reveal button and swatch are named so a class map can style them without the markup having to carry a class for them to be found by.
const ( PartNumberDecrement Part = "number-decrement" PartNumberIncrement Part = "number-increment" )
NumberInput parts. The input is the control the label points at; the two buttons are the component's own.
const ( PartSliderOutput Part = "slider-output" PartSliderEdges Part = "slider-edges" PartSliderEdge Part = "slider-edge" )
Slider parts.
const ( PartRangeLow Part = "range-low" PartRangeHigh Part = "range-high" PartRangeOutput Part = "range-output" PartRangeTrack Part = "range-track" )
RangeSlider parts. The two inputs are the component's thumbs; the track is the positioning context the sheet overlays them on.
const ( PartCounterDecrement Part = "counter-decrement" PartCounterValue Part = "counter-value" PartCounterIncrement Part = "counter-increment" )
Counter parts.
Disclosure parts. The summary and the panel are shared with Menu, which composes this anatomy for its dropdown panels.
const ( PartLegend Part = "legend" PartGroupDesc Part = "group-desc" PartFields Part = "fields" PartGroupError Part = "group-error" )
Fieldset parts.
const ( PartRoot Part = "root" PartLabel Part = "label" PartControl Part = "control" PartHint Part = "hint" PartError Part = "error" PartIcon Part = "icon" PartText Part = "text" PartHeader Part = "header" PartTitle Part = "title" PartDesc Part = "desc" PartBody Part = "body" PartMarker Part = "marker" PartActions Part = "actions" PartStatus Part = "status" // PartVisuallyHidden is text that must be read and must not be // seen. It exists as a shared part because more than one component // needs it and every one of them must hide it the same way — // clipped, never display: none, which would take it out of the // accessibility tree along with the view. PartVisuallyHidden Part = "visually-hidden" )
The shared vocabulary. Component-specific parts live beside their component.
const ( PartJSONColon Part = "json-colon" PartJSONType Part = "json-type" PartJSONCount Part = "json-count" PartJSONStr Part = "json-str" PartJSONNum Part = "json-num" PartJSONBool Part = "json-bool" PartJSONNull Part = "json-null" PartJSONEmpty Part = "json-empty" )
JSONTreeParts: the primitive has no interactive parts beyond the details the browser owns, so the anatomy is textual (the value, the node, the summary, the list, the key) — and, under the value, one part per JSON scalar kind, so a class map can colour a string without colouring a number. Every one renders the same span the shared PartText did; only the name a class map can target differs.
const ( PartSectionHead Part = "section-head" PartSectionBody Part = "section-body" PartSectionBrow Part = "section-eyebrow" PartDividerLine Part = "divider-line" )
Layout parts.
const ( PartFigure Part = "figure" PartImage Part = "image" PartCaption Part = "caption" PartToolbar Part = "toolbar" PartPrev Part = "prev" PartNext Part = "next" PartDownload Part = "download" )
Lightbox viewer parts.
const ( PartMenuCaret Part = "menu-caret" PartMenuItem Part = "menu-item" PartMenuTrigger Part = "menu-trigger" PartMenuToggle Part = "menu-toggle" PartMenuForm Part = "menu-form" )
Menu parts. The summary is the trigger on the summary path; the trigger-element path renders a wrapper (menu-trigger) beside a summary-less details (menu-toggle) that the module pairs by id.
const ( PartMultiSelectChips Part = "multiselect-chips" PartMultiSelectGroup Part = "multiselect-group" PartMultiSelectRow Part = "multiselect-row" )
MultiSelect parts. The summary and the panel are the Disclosure's shared parts; the row is the label that wraps its checkbox.
const ( PartBadgeDismiss Part = "badge-dismiss" PartToolbarGroup Part = "toolbar-group" PartToolbarLabel Part = "toolbar-label" PartToolbarSpacer Part = "toolbar-spacer" PartToolbarSearch Part = "toolbar-search" PartPagination Part = "pagination" PartPaginationLink Part = "pagination-link" PartPaginationGap Part = "pagination-gap" PartStep Part = "step" PartStepRow Part = "step-row" PartStepText Part = "step-text" PartStepHint Part = "step-hint" )
Badge / Tag / Toolbar / Pagination / Steps parts. PartRoot is each component's outermost element; Badge and Tag share every part they have, because a tag is a badge with a dismiss control and the two must not be allowed to drift apart.
const ( PartPageEyebrow Part = "page-eyebrow" PartPageText Part = "page-text" PartPageSubtitle Part = "page-subtitle" PartPageActions Part = "page-actions" PartPageTitleRow Part = "page-title-row" )
PageHeader parts.
const ( PartEmptyTitle Part = "empty-title" PartEmptyDesc Part = "empty-desc" PartEmptyAct Part = "empty-action" )
EmptyState parts.
const ( PartDetailRow Part = "detail-row" PartDetailTerm Part = "detail-term" PartDetailValue Part = "detail-value" )
DetailList parts.
const ( PartRailList Part = "rail-list" PartRailItem Part = "rail-item" PartRailLink Part = "rail-link" PartRailEyebrow Part = "rail-eyebrow" PartRailCount Part = "rail-count" )
Rail parts. The label is a plain label, not a heading: the rail is a complementary landmark already named by its aria-label, and a heading here would inject a stray, out-of-order entry into the page outline.
const ( PartSidebarGroup Part = "sidebar-group" PartSidebarGroupList Part = "sidebar-group-list" PartSidebarGroupToggle Part = "sidebar-group-toggle" PartSidebarToggle Part = "sidebar-toggle" PartSidebarDrawer Part = "sidebar-drawer" PartSidebarInline Part = "sidebar-inline" PartSidebarItem Part = "sidebar-item" PartSidebarPrepend Part = "sidebar-prepend" )
Sidebar parts.
SortableList parts.
const ( PartSpinnerRing Part = "spinner-ring" PartSpinnerDots Part = "spinner-dots" PartSpinnerDot Part = "spinner-dot" PartSpinnerGrid Part = "spinner-grid" PartSpinnerCell Part = "spinner-cell" PartSkeleton Part = "skeleton-line" )
Spinner and Skeleton parts.
const ( PartCardHeader Part = "card-header" PartCardBody Part = "card-body" PartCardInner Part = "card-inner" )
Card parts.
const ( PartTable Part = "table" PartScroll Part = "scroll" PartHead Part = "head" PartRow Part = "row" PartSort Part = "sort" PartCell Part = "cell" PartEmpty Part = "empty" )
Table parts. PartCaption, PartHeader and PartBody are the shared names. PartRoot is the wrapper div, PartScroll the focusable region the table horizontally scrolls inside, and PartTable the table itself.
Tabs parts.
TableOfContents parts.
const ( PartTreeItem Part = "tree-item" PartTreeRow Part = "tree-row" PartTreeToggle Part = "tree-toggle" PartTreeGroup Part = "tree-group" )
Tree parts. The row holds the toggle and the label; the group is the child list a branch reveals.
const ( PartDropZone Part = "drop-zone" PartDropCTA Part = "drop-cta" PartDropHint Part = "drop-hint" PartDropInput Part = "drop-input" PartDropList Part = "drop-list" )
FileUpload parts.
const ( PartErrorList Part = "error-list" PartErrorItem Part = "error-item" PartErrorLink Part = "error-link" )
ValidationSummary parts.
const ( PartTimelineItem Part = "timeline-item" PartTimelineMark Part = "timeline-mark" PartTimelineTime Part = "timeline-time" PartTimelineHead Part = "timeline-head" PartTimelineMeta Part = "timeline-meta" PartTimelineBody Part = "timeline-body" )
Timeline parts.
const (
PartFieldRow Part = "field-row"
)
Field parts.
const (
PartOptionChoice Part = "option-choice"
)
Rating parts: each choice is one radio (PartControl) wrapped by its label (PartOption), the glyph inside the label aria-hidden.
const (
PartPane Part = "pane"
)
PaneHost parts. A slot's modifier (pane--primary, pane--secondary, pane--tertiary) resolves from the same class map through Classes.Variant(PartPane, slot), the way every variant-taking part in this package resolves.
const (
PartProgressValue Part = "progress-value"
)
Progress parts. The bar is the element; the description is the human sentence beside it.
const (
PartSteps Part = "steps"
)
StepWizard parts.
const (
PartToastToneWord Part = "toast-tone-word"
)
Toast parts.
type Parts ¶
type Parts struct {
// Attrs add attributes to named parts. An attribute the component
// owns is never beaten, and the keys refused on every way in are
// refused here too (see refused).
Attrs PartAttrs
// Slots replace named parts' content. Only the parts a component
// lists as fillable do anything; the rest are ignored rather than
// silently half-applied.
Slots Slots
// Binds keep named parts in step with client signals: an
// attribute anywhere the allow-lists allow, and text or html only
// on a fillable part, where a Bind may replace what a Slot may.
Binds Binds
}
Parts is what a caller may set on a component's named parts: extra attributes, replacement content for the parts the spec lists as fillable, and a binding to a client signal. It is one value rather than three loose fields so the harness can find it: a component either offers its parts or does not, and which parts a caller can reach is a question with one answer per component.
func (Parts) Box ¶
Box builds the render box that applies a caller's Parts. The fillable names are the parts whose content a caller may replace — the spec's Fillable list — and a text or html Bind on any other part is refused at render: it would replace content the component guarantees, which is the same reason a Slot is offered only there.
type PasswordProps ¶
type PasswordProps struct {
Name string
Placeholder string
Required bool
Disabled bool
Invalid bool
// ID lands on the inner input, not the shell: the shell is
// styling, and a Field label's for= must point at the control.
ID string
// Extra attrs land on the inner input too (autocomplete,
// inputmode): they are attributes of the control, and putting them
// on the shell would swallow them.
Extra html.Attrs
DescribedBy string
// Parts: attrs and binds on the shell, the input and the
// reveal button. Strings carry the reveal button's two
// names).
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
}
PasswordProps configures a password control.
type ProgressProps ¶
type ProgressProps struct {
// Value is the current progress. 0 to Max renders a determinate
// bar; a negative value renders an indeterminate one. A value
// past Max is clamped to Max at render; NaN and the infinities
// render indeterminate, because a number that is not a number
// cannot label progress.
Value float64
// Max is the ceiling. 0 (and any non-finite or negative value)
// takes 100.
Max float64
// Label names the bar for assistive tech. Required: a progress
// bar with no name is a stripe a screen reader cannot identify.
Label string
// LabelVisible renders the label as text above the bar (wired to
// the element through aria-labelledby) instead of an aria-label.
LabelVisible bool
// Description is an optional human sentence beside the bar ("73
// of 100", "Uploading…"). Scrubbed, never refused: it is data a
// request can carry.
Description string
ID string
ExtraAttrs html.Attrs
// Parts: attrs on the root and the value. No part is fillable.
Parts Parts
}
ProgressProps configures one bar.
type RailItem ¶
type RailItem struct {
// Anchor is the fragment id of the section this entry links to,
// without the leading #. Required: an entry that links nowhere is
// not an entry.
Anchor string
// Text is the visible link label. Required.
Text string
// Eyebrow is the leading chip beside the label (a number, a
// glyph); empty hides it.
Eyebrow string
// Count is the trailing chip (a document count); empty hides it.
Count string
}
RailItem is one entry in the rail.
type RailProps ¶
type RailProps struct {
// Label names the landmark and heads the list. Required: a
// complementary landmark with no name is a region a screen reader
// cannot jump to by name.
Label string
// Items are the entries, in display order. Required and non-empty.
Items []RailItem
// ObserveSelector is the CSS selector of the region whose sections
// the module watches to mark the active entry. Empty renders a
// purely static rail: the links work, nothing is marked.
ObserveSelector string
// TargetSelector narrows which elements inside the observed region
// count as sections. Empty takes the module's default (the
// h2/h3/h4 elements that carry an id).
TargetSelector string
ID string
ExtraAttrs html.Attrs
// Parts: attrs on the root and the entries. No part is fillable:
// every element the rail draws carries its own guarantee.
Parts Parts
}
RailProps configures a rail.
type RangeSliderProps ¶
type RangeSliderProps struct {
// Name is the base form-field name. Two inputs ship, Name+"-min"
// and Name+"-max", so the server receives the pair without
// parsing a composite string.
Name string
// Label is the group's name, read by assistive technology and
// built into each thumb's name (RangeLow / RangeHigh).
Label string
// Min, Max, Step as for Slider.
Min int
Max int
Step int
// ValueLow and ValueHigh are the thumbs' values. Both zero means
// Min and Max. Values outside the bounds clamp to them, and a
// crossed pair is ordered low, high — the same repair the module
// makes of a dragged pair.
ValueLow int
ValueHigh int
// ShowValue renders the pair's one output sentence, from
// RangeValue; the module keeps it in step using the same
// sentence, which travels with the output.
ShowValue bool
// Disabled disables both thumbs.
Disabled bool
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on every part. Strings carry the two
// thumbs' names and the output sentence.
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
}
RangeSliderProps configures the two-thumb range pair.
type RatingProps ¶
type RatingProps struct {
// Name is the form-field name. Required; the group submits the
// chosen value 1..Max under it.
Name string
// Label names the group for assistive technology. Required.
Label string
// Max is the ceiling. Default 5; below 1 is refused.
Max int
// Value is the current choice, 0 (none) to Max.
Value int
// Icon is the glyph cloned into every choice. The default is a
// star; a caller's icon reaches every choice the same way.
Icon render.HTML
// Disabled disables every radio.
Disabled bool
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on every part. Strings carry each
// choice's name (RatingChoice).
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
}
RatingProps configures a rating as a radio group.
type RepeaterItem ¶
RepeaterItem is one repeated row: the fields are the caller's, the remove control is the component's.
type RepeaterProps ¶
type RepeaterProps struct {
// Name is the group's name. Required; the submit controls' names
// derive from it when the caller does not give their own.
Name string
// Label names the group for assistive technology and names the
// items region. Optional: a repeater beside its own heading may
// not need one, though two unnamed repeaters on a page are two
// identical entries in a landmarks list.
Label string
// Items are the rendered rows, in order.
Items []RepeaterItem
// MinItems is the floor below which removal is refused (the
// remove controls render disabled). MaxItems is the ceiling above
// which addition is refused. Zero MaxItems is unlimited.
MinItems int
MaxItems int
// AddLabel and RemoveLabel override the add control's visible
// text and the remove controls'; the remove control's accessible
// name always carries its 1-based position.
AddLabel string
RemoveLabel string
// AddName and AddValue name the add control as a submit control
// (a FormRepeater's "<Name>_add=1"); RemoveName names the remove
// controls, whose value is the row's 0-based index. Empty names
// render plain buttons the surrounding form does not carry.
AddName string
AddValue string
RemoveName string
// Action is the same-origin URL the add and remove operations go
// to when the result swaps in place; it is required together with
// Island and useless without it — a plain form repeater needs no
// Action, because the surrounding form's own action is the
// no-script destination and the submit controls ride it.
Action string
// Island is where an add or remove result lands. Required when
// Action is set, refused half-wired like every Island.
Island Island
// Status is the sentence the live region carries — the server's
// own words about the operation that just happened, re-rendered
// with the region after an island swap.
Status string
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on every part. Strings carry the add
// control's text and the remove controls' names.
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
}
RepeaterProps configures a repeated field group.
type Row ¶
type Row struct {
// ID lands on the <tr> as id=, for a keyed swap: successive
// renders of a live table differ only on the rows that changed.
ID string
// Cells maps a column Key to the rendered cell HTML. A column
// with no entry renders an empty cell; a key naming no column is
// refused at render, because a silent drop hides a typo.
Cells map[string]render.HTML
}
Row is one table row. The shape is ui.DataTable's, so a caller moves between the two without repacking.
type SectionProps ¶
type SectionProps struct {
// Title is the heading. It is also what makes this a landmark: a
// section with a name is navigable, a section without one is noise
// in the landmark list, so Section renders a plain div until it
// has a title to be named by.
Title string
// Eyebrow is a short kicker above the title ("01 / Overview"). It
// is aria-hidden: it decorates a heading the reader has already
// heard, and reading both is hearing the section's name twice. A
// section named by Label alone renders it too — the caller's
// heading rides in the body, and the kicker decorates it from
// above.
Eyebrow string
// Level is the heading level, 2 by default. It is a real decision
// and not a style: heading levels are how a screen reader user
// moves through a page, and a section under an <h1> that renders
// an <h3> leaves a hole in the outline.
Level int
// Description is supporting text under the heading.
Description string
// DescriptionHTML is supporting text that carries markup — code,
// links. When set it takes precedence over Description.
DescriptionHTML render.HTML
// Label names the region when there is no Title to name it by.
// A named section without a heading is still a landmark; an
// unnamed one renders as a plain div. With both set, Title wins:
// the heading names the region and Label is not read.
Label string
// Actions sit opposite the heading — a button, a filter.
Actions render.HTML
Gap string
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on every part the region draws.
Parts Parts
}
SectionProps is a titled region of a page.
type SelectProps ¶
type SelectProps struct {
Name string
// DescribedBy is the aria-describedby a Field hands down. It is
// the whole reason a hint or an error reaches assistive tech: the
// text is on screen either way, but without this attribute a
// screen reader user hears the label and nothing else — no
// format hint, and no reason the control is red.
DescribedBy string
// Options is the list of choices.
Options []Option
// Selected marks the option whose Value it matches. Empty selects
// the placeholder (or the first option when there is none).
Selected string
// Placeholder renders a disabled first option with an empty value.
// That empty value is also what makes Required enforceable: the
// browser reads it as unfilled.
Placeholder string
Required bool
Disabled bool
Invalid bool
ID string
Extra html.Attrs
}
SelectProps configures a dropdown.
type SidebarItem ¶
type SidebarItem struct {
// Label is the entry's text. Required.
Label string
// Href is the link's destination. Required for leaves; refused on
// group parents (a group parent is a disclosure, not a link).
Href string
// Icon is optional inline HTML before the label.
Icon render.HTML
// Active marks the current page's link.
Active bool
// Open opens a group at SSR. Inert on leaves.
Open bool
// MatchPrefix, when non-empty, is emitted as the leaf link's
// data-fui-match-prefix value: the runtime's active-link module
// re-derives the item's current-state on sub-paths after a client
// navigation, using this value (not the href) as the section
// prefix. The caller resolves the active state for first paint;
// this is the same rule, handed to the client.
MatchPrefix string
// Children make this entry a group. Mutually exclusive with Href.
Children []SidebarItem
}
SidebarItem is one nav entry: a link, or a group with children.
type SidebarProps ¶
type SidebarProps struct {
NavLabel string
// Title is the optional heading above the list.
Title string
// Items, in order. Required non-empty.
Items []SidebarItem
// Variant names the layout posture: "persistent" (always shown),
// "collapsible" (toggle collapses to a rail), "off-canvas"
// (drawer-only), "auto-hide" (a rail at rest that reveals on hover
// or focus — pure presentation, the sheet's own). Empty takes
// persistent.
Variant string
// Collapse names the collapse behaviour for the collapsible
// variant: "none" (server-owned state), "auto" (the module owns
// and restores it). Empty takes none.
Collapse string
// ServerCollapsed ships the server-owned collapsed state for the
// collapsible variant (data-collapsed on the root, aria-expanded
// and the state-matched label on the toggle). Nil means the state
// is not the server's to say here: with Collapse "auto" the module
// restores it after hydration, and no data-collapsed ships.
ServerCollapsed *bool
// DrawerName names the widget the mobile drawer opens; empty
// renders no drawer trigger (the caller mounts the drawer).
DrawerName string
// DrawerLabel names the drawer trigger button. Empty leaves the
// trigger unnamed — a caller rendering the trigger passes the
// words, this package says none of its own.
DrawerLabel string
// CollapseStorageKey names the storage the collapse state lives
// in when Collapse is auto. Empty means server-owned: the module
// never writes storage without it.
CollapseStorageKey string
// HideDrawerTrigger suppresses the drawer trigger button (a host
// that opens the drawer from its own chrome).
HideDrawerTrigger bool
// CollapseLabel / ExpandLabel are the collapse toggle's two
// accessible names, resolved by the caller. Both always ride the
// button as data-hui-sidebar-collapse-label / -expand-label: the
// module re-says them after a client-side toggle and carries no
// sentence of its own. Empty falls back to NavLabel for the
// button's initial aria-label.
CollapseLabel string
ExpandLabel string
// GroupMarkup selects the dialect for groups: "" or "details"
// (native details + the disclosure module's persist key) or
// "button" (aria-expanded + aria-controls + hidden, which the
// sidebar module's group-toggle mirror owns).
GroupMarkup string
// GroupIDPrefix derives each group's id (the button dialect's
// aria-controls target) and per-group persist key (the details
// dialect), as <prefix>-g<N>. Empty takes DrawerName + "-inline",
// or "sidebar-inline" when DrawerName is empty too.
GroupIDPrefix string
// Prepend / Footer are optional slots above and below the list.
Prepend render.HTML
ID string
ExtraAttrs html.Attrs
// Parts: attrs on the shell, the controls, the region's parts and
// every item part.
Parts Parts
}
SidebarProps configures the sidebar.
type SkeletonProps ¶
type SkeletonProps struct {
// Label is what is loading, announced once through a live region
// — "Loading apps". Required for the same reason Spinner's is.
Label string
// Lines is how many bars to draw. Zero means one.
Lines int
// Shape is a class map hint: "text", "title", "block", "circle".
Shape string
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on the root and the bars.
Parts Parts
}
SkeletonProps is the placeholder shown while content loads.
type SliderProps ¶
type SliderProps struct {
// Name is the form-field name. Required.
Name string
// Label is the visible label. Required.
Label string
// Min and Max bound the range. Both zero means 0..100; a Min
// above or equal to a Max is refused.
Min int
Max int
// Step is the granularity. Default 1; positive only.
Step int
// Value is the initial value. Outside the range clamps to the
// nearest bound, the way the browser treats a dragged thumb; a
// value between steps renders as given and snaps on first
// interaction — the module mirrors whatever the thumb says, so
// there is no disagreement to refuse.
Value int
// ShowValue renders the output beside the label and the hook the
// module mirrors the live value through.
ShowValue bool
// ShowEdgeLabels renders Min and Max under the track.
ShowEdgeLabels bool
// Disabled disables the control.
Disabled bool
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on every part.
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
}
SliderProps configures a labelled range control.
type Slots ¶
Slots hold caller content for named parts. A slot REPLACES what the component would have put there, which is what makes it useful and what makes it dangerous: a component offers a slot only where its own content carries no guarantee, and the harness renders every declared slot filled with something hostile to prove it.
type SortableItem ¶
type SortableItem struct {
// Key is the stable identifier the server applies the new order
// by. Required. It is data the database hands the page, not
// configuration: a space, a quote, `#` or markup renders escaped
// in its attribute and control bytes are scrubbed — only the
// empty key refuses.
Key string
// Label is the row's visible text and the drag name. Required.
Label string
// Content, when set, replaces the label as the row's body. Use
// for richer rows; the grip and the announcements still use
// Label.
Content render.HTML
}
SortableItem is one row.
type SortableListProps ¶
type SortableListProps struct {
// Items are the rows in initial order. May be empty: an empty
// column renders a valid sortable <ol> with no rows and stays a
// drop target.
Items []SortableItem
// Label is the list's accessible name. Required.
Label string
// RPCPath, when set, is POSTed after every successful reorder:
// order=<comma-separated keys>, plus container=<id> when
// Container is set, version=<token> when Version is set, and
// moved=<key> on a cross-container drop. The server confirms with
// 2xx or rejects (the DOM reverts).
RPCPath string
// Group is the board id shared by linked lists (kanban): lists
// with the same non-empty Group accept cross-container drag and
// keyboard moves between them, including into an empty one.
Group string
// Container is the per-column id sent as the container field so
// the server can route the write without inferring the column
// from the key set. Distinct from Group because a board has one
// Group and N containers.
Container string
// Version is an optional optimistic-concurrency token appended to
// every commit. When set, a 409 fires the conflict path instead
// of a blanket rollback.
Version string
// ConflictRPC, alongside Version, is GET-fetched on a 409: the
// response body (fresh rows) replaces the list's contents,
// server-rendered reconciliation. Without it a 409 falls back to
// rollback.
ConflictRPC string
ID string
ExtraAttrs html.Attrs
// Parts: attrs on the root and the rows. No part is fillable:
// the rows are the caller's data.
Parts Parts
Strings *Strings
}
SortableListProps configures one list.
type SpacerProps ¶
type SpacerProps struct {
// Grow is how much of the row's slack this spacer takes against
// its growing siblings. 1 through 4 — 0 is refused because a
// spacer that cannot grow is a typo rather than a choice (the
// typed Spacer defaults it to 1), and above 4 is refused because
// the stylesheet wires exactly those four factors: a number the
// sheet does not carry would be a factor that renders as 1.
//
// It travels as data-hui-grow rather than a style, because an
// inline style is a rule the CSP drops and a class per factor is
// a class the class map has to enumerate from a number it cannot see.
Grow int
// Min and Max bound the space, as names from the gap scale rather
// than lengths: a spacer with a floor keeps a contents list legible
// when the value is missing, and one with a ceiling keeps two
// distant words from being pushed to the edges of the screen.
Min string
Max string
// Leader draws a dotted line across the space — the leader between
// a term and its value in a contents list, which is what ties the
// two together once the row is wider than the pair.
Leader bool
// Rule draws a hairline rule across the space, for when the line
// should read as a divider-in-waiting rather than a tie. A leader
// and a rule in the same space are two answers to one question,
// and are refused together.
Rule bool
ID string
ExtraAttrs html.Attrs
}
SpacerProps is the flexible space in a row: between a label and a value in a contents list, between the safe action and the destructive one.
type Spec ¶
type Spec struct {
// Name is the exported function's name, exactly. The coverage
// gate matches on it.
Name string
// Anatomy lists the parts this component draws. A class map styles these
// and only these; a part listed here and never rendered is a
// class in the stylesheet with nothing to land on.
Anatomy []Part
// Fillable are the parts a caller may replace through Slots. The
// empty set is the correct answer for most components: a slot is
// offered where the component's own content carries no guarantee.
Fillable []Part
// Hooks are the data-hui-* attributes this component publishes for
// the runtime. Naming them here is what lets a test prove the
// runtime is not bound to an attribute nothing renders.
Hooks []string
// WithParts renders the component with a caller's Parts applied.
// A component that offers its parts must provide it: it is how the
// harness proves that filling a slot or adding an attribute cannot
// break the contract, and a part nothing tests is a part that will.
WithParts func(s Classes, parts Parts) render.HTML
// Cases renders the component at a given Classes. A nil Classes means
// unstyled, which is what the contract is asserted against.
Cases func(k Kit) []Case
}
Spec describes one component and how to render it.
type SpinnerProps ¶
type SpinnerProps struct {
// Label says what is being waited for — "Loading apps". Required,
// and it is not decoration: a spinner with no label is a moving
// shape that tells a screen reader user nothing at all, and the
// one thing they need to know is that waiting is the correct thing
// to be doing right now.
Label string
// Announce puts the label in a live region, so it is read when the
// spinner appears. Off by default: a spinner rendered WITH the
// page has not "happened" — the same rule Alert follows — and
// announcing it on load talks over the page.
//
// Turn it on for a spinner that replaces content after an action.
Announce bool
// Size is a class-map hint ("sm", "lg").
Size string
// Variant is the animated shape, a class-map hint: "" draws a
// bordered ring, "dots" three pulsing dots, "grid" a rippling
// square of nine. Every shape is aria-hidden — the shape is a
// picture of waiting and the label is what waiting is FOR.
Variant string
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on the root and the shape.
Parts Parts
}
SpinnerProps is the "working" indicator.
type StackProps ¶
type StackProps struct {
// Gap is a name from the scale, passed through to the class map. It is
// not a length, because a system with arbitrary gaps has no
// rhythm — and the one the framework ships proves the point: its
// Grid takes a free-form Min that nothing ever read.
Gap string
// Align is cross-axis alignment: "start", "center", "end". Empty
// stretches, which is what a stack of cards wants.
Align string
// Justify is main-axis distribution: "start", "center", "end",
// "between". Empty packs to the start, which is what a page's
// blocks do.
Justify string
// Tag overrides the element. A list of things should be a list;
// this is how a Stack becomes one without a second component.
Tag string
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on the root.
Parts Parts
}
StackProps is vertical flow: one thing after another, with one gap.
type StatCardProps ¶
type StatCardProps struct {
// Label says what is counted. Required.
Label string
// Value is the number, formatted by the caller. Required: a stat
// card with no value is a label in a box.
Value string
// Trend is the movement ("+12% vs. last week"). Optional.
Trend string
// Direction names which way the trend reads — "up", "down" or
// "flat". The trend's colour is the class map's to draw from it;
// the direction must also be in the Trend's own words for a
// reader who cannot see the colour, which is why Direction is a
// variant hint and never the only carrier of meaning.
Direction string
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on every part the card draws. The value
// is the part a dashboard binds to a signal.
Parts Parts
}
StatCardProps is one metric held up for the page: a labelled value, and how it is moving.
type Step ¶
type Step struct {
// Label is the step's name. Required.
Label string
// Hint is the supporting line under the label.
Hint string
// Href makes the step a link — a completed step the reader can go
// back to. Every href goes through the anchor policy; one the
// policy refuses is the developer's mistake, said at render like
// every configured href in this package.
Href string
// Marker overrides the glyph in the marker circle — a zero-padded
// number ("01"), a caller's check icon. It is aria-hidden either
// way: the marker is a picture of the step's state, and the label
// beside it is what a reader hears.
Marker render.HTML
// State overrides the state derived from Current: "done",
// "current" or "todo". Empty derives. An explicit state is how a
// rail says a later step finished while an earlier one is still
// open.
State string
}
Step is one entry on a Steps rail.
type StepWizardProps ¶
type StepWizardProps struct {
// Steps is the flow. At least one.
Steps []WizardStep
// Current is the 0-based step in progress. Outside the list is
// refused.
Current int
// Action and Method are the form's own. Method defaults to POST;
// anything but GET or POST is refused.
Action string
Method string
// HiddenFields carry state between steps.
HiddenFields []render.HTML
// Errors is the rendered validation summary for a failed submit.
// When set, ID is required and the form asks the runtime to move
// focus to the summary on arrival.
Errors render.HTML
// Island, when set, makes the submit a region update: the same
// form, the same controls, the answer swapped into the signal.
// Partial is refused like every Island.
Island Island
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on every part. Strings carry the three
// controls, the rail's name and each dot's.
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
}
StepWizardProps configures the wizard.
type StepsProps ¶
type StepsProps struct {
// Steps are the entries in order. At least one.
Steps []Step
// Current is the 1-based step in progress: the steps before it are
// done, it is current, the rest are todo. 0 means nothing has
// started yet. Must not exceed len(Steps).
Current int
ID string
ExtraAttrs html.Attrs
}
StepsProps configures a step indicator.
type Strings ¶
type Strings struct {
// DismissTitled names a dismiss control whose target follows it:
// an Alert's, a SystemBanner's. The title follows the colon and a
// space; a format taking it as %s.
DismissTitled string
// RemoveLabelled names a remove control by what it removes: a
// Tag's chip. A format taking the value's name as %s.
RemoveLabelled string
// ActionFailed is what a failed mutation announces when the caller
// supplied nothing better. A sentence, not a word: it says the
// save did not happen and that trying again is allowed.
ActionFailed string
// PickColor names the colour swatch, which carries no visible
// label. A format taking the field's name as %s.
PickColor string
// ShowPassword and HidePassword name the reveal button in each of
// its two states. Imperative, not rendered visually; they also
// travel as data so the runtime can swap them.
ShowPassword string
HidePassword string
// RevealShow is the reveal button's visible text, and RevealHide
// is what the runtime swaps it to. One word each; RevealHide is
// never rendered by the server.
RevealShow string
RevealHide string
// Previous and Next label the pager's ends, which are disabled
// anchors rather than absent ones. One word each; they carry no
// arrows, so a translation may add its own.
Previous string
Next string
// ToneInfo, ToneSuccess, ToneWarning and ToneDanger are the tone
// said before a title — a SystemBanner's, and an Alert's when the
// caller passes one as ToneWord — because the title says WHAT
// happened and the
// tone is the only thing saying how serious it is. One word each,
// the one a reader understands rather than the stylesheet's name
// for the colour ("Error", not "Danger"); the colon and space that
// follow are added in the assembly.
ToneInfo string
ToneSuccess string
ToneWarning string
ToneDanger string
// FileSelected says one file was chosen, with {name} where the
// file's name goes. The runtime writes the name in when it knows
// it; the server never renders this string with a value in it,
// because before the reader picks there is no value to say.
FileSelected string
// FilesSelected says several files were chosen, with {n} for the
// count and {names} for the joined list. Substituted by the runtime
// like FileSelected's {name}, for the same reason: neither the
// count nor the names exist until the reader has picked.
FilesSelected string
// LightboxViewerLabel is the accessible name of the open image
// viewer: what a screen reader says when the viewer takes focus.
// A short noun phrase; the image's own alt travels beside it.
LightboxViewerLabel string
// LightboxPrevious and LightboxNext name the viewer's nav buttons.
// They name the action on this surface ("Previous image"), not the
// pager's bare word: a reader inside a viewer needs to know what
// stepping moves.
LightboxPrevious string
LightboxNext string
// LightboxDownload names the anchor that saves the image being
// viewed.
LightboxDownload string
// TableSortBy names a sort control whose column carries no
// visible header text: an actions or icon column that can still
// be sorted. A format taking the column's Key as {column}; the
// token is written in at render, when the anchor is built —
// unlike the {n} the runtime substitutes, the key is known on
// the server.
TableSortBy string
// TableSortedBy says what a changed table is now sorted by, with
// {column} where the column's header goes and {direction} where
// the direction word goes. Rendered into data-hui-table-announcement
// at render and copied into the status after a swap, so a
// translated page announces in its own language.
TableSortedBy string
// SortAscending and SortDescending are the direction words
// TableSortedBy carries. One lowercase word each: they sit inside
// a sentence, after a comma.
SortAscending string
SortDescending string
// CounterLabel names the counter group, which carries no visible
// label of its own. One noun.
CounterLabel string
// CounterDecrement and CounterIncrement name the counter's two
// buttons. One word each; the counter's value is the context.
CounterDecrement string
CounterIncrement string
// BackToTop names the back-to-top anchor, whose glyph carries no
// words. A short imperative.
BackToTop string
// NumberDecrement and NumberIncrement name the stepper's two
// buttons, which need the field's name to tell them from any
// other stepper's. Formats taking the label as %s.
NumberDecrement string
NumberIncrement string
// RangeLow and RangeHigh name the two thumbs of a range pair —
// "Minimum %s" and "Maximum %s", the label standing in for the
// thing bounded. RangeValue is the pair's one output sentence,
// "%s to %s", low first.
RangeLow string
RangeHigh string
RangeValue string
// RatingChoice names one rating radio: "%d out of %d", the chosen
// value and the ceiling.
RatingChoice string
// TagInputAdd names the control that commits the draft, a format
// taking the field's label as %s. TagInputAdded and
// TagInputRemoved are what the status region says after a chip
// operation, with {name} where the chip's text goes — the runtime
// writes it when the operation has happened.
TagInputAdd string
TagInputAdded string
TagInputRemoved string
// RepeaterAdd names the add control. RepeaterRemove names one
// remove control, a format taking the item's 1-based position as
// %d, because twelve controls all called Remove tell a screen
// reader user nothing.
RepeaterAdd string
RepeaterRemove string
// NotificationCount is the bell's accessible name, "%d unread
// notifications" — the count the anchor carries, said in words.
NotificationCount string
// StepBack, StepNext and StepSubmit are the wizard's three
// controls; Next is the one weighted action until the last step
// makes it Submit. StepOf is the rail's name, "Step %d of %d",
// and StepName is one dot's, "Step %d: %s" with the step's
// heading as %s.
StepBack string
StepNext string
StepSubmit string
StepOf string
StepName string
// TableOfContentsLabel names the contents navigation, which is a
// landmark a screen reader jumps to by name. A short prepositional
// phrase naming what the list is of.
TableOfContentsLabel string
// ComboboxLoading is what the status region says while results
// are being fetched. One word or a short phrase.
ComboboxLoading string
// ComboboxNoResults is what the status region says when a query
// matched nothing.
ComboboxNoResults string
// ComboboxResultCount announces how many results a query found,
// "{n}" where the count goes — the module writes the count in when
// the results arrive, so the sentence travels as an attribute and
// the placeholder is a name, not a fmt verb.
ComboboxResultCount string
// ComboboxResultsLabel names the listbox: "<Label> results" is
// assembled at render, so the word here is the noun.
ComboboxResultsLabel string
// CarouselSlide names one slide and the total, "Slide {n} of
// {total}" — {n} and {total} are filled at render (the module
// re-says it into the status after each step).
CarouselSlide string
// CarouselGoTo names a dot control, "Go to slide {n}".
CarouselGoTo string
// JSONObject names an object node in a JSON tree. One word.
JSONObject string
// JSONArray names an array node in a JSON tree. One word.
JSONArray string
// JSONNull is the null literal. One word.
JSONNull string
// JSONTrue / JSONFalse are the boolean literals. One word each.
JSONTrue string
JSONFalse string
// JSONEmptyObject / JSONEmptyArray are what an empty collection
// renders: the literal braces/brackets. One token each.
JSONEmptyObject string
JSONEmptyArray string
// JSONTruncated is the mark a truncated string ends with.
JSONTruncated string
// ThereIsAProblem heads the list a failed submit focuses. A short
// sentence; it names the fact, the list names each field.
ThereIsAProblem string
// BreadcrumbsLabel names the trail's navigation landmark, which a
// screen reader jumps to by name. One word.
BreadcrumbsLabel string
// SortableItemRole is the roledescription every row carries: it
// tells a screen reader what kind of thing the row is before any
// key is pressed. Two words.
SortableItemRole string
// SortableDragLabel names one row by what it offers: a format
// taking the row's visible label as %s, applied at render.
SortableDragLabel string
// SortableGrabbed is said when a row is picked up, with {label}
// where the row's name goes. Substituted by the runtime when the
// grab happens, so the sentence travels as an attribute.
SortableGrabbed string
// SortablePosition says where the grabbed row now is, with
// {position} and {list} (the list's own name) written in by the
// runtime after each move.
SortablePosition string
// SortableMoved says the row changed lists, with {list} and
// {position}: the kanban crossing, announced after it lands.
SortableMoved string
// SortableSaved confirms a commit the server accepted.
SortableSaved string
// SortableReverted says a failed commit put the rows back.
SortableReverted string
// SortableCancelled says Esc put the grabbed row back where it
// started, uncommitted.
SortableCancelled string
// SortableConflictReverted says a 409 was reconciled by putting
// the rows back.
SortableConflictReverted string
// SortableConflictRefreshed says a 409 was reconciled by
// replacing the list with the server's own rows.
SortableConflictRefreshed string
// MultiSelectPlaceholder is what the chips strip says when
// nothing is picked. A short phrase; the chips replace it the
// moment one is.
MultiSelectPlaceholder string
// MultiSelectRemoveLabel names a chip's remove control, with
// {label} where the picked option's name goes — the runtime
// writes it in when it builds the chip.
MultiSelectRemoveLabel string
}
Strings are the strings the components say. Every field defaults to the English the components rendered before this type existed, so a nil or partially-set value is safe; DefaultWords returns them all and ProbeWords returns one probe token per field.
Fields holding a %s or %d are format strings, applied with fmt.Sprintf at the site that owns the numbers. {n} is substituted by the runtime, not the server: those strings travel as data-* attributes and the count is written in when it is known.
func DefaultStrings ¶
func DefaultStrings() *Strings
DefaultStrings returns a fresh copy of the English defaults, every field set. Fresh so a caller cannot mutate the package's copy through it.
func ProbeStrings ¶
func ProbeStrings() *Strings
ProbeStrings returns a Strings whose every field is its own name in angle brackets — formats as the name plus their placeholders, so `<RemoveLabelled env=prod>` renders where "Remove env=prod" would. A render against it shows exactly which words came through the table; a real English word in one is a word that bypassed it.
func (*Strings) Resolve ¶
Resolve is how a component reaches its strings: the caller's when a layer above resolved them from the request, the harness's probe when a test is looking, and the English defaults otherwise. A caller's Strings may be partial: every empty field falls back to its English default, so a Strings that sets one string does not silently unname the reveal button. Safe on a nil receiver, which is what an unset prop is.
type SwitchProps ¶
type SwitchProps struct {
// Name is the key the switch submits under when on.
Name string
// Value overrides what an on switch submits. Empty submits "on",
// the HTML default, which is right for a lone "email me" toggle.
Value string
// Label is the visible text beside the track. Required, same rule
// as every choice.
Label string
Checked bool
Disabled bool
ID string
// Extra attrs land on the input, the control that submits.
Extra html.Attrs
}
SwitchProps configures a toggle.
type SystemBannerProps ¶
type SystemBannerProps struct {
// ID is the message's identity, not just the element's: the
// runtime remembers it so the same message is not shown twice.
// Required.
ID string
// Tone is "info" (the default), "warning", "danger" or
// "success". The class map looks it up as root--<tone>, and the word
// a screen reader hears is derived from it, so a tone nobody
// spelled is refused rather than silently rendered untinted.
Tone string
// Title is the headline. Required: "Connection lost" is the
// message; the detail is detail.
Title string
// Text is the detail, in prose.
Text string
// Action is the one control the message offers — "Retry now",
// "View the deploy". One, because a system banner is a bar
// across the top of the page, not a form.
Action render.HTML
// Dismiss renders the dismiss button. Nil means yes: a system
// message the reader cannot send away is furniture that outstays
// its news, and the cases that want it gone — the offline
// banner, whose ending is the reconnect — say so explicitly:
// Dismiss on an Offline banner is refused at render.
Dismiss *bool
// DismissLabel names the dismiss control. Defaults to
// "Dismiss: <Title>", because three banners each called
// "Dismiss" say which nothing.
DismissLabel string
// Shown renders the banner visible. The default is hidden: the
// banner ships hidden and something shows it.
Shown bool
// Icon is decoration beside the title, hidden from assistive
// technology (the tone word in words carries the severity).
Icon render.HTML
// Offline marks this banner as the built-in connection message.
// The root carries data-hui-system-offline for the module that
// binds it to show when the framework reports the connection lost
// and hide on reconnect — so it always ships hidden, and Shown on
// an Offline banner is refused: that module owns it.
Offline bool
ExtraAttrs html.Attrs
// Parts: attrs only. Nothing here is fillable — Action
// already takes the page's own control, and everything else a
// banner draws is what a screen reader is given to tell one
// message from another.
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
}
SystemBannerProps is a message about the system rather than the page: offline, a deploy in progress, maintenance, a new version.
The difference from an Alert is who owns it. An alert is part of a page's answer; a system banner is placed once at the top of the shell, above every page, and what it says is true of the system the reader is standing in. That is also why it ships hidden: the slot is always there, and a message arrives in it — the runtime shows the offline one when the framework reports the connection lost, and anything else is a server render or an island swap into the slot.
type TOCItem ¶
type TOCItem struct {
// ID is the fragment id of the heading this entry links to,
// without the leading #. Required.
ID string
// Label is the entry's visible text. Required.
Label string
// Level is the heading's level, 1 to 6; 0 takes 2. It names the
// item's variant (h2, h3, …) so a class map can indent by depth.
Level int
}
TOCItem is one entry.
type Tab ¶
type Tab struct {
// Label is the tab's visible text. Required.
Label string
// Panel is the tab's panel content.
Panel render.HTML
// Href overrides the fragment href (a same-origin deep link).
Href string
// Disabled removes the tab from the keyboard rotation.
Disabled bool
}
Tab is one tab: its label and its panel's content.
type TableOfContentsProps ¶
type TableOfContentsProps struct {
// Label names the landmark. Empty takes
// Strings.TableOfContentsLabel.
Label string
// Items are the entries, in document order. Required and
// non-empty: an empty contents landmark is a name with nothing
// under it, and the no-script contract is the rendered list.
Items []TOCItem
// TargetSelector is the CSS selector of the content region whose
// headings the module watches to mark the active entry. Empty
// renders a purely static list: every link works, nothing is
// marked.
TargetSelector string
ID string
ExtraAttrs html.Attrs
// Parts: attrs on the root and the entries. No part is fillable:
// the list is the contract.
Parts Parts
Strings *Strings
}
TableOfContentsProps configures the contents navigation.
type TableProps ¶
type TableProps struct {
// Columns is the column definitions. Required.
Columns []Column
// Rows is the rendered rows.
Rows []Row
// Caption is the table's caption: text, escaped. A table is named
// by its caption and by nothing else — there is no AriaLabel —
// and a caller who wants the table named gives one.
Caption string
// SortBy is the active sort column's Key. Empty means no column
// is sorted.
SortBy string
// SortDir is the active sort's direction. Empty means ascending,
// the direction an inactive column's anchor sorts by.
SortDir SortDir
// Path is the screen's own path: each sort href is it plus the
// carried query, the sort parameters replaced. Empty means the
// current document — a relative "?query" href. When set it must
// be same-origin: a sort anchor pointing off-origin is a mistake
// refused at render.
Path string
// Query is the query the screen's URL already carries — the
// search, the filters, the page — and survives a sort beside the
// sort keys.
Query url.Values
// SortParam and DirParam name the sort key and direction
// parameters. They default to "sort" and "dir".
SortParam string
DirParam string
// Island is where a sort goes when the table is embedded in a
// region rather than being the page: the sort anchors then carry
// the RPC contract beside their hrefs — the page without script,
// the region update with it, the URL written after the swap.
// Optional, the Form posture: the URL is the truth for a list,
// and a list screen's sort anchors are plain navigations the
// client router intercepts when script is present. An Island
// that looks wired and is not is refused, whichever shape the
// table renders.
Island Island
// Empty renders in the body's one row when there are no rows, in
// a cell spanning every column. Nil renders an empty <tbody>;
// the head stays either way — an empty result still has named
// columns, and the sort controls stay usable.
Empty render.HTML
// Summary is a sentence about the result window the caller owns,
// e.g. "Showing 8 of 10". Appended to the sort sentence the
// announcement carries, with a space, when given: the primitive
// knows the sort, and only the caller knows the window.
Summary string
// the root, never inside the table, so a pager's nav landmark
// never nests in a table. Nil renders nothing — the scroll region
// is the root's only child.
Footer render.HTML
ID string
ExtraAttrs html.Attrs
// Parts: attrs on every part. Nothing here is fillable — the
// cells are the caller's own content, and a slot that replaced a
// header would drop the sort control inside it.
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
}
TableProps configures a table.
type TabsProps ¶
type TabsProps struct {
// Name is the signal the selection lives in. Required: the strip's
// whole contract is that clicking a tab writes the signal and the
// wrapper mirrors it.
Name string
// Tabs, in order. Required, at least one.
Tabs []Tab
// Active is the selected tab's index. Out-of-range takes 0.
Active int
// VacateHidden ships hidden panels EMPTY with their content in an
// adjacent JSON stash the module restores on first show, so
// page-scoped locators cannot match hidden text.
VacateHidden bool
// StateAttrs mirrors data-state="active"/"inactive" onto every tab
// after client-side switches, the attribute Radix-style ports pin
// their locators to.
StateAttrs bool
// ID is the prefix the tab and panel ids derive from ("<ID>-tab-<n>"
// and "<ID>-panel-<n>"). Empty takes Name; a page with two strips
// on one signal-distinct name can still disambiguate ids with it.
ID string
ExtraAttrs html.Attrs
// Parts: attrs on the root, the tabs and the panels.
Parts Parts
}
TabsProps configures a tab strip.
type TagInputProps ¶
type TagInputProps struct {
// Name is the form-field name. Required: every committed value
// submits under it, as the standard repeated-key pattern.
Name string
// Label is the visible label. Required.
Label string
// Values are the committed tags, rendered as chips and as hidden
// inputs — the list on screen and the values in the form are the
// same set, which is the whole point of rendering the chips at
// all: what a reader sees remove is what a submit stops carrying.
Values []string
// Placeholder is the draft input's placeholder. A placeholder is
// not a name; the label is.
Placeholder string
// MaxLength caps one tag's length, in characters. Zero is no cap;
// negative is refused. The cap applies to the rendered values
// too, so a server value longer than the cap cannot submit
// unchanged while a typed one is refused.
MaxLength int
// Help is the rule the values obey.
Help string
// Disabled takes the chips' remove controls, the draft input and
// the add control out.
Disabled bool
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on every part. Strings carry the add
// control's name, the remove controls' names, and the two
// sentences the status says after a chip operation.
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
}
TagInputProps configures a free-form tag field.
type TagProps ¶
type TagProps struct {
// Label is the visible text. Required.
Label string
// Icon renders before the label.
Icon render.HTML
// DismissHref adds the dismiss control, an × that keeps a real
// href: removing a filter is the server's decision, and the href
// is the dismiss that needs no script.
DismissHref string
// Island is where the dismiss goes with script: removing a filter
// is an in-page state change, so the × carries the RPC contract
// beside its href — the page without script, the region update
// with it, and the URL written after the swap. Required when
// DismissHref is set; ignored otherwise.
Island Island
// DismissAriaLabel names the × for screen readers. Defaults to
// "Remove <Label>".
DismissAriaLabel string
// Href makes the whole chip an anchor — a filter link — with the
// label and any dismiss inside it. The same anchor policy as
// every href this package writes; one chip, one label, whatever
// shape it renders.
Href string
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on the root and the dismiss control.
// Strings carry the dismiss control's name.
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
}
TagProps is a tag: a badge-shaped chip standing in for an active filter, removable in place.
type TextareaProps ¶
type TextareaProps struct {
Name string
// DescribedBy is the aria-describedby a Field hands down. It is
// the whole reason a hint or an error reaches assistive tech: the
// text is on screen either way, but without this attribute a
// screen reader user hears the label and nothing else — no
// format hint, and no reason the control is red.
DescribedBy string
Value string
// Placeholder is the prompt shown when empty.
Placeholder string
// Rows sets the rows attribute. Zero omits it and lets the
// stylesheet size the box, so an unspecified height stays the
// system's decision rather than the caller's guess.
Rows int
Required bool
Disabled bool
Invalid bool
// Autogrow opts the control into the core runtime's auto-resize
// (textarea.js: every input event resets the height to the
// scrollHeight, so the field always shows all its content). It is
// the one data-fui-* attribute a component here renders, and it
// is a prop rather than an extra because every seam a caller can
// reach — Safe, the part-attrs sanitiser — refuses the prefix
// precisely so decoration cannot become a request; autogrow is a
// behaviour of the control itself, not a decoration, and the
// styled layer's TextArea has no other way to say it.
Autogrow bool
ID string
Extra html.Attrs
}
TextareaProps configures a multiline control.
type TimelineProps ¶
type TimelineProps struct {
// Label names the list for assistive tech — "Deploy history".
Label string
Events []Event
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on the list and every part it draws.
Parts Parts
}
TimelineProps is a sequence of events.
type ToastProps ¶
type ToastProps struct {
// Tone is one of info, success, warning, danger. The class map
// colours the row from it; the tone word carries it to a reader.
Tone string
// Icon is the decorative glyph, hidden from readers: the tone
// word is what tells them the kind of news. Empty renders no icon.
Icon render.HTML
// Title is the headline; Body is the detail. One of them is
// required — a toast that says nothing is decoration.
Title string
Body string
// DismissHref makes the toast dismissable with a link that keeps
// a real href, and requires a complete Island: dismissing an
// in-page region is an in-page state change, never a route.
DismissHref string
DismissLabel string
// TTLMS is how long the module keeps the toast before it goes, on
// the runtime path. Zero means it stays until dismissed. Negative
// is refused.
TTLMS int
// Live is how the toast interrupts. The default is polite: a
// toast is an arrival, and arrivals wait their turn; assertive is
// for the failures a reader must hear before doing anything else.
Live Live
// Island is where the dismiss goes with script. Required when
// DismissHref is set; ignored otherwise.
Island Island
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on every part. Strings carry the tone
// word and the dismiss control's name.
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
}
ToastProps configures one toast.
type ToastStackProps ¶
type ToastStackProps struct {
// Label names the stack for assistive technology. Required: the
// stack is a landmark a reader can jump to, and an unnamed one is
// a hole.
Label string
// Toasts are the rendered rows. The runtime path inserts into the
// stack; the server-rendered rows are already home.
Toasts []render.HTML
// Max is how many rows the module keeps before dropping the
// oldest. Default 4; zero takes the default; negative is refused.
Max int
ID string
ExtraAttrs html.Attrs
Parts Parts
// Strings carry the dismiss label template a runtime-inserted
// toast names itself by ("%s" where the toast's title goes).
Strings *Strings
}
ToastStackProps configures the one stack a layout mounts.
type ToggleActionProps ¶
type ToggleActionProps struct {
// Endpoint is the URL hit when toggling idle → committed.
// Required, and same-origin.
Endpoint string
// Method defaults to POST and may be PUT, PATCH or DELETE. It
// applies to both the commit and the untoggle request.
Method string
// IdleLabel is the text in the un-committed state. Required.
IdleLabel string
// CommittedLabel is the text while committed. Required, and it
// must differ from IdleLabel: the flip is the signal.
CommittedLabel string
// IdleIcon and DoneIcon are decoration beside each label.
IdleIcon render.HTML
DoneIcon render.HTML
// Committed is the state the server knows: render it true when
// the action is already active, so first paint matches server
// state instead of flashing through the wrong label.
Committed bool
// Group, when set, joins this button to a client-side mutex:
// committing any button with the same key reverts the
// previously-committed sibling, with no second request.
Group string
// AllowUntoggle lets a click on a committed button revert it to
// idle. Without it (and without UntoggleEndpoint) the button is
// sticky once committed, like OptimisticAction.
AllowUntoggle bool
// UntoggleEndpoint is the URL hit when reverting committed →
// idle. Setting it implies AllowUntoggle; when empty the revert
// flips locally with no request.
UntoggleEndpoint string
// Variant and Size are class-map vocabulary.
Variant string
Size string
// Disabled is the state at render time.
Disabled bool
// FailedText is what the status span announces on a failure.
FailedText string
ID string
ExtraAttrs html.Attrs
// Parts: attrs only, for the same reason as
// OptimisticActionProps.
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
}
ToggleActionProps is the three-state cousin: idle → pending → committed, and back, with the initial state shipped from the server.
type ToolbarProps ¶
ToolbarProps configures a toolbar. The toolbar carries no role of its own: role="toolbar" promises arrow-key roving that this script-free package cannot implement, and an unfulfilled promise is worse than none. A caller who ships the keyboard handling can add it through ExtraAttrs.
type ToolbarSearchProps ¶
type ToolbarSearchProps struct {
// Island is required: a search refilters the list the toolbar
// sits on, which is an in-page state change — never a route.
Island Island
}
ToolbarSearchProps is the toolbar's search field: the one child allowed to take the row's slack, and the GET form that makes a search an island update rather than a navigation. The form carries no action, so without script it submits to the page it is on — which is the search's own URL — and no push-state, because the canonical URL is the server's to name in X-Gofastr-Push-State once it knows what matched.
type TreeNode ¶
type TreeNode struct {
// ID is unique within the tree and becomes the treeitem's element
// id. Required, and a bare id: letters, digits, `-`, `_` — a
// space, quote, `#` or markup refuses at render. Unlike
// SortableItem.Key this is not data: the id pairs with
// href="#<id>" fragments and signal names, so slugify stored
// values before they reach the tree.
ID string
// Label is the row's visible text. Required.
Label string
// Href, when set, makes the row's label a link. A branch with
// Href keeps its toggle; a dangerous href degrades to a plain
// label rather than a clickable vector.
Href string
// Children are statically-known descendants. Empty for leaves.
Children []TreeNode
// LazyPath, when set and Children is empty, makes this a branch
// whose children load on first expand: the toggle carries the
// kernel's rpc wiring against LazyPath and the child group is
// bound to the signal the response swaps in. Children wins when
// both are set — the children are already there.
LazyPath string
// Expanded forces the branch open on first paint.
Expanded bool
// Selected sets aria-selected="true" on the treeitem.
Selected bool
}
TreeNode is one entry in the tree.
type TreeProps ¶
type TreeProps struct {
// Label is the aria-label on the role="tree" wrapper. Required.
Label string
// Nodes are the root-level entries. Required and non-empty: a
// tree with nothing in it is a landmark that says nothing.
Nodes []TreeNode
// LazySignalPrefix names the signal namespace the lazy branches
// bind their child groups to (each lazy branch's group carries
// data-fui-signal="<prefix>-<node-id>"). Required when any node
// uses LazyPath, ignored otherwise.
LazySignalPrefix string
// ID is the tree wrapper's element id. Required.
ID string
ExtraAttrs html.Attrs
// Parts: attrs on the root and the rows. No part is fillable: the
// tree is the contract.
Parts Parts
}
type ValidationSummaryProps ¶
type ValidationSummaryProps struct {
// Title heads the summary. Defaults to "There is a problem".
Title string
// Level is the title's heading level, 2 by default.
Level int
Errors []FieldError
// ID names the summary's root. Required, like the control ids the
// errors link to: the title's id is derived from it, and two
// summaries on one page without ids would share one title id —
// breaking both labels and both announcements.
ID string
ExtraAttrs html.Attrs
// Parts: attrs and binds on the root, the title, the list and
// its items. Strings carry the title a failed submit
// focuses).
Parts Parts
// Strings are the strings this component says. Nil means the English
// defaults; a layer above sets them from the request's language.
Strings *Strings
}
ValidationSummaryProps is the list of everything wrong with a form.
type WizardStep ¶
type WizardStep struct {
// Heading is the step's name. Required: the rail's dots and the
// step's own heading say it, and a step with no name is a
// nameless place in a flow.
Heading string
// Description is the supporting line under the heading.
Description string
// Fields are the step's form fields.
Fields []render.HTML
}
WizardStep is one step of the flow.
Source Files
¶
- action.go
- agents.go
- behavior.go
- box.go
- breadcrumbs.go
- button.go
- carousel.go
- carousel_behavior.go
- carousel_spec.go
- choice.go
- collections.go
- collections_behavior.go
- combobox.go
- combobox_behavior.go
- control.go
- controls.go
- controls_behavior.go
- counter.go
- disclosure.go
- disclosure_behavior.go
- feedback.go
- feedback_behavior.go
- field.go
- form.go
- gallery.go
- headless.go
- island.go
- jsontree.go
- layout.go
- lightbox.go
- menu.go
- menu_behavior.go
- multiselect.go
- multiselect_behavior.go
- nav.go
- navigation_behavior.go
- notification.go
- own.go
- page.go
- panehost.go
- panehost_behavior.go
- progress.go
- rail.go
- rail_behavior.go
- sidebar.go
- sidebar_behavior.go
- sortablelist.go
- sortablelist_behavior.go
- spec.go
- specimen.go
- status.go
- stepwizard.go
- strings.go
- surface.go
- system.go
- table.go
- tabs.go
- tabs_behavior.go
- toc.go
- toc_behavior.go
- tree.go
- tree_behavior.go
- upload.go
- validate.go
- validation.go
- when_behavior.go
- wizard_behavior.go