@gnome-ui/react
v1.64.0
Published
React component library following GNOME Human Interface Guidelines
Readme
@gnome-ui/react
React component library following the GNOME Human Interface Guidelines, built on the Adwaita design language.
Live documentation: Storybook →
Installation
npm install @gnome-ui/reactSetup
Import the stylesheet once at the root of your app:
// main.tsx or App.tsx
import "@gnome-ui/react/styles";Quick example
import { Button } from "@gnome-ui/react";
export default function App() {
return (
<Button variant="suggested" onClick={() => console.log("saved")}>
Save Changes
</Button>
);
}Provider & formatting
GnomeProvider supplies locale, text direction, color scheme, and default Intl formatting options to gnome-ui components. When locale is omitted, the browser locale is used.
import { GnomeProvider } from "@gnome-ui/react";
export default function App() {
return (
<GnomeProvider
locale="en-US"
numberFormat={{ notation: "compact", compactDisplay: "short" }}
dateTimeFormat={{ dateStyle: "medium" }}
>
{/* CounterCard, StatCard, charts, CountDownTimer, etc. inherit this. */}
</GnomeProvider>
);
}Use compact notation for values like 1K; omit numberFormat or set notation: "standard" for full values like 1,000.
<GnomeProvider locale="en-US" numberFormat={{ notation: "standard" }}>
{/* numbers render as 1,000 */}
</GnomeProvider>Custom components can consume the same defaults:
import { useNumberFormatter, useDateTimeFormatter } from "@gnome-ui/react";
function Metric({ value, date }: { value: number; date: Date }) {
const number = useNumberFormatter({ maximumFractionDigits: 1 });
const day = useDateTimeFormatter({ weekday: "short" });
return `${number.format(value)} · ${day.format(date)}`;
}Color scheme
Pass colorScheme to GnomeProvider to control the app theme. The provider applies the data-theme attribute to document.documentElement automatically — no manual DOM manipulation needed.
| Value | Behavior |
|-------|----------|
| "system" (default) | Follows the OS prefers-color-scheme preference |
| "light" | Forces light theme |
| "dark" | Forces dark theme |
import { GnomeProvider } from "@gnome-ui/react";
// Controlled by user preference stored in your app state/localStorage
export default function App({ colorScheme }) {
return (
<GnomeProvider colorScheme={colorScheme}>
{/* all gnome-ui components respond automatically */}
</GnomeProvider>
);
}Consume the current scheme in any component:
import { useColorScheme, useResolvedColorScheme } from "@gnome-ui/react";
function ThemeAwareImage() {
const resolvedColorScheme = useResolvedColorScheme(); // "light" | "dark"
return (
<img src={resolvedColorScheme === "dark" ? "/logo-dark.svg" : "/logo.svg"} />
);
}useColorScheme()— returns the value passed toGnomeProvider("light","dark", or"system").useResolvedColorScheme()— always returns"light"or"dark", resolving"system"against the OS preference in real time.
Accent color
Pass accentColor to GnomeProvider to set the app-wide accent color. The provider applies the correct CSS custom properties to document.documentElement automatically.
Two types of values are accepted:
| Value | Behavior |
|-------|----------|
| Named palette ("blue", "green", "yellow", "orange", "red", "purple", "brown") | Theme-aware — uses the correct shade for light/dark mode automatically. Defaults to "blue". |
| Any CSS color string ("#ff0000", "oklch(…)", etc.) | Applied directly; same value in light and dark mode. |
import { GnomeProvider } from "@gnome-ui/react";
export default function App({ accentColor }) {
return (
<GnomeProvider accentColor={accentColor}>
{/* "green", "#a020f0", or any CSS color */}
</GnomeProvider>
);
}Consume the accent color in any component:
import { useAccentColor } from "@gnome-ui/react";
function AccentDot() {
const accent = useAccentColor(); // e.g. "green" or "#ff0000"
return <span style={{ background: accent }} />;
}useAccentColor()— returns the raw value passed toGnomeProvider(named color or CSS string).
Tree-shaking
The package ships per-component entry points, so bundlers (webpack, Rollup, esbuild, Vite) can eliminate unused components automatically. Named imports from the root entry work with any bundler that respects "sideEffects":
// Only Button is included in the bundle
import { Button } from "@gnome-ui/react";Per-component paths are also available for explicit control:
import { Button } from "@gnome-ui/react/components/Button";Components
Controls
| Component | Description |
|-----------|-------------|
| Button | Default, Suggested, Destructive, Flat, Raised variants; osd overlay modifier; sm/md/lg sizes; pill and circular shapes |
| IconButton | Accessible icon-only action button composed from Button, Icon, and optional Tooltip; supports variants, sizes, disabled state, and refs |
| SplitButton | Primary action button with attached dropdown arrow; Default, Suggested, Destructive variants |
| ButtonContent | Icon + label layout helper for buttons that contain both an icon and text |
| Switch | On/off toggle for settings that apply immediately |
| Checkbox | Multi-selection with checked, unchecked, and indeterminate states |
| RadioButton | Single-selection within a group; keyboard arrow-key navigation |
| TextField | Text input with label, helper text, and error state |
| SpinButton | Numeric input with −/+ buttons, keyboard nav, decimal support |
| Slider | Draggable range control with tick marks, decimal steps, and keyboard nav |
| Dropdown | Expandable option list with keyboard nav, flip positioning, and descriptions |
| MultiSelectDropdown | Checkbox-list variant of Dropdown for selecting multiple values from a single trigger |
| FilterableMultiSelectDropdown | MultiSelectDropdown plus a filter field for narrowing long option lists |
| FontPicker | Button that opens a family/size/weight chooser; trigger previews the current selection rendered in that font — mirrors GtkFontDialogButton |
| EmojiPicker | Searchable emoji grid in a Popover, grouped by category with a jump-to-category tab bar — mirrors GtkEmojiChooser |
| FileDropZone | Drag-and-drop file upload target with hover/active states and a click-to-browse fallback |
| ScrollToTop | Fixed-position OSD button that scrolls to the top; auto-hides below a scroll threshold (visible="auto"), six anchor positions, semi-transparent until hovered |
| SearchBar | Collapsible search bar with auto-focus, clear button, filter row, inline variant, and autocomplete popover (suggestions / loadingSuggestions) |
| Link | Inline hyperlink with accent colour, animated underline, and external-URL variant |
| ToggleGroup / ToggleGroupItem | Mutually-exclusive toggle buttons; icon-only, label-only, or icon + label |
| InlineViewSwitcher / InlineViewSwitcherItem | Compact inline view switcher; default, flat, and round variants |
| PathBar | Breadcrumb path bar for hierarchical navigation; ancestor segments are interactive buttons, current segment is highlighted |
Display
| Component | Description |
|-----------|-------------|
| Text | 12 Adwaita type styles: large-title, title-1…4, heading, body, caption… |
| Icon | Inline SVG icon. Accepts @gnome-ui/icons definitions, simple-icons icons, or any { path } object; inherits currentColor |
| Avatar | Circular user image with deterministic-color initials fallback |
| AvatarGroup | Overlapping stack of avatars with configurable max visible count and +N overflow indicator |
| AvatarRotator | Single avatar surface that crossfades through multiple image sources |
| Badge | Counter or status dot, optionally anchored over another element |
| StatusBadge | Pill-shaped text label for entity status — published, beta, new, etc.; 6 variants |
| Blockquote | Styled pull-quote with left-border accent; default, info, warning, error, success variants; optional icon and attribution |
| Spinner | Indeterminate loading indicator; sm/md/lg sizes |
| ProgressBar | Determinate (0–1) and indeterminate progress indicator |
| SegmentedBar | Multi-segment horizontal bar for proportional distributions (e.g. language breakdown); hover tooltip and highlight; auto color palette from GNOME tokens |
| Skeleton | Content-shaped loading placeholder; rectangular, circular, and multi-line text variants with optional shimmer |
| CountDownTimer | Countdown timer showing remaining time until a specified date; date, time, or datetime formats; executes callback on completion |
| StatusPage | Empty-state page with icon, title, description, and optional actions; compact prop for sidebars/popovers |
| Separator | Horizontal/vertical dividing line between content groups |
| Chip | Compact pill-shaped label for tags, filters, and multi-select; static, removable, and selectable modes |
| ShortcutLabel | Renders keyboard shortcut tokens (e.g. Ctrl+S) as individual key cap pills |
| WindowTitle | Two-line title + subtitle widget for use inside a HeaderBar |
| Timeline | Ordered sequence of events connected by a visual connector line; vertical (activity feed) and horizontal (stepper) orientations; solid, dotted, and none variants |
| ContributionGraph | Activity heatmap calendar (GitHub-style); pure SVG, keyboard-navigable grid, responsive week count, dark mode and accent-color aware |
Layout & containers
| Component | Description |
|-----------|-------------|
| Box | Flex layout primitive equivalent to GtkBox — vertical or horizontal, with GNOME HIG spacing scale |
| Card | Elevated surface for grouping content; static or interactive (activatable) |
| Frame | Bordered surface without background fill — mirrors GtkFrame |
| Bin | Single-child transparent wrapper — mirrors AdwBin |
| HeaderBar | Title bar with centered title and leading/trailing action slots |
| Toolbar | Horizontal action bar with 6 px padding/gap for flat and raised buttons |
| Spacer | Invisible flex: 1 filler to push trailing items to the end of a Toolbar |
| ToolbarView | Layout with pinned top/bottom bars and scrollable center content — mirrors AdwToolbarView |
| LinkedGroup | Renders children as a single connected unit with merged borders; horizontal and vertical |
| Sidebar / SidebarSection / SidebarItem | Lateral navigation panel with named sections, suffix widgets, and context menus |
| BoxedList | Rounded bordered list of rows — canonical GNOME settings pattern |
| ActionRow | Settings row with title, subtitle, leading icon, and trailing widget |
| ButtonRow | Full-width activatable row styled as a button inside a BoxedList; Default, Suggested, Destructive |
| ExpanderRow | Collapsible ActionRow that reveals nested rows; controlled and uncontrolled |
| SwitchRow | ActionRow with a built-in Switch trailing widget |
| CheckRow | ActionRow with a built-in Checkbox trailing widget |
| ComboRow | ActionRow with a built-in Dropdown for selecting a value |
| EntryRow | Inline text entry row — title doubles as floating label |
| PasswordEntryRow | EntryRow variant with show/hide password toggle |
| SpinRow | ActionRow with a built-in SpinButton for numeric values |
| WrapBox | Wrapping flex container for tag/chip lists that flows across multiple lines — mirrors AdwWrapBox |
| TabBar / TabItem / TabPanel | Tab-based navigation with keyboard support, optional close buttons, count badge for unread indicators, and inline variant |
| ViewSwitcher / ViewSwitcherItem | Segmented pill control for switching between 2–4 top-level views |
| ViewSwitcherSidebar / ViewSwitcherSidebarItem | Sidebar-based view switcher — replaces GtkStackSidebar |
| Carousel / CarouselIndicatorDots / CarouselIndicatorLines | Swipeable page carousel with multi-slide viewports, peeking and de-emphasised neighbours, seamless infinite looping, optional edge arrows and dot or line indicators — mirrors AdwCarousel |
| ShortcutsDialog | Modal listing keyboard shortcuts with integrated search |
| WidgetManager | Card that manages a controlled collection of widgets picked from a catalog; edit-mode trigger opens a Modal/BottomSheet/Drawer picker with staged add/remove and confirm/cancel |
Overlays
| Component | Description |
|-----------|-------------|
| Toast / Toaster | Non-blocking temporary notification with auto-dismiss, action, and queue support |
| Dialog | Blocking modal with title, body, focus trap, and configurable buttons |
| Modal | Large overlay for rich content, forms, and settings; scrollable body, header bar with close button and optional primary/secondary actions |
| BottomSheet | Slide-up panel from the bottom of the viewport with drag handle and optional title |
| Drawer | Slide-over panel that opens from the left or right with React content |
| Tooltip | Floating informational label on hover/focus with auto-flip positioning |
| Popover | Floating interactive panel with arrow and auto-flip positioning |
| Banner | Persistent message strip with optional action and dismiss |
Preferences
| Component | Description |
|-----------|-------------|
| PreferencesGroup | Titled BoxedList section with optional description and header suffix widget |
| PreferencesPage | Named page that contains one or more PreferencesGroup sections |
| PreferencesDialog | Tabbed preferences window — mirrors AdwPreferencesDialog |
Adaptive layout
| Component | Description |
|-----------|-------------|
| useBreakpoint | Hook tracking viewport width against GNOME breakpoints (400 / 550 / 860 px) |
| Clamp | Constrains content to a max width, centering it — mirrors AdwClamp |
| NavigationSplitView | Two-pane layout that collapses to a single pane at ≤ 400 px; sidebar shown first (mobile-first default) |
| OverlaySplitView | Sidebar becomes slide-over overlay at ≤ 400 px; supports backdrop, Escape, and swipe-to-dismiss |
| NavigationView / NavigationPage | Mobile-style navigation stack with forward/back slide transitions — mirrors AdwNavigationView |
| ViewSwitcherBar | Bottom bar for ViewSwitcher items on narrow screens (≤ 550 px) |
| BreakpointBin | Applies layout changes when the component crosses a size threshold — CSS container queries equivalent |
Testing
Unit tests (Vitest + Testing Library, jsdom) cover component logic and
rendering. For behavior a simulated DOM can't verify faithfully — the real
OS clipboard, the real prefers-reduced-motion media query — real-browser
tests run against Storybook via Playwright:
npm run test:browser --workspace @gnome-ui/reactThese also run in the repository CI workflow.
