Guides
Extending the system
The shared core is exported, so you can build new overlay-based components on the same foundation the suite uses — and they inherit theming, focus management, and positioning for free.
Building a new component
Extend BaseComponent and implement the lifecycle hooks. The base class
gives you option merging, a namespaced uid, an event surface, tracked
listeners, a ThemeEngine, and the open()/close()
scaffolding. You implement onMount(), onUnmount(), and
optionally onDestroy().
import { BaseComponent, OverlayManager } from "./dist/ui-suite.esm.js";
import { createEl } from "./src/core/dom.js";
const DEFAULTS = { theme: "auto", onChange: null };
export default class ColorPicker extends BaseComponent {
constructor(el, options = {}) {
super(el, DEFAULTS, options, { prefix: "dt" }); // dt- keeps tokens applying
this.listen(this.el, "click", () => this.open());
}
onMount() {
this.body = createEl("div", { className: "dt-colorpicker-body" });
this.overlay = new OverlayManager({
anchor: this.el,
mode: "popover",
component: "colorpicker",
panelClass: "dt-colorpicker",
onRequestClose: () => this.close(),
});
const panel = this.overlay.open(this.body);
this.theme.register(panel); // tokens + light/dark for free
this._render();
}
onUnmount() { this.overlay.close(); }
_render() {
// build DOM from createEl(...) using --dt-* tokens for all colors
}
}
You get the hard parts for free
Portaling, viewport-aware positioning, outside-click and Escape handling, focus trap/restore, the overlay stack, and theme stamping all come from the core. Your component only owns its domain.
Naming conventions
- Class names are
PascalCase(DateTimePicker,SelectPicker). - CSS classes and attributes use the
dt-prefix (dt-scope,dt-panel,dt-option) so they share the token namespace. - Pass
{ prefix: "dt" }tosuper(...)so youruidand data attributes line up with the suite and tokens apply. - Design tokens are always
--dt-*; introduce new ones sparingly and document them. - Events are lowercase (
change,open,close); paired option callbacks areonChange,onOpen,onClose.
Where logic belongs
The guiding rule: infrastructure goes in the core; domain logic stays in the component.
| Concern | Lives in |
|---|---|
| Overlay rendering, positioning, dismissal | Core — OverlayManager, PositioningEngine |
| Focus trap & restore | Core — FocusManager |
| Theming & light/dark | Core — ThemeEngine |
| Form binding & hidden values | Core — InputAdapter |
| Large-list windowing | Core — VirtualList |
| Value model, parsing, formatting | Component |
| Domain UI (calendar grid, option rows) | Component |
| Selection rules & keyboard semantics | Component |
If you find yourself re-implementing positioning, focus, or theming inside a component, that logic likely belongs in (or already exists in) the core. Reuse the primitive instead of duplicating it — that is exactly how DateTimePicker and SelectPicker stay small and consistent.
Available core exports
import {
BaseComponent, OverlayManager, PositioningEngine,
FocusManager, ThemeEngine, InputAdapter, VirtualList,
EventEmitter, InertialWheel, resolveTouch,
} from "./dist/ui-suite.esm.js";