@dotnaos/ui-base
Generic web foundations for DotNaos interfaces, built on top of the shared @dotnaos/design package.
Install
bun add @dotnaos/ui @dotnaos/ui-base
Web apps should import the complete public UI stylesheet before rendering the components:
import "@dotnaos/ui/styles.css";
Import
import { Button, Card, ThemeProvider } from "@dotnaos/ui-base";
The package exposes one web component family. Layout structures and native components live in their own packages so Base stays small and domain-neutral:
import { Button, Card } from "@dotnaos/ui-base";
import { ContentPageLayout } from "@dotnaos/ui-layout";
import { NativeContainer } from "@dotnaos/ui-native";
Strict component identity and finite Slot contracts are built into the normal components. There is
no separate strict-mode component tree or public strict entrypoint.
Button intent and shape are expressed as variants of one component:
<Button variant="primary" label="Save" icon="save" onPress={save} />
<Button variant="secondary" label="Cancel" onPress={cancel} />
<Button variant="ghost" label="More" iconAfter="chevronDown" onPress={open} />
<Button variant="icon" accessibilityLabel="Delete item" icon="trash" onPress={remove} />
The public button API accepts structured data only. Icons must use names from the DotNaos icon catalog.
Autocomplete
Autocomplete is a controlled text input with floating, fuzzy-matched suggestions:
import { Autocomplete } from "@dotnaos/ui-base";
<Autocomplete
accessibilityLabel="Project"
value={query}
onValueChange={setQuery}
options={[
{ value: "Design System", label: "Design System" },
{ value: "DevOps Client", label: "DevOps Client" },
]}
/>
Set keepOpenOnSelect for continuous completion, such as browsing successive path segments.
New suggestions appear after selection without another keystroke; Escape and blur still close them.
While focused, the floating panel stays mounted during filtering and fetching. Loading keeps
the previous results visible but inactive, with a small neutral spinner in the input; the first
request uses quiet placeholders. Empty results show No suggestions. Neither state is selectable.
Matched characters use a subtle medium weight in the surrounding text color, without underlines.
Optional backAction adds a separate navigation button above the list. It is never an
automatic result or part of arrow-key wrapping: a fresh Up press from the first result
focuses it, Enter activates it, and Down returns to the first result. Held Up presses stop
at the first result. Escape closes the popup and returns focus to the input.
Enable horizontalNavigation to accept the active result with Right and invoke backAction
with Left while the popup is open. Modifier keys, text selections, and composition retain
text-editing behavior; held horizontal arrows do not skip through multiple levels.
The first enabled result is selected automatically. Arrow keys navigate, Enter accepts,
and Escape dismisses. Tab normally leaves the input; opt into repeated Tab completion with
completeOnTab (Shift+Tab always leaves). Accepting a result writes its value into the input
and calls onSelect if supplied. Matching characters in the label are highlighted.
Load remote or filesystem options in the host, pass loading while pending, and discard stale
responses there. Use query when only part of the input should be matched, such as the last
path segment. The component itself performs no network or filesystem access.
QR codes
QrCode renders a self-contained SVG without contacting an external QR service. It keeps the required four-module quiet zone and fixed black-on-white contrast for reliable scanning.
import { QrCode } from "@dotnaos/ui-base";
<QrCode
accessibilityLabel="Open Devbox Mobile"
value="https://devbox.os-pc.vpn.os-home.net/mobile"
size={184}
/>
Use errorCorrectionLevel="H" when the code needs additional damage tolerance.
Geometry capabilities
Rounded geometry is expressed through small capability interfaces instead of repeated component-specific
props. RadiusProps provides radius="theme" | "full"; AspectProps provides
aspect="auto" | "square"; and GeometryProps combines both. The defaults are theme and auto.
theme follows the active theme's corner treatment. full always uses a fully rounded corner and is
independent of the global squircle or superellipse setting. The aspect ratio determines the silhouette:
<Button variant="primary" label="Continue" radius="full" />
<Surface radius="full">Pill surface</Surface>
<Surface radius="full" aspect="square">Circular surface</Surface>
Container, Surface, Box, and Card expose both capabilities. Text buttons, Input, Textarea,
and the Select trigger expose only radius. Components with a fixed silhouette use the same contract
internally: icon buttons are full + square, while chips, slider parts, and tab pills are full + auto.
Content and layout-only primitives do not expose geometry props.
CDN usage
Use the public npm package through npm-compatible CDNs:
import { Button } from "https://esm.sh/@dotnaos/ui-base@VERSION";
import { Button } from "https://cdn.jsdelivr.net/npm/@dotnaos/ui-base@VERSION/+esm";
import { Button } from "https://unpkg.com/@dotnaos/ui-base@VERSION/dist/index.js";
The unpkg entrypoint serves the built ESM file directly. Because react, react-dom, and react/jsx-runtime remain peer/runtime imports, esm.sh and jsDelivr +esm provide the smoothest browser CDN experience.
Build
bun --filter @dotnaos/ui-base build
Licensing
This package is published under the MIT license and includes LICENSE and THIRD_PARTY_NOTICES.md in the npm tarball.
The package owns its component implementations directly and does not wrap or select another component library.