API
nsh/base
nsh/base is the base component layer of an app’s UI: unstyled components that own behavior, state, focus and
accessibility, on every platform. It sits between the primitives (nsh and the nsh/<module> modules) and the
app’s own component library, as gpui-base sits between gpui and a styled library in GPUI Kit (see
Modules). It provides controls (Button, Checkbox, Radio in a RadioGroup, Switch, Tab in Tabs), regions that expand and collapse (Collapsible), a progress bar (Progress), workspaces the user arranges (ResizablePanels in a
ResizablePanelGroup, and DockArea’s splits, tab groups and docks), documents of Markdown or HTML (TextView), a code editor (Editor) and the changes between texts (DiffView), selections across texts
(SelectionArea), popups shown on top of everything (Popover, Menu and ContextMenu with their MenuItem,
MenuSeparator and Submenu, Tooltip, Sheet), toasts (Toast in a ToastStack, their lifecycle in a ToastManager), navigation (a NavStack of NavPages driven
by the state you create with createNavStack, and Dialog for content presented over everything else), safe areas
(SafeAreaView, safeArea() and safeAreaInsets()), the system’s alert dialogs (AlertDialog), the software
keyboard (Keyboard, keyboardFrame() and KeyboardAvoidingView). Pages and dialogs also decide the status bar
(statusBar).
The look is the app’s: what goes inside a page, a dialog or a header is your own JSX, drawn from the primitives with
styles, Tailwind classes and your theme, Rust components from your own crate,
or a component library the community builds on nsh/base. Every host serves nsh/base; Rust apps use the same API
from the nsh-base crate (nsh_base::{button, safe_area_view, …}).
use nsh_base::{
AvoidBehavior, Edge, MarkdownExtension, MarkdownOptions, alert_dialog, button, checkbox, dialog, diff_view, dock_area, editor,
h_resizable, keyboard_avoiding_view, nav_page, nav_stack, radio, radio_group, resizable_panel, safe_area_view,
selection_area, switch, tab, tabs, text_view, theme, toast, toast_stack, v_resizable,
};import {
AlertDialog, Button, Checkbox, Collapsible, ContextMenu, createNavStack, Dialog, DiffView, DockArea, Editor, Keyboard, keyboardFrame, KeyboardAvoidingView, Menu, Progress,
MenuItem, MenuSeparator, NavPage, NavStack, Popover, Radio, RadioGroup, ResizablePanel, ResizablePanelGroup, SafeAreaView, safeArea, safeAreaInsets, SelectionArea, Sheet,
Submenu, Switch, Tab, Tabs, TextView, Toast, ToastManager, ToastStack, Tooltip,
} from "nsh/base";
import type {
AlertDialogAction, AlertDialogOptions, AlertDialogPresentation, AlertDialogRole, AvoidBehavior, ButtonProps,
CheckboxProps, CollapsibleProps, DialogChangeReason, DialogProps, DiffAnnotation, DiffFile, DiffHunk, DiffLineRange, DiffSeparator, DiffStats, DiffViewProps, DiffViewRef, DockAreaLayout, DockNode, DockRegion, EditorDecoration, EditorDiagnostic, EditorProps, EditorRef, EditorSearch, EditorSearchResult, EditorSelection, Edge, Edges, HeaderStyle, NavPageProps, NavStackProps, NavStackState, ProgressProps, StatusBar,
RadioGroupProps, RadioProps, SelectionAreaProps, StatusBarForeground, SwitchProps, TabProps, TabsProps, TextViewProps, TextViewDocument, MarkdownExtension, MarkdownOptions,
ToastEntry, ToastMotion, ToastOptions, ToastProps, ToastStackProps, ToastTransitionStatus,
} from "nsh/base";This page is the module’s index: each component has an element page with its examples, props and platform notes. For walkthroughs, see the Navigation guide and Forms and keyboard.
| TSX | Rust | What it is |
|---|---|---|
Button | button() | A press target with the disabled and selected states and a role for screen readers. |
Checkbox | checkbox() | A checked, unchecked or indeterminate control with an indicator the app styles and marks. |
Radio, RadioGroup | radio(), radio_group() | One option of a set the user picks one of, and the set; the app owns which one is checked. |
Switch | switch() | An on / off control with a track and a thumb the app styles. |
Tab, Tabs | tab(), tabs() | One tab of a tab list, and the list; the app owns which one is selected and shows its content. |
Collapsible | collapsible() | A region whose content expands and collapses; the app owns open and its trigger. |
Progress | progress() | A progress bar; the app owns value (0 to 100) and indeterminate. |
ResizablePanelGroup, ResizablePanel | h_resizable(), v_resizable(), resizable_panel() | Panels side by side or stacked, with handles the user drags to resize them. |
DockArea | dock_area() | A workspace of splits, tab groups and edge docks the user arranges; its layout is the app’s data. |
NavStack, NavPage, createNavStack | nav_stack(), nav_page() | A native navigation stack and its pages. |
Dialog | dialog() | Content presented over everything else: sheets, full-screen flows, dialogs. |
SafeAreaView | safe_area_view() | A view padded clear of system UI and headers. |
safeArea(), safeAreaInsets() | safe_area(), cx.insets() | The insets themselves, reactive. |
KeyboardAvoidingView | keyboard_avoiding_view() | A view that keeps its content above the software keyboard. |
Keyboard.dismiss(), keyboardFrame() | dismiss_keyboard(), keyboard_height() | Hides the keyboard; its height over the surface. |
AlertDialog | alert_dialog() | The platform’s alert or action sheet. |
TextView | text_view() | A document of Markdown, HTML or blocks, drawn with texts and views, for streamed AI replies. |
Editor | editor() | A code editor: syntax highlighting, several carets, folding, find and replace, diagnostics. |
DiffView | diff_view() | The changes between two texts or of a patch, side by side or unified, with per-change actions. |
SelectionArea | selection_area() | One selection across the texts inside it. |
Popover | popover() | Content anchored to a trigger, on top of everything. |
Menu, ContextMenu, MenuItem, MenuSeparator, Submenu | menu(), … | Menus: popups with cascading submenus on desktops, sheets on phones. |
Tooltip | tooltip() | A hint next to its trigger. |
Sheet | sheet() | A panel at an edge of the screen over a backdrop. |
Toast, ToastStack, ToastManager | toast(), toast_stack(), ToastManager | Unstyled toasts: a semantic root, a stack of layers, their lifecycle. |
statusBar on pages and dialogs | .status_bar(..) | The status bar while a page or dialog is up. See Status bar. |
In Rust, theme() reads the app’s theme as design tokens (theme().primary, theme().radius), the same tokens
TSX’s theme classes use.
#Controls
#Button
A press target that owns its behavior and has no look: presses, the disabled and selected states and its role for
screen readers. Its look is the app’s class and style with state variants, its content is its children. See
Button.
#Checkbox
A checked, unchecked or indeterminate control that owns its behavior and has no look: presses, keyboard activation,
the disabled state and the checkbox role and value for screen readers (mixed while indeterminate), with the value
owned by the app (checked, indeterminate, onChange). The app styles the checkbox and its indicator, whose
checked:, indeterminate: and disabled: classes follow the checkbox, and puts its own mark in the indicator
(indicator). See Checkbox.
#Radio and RadioGroup
One option of a set the user picks exactly one of, and the set around them. A radio owns its behavior and has no
look: presses, keyboard activation, the disabled state and the radio role and checked state for screen readers. The
group is the radio group screen readers announce and holds no value: the app tells each radio whether it is checked
(checked), and a press on an unchecked one asks for it (onChange). The app’s indicator and label are the radio’s
children, whose group-checked: classes follow it. See Radio.
#Switch
An on / off control that owns its behavior and has no look: presses, keyboard activation, the disabled state and the
switch role and value for screen readers, with the value owned by the app (checked, onChange). The app styles the
switch, its track and its thumb, whose checked: and disabled: classes follow the switch. See
Switch.
#Tab and Tabs
The tabs of a tab list and the list around them. A tab owns its behavior and has no look: presses, keyboard
activation, the disabled state and the tab role and selected state for screen readers. The list is the tab list
screen readers announce and holds no value: the app tells each tab whether it is selected (selected), hears
presses (onPress) and shows the selected section’s content itself. The app’s label is the tab’s children, whose
group-selected: classes follow it. See Tabs.
#Collapsible
A region whose content expands and collapses, with no look: its children show always (a summary, the trigger), its
content after them while open. The app owns open and the trigger that flips it, and says the expanded state to
screen readers there. The content is made once and kept while collapsed, so what is inside keeps its state. See
Collapsible.
#Progress
A linear progress bar, with no look: a track with an indicator inside it, the indicator value percent of the track’s
width. The app owns value (0 to 100) and indeterminate; screen readers get the progress bar role, the range and the
value, and no value while indeterminate, when the indicator’s width and motion are the app’s. See
Progress.
#Workspaces
#ResizablePanelGroup and ResizablePanel
Panels side by side or stacked, with a handle between each two that the user drags to share the room. The group owns
the drag, which runs natively, each panel’s limits (minSize, maxSize) and the resize cursor; the sizes are the
app’s (size, reported with onResize), and so are the handles’ look and the panels’ content. See
Resizable.
#DockArea
A dockable workspace: panels in tab groups, groups split side by side or stacked, and docks on the left, right and
bottom edges. The layout is data the app owns (layout, reported with onLayoutChange); the area owns tab drags and
drops, resizing, docks, zoom and the lock, keeps each panel’s content as it moves, and presents the same layout with
drawers and a bottom sheet when it is narrow. The tabs, handles, drop indicator and the panels’ content are the
app’s. See Dock.
#Documents
#TextView
TextView shows a document of Markdown, HTML or blocks the app builds, drawn with Text
elements and views: headings, lists, code, tables, images, formulas, footnotes and the app’s own syntax. It is made for
AI chat replies that stream in, with a reading typography in the theme’s colors that the app restyles part by part,
and render functions that put the app’s content in place. See TextView.
#Code
#Editor
Editor is a code editor for more than fifty languages: syntax highlighting, line numbers, several carets, folding,
soft wrap, find and replace, diagnostics and decorations, with the keys of code editors. The text is the app’s
(value and onChange), and so is the find bar, which drives the editor’s search. It comes with a look built from
the theme’s tokens that the app restyles part by part. See Editor.
#DiffView
DiffView shows the changes between two texts, or of the files of a patch, as code review tools do: side by side or
unified, the words changed within lines highlighted, unchanged lines collapsed into separators that expand, in the
Editor’s syntax colors. The app’s actions keep or revert each change. See DiffView.
#Selection
#SelectionArea
SelectionArea makes the texts inside it select together, as a web page’s do: one selection runs across views,
Text elements and TextViews, in reading order. See SelectionArea.
#Navigation
A NavStack of NavPages is UINavigationController on iOS and a stack with a toolbar and predictive back on
Android; on the desktops and the web each page shows the app’s own header. See
NavStack, which also covers createNavStack and leaving a page.
#Dialog
Dialog presents content over everything else, including the stack’s header, in its own native window layer. Its
popup and backdrop are styled by the app. See Dialog.
#Safe areas
#SafeAreaView
SafeAreaView pads its content by the insets where it renders: the nearest page’s (below its header), the nearest
dialog’s, or else the surface’s safe area. See SafeAreaView.
#safeArea and safeAreaInsets
safeArea() is the surface’s safe area; safeAreaInsets() the insets where a component renders. Both are reactive
Edges ({ top, right, bottom, left } in points). See
safeArea and safeAreaInsets.
#Alert dialogs
#AlertDialog
AlertDialog.show(options) shows the platform’s own alert or action sheet and resolves with the action the user
chose. See AlertDialog.
#Keyboard
Keyboard.dismiss() hides the software keyboard and keyboardFrame() tells you how much of the screen it covers. See
Hiding the keyboard and
The keyboard’s height.
#KeyboardAvoidingView
KeyboardAvoidingView keeps its content above the software keyboard, moving with it. See
KeyboardAvoidingView.
#Status bar
The status bar belongs to what is on screen, as in UIKit, where each view controller declares its
preferredStatusBarStyle and the topmost one decides. In NSH the pages and dialogs are those view controllers: a
NavPage or a Dialog declares the status bar it wants with statusBar, and the app declares its default in
nsh.json.
use nsh_base::nav_page;
use nsh_core::ui::prelude::*;
fn photo_viewer() -> Screen {
nav_page().header_visible(false).status_bar(
StatusBarSetting::default()
.foreground(StatusBarStyle::Light)
.hidden(true)
.animated(true),
)
}import { NavPage } from "nsh/base";
function PhotoViewer() {
return (
<NavPage headerVisible={false} statusBar={{ foreground: "light", hidden: true, animated: true }}>
…
</NavPage>
);
}statusBar takes these fields, each optional (in Rust, a StatusBarStyle alone, or StatusBarSetting’s builder
methods of the same names):
| Field | Type | Description |
|---|---|---|
foreground | "auto" | "light" | "dark" (Rust: StatusBarStyle::Default, Light, Dark) | The color of the content (time, battery, signal): "light" for dark backgrounds, "dark" for light ones, "auto" the platform’s for the current appearance. |
hidden | boolean | Hides the status bar. |
animated | boolean | Animates the change when the page or dialog comes and goes. |
The value is reactive: statusBar={{ foreground: dark() ? "light" : "dark" }} follows the signal, as does a Rust
closure that reads one.
#Which one applies
The page or dialog shown most recently decides, field by field: a page pushed onto a stack is over the pages below it, and an open dialog is over the pages. A field it leaves out comes from the one below it, and in the end from the app’s default. When the page is popped or the dialog closes, the one below it applies again.
nav_page()
.title("Inbox")
.status_bar(StatusBarStyle::Dark);
// Pushed over it: hidden, with the inbox's dark content when it shows again.
nav_page()
.title("Photo")
.status_bar(StatusBarSetting::default().hidden(true));<NavPage title="Inbox" statusBar={{ foreground: "dark" }}>…</NavPage>
// Pushed over it: hidden, with the inbox's dark content when it shows again.
<NavPage title="Photo" statusBar={{ hidden: true }}>…</NavPage>#The app’s default
nsh.json’s "statusBar" is the setting under every page and dialog, as Info.plist’s UIStatusBarStyle and
UIStatusBarHidden are in a UIKit app:
{
"statusBar": { "foreground": "light", "hidden": false }
}
Both fields are optional. Without it the content is "auto" and the bar shows. Packaged iOS apps also show it on the
launch screen.
#The status bar on each platform
- iOS: hiding and showing animate with a fade. In an app embedded in a native one,
the host app’s view controller decides how the status bar looks. The host applies NSH’s setting by returning
NshAppView.preferredStatusBarStyle,NshAppView.prefersStatusBarHiddenandNshAppView.preferredStatusBarUpdateAnimationfrom its view controller. - Android: apps draw edge to edge, behind the status bar (Android 15, API 35): the app’s own background is the
bar’s, and
foregroundkeeps its content readable on it. - Desktops and the web: the window’s title bar and the browser’s bars are the system’s and the browser’s;
statusBarandnsh.json’s"statusBar"are for the phones.
{
"capabilities": {
"statusBar": true
}
}
#Related
- Navigation guide.
- Forms and keyboard.
- Button, Checkbox, Radio, Switch, Tabs, Collapsible, Progress, NavStack, Dialog, SafeAreaView, KeyboardAvoidingView, AlertDialog, TextView, Editor, DiffView, SelectionArea, Text and Input.
- Device and environment.
- nsh/android:
BackHandler,Toast.showfor short messages and other Android-only APIs.