Dashboard Widget
import { DashboardWidget } from '@absoluteui/components/dashboard-widget';import '@absoluteui/components/dashboard-widget/style.css';Using Angular? See Dashboard Widget for Angular.
What it does
Section titled “What it does”A titled dashboard panel (widget container, collapsible widget, dashboard tile). DashboardWidget enhances a host element in place: a header with a heading, an optional subtitle, and action buttons (custom icon actions, collapse, maximize, remove) is inserted as the host’s first child. The host’s other children are the body; they are never moved, so framework-owned content is safe. Collapse is a disclosure button. Maximize shows the widget in the top layer as a modal dialog. Remove emits a cancelable event; the application removes the widget or its Dashboard Grid item.
When to use
Section titled “When to use”- Panels inside a Dashboard Grid (pass data-aui-item on the host).
- Titled content blocks on a dashboard that users collapse, expand to full screen, or remove.
When not to use
Section titled “When not to use”- Generic content cards without widget actions: use Card.
- Dialogs opened from elsewhere on the page: use Dialog.
- Page sections that should not be landmarks: the host becomes role=region unless it already has another role.
Examples
Section titled “Examples”Enhance a panel: heading, collapse, and maximize
Section titled “Enhance a panel: heading, collapse, and maximize”import { DashboardWidget, type DashboardWidgetToggleDetail } from '@absoluteui/components/dashboard-widget';
const host = document.createElement('section');const body = document.createElement('p');body.textContent = '1,204 open tickets';host.append(body);document.body.append(host);
const widget = DashboardWidget.create(host, { title: 'Support queue', subtitle: 'Updated hourly', headingLevel: 2 });host.addEventListener('aui-toggle', (event) => { const { collapsed } = (event as CustomEvent<DashboardWidgetToggleDetail>).detail; host.dataset.collapsed = String(collapsed && widget.collapsed);});Custom actions and a removable widget inside a Dashboard Grid
Section titled “Custom actions and a removable widget inside a Dashboard Grid”import { DashboardGrid } from '@absoluteui/components/dashboard-grid';import { DashboardWidget, type DashboardWidgetActionDetail, type DashboardWidgetRemoveDetail } from '@absoluteui/components/dashboard-widget';
const gridHost = document.createElement('div');const widgetHost = document.createElement('section');widgetHost.dataset.auiItem = 'sales';gridHost.append(widgetHost);document.body.append(gridHost);
const grid = DashboardGrid.create(gridHost, { label: 'Overview', items: [{ id: 'sales', x: 0, y: 0, w: 6, h: 3 }], editable: true });const widget = DashboardWidget.create(widgetHost, { title: 'Sales', removable: true, busy: true, actions: [{ id: 'refresh', label: 'Refresh sales', icon: 'refresh' }],});widgetHost.addEventListener('aui-action', (event) => { const { id } = (event as CustomEvent<DashboardWidgetActionDetail>).detail; if (id === 'refresh') widget.update({ busy: true });});widgetHost.addEventListener('aui-remove', (event) => { const { id } = (event as CustomEvent<DashboardWidgetRemoveDetail>).detail; if (id !== null) grid.removeItem(id);});Widgets without the maximize button
Section titled “Widgets without the maximize button”import { configureAbsoluteUI } from '@absoluteui/core';
configureAbsoluteUI({ components: { dashboardWidget: { maximizable: false } } });import { DashboardWidget } from '@absoluteui/components/dashboard-widget';import '@absoluteui/components/dashboard-widget/style.css';
const host = document.querySelector<HTMLElement>('#tickets');if (host) { DashboardWidget.create(host, { title: 'Open tickets', headingLevel: 2, removable: true, actions: [{ id: 'refresh', label: 'Refresh tickets', icon: 'refresh' }] }); host.addEventListener('aui-remove', () => { host.remove(); });}More usage
Section titled “More usage”import { DashboardWidget } from '@absoluteui/components/dashboard-widget';
const host = document.querySelector<HTMLElement>('#sales');if (host) DashboardWidget.create(host, { title: 'Sales', subtitle: 'Last 30 days', removable: true });Anatomy
Section titled “Anatomy”<section class="aui-widget [aui-widget--collapsed] [aui-widget--maximized]" role="region" aria-labelledby="{title id}" [aria-busy]> (consumer host) <div class="aui-widget__header"> (inserted first) <div class="aui-widget__titles"> <h3 class="aui-widget__heading"><span class="aui-widget__title" id>Title</span></h3> <p class="aui-widget__subtitle"> (hidden when empty) </div> <div class="aui-widget__actions"> <button class="aui-widget__action aui-widget__action--custom" data-action="custom:{id}"> (actions) <button class="aui-widget__action aui-widget__toggle" aria-expanded> (collapsible) <button class="aui-widget__action aui-widget__maximize"> (maximizable) <button class="aui-widget__action aui-widget__remove"> (removable) </div> </div> ...body: the host's own children, untouched...</section>API reference
Section titled “API reference”Factory
Section titled “Factory”DashboardWidget.create(host: HTMLElement, options: DashboardWidgetOptions): DashboardWidgetGlobal configuration key: dashboardWidget (see Configuration).
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
title |
string |
Heading text; names the region and the action buttons. Non-empty. Required. | |
headingLevel |
2 | 3 | 4 | 5 | 6 |
3 |
Heading element level; changing it with update() throws. Set at creation only. |
subtitle |
string |
Supporting text under the heading (hidden when empty). | |
actions |
readonly DashboardWidgetAction[] |
Extra header icon buttons { id, label, icon } (unique ids, non-empty labels); activation emits aui-action. | |
removable |
boolean |
false |
Show a remove button that emits the cancelable aui-remove. |
collapsed |
boolean |
false |
Initial and controlled collapsed state (update() sets it without an event). |
busy |
boolean |
false |
Set aria-busy=true on the host while content loads. |
collapsible |
boolean |
true |
Show the collapse/expand button. Globally configurable. |
maximizable |
boolean |
true |
Show the maximize/restore button. Globally configurable. |
locale |
string |
"en-US" |
Locale of the action button names. Globally configurable. Inherited from common configuration. |
direction |
'ltr' | 'rtl' |
"ltr" |
Resolved with the other options; the layout itself follows the document direction (logical CSS). Globally configurable. Inherited from common configuration. |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
host |
HTMLElement |
The enhanced host. |
header |
HTMLDivElement |
The inserted header element (first child of the host). |
collapsed |
boolean |
Collapsed state. |
maximized |
boolean |
Maximized (modal) state. |
Methods
Section titled “Methods”| Method | Description |
|---|---|
update(options: Partial<DashboardWidgetOptions>): void |
Merge, validate, and re-render the header (collapsed applies without an event). Throws when headingLevel changes. |
setCollapsed(collapsed: boolean): void |
Collapse or expand without an event. |
setMaximized(maximized: boolean): void |
Maximize into a modal dialog in the top layer, or restore; emits aui-maximize when the state changes. |
destroy(): void |
Restore if maximized; remove the header, classes, aria-busy, aria-labelledby, and the region role it set. Body children stay. |
Events
Section titled “Events”| Event | Detail | Bubbles | Cancelable | Description |
|---|---|---|---|---|
aui-toggle |
DashboardWidgetToggleDetail { collapsed: boolean } |
No | No | The user activated the collapse/expand button. |
aui-maximize |
DashboardWidgetMaximizeDetail { maximized: boolean } |
No | No | The widget was maximized or restored (button, Escape, or setMaximized). |
aui-action |
DashboardWidgetActionDetail { id: string } |
Yes | No | The user activated a custom header action. |
aui-remove |
DashboardWidgetRemoveDetail { id: string | null } |
Yes | Yes | The user activated the remove button; id is the host’s data-aui-item (its Dashboard Grid item) or null. The widget takes no default action: remove the element or call grid.removeItem(id). |
Content areas
Section titled “Content areas”| Area | Description |
|---|---|
body (host children) |
Every host child other than the inserted header is the body. It stays where it is (framework-owned content is never moved) and is hidden with display: none while collapsed. |
CSS classes
Section titled “CSS classes”All rules live in the aui.components cascade layer, so application styles override them without specificity battles.
| Class | Purpose |
|---|---|
aui-widget |
Host panel. |
aui-widget--collapsed | --maximized |
State modifiers on the host. |
aui-widget__header | __titles | __heading | __title | __subtitle |
Header, title group, heading element, title text (labels the region/dialog), subtitle. |
aui-widget__actions |
Action button group. |
aui-widget__action |
Every action button; modifiers aui-widget__action–custom, aui-widget__toggle, aui-widget__maximize, aui-widget__remove. data-action is custom:<id>, toggle, maximize, or remove. |
Icon slots
Section titled “Icon slots”| Slot | Default icon |
|---|---|
collapse / expand |
chevron-down |
maximize |
maximize |
restore |
minimize |
remove |
trash |
custom actions (DashboardWidgetAction.icon) |
none |
Design tokens
Section titled “Design tokens”Tokens this stylesheet reads (verified in CI). Override them in a theme or with the Theme Designer.
--aui-border-width | --aui-color-backdrop | --aui-color-border | --aui-color-focus-ring | --aui-color-hover | --aui-color-surface | --aui-color-text | --aui-color-text-muted | --aui-duration-fast | --aui-easing-standard | --aui-focus-ring-offset | --aui-focus-ring-width | --aui-font-family-sans | --aui-font-size-md | --aui-font-size-sm | --aui-font-weight-semibold | --aui-line-height-tight | --aui-radius-lg | --aui-radius-sm | --aui-shadow-lg | --aui-shadow-sm | --aui-space-1 | --aui-space-2 | --aui-space-3 | --aui-space-6 | --aui-space-inset | --aui-touch-target-min
TypeScript definitions
Section titled “TypeScript definitions”interface DashboardWidgetAction { id: string; label: string; icon: IconRef }interface DashboardWidgetToggleDetail { collapsed: boolean }interface DashboardWidgetMaximizeDetail { maximized: boolean }interface DashboardWidgetActionDetail { id: string }interface DashboardWidgetRemoveDetail { id: string | null }Accessibility
Section titled “Accessibility”Pattern: Labelled region with a heading and header buttons; collapse follows the WAI-ARIA APG Disclosure pattern; maximize follows the APG modal Dialog pattern (top layer through the Popover API).
Keyboard
Section titled “Keyboard”| Key | Context | Action |
|---|---|---|
| Tab / Shift+Tab | Any | Moves through the header buttons and body content in DOM order. |
| Enter / Space | Collapse button | Toggles the body (aria-expanded); emits aui-toggle. Focus stays on the button. |
| Enter / Space | Maximize button | Maximizes into a modal dialog; focus moves to the restore button and is trapped inside the widget; page scroll is locked. |
| Escape | Maximized | Restores the widget (topmost overlay first); focus returns to the maximize button. |
| Tab / Shift+Tab | Maximized | Cycles within the widget (focus trap). |
| Enter / Space | Remove or custom action button | Emits aui-remove (cancelable) or aui-action. |
| Element | Role |
|---|---|
| host | region (set unless the host already has another role); dialog while maximized |
| heading | heading (native h2-h6) |
| action buttons | button (native) |
| icons | none (decorative) |
ARIA attributes
Section titled “ARIA attributes”| Attribute | Element | Value |
|---|---|---|
aria-labelledby |
host | id of the title text (region and dialog name) |
aria-modal |
host | “true” while maximized (role=dialog) |
aria-busy |
host | “true” while busy |
aria-expanded |
collapse button | “true” when expanded, “false” when collapsed |
aria-label and title |
action buttons | Localized ‘Collapse {title}’ / ‘Expand {title}’, ‘Maximize {title}’ / ‘Restore {title}’, ‘Remove {title}’, or the custom action label |
Header buttons show a focus-ring-width outline in color-focus-ring. Re-rendering keeps focus on the same action. Maximize moves focus to the restore button; restore returns it to the maximize button.
WCAG 2.2 success criteria addressed
Section titled “WCAG 2.2 success criteria addressed”| Criterion | Level | Note |
|---|---|---|
| 1.3.1 Info and Relationships | A | |
| 2.1.1 Keyboard | A | |
| 2.1.2 No Keyboard Trap | A | |
| 2.4.3 Focus Order | A | |
| 2.4.6 Headings and Labels | AA | |
| 2.4.7 Focus Visible | AA | |
| 2.5.8 Target Size (Minimum) | AA | |
| 4.1.2 Name, Role, Value | A |
Automated test results: Accessibility and compliance.
Notes and known caveats
Section titled “Notes and known caveats”- The region is named by the visible title; action names include the title, so several widgets on one page stay distinguishable.
- Collapse hides the body with display: none, so hidden content is removed from the accessibility tree and tab order.
- Maximized, outside pointer presses do not restore the widget; Escape and the restore button do.
- The collapse button is not shown while maximized.
- Manual screen-reader verification (NVDA, JAWS, VoiceOver) is pending.
- The collapse button has no aria-controls (the body is every host child except the header).
- Many widgets on a page create many region landmarks; give hosts another role (for example role=group) when that is too noisy.
Behavior
Section titled “Behavior”States
Section titled “States”expanded, collapsed, maximized (modal), busy, action hover, action focus-visible.
State transitions
Section titled “State transitions”| From | Trigger | To |
|---|---|---|
| expanded | collapse button | collapsed; aui-toggle { collapsed: true } |
| collapsed | expand button | expanded; aui-toggle { collapsed: false } |
| any | maximize button / setMaximized(true) |
maximized: role="dialog", aria-modal, top layer, focus trapped, scroll locked; aui-maximize |
| maximized | Escape, restore button, setMaximized(false) |
previous role restored; focus to the maximize button; aui-maximize |
| any | update({ collapsed }), setCollapsed() |
collapsed state set, no event |
Accessibility notes
Section titled “Accessibility notes”- Action names include the title, so several widgets remain distinguishable.
- Collapsed bodies are
display: none: removed from the accessibility tree and tab order. - Maximized, focus is trapped and outside presses do not restore; Escape and the restore button do (WCAG 2.1.2: no trap without an exit).
- The collapse button is hidden while maximized. Manual screen-reader verification is pending.
Responsive behavior
Section titled “Responsive behavior”Fills its container and scrolls its content (overflow: auto). Actions wrap. Maximized, the widget is fixed over the viewport inset by space-6. Action buttons are at least touch-target-min.
Right-to-left
Section titled “Right-to-left”Logical properties throughout; the collapsed chevron rotation is mirrored.
Theming
Section titled “Theming”Role tokens only; maximized uses shadow-lg and a color-backdrop backdrop. Forced colors: CanvasText border. The chevron transition is removed under reduced motion.
Global configuration
Section titled “Global configuration”configureAbsoluteUI({ components: { dashboardWidget: { maximizable: false } } });Global options: collapsible, maximizable, plus inherited locale and direction. Changes apply to existing widgets immediately.
Component configuration
Section titled “Component configuration”Instance options override global and theme defaults. All options are dynamic except headingLevel.
Built-in actions use chevron-down (collapse), maximize / minimize (maximize / restore), and trash (remove). Custom actions take any IconRef.
Security
Section titled “Security”Title, subtitle, and labels use textContent and attributes; the body is never read or re-parsed. CSP-safe.
Data handling
Section titled “Data handling”No persistence, network access, or telemetry. Store collapsed state from aui-toggle if needed.
Performance
Section titled “Performance”The header is rebuilt on every update() (a handful of buttons); the body is untouched. One configuration subscription per instance; maximize adds a focus trap, a scroll lock, and an overlay registration only while maximized. Not separately budgeted: covered by the Dashboard Grid budget (create with 50 items < 40 ms in headless Chromium, e2e performance test).
Supported data scale
Section titled “Supported data scale”Dashboards of up to 50 widgets (the Dashboard Grid target).
Edge cases
Section titled “Edge cases”- A host with its own role (other than
region) keeps it;aria-labelledbyis still set. - Without
HTMLElement.showPopoverthe maximized widget is fixed-positioned only, not in the top layer. - Re-rendering keeps focus on the same action button.
aui-removedoes nothing by itself;preventDefault()only matters to other listeners.
Errors
Section titled “Errors”| Code | Category | Cause |
|---|---|---|
DASHBOARD_WIDGET_OPTIONS |
configuration | Empty title; headingLevel outside 2..6 or changed by update(); non-boolean flags; invalid or duplicate action ids or empty labels. |
Known limitations
Section titled “Known limitations”- Maximize depends on the Popover API for the top layer.
- No
aria-controlson the collapse button. headingLevelis init-only.- Manual screen-reader verification is pending.
Unsupported scenarios
Section titled “Unsupported scenarios”- HTML in the title or subtitle.
- Non-modal full-screen mode.