Skip to content

Roadmap — @gnome-ui/react

Component implementation plan following the GNOME Human Interface Guidelines.

Legend: ✅ Done · 🚧 In progress · ⬜ Pending


Next Package Priorities

Framework expansion will proceed in this order. All three packages build on the framework-agnostic tokens and themes provided by @gnome-ui/core.

Priority Status Package Description
1 🚧 @gnome-ui/web-components Framework-agnostic Custom Elements for GNOME widgets. Foundation: gnome-button, gnome-dialog, gnome-menu, gnome-toast, and gnome-popover; uses semantic HTML and light DOM, exposes standard DOM events, preserves accessibility, and remains compatible with htmx and server-rendered fragments.
2 ⬜ @gnome-ui/angular Angular package built after the Web Components foundation. Provide standalone components, Angular Forms integration where applicable, and reuse @gnome-ui/core tokens plus Web Components rather than duplicating styling and behavior. Blocked on Priority 1.
3 🚧 @gnome-ui/react-native React Native package targeting iOS/Android/GNOME-mobile shells. No DOM to reuse from Web Components, so components are rebuilt with native primitives (View, Text, Pressable) and StyleSheet; consumes @gnome-ui/core tokens via a generated RN-compatible theme object (JS values, not CSS custom properties) and mirrors the @gnome-ui/react component API/props where the platforms overlap. Independent of Priority 1/2 — can start in parallel since it does not depend on the Web Components foundation.

Tier 1 — Base

Foundation components. Everything else depends on these.

Status Component Description
✅ Button Default, Suggested, Destructive, Flat, Pill, Circular
✅ Text All 12 Adwaita styles: large-title, title-1…4, heading, body, document, caption, caption-heading, monospace, numeric
✅ Link Inline hyperlink with accent colour, hover underline, and external-URL variant
✅ Text Field Text input with label, helper text, and error state
✅ Switch On/off toggle — replaces checkbox in settings UIs
✅ Checkbox Multi-selection with indeterminate state
✅ Radio Button Single selection within a group

Tier 2 — Layout & Containers

Structure and grouping. Core patterns of GNOME app UIs.

Status Component Description
✅ Separator Horizontal/vertical divider line
✅ Card Elevated surface for grouping related content
✅ Boxed List Rounded bordered list of ActionRow items — the most common GNOME pattern
✅ Action Row Row with title, subtitle, and an end widget (switch, button…)
✅ Header Bar Title bar with centered title and action buttons

Tier 3 — Navigation

Status Component Description
✅ Tabs / Tab Bar Tab-based navigation
✅ View Switcher Segmented control for switching between views
✅ Sidebar Lateral navigation panel
✅ Search Bar Collapsible search bar
✅ PathBar Breadcrumb path bar for hierarchical navigation; ancestor segments are interactive buttons, current segment is bold non-interactive label; optional per-segment icons — issue #17

Tier 4 — Feedback

Status Component Description
✅ Spinner Indeterminate loading indicator
✅ Progress Bar Determinate and indeterminate progress
✅ Skeleton Content-shaped loading placeholder for web-style skeleton screens; pragmatic extension beyond GNOME HIG loading patterns — issue #95
✅ Toast Non-blocking temporary notification
✅ Banner Persistent message at the top of a view
✅ Dialog Blocking modal with title, body, and buttons
✅ Tooltip Informational text on hover
✅ Status Page Empty state with icon, title, and description
✅ AnimatedIcon Plays the CSS animation embedded in an animated icon from @gnome-ui/icons (Syncing, Recording, Downloading, Connecting); always honors prefers-reduced-motion. Pragmatic web analog to GTK 4.22's GtkSvg native animated-SVG renderer — see @gnome-ui/icons — Icon Library below

Tier 5 — Advanced Controls

Status Component Description
✅ Dropdown / Select Expandable option list
✅ Slider Numeric range with draggable handle
✅ Spin Button Numeric input with +/− buttons
✅ Avatar Circular user image with initials fallback
✅ Badge Counter or status indicator overlaid on another element
✅ Popover Floating panel anchored to a trigger element

Tier 6 — Adaptive Layout

Responsive primitives mirroring the libadwaita adaptive layout system.

GNOME breakpoints (1 sp ≈ 1 px at 1× density): | Threshold | Pattern triggered | |-----------|-------------------| | ≤ 400 sp | Collapse split views to single pane; sidebar becomes overlay | | ≤ 550 sp | Move ViewSwitcher from header bar to a bottom bar | | ≤ 860 sp | Collapse outer pane in nested two-level split views |

Sizing guidelines for sidebars: - Width fraction: 25 % of total width - Min width: 180 sp · Max width: 280 sp

Status Component Description
✅ useBreakpoint Hook that tracks viewport width against GNOME breakpoints and fires callbacks on change — mirrors AdwBreakpoint
✅ Clamp Constrains content to a maximum width while allowing it to shrink freely — mirrors AdwClamp
✅ NavigationSplitView Two-pane sidebar + content layout; collapses to a single navigable pane at ≤ 400 sp — mirrors AdwNavigationSplitView
✅ OverlaySplitView Sidebar + content layout where the sidebar becomes a slide-over overlay at ≤ 400 sp — mirrors AdwOverlaySplitView
✅ ViewSwitcherBar Bottom bar that replaces the header-bar ViewSwitcher on narrow windows (≤ 550 sp) — mirrors AdwViewSwitcherBar

Tier 7 — GNOME 48–50 (libadwaita 1.7–1.9)

New widgets introduced in libadwaita 1.7 (GNOME 48), 1.8 (GNOME 49), and 1.9 (GNOME 50 "Tokyo", March 2026).

libadwaita 1.7 — GNOME 48

Status Component Description
✅ ToggleGroup Unified group of mutually-exclusive toggle buttons — replaces the pattern of multiple Button in a box; mirrors AdwToggleGroup
✅ WrapBox Flexible wrapping layout for tag/chip lists that flows across multiple lines — mirrors AdwWrapBox
✅ Chip Compact pill-shaped label for tags, filters, and multi-select states; static, removable, and selectable modes

libadwaita 1.8 — GNOME 49

Status Component Description
✅ ShortcutsDialog Modal listing keyboard shortcuts with integrated search — mirrors AdwShortcutsDialog (replaces deprecated GtkShortcutsWindow)

libadwaita 1.9 — GNOME 50

Status Component Description
✅ Sidebar (v2) Rewrite of the existing Sidebar component following AdwSidebar: named sections, per-row suffix widgets, context menus, and tooltip
✅ ViewSwitcherSidebar Sidebar-based view switcher — mirrors AdwViewSwitcherSidebar (replaces GtkStackSidebar)
✅ BreakpointBin Applies layout changes when the component (not the viewport) crosses a size threshold — CSS container queries equivalent of AdwBreakpointBin

Cross-cutting — accessibility

Status Item Description
✅ High-contrast support Add @media (prefers-contrast: more) overrides to design tokens and all components — formalised in libadwaita 1.8

Cross-cutting — internationalization

Status Item Description
✅ Provider-level Intl formatting GnomeProvider supplies locale, dir, numberFormat, and dateTimeFormat; useNumberFormatter and useDateTimeFormatter apply those defaults across @gnome-ui/react, @gnome-ui/layout, and @gnome-ui/charts

Tier 8 — Style-class Utilities & Composition Helpers

Lightweight components and props derived from the libadwaita 1.9 style-class reference. These fill gaps between what we already ship and what the full Adwaita toolkit offers.

Layout primitives

Status Component Description
✅ Toolbar .toolbar box: flat-buttons, 6 px margins/gap — wraps AdwHeaderBar, GtkActionBar, and generic tool rows
✅ Spacer .spacer separator: invisible flex: 1 filler for Toolbar/HeaderBar to push trailing items to the end — mirrors GtkSeparator.spacer
✅ LinkedGroup .linked box: children rendered as a single connected unit with no gap and merged borders — canonical GNOME pattern for button groups and segmented inputs
✅ Frame .frame container: simple bordered surface (border + border-radius) without background — mirrors GtkFrame default styling

BoxedList / ActionRow variants

Status Component Description
✅ BoxedList variant="separate" Add variant="separate" to BoxedList: renders each child as its own rounded card — mirrors .boxed-list-separate
✅ ButtonRow Full-width activatable row styled as a button inside a BoxedList — mirrors AdwButtonRow; supports suggested and destructive variants
✅ ActionRow variant="property" Add variant="property" to ActionRow: flips weight so the subtitle is the primary text (read-only property display) — mirrors .property style class
✅ ExpanderRow Collapsible ActionRow that reveals nested rows on activation — mirrors AdwExpanderRow

Button additions

Status Component Description
✅ SplitButton Primary action button with an attached dropdown arrow — mirrors AdwSplitButton; supports suggested and destructive variants
✅ IconButton Accessible icon-only action button composed from Button, Icon, and optional Tooltip; supports variants, sizes, disabled state, refs, and HTML button attributes — issue #102
✅ Button raised variant Add variant="raised" to Button: explicit raised look for buttons inside flat/toolbar contexts — mirrors .raised style class
✅ Button osd modifier Add osd prop to Button: dark semi-transparent style for controls overlaid on media/images — mirrors .osd style class
✅ CopyButton Icon button that copies a value to the clipboard via navigator.clipboard, swapping to a checkmark and "Copied!" tooltip/live-region announcement as confirmation; composed from IconButton — no @gnome-ui/platform dependency required

View Switcher additions

Status Component Description
✅ InlineViewSwitcher Compact inline view switcher built on ToggleGroup internals; flat and round style variants — mirrors AdwInlineViewSwitcher (GNOME 48)

StatusPage addition

Status Component Description
✅ StatusPage compact prop Add compact prop to the existing StatusPage: reduces spacing and icon size for sidebars/popovers — mirrors .compact style class

Tab / Search inline variant

Status Component Description
✅ TabBar inline prop Add inline prop to TabBar: removes the header-bar background so the bar blends into any surface — mirrors .inline style class
✅ SearchBar inline prop Add inline prop to SearchBar: same neutral-background treatment as above — mirrors .inline style class
✅ SearchBar autocomplete suggestions prop + Popover-based typeahead list anchored to the input; keyboard navigation (↑↓ Enter); role="listbox" + aria-activedescendant; replaces deprecated GtkEntryCompletion following the GTK4 AdwSearchBar + GtkPopover + GtkListView pattern — issue #24

Tier 9 — Stories & Composition Examples

Full-page composition stories that demonstrate real-world use of the component library.

Status Story Description
✅ Layout/Dashboard Full-page app layout: Toolbar with logo + inline SearchBar + action buttons + avatar Popover, collapsible sidebar with SidebarItem + Badge, content area with Card, BoxedList, ExpanderRow, InlineViewSwitcher, StatusPage, and footer Toolbar
✅ Layout/FileManager GNOME Files (Nautilus)–style file browser: PathBar breadcrumb navigation in toolbar, collapsible Sidebar with Places + Network sections, InlineViewSwitcher for grid/list toggle, folder drill-down, and mobile overlay sidebar — issue #16
✅ Layout/Settings GNOME Settings–style preferences app: dual-headerbar pattern, 14-category sidebar with per-category icons, sub-page drill-down (Accessibility → Seeing), SwitchRow toggle rows, ActionRow for value navigation, PreferencesGroup sections

Tier 10 — Sidebar Enhancements (identified via Dashboard story)

Gaps discovered while building the Dashboard composition story.

Status Component Description
✅ Sidebar collapsed prop Built-in icon-only (mini/rail) mode: collapsed prop animates width (240 px → 56 px), hides labels/suffixes/section titles, and auto-shows tooltips on hover. SidebarCollapsedContext and useSidebarCollapsed hook exported for custom consumers. Dashboard story updated to use the real Sidebar component.

Tier 11 — Sidebar 1.9 Completeness

Gaps vs AdwSidebar in libadwaita 1.9 identified by reviewing the release notes.

Status Component Description
✅ Sidebar search/filter Built-in filter prop + SearchBar integration; shows a StatusPage placeholder when the filtered list is empty — mirrors AdwSidebar's GtkFilter support
✅ Sidebar adaptive mode mode prop ("sidebar" \| "page") that switches to a boxed-list layout on narrow viewports (≤ 400 sp), mirroring AdwSidebar mobile behaviour
✅ SidebarItem drop target onDrop / acceptTypes props to turn individual rows into drag-and-drop targets — mirrors AdwSidebar per-row drop target support

Tier 12 — Boxed List Row Variants

Specialised row types present in the libadwaita widget gallery but not yet implemented.

Status Component Description
✅ SwitchRow ActionRow with an embedded Switch as the end widget — mirrors AdwSwitchRow; the canonical GNOME settings toggle pattern
✅ ComboRow ActionRow with an inline dropdown selector — mirrors AdwComboRow; common for single-choice preferences
✅ EntryRow ActionRow where the subtitle area is a live text input — mirrors AdwEntryRow
✅ PasswordEntryRow EntryRow variant with masked input and a reveal toggle — mirrors AdwPasswordEntryRow
✅ SpinRow ActionRow with an embedded SpinButton — mirrors AdwSpinRow

Tier 13 — Preferences UI

Full preferences-window pattern used by most GNOME applications.

Status Component Description
✅ PreferencesGroup Titled section that wraps a BoxedList with an optional description — mirrors AdwPreferencesGroup
✅ PreferencesPage Scrollable page composed of PreferencesGroup sections — mirrors AdwPreferencesPage
✅ PreferencesDialog Multi-page settings dialog using PreferencesPage tabs — mirrors AdwPreferencesDialog (replaces AdwPreferencesWindow)

Tier 14 — Missing Navigation & Overlays

Navigation and overlay patterns present in the widget gallery but not yet shipped.

Status Component Description
✅ NavigationView Single-pane push/pop navigation stack — mirrors AdwNavigationView; the mobile-first counterpart to NavigationSplitView
✅ BottomSheet Slide-up panel that overlays content from the bottom edge — mirrors AdwBottomSheet (libadwaita 1.6+)
✅ Carousel Swipeable horizontal/vertical content carousel with CarouselIndicatorDots and CarouselIndicatorLines — mirrors AdwCarousel
✅ AlertDialog role="alertdialog" + responses/onResponse API added to Dialog — mirrors AdwAlertDialog
✅ AboutDialog variant="about" + app info props added to Dialog (details/credits/legal tabs) — mirrors AdwAboutDialog

Tier 15 — Layout & Utility Gaps

Small primitives and helpers present in the widget gallery that round out the system.

Status Component Description
✅ Bin Single-child container with no visual styling — mirrors AdwBin; useful as a base for custom components
✅ ToolbarView Layout container that attaches a HeaderBar/ActionBar at top or bottom and scrolls only the middle content — mirrors AdwToolbarView
✅ WindowTitle Two-line title + subtitle widget centred in a HeaderBar — mirrors AdwWindowTitle
✅ ShortcutLabel Read-only display of a keyboard shortcut (e.g. Ctrl+S) with proper key-cap styling — mirrors GtkShortcutLabel
✅ ButtonContent Icon + label layout helper for buttons with both an icon and text — mirrors AdwButtonContent

@gnome-ui/icons — Icon Library

Framework-agnostic Adwaita symbolic icon definitions. Each icon is a plain IconDefinition object (SVG path data) consumed by the <Icon> component in @gnome-ui/react.

Status Category Icons
✅ Navigation GoPrevious, GoNext, GoHome, GoUp, PanDown, PanUp, PanStart, PanEnd
✅ Actions Add, Remove, Delete, Edit, Copy, Paste, Cut, Undo, Redo, Save, DocumentOpen, Close, Search, Refresh, Share, Attachment
✅ UI OpenMenu, ViewMore, ViewSidebar, ViewReveal, ViewConceal, Settings
✅ Status Information, Warning, Error, Check
✅ People & Identity Person, Accessibility
✅ System & Hardware Applications, Notifications, InputMouse, InputKeyboard, InputTablet, ColorManagement, Printer, Lock
✅ Misc Star, StarOutline, Heart
✅ Media MediaPlay, MediaPause, MediaSkipForward, MediaSkipBackward

Tier 17 — @gnome-ui/layout Package

Dedicated npm package that ships the full-page application shell as a first-class primitive. Consumers can compose any GNOME application layout without pulling in the full @gnome-ui/react bundle.

Status Component Description
✅ Layout Full-page shell with four named zones: topBar (pinned header), sidebar (fixed-width navigation), children (scrollable content), and bottomBar (pinned footer). All zones are optional. Mirrors the composition pattern demonstrated in Layout/Dashboard. Ships as @gnome-ui/layout with its own CSS output, Vitest unit tests, and Storybook story (Layout/Layout).

Tier 16 — Platform Integration

New workspaces that bridge the React layer with the GNOME host process. See ARCHITECTURE.md for the full dependency graph and communication model.

@gnome-ui/platform — TypeScript API layer

Pure TypeScript package. Communicates with GNOME via the WebKitGTK window.webkit.messageHandlers bridge or XDG Desktop Portals. Falls back to no-op stubs in standard browsers / test environments.

Status Module Description
✅ settings getSetting/setSetting/onSettingChanged — WebKitGTK via the bridge (request/response correlation for the async Gio.Settings.get_value() round-trip, plus a changed-signal subscription filtered by key). No browser fallback — there is no web equivalent of an app-schema-scoped GSettings store.
✅ notifications sendNotification/withdrawNotification/onNotificationAction — WebKitGTK via the bridge (Gio.Notification, action buttons), with a real browser Notification fallback (permission flow, single click routed through the same action-event shape as a synthetic 'default' action).
✅ fileChooser openFile/saveFile/selectFolder — WebKitGTK via the bridge (GtkFileChooserDialog / XDG portal), request/response correlated. No browser fallback — the File System Access API only hands back opaque handles, never real filesystem paths.
✅ colorScheme getColorScheme/setColorScheme/onColorSchemeChanged — WebKitGTK via the bridge (maps to Adw.StyleManager; set only ever overrides this app's own rendering, never the desktop-wide preference), with a real matchMedia('(prefers-color-scheme: dark)') fallback for get/subscribe in browsers/PWAs. set has no browser fallback — there is no JS API to force the browser's own rendering into a scheme.
✅ window getWindowState/setMaximized/setFullscreen/minimizeWindow/closeWindow/onWindowStateChanged — WebKitGTK via the bridge (Gtk.Window's maximized/fullscreened/is-active). Browser/PWA fallback for fullscreen (real Fullscreen API), focused (real document.hasFocus()), and close (real window.close(), subject to the browser's own script-only restriction); maximized/minimize have no browser equivalent and either report false or reject.
✅ clipboard readText/writeText/readImage/writeImage/readFiles/writeFiles — WebKitGTK via the bridge (request/response correlation for the async Gdk.Clipboard reads; images cross the bridge as base64 data: URLs). Real navigator.clipboard fallback for text and images in browsers/PWAs (Blob⇄data: URL conversion keeps both paths returning the same shape). Files have no browser fallback — same constraint as fileChooser: browsers never expose real filesystem paths to page scripts.
✅ portals callPortal/onPortalSignal — the generic escape hatch behind the other portal-backed modules: an arbitrary { interface, method, args } D-Bus call (request/response correlated, bridging the real portal Request/Response two-step) plus signal subscription filtered by interface+signal. WebKitGTK only — portals are meaningless without a sandboxed host.

@gnome-ui/hooks — React hooks

React hooks that surface every @gnome-ui/platform module as idiomatic React state.

Status Hook Description
✅ useRuntime Full runtime snapshot: shell, engine, browser, OS
✅ usePlatform Convenience booleans for the current shell context (isGnomeWebView, isPWA…)
✅ useNativeEvent Subscribe to an event dispatched by the GJS host via gnome: prefix
✅ useBreakpoint Reactive isMobile, isTablet, isDesktop flags based on GNOME HIG breakpoints
✅ useSettings Read and write a GSettings key; re-renders on external changes, optimistic writes, exposes loading/error
✅ useNotification Returns send/dismiss, scoped to the component's lifetime — notifications sent through it are auto-withdrawn and onAction listeners auto-unsubscribed on unmount
✅ useColorScheme Returns the resolved "light"/"dark" scheme and a "light"/"dark"/"system" setter, reactive to external changes — talks to Adw.StyleManager via the bridge, distinct from @gnome-ui/react's GnomeProvider-based hook of the same name
✅ useFileChooser Returns open()/save()/selectFolder() triggers and the resolved path/paths as reactive state, plus loading/error
✅ useClipboard Returns { value, copy, paste } with reactive clipboard state, plus loading/error — text only; use @gnome-ui/platform's clipboard module directly for images/files
✅ useWindowState Returns { maximized, fullscreen, focused } and matching actions (setMaximized, setFullscreen, minimize, close), plus loading/error
✅ useHapticFeedback Trigger haptic feedback via feedbackd (native) or Vibration API (browser) — issue #81

GNOME 50 Compatibility

Items identified from GNOME 50 (libadwaita 1.9, March 2026) that require new work or updates.

Accessibility — prefers-reduced-motion

Status Item Description
✅ ExpanderRow Disable grid-template-rows transition and chevron rotate on reduced-motion
✅ PanelCard (@gnome-ui/layout) Disable grid-template-rows collapse transition on reduced-motion
✅ Layout (@gnome-ui/layout) Disable mobile sidebar slide-in transition on reduced-motion

CSS theming

Status Item Description
✅ Unified style.css GNOME 50 deprecates autoloaded style-dark.css / style-hc.css in favour of a single file with @media queries — tokens.css already follows this pattern

Adaptive layout guidance

Status Item Description
✅ Mobile-first audit Verified 400/550/860 sp thresholds and mobile-first defaults; added swipe-to-dismiss to OverlaySplitView; added NarrowViewport stories to NavigationSplitView, OverlaySplitView, and BreakpointBin — issue #15

New widgets

Status Component Description
✅ ColumnView Multi-column sortable data table — mirrors GtkColumnView / AdwColumnView (issue #14)

GNOME 51 Updates

Items identified from GNOME 51 "A Coruña" (released 16 September 2026), which ships libadwaita 1.10 and GTK 4.23. Sources: Libadwaita 1.10 release notes, What's New for Developers in GNOME 51, Introducing GNOME 51.

libadwaita 1.10 lets both sidebar widgets host arbitrary widgets before and after their item list (e.g. an account switcher or prominent title at the top, a help button at the bottom), and adds extra slots to sections and items.

Status Item Description
✅ Sidebar prefix / suffix props New prefix?: ReactNode and suffix?: ReactNode rendered above and below the scrollable item list (outside the scroll area, so they stay pinned). Must interact correctly with searchable (prefix renders above the search bar), collapsed (slots stay visible but should support icon-only content; consumers can read useSidebarCollapsed), and mode="page" (slots render above/below the boxed list). Mirrors AdwSidebar:prefix / :suffix
✅ ViewSwitcherSidebar prefix / suffix props Add prefix / suffix as the libadwaita-aligned names for the existing header / footer slots. Keep header / footer as deprecated aliases (JSDoc @deprecated) for one major version; showHeaderSeparator / showFooterSeparator apply to the new names too. Mirrors AdwViewSwitcherSidebar:prefix / :suffix
✅ SidebarSection suffix prop Widget rendered at the end of the section header row (e.g. an "add" IconButton or a count Badge), aligned like PreferencesGroup's headerSuffix. Hidden when the sidebar is collapsed; must not toggle the section when clicked if the section is collapsible (stop propagation)
✅ SidebarItem prefix prop Arbitrary widget rendered before the label, as an alternative to icon (e.g. an Avatar, a colour dot, a status indicator). When both icon and prefix are set, prefix wins. In collapsed mode the prefix replaces the icon in the rail. Mirrors AdwSidebarItem:prefix
Status Item Description
✅ Dropdown flat prop Borderless, background-less trigger that only shows a hover/active background — mirrors the new .flat style class for GtkDropDown
✅ Auto-flat inside toolbars Dropdown becomes flat automatically when rendered inside HeaderBar, Toolbar or ToolbarView top/bottom bars (the bars set a data-gnome-toolbar attribute that the dropdown CSS keys off; overlays render in portals, so dropdowns inside popovers/dialogs opened from a toolbar keep their regular look), matching libadwaita's automatic flat styling in toolbars
✅ Dropdown raised prop Opt-out of the automatic toolbar flat style — mirrors the .raised style class override. Also apply to MultiSelectDropdown and FilterableMultiSelectDropdown for consistency

AboutDialog — Other Apps section

Status Item Description
✅ AboutDialog otherApps prop otherApps?: { name: string; summary?: string; icon?: ReactNode; url: string }[] rendered as a boxed list of ActionRows linking to the developer's other applications — the section already exists in AdwAboutDialog but is missing here
✅ AboutDialog otherAppsTitle prop Custom header for the Other Apps section (default: "Other Apps by {developerName}", falling back to "Other Apps"). The dialog has no localisation mechanism yet — its tab and section labels are English strings. Mirrors the new AdwAboutDialog:other-apps-title property

Icon weight — lighter large icons

libadwaita 1.10 renders larger icons with a reduced stroke weight so they look visually consistent with small icons; AdwStatusPage icons and GtkImage with icon-size: large now appear thinner, and AdwSpinner respects the -gtk-icon-weight CSS property.

Status Item Description
✅ Icon weight token --gnome-icon-weight in @gnome-ui/core, on the font-weight scale (100–900, default 400) like GTK's -gtk-icon-weight. Components scale stroke widths by var(--gnome-icon-weight) / 400
✅ Spinner icon weight Spinner border width follows --gnome-icon-weight (default renders unchanged) — mirrors AdwSpinnerPaintable icon weight support
⬜ StatusPage thinner icon Blocked: @gnome-ui/icons definitions are filled paths (no strokes), so there is no stroke weight to reduce. GTK 4.23 thins large icons through stroke-based symbolic SVGs. Revisit if the icon set gains stroke-based variants; an SVG feMorphology erode filter was considered and rejected as an approximation
⬜ Icon large-size weight Blocked for the same reason as StatusPage
✅ Web Components parity gnome-spinner border width follows --gnome-icon-weight
⬜ React Native parity React Native cannot read CSS custom properties; would need an iconWeight value in GnomeProvider's theme

OverlaySplitView — overlay styling hook

Status Item Description
✅ Overlay-mode styling hook Expose a stable data-overlay attribute (documented as a [data-overlay] selector — CSS module class names are hashed, so they are not a public styling API) on the sidebar pane while it is shown as an overlay on narrow viewports, so consumers can style it differently from the docked sidebar (e.g. shadow, background). Mirrors the unique style class libadwaita 1.10 adds to AdwOverlaySplitView's overlay sidebar

ShortcutLabel — modifier ordering

Status Item Description
✅ Natural modifier ordering Modifiers are displayed in a fixed order regardless of input order — Hyper → Super → Ctrl → Alt → Shift → Cmd/Meta, i.e. ⌃ → ⌥ → ⇧ → ⌘ — with regular keys after them in their written order. Order taken from get_labels() in libadwaita's adw-shortcut-label.c
✅ macOS key labels Already covered: ShortcutLabel renders Apple-style symbols (⌃ ⌥ ⇧ ⌘ ⌫ ⎋ ↵) on every platform by default, and symbols={false} shows plain names — no platform detection needed

Accessibility — system Reduced Motion

GNOME 51 adds a system-wide Reduced Motion setting, respected by GTK in GtkSpinner, GtkStack and GtkRevealer. The web equivalent is prefers-reduced-motion.

Status Item Description
✅ prefers-reduced-motion coverage Already honoured across components (see GNOME 50 Compatibility); Spinner slows its animation instead of stopping it, matching GTK
✅ Stack / Revealer-like transitions audit Audited NavigationView, Carousel, ViewSwitcher, Expander, Banner, Toast, Drawer and BottomSheet. Fixed two gaps: the Drawer push variant's width animation kept running (its animation-name rule out-ranked the reduced-motion reset), and Banner had no reduced-motion rules. BottomSheet already skips its close animation in JS and Carousel swaps smooth scrolling for instant jumps
✅ Reduced-motion hook Already available as usePrefersReducedMotion in @gnome-ui/hooks (re-exported by @gnome-ui/react). No host bridge needed: inside a GNOME app, WebKitGTK maps the system animation setting to prefers-reduced-motion. @gnome-ui/react-native keeps its own useReducedMotion from GnomeProvider

Not applicable

These changes are GObject/platform-specific and have no equivalent in a web component library; listed for completeness.

Item Reason
AdwCssClassBinding / adw_bind_property_to_css_class() Declarative GObject property → CSS class binding; React props + className already cover this
GtkEnumList (replaces the now-deprecated AdwEnumListModel) GType enum model for dropdowns; Dropdown takes plain option arrays
GtkSvgWidget, native SVG icon rendering, SVG filter effects Browsers render SVG natively
CSS font-width property Toolkit-specific; browsers already support font-stretch / font-width
AdwClampScrollable get_border() GtkScrollable internals
Android port, Android settings backend, "Ministream" library Platform/build infrastructure

@gnome-ui/charts — Chart Components

Data visualisation components built on top of Recharts, fully styled with Adwaita design tokens.

Status Component Description
✅ LineChart Multi-series time-series line chart with optional grid and legend
✅ BarChart Grouped bar chart for categorical comparisons
✅ AreaChart Filled-area chart with stacking and gradient fill options
✅ PieChart Pie and donut chart for part-to-whole comparisons
✅ RadarChart Radar/spider chart for multi-attribute comparisons across subjects
✅ RadialBarChart Concentric arc bars for multiple circular progress metrics
✅ TreeMap Proportional rectangles for hierarchical data with optional grouping
✅ CloudChart Word/tag cloud with value-proportional font sizing
✅ SparkLineChart Minimal inline line sparkline for embedding in cards and tables
✅ SparkAreaChart Minimal inline area sparkline with optional gradient fill
✅ SparkBarChart Minimal inline bar sparkline for compact trend display
✅ ScatterChart Scatter/bubble chart for correlation between two numeric variables; ZAxis encodes a third dimension as bubble size
✅ FunnelChart Funnel visualization for conversion rates and sales pipelines
✅ ComposedChart Mixed chart combining bars, lines, and areas on shared axes
✅ GaugeChart Single-value speedometer/gauge chart for KPI dashboards, complementing StatCard
✅ Heatmap Generic matrix heatmap for correlation and density data (distinct from ContributionGraph's calendar layout)
✅ SankeyChart Flow diagram for multi-stage funnels and user journeys
✅ BulletChart Bullet graph: performance value vs. target with qualitative range bands, complements GaugeChart in dense KPI rows
✅ WaterfallChart Floating-bar chart for the cumulative effect of sequential increases/decreases — revenue bridges, budget breakdowns
✅ BoxPlot Box-and-whisker plot for distribution, quartiles, and outliers across one or more groups; accepts raw values or precomputed statistics
✅ SparkGaugeChart Compact inline gauge for embedding in cards and table cells
✅ SparkPieChart Compact inline pie/donut for part-to-whole composition, embeddable in cards and table cells
✅ SparkBulletChart Compact inline bullet graph for embedding in cards and table cells

Tier 18 — Data Display

Read-only data display widgets rendered in pure HTML/SVG — no Recharts dependency.

Status Component Description
✅ ContributionGraph Activity heatmap calendar: a 52-week grid of rounded SVG cells where colour intensity (Adwaita green palette) represents activity count; supports dark mode, keyboard navigation (role="grid"), and screen-reader labels — issue #21

Tier 19 — Dashboard Components (@gnome-ui/layout)

Purpose-built components for composing dashboard and monitoring views.

Status Component Description
✅ DashboardGrid Responsive CSS Grid container for arranging dashboard widgets; supports column count and per-item span — issue #82
✅ StatCard Key metric display with optional trend indicator (direction, percentage, period) and loading skeleton — issue #83
✅ ProgressCard Resource usage card with labelled progress bar; color thresholds at 75 % (warning) and 90 % (critical) — issue #84
✅ ActivityFeed Chronological event list with relative timestamps, icons, and truncation — issue #85
✅ QuickActions Grid of shortcut action buttons with keyboard navigation — issue #86
✅ SectionHeader Section title row with optional subtitle and trailing action slot — issue #88
✅ EmptyState Centered empty-state illustration: icon, title, description, optional CTA — issue #89
✅ StatusIndicator Service/connection status dot: online, offline, warning, error, loading — issue #87
✅ ErrorState Error state with preset types (generic, network, permission, not-found) and recovery action slot — issue #90

Tier 20 — Atomic & Molecular Gaps

Widgets from the GTK4/libadwaita catalog (or well-established HIG-adjacent patterns) not yet covered by the ~96 components already shipped in @gnome-ui/react. Scoped to atoms and simple molecules only — no new organism/page-level compositions. Verified against the current component tree to avoid duplicating existing functionality (e.g. ColorPicker already covers Adwaita accent-color swatches via GNOME_PALETTE, so it is intentionally excluded here).

Atoms

Status Component Description
✅ LevelBar Discrete level indicator with colour-coded low/high/full offset zones — mirrors GtkLevelBar; distinct from ProgressBar (determinate task progress) and SegmentedBar (proportional category breakdown)
✅ Expander Standalone disclosure triangle + collapsible content — mirrors GtkExpander; complements ExpanderRow, which only works nested inside a BoxedList row
✅ PasswordField Standalone masked TextField with a built-in reveal/conceal toggle, for login forms and dialogs outside a settings-row context — reuses the reveal-icon pattern from PasswordEntryRow without requiring ActionRow
✅ Divider Horizontal rule with an optional centred label (e.g. "OR") — common auth/login-form pattern; distinct from the plain Separator line
✅ RatingStars Star rating display and interactive input, keyboard-navigable — common HIG-adjacent pattern for review/quality widgets, pairs with Icon's Star/StarOutline
✅ FileTypeIcon Small icon (optionally with a thumbnail) resolved from a file's MIME type or extension — useful for file-manager-style listings, complementing the existing Layout/FileManager story
✅ Callout Inline, dismissible admonition box (info/warning/tip variants) for contextual help text within forms and cards — distinct from Banner (persistent, view-level) and Toast (temporary, notification-level)
✅ StepIndicator Numbered "Step X of Y" progress indicator for onboarding/wizard flows — complements the existing CarouselIndicatorDots/CarouselIndicatorLines with a labelled, linear alternative
✅ RangeSlider Dual-thumb slider for selecting a min/max range — Slider is single-thumb only; needed for range filters (price, date range, etc.)
✅ TextTruncate Single/multi-line text truncation with an automatic tooltip revealing the full content on overflow — mirrors GtkLabel's ellipsize property
✅ Kbd Standalone single key-cap (e.g. Enter, Esc) for inline instructional text ("press Enter to continue") — complements ShortcutLabel, which only renders full +-delimited combos and doesn't expose its key-cap rendering separately
✅ Highlight Inline <mark>-based text highlighting for matched search terms — pairs with SearchBar's suggestion list and any filterable list/table
✅ VisuallyHidden Reusable "sr-only" utility — visually hides content while keeping it in the accessibility tree; extracts the recipe currently duplicated inline inside CopyButton's live-region announcement
✅ Overlay Standalone backdrop/scrim layer with fade transition and click-to-dismiss — extracts the near-identical backdrop implementation currently duplicated across Modal, Dialog, and BottomSheet

Molecules

Status Component Description
✅ Calendar Month-grid date display with keyboard navigation — mirrors GtkCalendar; usable standalone or as the panel inside DatePicker
✅ DatePicker TextField trigger + Popover-anchored Calendar — mirrors the GtkCalendar + GtkPopover composition pattern used for date entry across GNOME apps. showTime adds TimePicker's hour/minute columns under the calendar, turning the emitted Date into a point in time: the day click then keeps the popover open and a Done button finishes the selection
✅ TimePicker Hour/minute selection built from paired SpinButtons in a Popover, with 12/24-hour format support. The columns live in an internal TimeFields, shared with DatePicker/DateRangePicker's showTime footer
✅ CalendarRange Start/end date-range selection sharing Calendar's grid engine (roving tabindex, month/year drill-down, min/max). Emits through onChange only once both ends have a value — a first click sets the anchor and paints a live preview band up to the hovered (or keyboard-focused) day, and the second click commits the range; picking backwards reorders the pair instead of failing. visibleMonths (default 1) renders N side-by-side month panels paged as one unit, so a range spanning months is picked without navigating. Adds minRange/maxRange day limits on top of min/max, aria-selected on every in-range cell plus start/in-range/end suffixes in the day labels, and Esc to cancel an in-progress range (after leaving the drill-down)
✅ DateRangePicker Popover-anchored CalendarRange behind a DatePicker-style trigger reading "1 Aug – 15 Aug 2026". Defaults to visibleMonths={2}, closes only on a complete range, and offers an optional preset sidebar (last 7 days, this month, last quarter) — the composition counterpart of DatePicker, mirroring GtkCalendar + GtkPopover. showTime gives each end its own hour/minute columns plus a Done button, keeping start ≤ end when both land on the same day
✅ FontPicker Button that opens a family/size/weight chooser — mirrors GtkFontDialogButton
✅ EmojiPicker Searchable emoji grid in a Popover — mirrors GtkEmojiChooser
✅ TagInput Type-to-add multi-value input rendering entries as removable Chips in a WrapBox — WrapBox/Chip currently only support static/pre-populated display, not interactive entry
✅ OtpInput Segmented PIN/verification-code input (one cell per digit, auto-advance, paste support) — common auth pattern, pairs naturally with PasswordEntryRow/PasswordField
✅ CopyField Read-only TextField/EntryRow with a built-in trailing CopyButton — for displaying copyable values (API keys, tokens, IDs) outside the CveIdentifier/CweIdentifier-style specialised components
✅ ChoiceCardGroup Card-based single-choice selector (large selectable cards instead of radio buttons) — mirrors the pattern used in GNOME Initial Setup / welcome flows
✅ FileDropZone Drag-and-drop file upload target with hover/active states, falling back to a GtkFileDialog-style click-to-browse trigger
✅ MultiSelectDropdown Checkbox-list variant of Dropdown for selecting multiple values from a single trigger — Dropdown/ComboRow are currently single-select only
✅ CodeBlock Static monospace code/config snippet display with optional line numbers and a CopyButton trailing action — distinct from TerminalView (live scrolling terminal output)
✅ WidgetManager Card that manages a controlled collection of widgets picked from a catalog, each rendering its own content via render(); edit-mode trigger opens a staged add/remove picker (Modal/BottomSheet/Drawer, configurable) applied only on confirm
✅ FieldGroup Generic form-field grouping with a shared label, help text, and error message, for arbitrary fields outside a BoxedList — PreferencesGroup is scoped specifically to wrapping settings rows
✅ Portal Reusable createPortal wrapper (mount target, SSR-safe no-op) — extracts the ad-hoc portal logic currently duplicated independently across 13 components (Dialog, Modal, Popover, Tooltip, BottomSheet, etc.)
✅ CoachMark Onboarding feature-discovery pattern: spotlights a target element and anchors a callout bubble (title, description, actions) beside it, with a CoachMarkTour orchestrator for sequential steps (Next/Back/Skip/Done + "X of N"). Pragmatic web-app pattern beyond GNOME HIG, built on Button/Portal and a viewport-aware flip positioner

Infrastructure

Status Item Description
✅ @gnome-ui/hooks tree-shaking sideEffects: false + vite-magic-tree-shaking per-hook entries; consumers importing a single hook no longer receive the full bundle — issue #76