Krizaka UI
Krizaka UI
Patterns

Desktop window

The window of a Mac app (Tauri 2 on the system WebView): a sidebar, the content and an inspector in a three-pane split — resizable by pointer and keyboard, collapsible — under a toolbar that moves the window and clears the traffic lights, at the desktop's density with a native-feeling focus ring. Its commands are written once for the menu bar, the page's shortcuts and the palette.

Web · ✓Mobile · n/aDesktop · ✓ desktop formBetaLayouts
import { DesktopWindow, useDesktopCommands, desktopMenus } from "@krizaka/ui/desktop-window";

Web only — React, from @krizaka/ui/desktop-window. Beta: its API may still change in a minor version.

  • Mobile · n/a. A phone has no windows: its screens are the list and detail, the tabs and the sheets. → List and detail

Why it is here. The Mac apps' window (Orazaka, Yomizaka, Akinaza; Tauri, ADR-002): three panes, the toolbar and the menu bar's commands (krizaka-ui#753).

When to use

  • The main window of a Tauri Mac app with a source list, a main view and the details of the selection (Finder, Mail, Xcode).
  • A two-pane window: omit inspector.

When not to use

  • A console with grouped sections and a collapsing sidebar of words.Use instead: App shell
  • The signed-in web app in a browser.Use instead: App frame
  • A phone or a tablet.Use instead: List and detail

Installation

Install

npm install @krizaka/ui @krizaka/tailwind @krizaka/tokens tailwindcss

Styles

@import "tailwindcss";
@import "@krizaka/tailwind";
@import "@krizaka/ui/tailwind.css";

Import

import { DesktopWindow, useDesktopCommands, desktopMenus } from "@krizaka/ui/desktop-window";

Examples

A library window

A source list, a list of files and the details of the selected one; ⌘B and ⌘I fold the panes, the menu bar gets the same commands.

Props

The window of a Mac app: sidebar · content · inspector, a toolbar that moves the window, the desktop's density.

PropTypeDefaultDescription
childrenrequiredReactNode—The main content under the toolbar.
labelsrequiredDesktopWindowLabels—The words of the panes, the dividers and the toggles — passed translated.
sidebarrequiredReactNode—The sidebar's content: a list of places, a Tree. It scrolls by itself.
classNamestring—Classes for the window ([--kz-window-height:34rem] to size it inside a page).
contentMinnumber360The least the content keeps when the window is narrow (default 360).
defaultInspectorOpenbooleantrueThe inspector starts open (default true) when uncontrolled.
defaultSidebarOpenbooleantrueThe sidebar starts open (default true) when uncontrolled.
defaultSizes{ sidebar?: number; inspector?: number; } | undefined—The sizes in px: the sidebar's, the inspector's. Persist them with onSizesChange.
inspectorReactNode—The inspector's content: the selected item's details. Without it, a two-pane window.
inspectorOpenboolean—The inspector is open (controlled).
onInspectorOpenChange((open: boolean) => void)—Called when the inspector folds or unfolds.
onSidebarOpenChange((open: boolean) => void)—Called when the sidebar folds or unfolds (the toolbar, a divider, the shortcut).
onSizesChange((sizes: { sidebar: number; inspector: number; }) => void)—Called with the sizes in px after a drag or a key: persist them.
shortcuts{ sidebar?: string | false; inspector?: string | false; } | undefined—The keys that fold the panes (a chord, or false for none): ⌘B and ⌘I by default. Pass false when the menu bar's commands (useDesktopCommands) own them.
sidebarOpenboolean—The sidebar is open (controlled). Pair with onSidebarOpenChange: the menu bar's command toggles it too.
titleReactNode—The toolbar's title, centred in the drag region.
toolbarEndReactNode—Before the inspector's toggle, at the end of the toolbar (actions, search).
toolbarStartReactNode—After the sidebar's toggle, at the start of the toolbar (back, forward).

Accessibility

  • The panes are aside landmarks named by labels; the toolbar is the window's header, the content its main.
  • The dividers are the only draggable things; the toolbar's drag region is the bar, its title and the gaps — never a control, so every button keeps its click and its focus.
  • The focus ring is the macOS one (a 3 px halo of the accent) and shows for the keyboard only.

Keyboard

KeysAction
Tab to a dividerFocuses it; it is a separator (WAI-ARIA window splitter) with its size as aria-valuenow.
← →Resizes the pane by 16 px (64 with Shift); the arrow pointing away from the pane's edge grows it, mirrored in right-to-left.
Home / EndThe smallest or the largest size.
Enter on a dividerFolds its pane; the focus goes to the toolbar's button that brings it back.
⌘B / ⌘IFold the sidebar and the inspector.

Best practices

  • Use it at a window width of 900 pt or more (Tauri's minimum width): the content keeps 360 pt, and the panes give way to it when the window is narrower.
  • Write the commands once with useDesktopCommands: it registers the chords in the page and returns the menus and handlers for setNativeMenu of @krizaka/app-desktop. Then pass shortcuts={{ sidebar: false, inspector: false }} to the window so ⌘B and ⌘I are not answered twice.
  • Keep the sizes: persist onSizesChange (a preference of the window) and give them back as defaultSizes.
  • Fold with the controlled sidebarOpen / inspectorOpen, so the menu's « Hide sidebar » and the toolbar's button are one state.
  • Put only what moves the window's content in the toolbar (back, search, the main action); never a form.
  • Controls inside use the desktop's density (32 px rows, 13 px text); do not enlarge them for touch.

Generated from the code of @krizaka/ui 3.65.0: its meta.ts, its examples and its types.Edit this documentation on GitHub

On this page