
💡 About
Lit components for building editor interfaces: fields, panels, docks, dialogs, trees and more. The JollyPixel editors are built with it, with light and dark themes and live collaboration included.
💃 Getting Started
This package is available in the Node Package Repository and can be easily installed with npm or yarn.
$ npm i @jolly-pixel/ui
# or
$ yarn add @jolly-pixel/uiIMPORTANT
lit is a peer dependency. Use one compatible copy in the application.
📖 Guides
Start with Getting started, then pick the task at hand.
Fields:
- Building an inspector: fields bound to a model with
FieldBinding, multi-selections and row layout. - Preview and commit: live preview on
jolly-input, one undo step and one network command onjolly-change. - Keeping an element in sync: render again when the model changes elsewhere.
Panels and shell:
- Hierarchy panels: a
jolly-treewith renaming, drag and drop and a row menu. - Dialogs: one-question helpers, dialog elements and inline confirmation.
- Editor layout: docks, tab groups and reacting to where panes are.
- Toolbars and menus: tool buttons, menus opened from a button, and keyboard ownership.
- Persisting settings: storage keys and the
StorageAdapterport. - Theming and density: scopes, user preferences, token overrides and canvases.
Collaboration and debugging:
- Collaboration: roster, per-row peer marks and field locks.
- Debug panels: the facade over a plain object, and a stats overlay.
📚 API
Each element registers when its own entry point is imported: @jolly-pixel/ui/elements/<name>, where <name> is the tag without jolly-. That entry also exports the element class, and the elements it renders register with it. The root entry point registers no element: it exports the element types, the theme, the controllers and the helpers. The facade and its types live in @jolly-pixel/ui/facade, and the network adapters in @jolly-pixel/ui/network.
import "@jolly-pixel/ui/elements/tree";
import { Dialog } from "@jolly-pixel/ui/elements/dialog";
import type { TreeNode } from "@jolly-pixel/ui";Import the element in the module whose template renders it, not once at the application entry: a lazily loaded panel then brings its own elements, and nothing else loads them. In this repository the @jolly-pixel/import-rendered-elements lint rule enforces it.
Each element page lists its properties, events and slots. A property marked property only has no HTML attribute.
Components
Each entry gives the HTML tag, then the class name.
Controls
Field controls share the field API. Building an inspector maps values to controls.
jolly-button(Button)jolly-button-group(ButtonGroup)jolly-checkbox(Checkbox)jolly-color(Color)jolly-color-picker(ColorPicker)jolly-control(Control)jolly-controls(Controls)jolly-flags(Flags)jolly-layer-grid(LayerGrid)jolly-number(NumberField)jolly-property-row(PropertyRow)jolly-range(Range)jolly-search(Search)jolly-select(Select)jolly-separator(Separator)jolly-slider(Slider)jolly-spin-slider(SpinSlider)jolly-text(Text)jolly-toggle(Toggle)jolly-tool-button(ToolButton)
Math fields
The vector, quaternion and transform fields take structural values and do not depend on Three.js.
jolly-point2d(Point2d)jolly-quaternion(Quaternion)jolly-transform(Transform)jolly-vector2(Vector2)jolly-vector3(Vector3)jolly-vector4(Vector4)- Axis fields: rules shared by every axis, and axis markers.
- Math value types:
Vec3Like,QuatLike,TransformLikeand the value helpers.
Containers
Editor layout and Dialogs cover how they fit together.
jolly-context-menu(ContextMenu)jolly-dialog(Dialog)jolly-dock(Dock)jolly-dock-layout(DockLayout)jolly-floating(Floating)jolly-folder(Folder)jolly-pane(PaneElement)jolly-pane-group(PaneGroup)jolly-rail(Rail)jolly-tab(Tab)jolly-tabs(Tabs)jolly-toolbar(Toolbar)- Layout data and functions: the snapshot a
jolly-dock-layoutpersists. - Dialog helpers: promise-based dialogs created under
document.body, exported from@jolly-pixel/ui/elements/dialog.
The root entry point also exports DockAlign, DockSide, DockSlot, RailOrientation, TabsOrientation and ToolbarOrientation.
Data
jolly-tree(Tree)- Tree data and functions: pure helpers over
TreeNodearrays.
Feedback
jolly-loading(Loading)jolly-log(LogElement), with itsLogQueuejolly-progress(Progress)jolly-spinner(Spinner)
Icons
The registry comes from the root entry point. The built-in glyphs register with jolly-icon.
import { Icon } from "@jolly-pixel/ui/elements/icon";
import {
getIcon,
hasIcon,
registerIcon
} from "@jolly-pixel/ui";jolly-icon(Icon)- Icon registry: registers application glyphs and exposes them to Lit templates.
BuiltinIconName,IconNameandIconGlyphdescribe the accepted names and glyphs.
Monitors
jolly-graph(GraphElement)jolly-monitor(MonitorElement)- Formatting functions
Stats
jolly-stats(StatsElement): renders one recorder metric and its history.
Peer presence
jolly-presence(PresenceElement)jolly-presence-stack(PresenceStack)jolly-avatar(Avatar)- Field collaboration state
Theme
Theming and density covers scope setup.
jolly-density-control(DensityControl)jolly-scope(ScopeHost)jolly-theme-control(ThemeControl)jolly-theme-preferences(ThemePreferences)- Theme exports and tokens:
themeStyles, the theme types and the token readers.
Facade
The facade builds the components from JavaScript and binds them to object properties. Debug panels walks through a panel.
import {
DockFacade,
Pane
} from "@jolly-pixel/ui/facade";The facade registers every element it can create, and exports its own types.
Pane: the entry point, andFacadeHostfor an existing element.DockFacade: wraps an authoredjolly-dock.- Builders: the surface every builder and container shares, and the exported types.
- Folders: group builders.
- Bindings: edit object properties.
- Monitors: display object properties.
- Buttons and separators
- Notes, elements and theme preferences
- Presence: peer snapshots.
Headless APIs
Classes, ports and functions that register no element.
Storage
StorageAdapter: the port stateful components persist through, withLocalStorageAdapterandMemoryStorageAdapter.
Interaction
PopoverController: positions a native popover against an anchor.- Overflow titles: full text as a tooltip on cut-off labels.
- Input layers:
inputLayers, the keyboard events that belong to the UI. - Drag sessions:
startPointerDragSession.
Stats recording
Recording is separate from rendering, and @jolly-pixel/ui/stats loads no element:
import {
StatsRecorder,
resolveMetricFormat,
resolveMetricRange,
type MetricDefinition,
type MetricSource
} from "@jolly-pixel/ui/stats";StatsRecorder: a DOM-free frame and metric recorder.- Metric definitions: aggregation, formatting and graph bounds.
MetricSourcelets another package describe metrics without depending on this one.
Color picker preferences
@jolly-pixel/ui/color-picker loads no element either. It exports the preference types, the values with their labels, and the defaults, so a settings page can edit the picker preferences from code that runs without a DOM:
import {
COLOR_PICKER_DEFAULTS,
COLOR_PICKER_OPTIONS,
type ColorPickerPreferences
} from "@jolly-pixel/ui/color-picker";Presence
- Presence and locking: the
PresenceSourceport, and itsRoomPresenceSourcenetwork adapter. - Peer identity:
promptPeerIdentity,peerIdentityand the profile helpers. - Room roster and peer marks: the
PeerRoster,PeerMarkTrackerandpeerBadgesnetwork adapters.
Lit helpers
FieldBinding: binds a field in a Lit template to one value.SubscriptionController: keeps a host subscribed to one source while connected.LazyTemplate: renders part of a template once the module that defines its elements is loaded.
Utilities
- Colour:
parseColorandformatHex. - Search queries:
SearchQueryand theSearchablehook. - Geometry:
Rectand anchored placement. - DOM: DOM guards and field event helpers.
🖼️ Examples Gallery
Every component has a gallery entry, which is also its end to end fixture.
pnpm run devOpen one example with /?example=controls/number, and add &chrome=off to hide the shell.
To add an example, put its module in examples/scripts/examples/<group>/ and register it in that folder's index.ts. Declare variants as options on the same page; the shell keeps them in the URL.
Contributors Guide
Read the contributing guide, and add tests with every feature or bug fix.
pnpm run test # unit (node:test) and type tests
pnpm run test:e2e # Playwright against the gallery
pnpm run lintEnd to end specs in test/e2e/ sit with the component they cover. Cross-component workflows go in scenarios/, shared helpers in support/.
IMPORTANT
node --test cannot import decorated components, so keep unit-test assertions in plain modules.
License
MIT
This package embeds Roboto Mono (weight 400, latin subset), licensed under the Apache License 2.0. See NOTICE for the full attribution.