Components / Structure
TitleBar
The title bar of an installed app that draws its own: a frameless Electron window, or an installed web app using Window Controls Overlay. The whole bar drags the window, every control inside stays clickable, and the app's window controls sit at its end.
When to useLink to "When to use"
- A desktop app without the system's title bar: Electron with
frame: falseortitleBarStyle: "hidden", or a web app whose manifest asks forwindow-controls-overlay. - The app's menus and title in the window's top edge, where people expect to drag the window.
Use something else when:
- the page runs in a browser tab: the site's header is a SiteHeader and an app's header is AppShell's
- the row holds a page's own actions: a Toolbar or a PageHeader
UsageLink to "Usage"
import { IconButton, Menubar, TitleBar } from "@arshad-shah/cynosure";
import { settings } from "@arshad-shah/cynosure/icons";
<TitleBar
label="Verql"
leading={<Menubar label="Application" menus={menus} size="sm" onSelect={run} />}
trailing={<IconButton icon={settings} label="Settings" variant="ghost" size="sm" />}
controls={{
minimize: () => ipc.minimize(),
toggleMaximize: () => ipc.toggleMaximize(),
close: () => ipc.close(),
maximized,
}}
>
orders.sql — Verql
</TitleBar>The title is centred on the whole bar while the leading and trailing content leave room, and ends in an ellipsis when they do not.
Each platformLink to "Each platform"
| Where | What to pass |
|---|---|
| Windows and Linux, frameless | controls: the bar draws minimize, maximize or restore, and close |
macOS, titleBarStyle: "hidden" | leadingInset={80} to clear the traffic lights, and onHeightChange to place them (Electron's setWindowButtonPosition) |
Window Controls Overlay (installed web apps, Electron's titleBarOverlay) | overlay: the system draws the controls, the bar takes the area it leaves |
Window controlsLink to "Window controls"
controls takes { minimize, toggleMaximize, close, maximized }, and each button shows only when its callback is given (a settings window may have only close). When maximized is true the middle button shows the restore icon and is named Restore. Keep maximized in step with the window, including changes the system makes (snapping, double-clicking the bar).
The controls are a part of TitleBar rather than a component of their own: they have one right place, at the window's edge after the trailing content, and are exactly as tall as the bar.
Overlay modeLink to "Overlay mode"
With overlay, the bar is fixed to the window's title bar area, read from env(titlebar-area-x), env(titlebar-area-y), env(titlebar-area-width) and env(titlebar-area-height), so it never runs under the controls the system draws, on whichever side it draws them. Where those values are missing (a browser tab, an engine without the overlay) it falls back to the top of the window, the full width and the --cy-title-bar-height token. Offset the page's content by the height onHeightChange reports.
PropsLink to "Props"
| Prop | What it does | Type | Default |
|---|---|---|---|
children | The title, centred on the bar (it ends in an ellipsis when there is no room). Any content: text, a SearchField. | ReactNode | |
leading | Content at the inline start, such as a Menubar or the app's mark. | ReactNode | |
trailing | Content at the inline end, before the window controls, such as IconButtons. | ReactNode | |
leadingInset | Pixels kept clear at the inline start for window buttons the system draws over the bar (macOS traffic lights: about 80). A fixed number, since the system draws them at a fixed size whatever the theme's scale. Default 0. | number | 0 |
overlay | Window Controls Overlay (installed web apps, Electron's titleBarOverlay): the bar is fixed to the window's title bar area, env(titlebar-area-x/y/width/height), so it never runs under the controls the system draws. Without those values it falls back to the top of the window, full width and the height token. Offset the page's content with onHeightChange. Default false. | boolean | false |
controls | Window controls drawn by the app (Linux, frameless windows): minimize, maximize or restore, and close, as tall as the bar at its inline end. Leave out where the system draws them (macOS, Window Controls Overlay). | TitleBarControls | |
onHeightChange | Called with the bar's height (border box, in pixels) on mount and whenever it changes, to offset content under an overlay bar or to place the system's own window buttons (Electron's traffic-light position). | ((height: number) => void) | |
label | Accessible name of the bar (a group). Default "Title bar". | string | "Title bar" |
labels | Names of the window controls, for other languages. | Partial<TitleBarLabels> | |
className | Layout only. | string | |
style | Layout only. Restyle through --cy-title-bar-* tokens. | CSSProperties |
Generated from the type definitions in @arshad-shah/cynosure 0.5.0.
Behaviour and accessibilityLink to "Behaviour and accessibility"
| Input | Result |
|---|---|
| Drag on the bar, the title or empty space | Moves the window (app-region: drag, Chromium-based hosts only) |
| Click, Enter or Space on a control | Calls minimize, toggleMaximize or close |
| Tab | Moves through the bar's controls in reading order, the window controls last (minimize, maximize, close) |
- Dragging: the bar has
app-region: drag(and-webkit-app-region). Interactive elements inside it, whoever rendered them (links, buttons, fields, labels, anything with atabindexor a widget role such as a menubar's titles), getno-drag, so they stay clickable. - Roles: the bar is a
groupnamed bylabel(default "Title bar"). The controls are buttons named Minimize, Maximize or Restore, and Close, each with a tooltip; rename them throughlabels. - Height:
onHeightChangereports the border-box height on mount and whenever it changes (ResizeObserver), not again for the same height. - Right to left: the bar mirrors.
leadingInsetis at the inline start (the right) and the controls at the inline end (the left), close outermost, as Windows draws its caption buttons in right-to-left languages. - Isolation: it never writes to
<html>or<body>; overlay mode positions the bar itself. Works inside a shadow root.
TouchLink to "Touch"
Each control is at least 24px to press, and 44px on coarse pointers; a tap acts.
ThemingLink to "Theming"
Tokens: --cy-title-bar-height, --cy-title-bar-bg, --cy-title-bar-ink, --cy-title-bar-border, --cy-title-bar-padding-inline, --cy-title-bar-gap, --cy-title-bar-title-font-size, --cy-title-bar-control-width (46px by default, as tall as the bar), --cy-title-bar-close-hover-bg and --cy-title-bar-close-hover-ink (close's danger fill on hover) and --cy-title-bar-z (overlay mode).
createTheme({ components: { titleBar: { height: "32px", controlWidth: "46px" } } });RelatedLink to "Related"
Menubar · AppShell · IconButton · Toolbar
These examples run Cynosure 0.5.0 (commit 50ce30b), the version on npm.