@vanelsas/baredom 0.1.2-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/LICENSE +21 -0
  3. package/README.md +444 -0
  4. package/dist/base.js +352 -0
  5. package/dist/x-alert.js +20 -0
  6. package/dist/x-avatar-group.js +12 -0
  7. package/dist/x-avatar.js +18 -0
  8. package/dist/x-badge.js +12 -0
  9. package/dist/x-breadcrumbs.js +15 -0
  10. package/dist/x-button.js +17 -0
  11. package/dist/x-cancel-dialogue.js +20 -0
  12. package/dist/x-card.js +8 -0
  13. package/dist/x-chart.js +45 -0
  14. package/dist/x-checkbox.js +12 -0
  15. package/dist/x-chip.js +10 -0
  16. package/dist/x-collapse.js +13 -0
  17. package/dist/x-command-palette.js +33 -0
  18. package/dist/x-container.js +7 -0
  19. package/dist/x-context-menu.js +20 -0
  20. package/dist/x-copy.js +26 -0
  21. package/dist/x-currency-field.js +22 -0
  22. package/dist/x-date-picker.js +37 -0
  23. package/dist/x-divider.js +11 -0
  24. package/dist/x-drawer.js +13 -0
  25. package/dist/x-dropdown.js +12 -0
  26. package/dist/x-fieldset.js +7 -0
  27. package/dist/x-file-download.js +9 -0
  28. package/dist/x-form-field.js +16 -0
  29. package/dist/x-form.js +11 -0
  30. package/dist/x-grid.js +8 -0
  31. package/dist/x-menu-item.js +11 -0
  32. package/dist/x-menu.js +13 -0
  33. package/dist/x-modal.js +14 -0
  34. package/dist/x-navbar.js +13 -0
  35. package/dist/x-notification-center.js +10 -0
  36. package/dist/x-pagination.js +17 -0
  37. package/dist/x-popover.js +13 -0
  38. package/dist/x-progress-circle.js +12 -0
  39. package/dist/x-progress.js +11 -0
  40. package/dist/x-radio.js +13 -0
  41. package/dist/x-search-field.js +17 -0
  42. package/dist/x-select.js +12 -0
  43. package/dist/x-sidebar.js +27 -0
  44. package/dist/x-skeleton.js +8 -0
  45. package/dist/x-slider.js +17 -0
  46. package/dist/x-spacer.js +6 -0
  47. package/dist/x-spinner.js +7 -0
  48. package/dist/x-stat.js +10 -0
  49. package/dist/x-stepper.js +17 -0
  50. package/dist/x-switch.js +12 -0
  51. package/dist/x-tab.js +9 -0
  52. package/dist/x-table-cell.js +26 -0
  53. package/dist/x-table-row.js +11 -0
  54. package/dist/x-table.js +16 -0
  55. package/dist/x-tabs.js +12 -0
  56. package/dist/x-text-area.js +20 -0
  57. package/dist/x-timeline-item.js +25 -0
  58. package/dist/x-timeline.js +10 -0
  59. package/dist/x-toast.js +26 -0
  60. package/dist/x-toaster.js +9 -0
  61. package/package.json +275 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,30 @@
1
+ # Changelog
2
+
3
+ All notable changes to BareDome will be documented in this file.
4
+
5
+ ## [0.1.0-alpha] - 2026-03-25
6
+
7
+ Initial alpha release of BareDome — 54 native Web Components built with ClojureScript and compiled to zero-dependency ESM modules.
8
+
9
+ ### Components
10
+
11
+ - **Layout** — x-container, x-grid, x-spacer, x-divider, x-sidebar, x-navbar
12
+ - **Typography & Display** — x-badge, x-chip, x-stat, x-avatar, x-avatar-group, x-skeleton
13
+ - **Feedback** — x-alert, x-spinner, x-progress, x-progress-circle, x-toast, x-toaster
14
+ - **Overlays** — x-modal, x-drawer, x-popover, x-context-menu, x-command-palette, x-cancel-dialogue
15
+ - **Navigation** — x-breadcrumbs, x-pagination, x-tab, x-tabs, x-menu, x-menu-item, x-stepper
16
+ - **Forms** — x-button, x-checkbox, x-radio, x-switch, x-select, x-slider, x-text-area, x-form, x-form-field, x-fieldset, x-search-field, x-currency-field, x-date-picker
17
+ - **Content** — x-card, x-collapse, x-chart, x-copy, x-file-download, x-dropdown
18
+ - **Data** — x-table, x-table-row, x-table-cell
19
+ - **Timeline** — x-timeline, x-timeline-item
20
+
21
+ ### Architecture
22
+
23
+ - Stateless rendering: `DOM = f(attributes, properties)`
24
+ - Zero framework runtime — no React, Lit, Vue, or virtual DOM
25
+ - Open shadow DOM with CSS custom properties for theming
26
+ - Light/dark mode via `@media (prefers-color-scheme: dark)`
27
+ - Reduced motion via `@media (prefers-reduced-motion: reduce)`
28
+ - Google Closure Advanced compiled — minified, dead-code-eliminated
29
+ - Per-component ESM modules — fully tree-shakeable
30
+ - Accessible by default (ARIA roles, keyboard navigation, focus management)
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alexander van Elsas
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,444 @@
1
+ # BareDOM
2
+
3
+ **Native web components. Zero runtime. No framework required.**
4
+
5
+ [![npm version](https://img.shields.io/npm/v/%40vanelsas%2Fbaredom.svg)](https://www.npmjs.com/package/@vanelsas/baredom)
6
+ [![license](https://img.shields.io/npm/l/%40vanelsas%2Fbaredom.svg)](./LICENSE)
7
+ [![ESM](https://img.shields.io/badge/module-ESM-blue.svg)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules)
8
+ [![Custom Elements v1](https://img.shields.io/badge/Custom%20Elements-v1-green.svg)](https://developer.mozilla.org/en-US/docs/Web/API/Web_components/Using_custom_elements)
9
+
10
+ ---
11
+
12
+ ## What is BareDOM?
13
+
14
+ BareDOM is a library of 54 UI components built entirely on web standards — Custom Elements v1, Shadow DOM, and ES modules. There is no framework runtime, no virtual DOM, and no JavaScript framework peer dependency. Every component is a native HTML element that you register once and use anywhere.
15
+
16
+ The core rendering model is deliberately simple:
17
+
18
+ ```
19
+ DOM = f(attributes, properties)
20
+ ```
21
+
22
+ Components are **stateless**. Every visual state is derived directly from attributes and properties at render time. There are no hidden reactive systems, no internal signals, no component lifecycles to manage. Set an attribute, the DOM updates. Remove it, the DOM updates back.
23
+
24
+ BareDOM is authored in ClojureScript and compiled to optimised, minified ES modules using Google Closure's advanced compilation pass.
25
+
26
+ BareDOM has been created using Claude Code. The CLAUDE.md file is added to the repository for your convenience.
27
+
28
+ ---
29
+
30
+ ## Why BareDOM?
31
+
32
+ **Works in any stack.** Because components are native HTML elements, they work wherever HTML works — vanilla JavaScript, React, Vue, Svelte, Angular, server-rendered HTML, or a static page. No adapter layer, no wrapper library.
33
+
34
+ **No framework lock-in.** Your components are not tied to the framework you are building with today. Migrate your app, keep your components.
35
+
36
+ **Tree-shakeable by design.** Each component is a separate ES module. Import only what you use; bundle tools eliminate the rest automatically.
37
+
38
+ **Full theming with CSS custom properties.** Every visual detail — colours, spacing, radius, shadows, typography — is exposed as a `--x-<component>-<property>` CSS custom property. Override at any scope: globally, per-page, per-instance.
39
+
40
+ **Light and dark mode included.** All components adapt automatically to `prefers-color-scheme`. No JavaScript required, no class toggling.
41
+
42
+ **Accessibility built in.** ARIA roles, live regions, keyboard navigation, focus management, and `prefers-reduced-motion` support are part of the component, not an afterthought. You do not need to layer accessibility on top.
43
+
44
+ **Open Shadow DOM.** Shadow roots are `mode: "open"` — inspectable in DevTools, styleable via `::part()`, and testable with standard DOM APIs.
45
+
46
+ ---
47
+
48
+ ## Installation
49
+
50
+ **Step 1 — Add the npm dependency to your `package.json`:**
51
+
52
+ ```json
53
+ {
54
+ "dependencies": {
55
+ "@vanelsas/baredom": "^0.1.1-alpha"
56
+ }
57
+ }
58
+ ```
59
+
60
+ Then run `npm install`.
61
+
62
+ **Step 2 — shadow-cljs:** no extra configuration needed. shadow-cljs resolves npm packages automatically via the `:npm-deps` or `node_modules` integration built into every shadow-cljs project.
63
+
64
+ ---
65
+
66
+ ## Usage
67
+
68
+ ### 1. Register components
69
+
70
+ Require each component module you need and call `.init` on it once, before any rendering. Only the components you require are included in your bundle.
71
+
72
+ ```clojure
73
+ (ns my-app.core
74
+ (:require
75
+ ["@vanelsas/baredom/x-button" :as x-button]
76
+ ["@vanelsas/baredom/x-alert" :as x-alert]
77
+ ["@vanelsas/baredom/x-toaster" :as x-toaster]
78
+ ["@vanelsas/baredom/x-toast" :as x-toast]))
79
+
80
+ (defn- register-components! []
81
+ (.init x-button)
82
+ (.init x-alert)
83
+ (.init x-toaster)
84
+ (.init x-toast))
85
+ ```
86
+
87
+ Call `register-components!` once in your `init!` entry point. Registration is idempotent — calling `.init` on an already-registered element is a no-op.
88
+
89
+ ### 2. Add a renderer
90
+
91
+ BareDOM components are plain DOM elements. You need no framework to use them — only a small helper that turns ClojureScript data structures into DOM nodes. Copy the following into your project as `renderer.cljs`:
92
+
93
+ ```clojure
94
+ (ns my-app.renderer
95
+ (:require [clojure.string :as str]))
96
+
97
+ ;;; ── Prop helpers ──────────────────────────────────────────────────────────
98
+
99
+ (defn- on-key? [k]
100
+ (str/starts-with? (name k) "on-"))
101
+
102
+ (defn- event-name [k]
103
+ ;; :on-click → "click" :on-value-change → "value-change"
104
+ (subs (name k) 3))
105
+
106
+ (defn- set-prop! [el k v]
107
+ (let [attr (name k)]
108
+ (cond
109
+ (on-key? k) (.addEventListener el (event-name k) v)
110
+ (nil? v) (.removeAttribute el attr)
111
+ (true? v) (.setAttribute el attr "")
112
+ (false? v) (.removeAttribute el attr)
113
+ :else (.setAttribute el attr (str v)))))
114
+
115
+ ;;; ── DOM creation ──────────────────────────────────────────────────────────
116
+
117
+ (declare create-nodes)
118
+
119
+ (defn- create-element [[tag & args]]
120
+ (let [has-props? (and (seq args) (map? (first args)))
121
+ props (when has-props? (first args))
122
+ children (if has-props? (rest args) args)
123
+ el (.createElement js/document (name tag))]
124
+ (doseq [[k v] props]
125
+ (set-prop! el k v))
126
+ (doseq [node (mapcat create-nodes children)]
127
+ (.appendChild el node))
128
+ el))
129
+
130
+ (defn create-nodes [x]
131
+ (cond
132
+ (nil? x) []
133
+ (false? x) []
134
+ (string? x) [(.createTextNode js/document x)]
135
+ (number? x) [(.createTextNode js/document (str x))]
136
+ (vector? x) [(create-element x)]
137
+ (seq? x) (mapcat create-nodes x)
138
+ :else []))
139
+
140
+ ;;; ── Mount ─────────────────────────────────────────────────────────────────
141
+
142
+ (defn render! [container view-fn]
143
+ (set! (.-innerHTML container) "")
144
+ (doseq [node (create-nodes (view-fn))]
145
+ (.appendChild container node)))
146
+
147
+ (defn mount! [container view-fn state-atom]
148
+ (render! container view-fn)
149
+ (add-watch state-atom ::render
150
+ (fn [_ _ _ _]
151
+ (render! container view-fn))))
152
+ ```
153
+
154
+ What it does:
155
+
156
+ - `set-prop!` — routes `:on-*` keys to `addEventListener`; boolean `true` sets the attribute to `""`; `false` / `nil` removes it; everything else calls `setAttribute`
157
+ - `create-nodes` / `create-element` — recursively turns hiccup vectors into DOM nodes
158
+ - `render!` — clears a container element and mounts the result of calling a view function
159
+ - `mount!` — same as `render!`, and also `add-watch`es a state atom so the view re-renders on every state change
160
+
161
+ ### 3. Write views with hiccup syntax
162
+
163
+ Views are plain ClojureScript functions that return nested vectors. The first element of each vector is a keyword matching the element tag name. An optional map of props follows, then children.
164
+
165
+ ```clojure
166
+ ;; String and number attributes
167
+ [:x-button {:variant "primary"} "Save changes"]
168
+ [:x-button {:variant "secondary" :size "sm"} "Cancel"]
169
+
170
+ ;; Boolean attributes — true sets the attribute, false/nil removes it
171
+ [:x-button {:variant "danger" :disabled true} "Delete"]
172
+ [:x-button {:variant "primary" :loading true} "Saving…"]
173
+ [:x-checkbox {:checked true}]
174
+ [:x-checkbox {:indeterminate true}]
175
+
176
+ ;; Nesting
177
+ [:x-grid {:columns "2" :gap "md"}
178
+ [:x-card "First card"]
179
+ [:x-card "Second card"]]
180
+
181
+ [:x-grid {:columns "4" :gap "md"}
182
+ [:x-stat {:label "Revenue" :value "$48,295" :trend "up" :variant "positive"}]
183
+ [:x-stat {:label "Users" :value "12,483" :trend "up"}]
184
+ [:x-stat {:label "Orders" :value "1,429" :trend "neutral"}]
185
+ [:x-stat {:label "Churn" :value "2.4%" :trend "down" :variant "danger"}]]
186
+
187
+ ;; Slots — use the :slot attribute to target named slots
188
+ [:x-navbar {:label "My App"}
189
+ [:span {:slot "brand" :style "font-weight:700"} "My App"]
190
+ [:div {:slot "actions"}
191
+ [:x-button {:variant "ghost" :size "sm"} "Sign out"]]]
192
+ ```
193
+
194
+ ### 4. Handle events and manage state
195
+
196
+ Event listeners are declared inline using `:on-<event-name>` keys. The key is stripped of `on-` and the remainder becomes the event name passed to `addEventListener`. Custom component events follow the same pattern — use the full event name after `on-`.
197
+
198
+ ```clojure
199
+ (defonce app-state (atom {:active-tab "overview"
200
+ :sidebar-collapsed false}))
201
+
202
+ ;; Standard DOM event
203
+ [:x-button
204
+ {:variant "ghost"
205
+ :on-click (fn [_] (swap! app-state update :sidebar-collapsed not))}
206
+ "Toggle sidebar"]
207
+
208
+ ;; Custom component event — :on-value-change listens for "value-change"
209
+ [:x-tabs
210
+ {:value (:active-tab @app-state)
211
+ :on-value-change (fn [e]
212
+ (swap! app-state assoc
213
+ :active-tab (.. e -detail -value)))}
214
+ [:x-tab {:value "overview"} "Overview"]
215
+ [:x-tab {:value "components"} "Components"]
216
+ [:x-tab {:value "settings"} "Settings"]]
217
+
218
+ ;; Custom event with detail payload
219
+ [:x-alert
220
+ {:type "success" :text "Changes saved." :dismissible true
221
+ :on-x-alert-dismiss (fn [e]
222
+ (js/console.log "dismissed by:" (.. e -detail -reason)))}]
223
+
224
+ ;; Sidebar with open/collapse state
225
+ [:x-sidebar
226
+ {:open (:sidebar-open @app-state)
227
+ :collapsed (:sidebar-collapsed @app-state)
228
+ :placement "left"
229
+ :on-toggle (fn [e]
230
+ (swap! app-state assoc :sidebar-open (.. e -detail -open)))}
231
+ ;; ... nav items ...
232
+ ]
233
+ ```
234
+
235
+ Wire everything together in your `init!`:
236
+
237
+ ```clojure
238
+ (defn view []
239
+ [:x-container {:size "xl" :padding "lg"}
240
+ ;; ... your UI built from component vectors ...
241
+ ])
242
+
243
+ (defn init! []
244
+ (register-components!)
245
+ (renderer/mount! (.getElementById js/document "app") view app-state))
246
+ ```
247
+
248
+ `mount!` calls `view` immediately and re-calls it on every `swap!` or `reset!` to `app-state`. The entire view is re-created from scratch on each render — no diffing, no virtual DOM, just plain DOM construction driven by the current value of the atom.
249
+
250
+ ### Theming
251
+
252
+ Override CSS custom properties at any scope:
253
+
254
+ ```css
255
+ /* Global overrides */
256
+ :root {
257
+ --x-button-radius: 4px;
258
+ --x-alert-radius: 8px;
259
+ }
260
+
261
+ /* Per-instance override */
262
+ #sidebar-save-btn {
263
+ --x-button-bg-primary: #0a5c99;
264
+ }
265
+ ```
266
+
267
+ ---
268
+
269
+ ## Components
270
+
271
+ ### Form (16)
272
+
273
+ | Tag | Description |
274
+ |-----|-------------|
275
+ | [`<x-button>`](./docs/x-button.md) | Action control. Variants: `primary`, `secondary`, `tertiary`, `ghost`, `danger`. Sizes: `sm`, `md`, `lg`. States: `disabled`, `loading`, `pressed`. Icon slots. |
276
+ | [`<x-checkbox>`](./docs/x-checkbox.md) | Boolean input. Reflects `checked` and `indeterminate` states to attributes. |
277
+ | [`<x-copy>`](./docs/x-copy.md) | Copy-to-clipboard utility button with success feedback. |
278
+ | [`<x-currency-field>`](./docs/x-currency-field.md) | Formatted currency input with locale-aware masking. |
279
+ | [`<x-date-picker>`](./docs/x-date-picker.md) | Calendar-based date selection with keyboard navigation. |
280
+ | [`<x-fieldset>`](./docs/x-fieldset.md) | Groups related form controls with a styled legend. |
281
+ | [`<x-file-download>`](./docs/x-file-download.md) | Download trigger that initiates a file transfer. |
282
+ | [`<x-form>`](./docs/x-form.md) | Form wrapper with coordinated validation state. |
283
+ | [`<x-form-field>`](./docs/x-form-field.md) | Label + input wrapper with error and hint text slots. |
284
+ | [`<x-radio>`](./docs/x-radio.md) | Single-choice input within a radio group. |
285
+ | [`<x-search-field>`](./docs/x-search-field.md) | Search input with integrated clear button and search icon. |
286
+ | [`<x-select>`](./docs/x-select.md) | Dropdown select control with custom styling. |
287
+ | [`<x-slider>`](./docs/x-slider.md) | Range slider with step, min/max, and value display. |
288
+ | [`<x-stepper>`](./docs/x-stepper.md) | Multi-step form progress indicator with navigation. |
289
+ | [`<x-switch>`](./docs/x-switch.md) | Toggle switch for boolean settings. |
290
+ | [`<x-text-area>`](./docs/x-text-area.md) | Multi-line text input with auto-resize option. |
291
+
292
+ ### Feedback (10)
293
+
294
+ | Tag | Description |
295
+ |-----|-------------|
296
+ | [`<x-alert>`](./docs/x-alert.md) | Semantic alert banner. Types: `info`, `success`, `warning`, `error`. Auto-dismiss with `timeout-ms`. Fires `x-alert-dismiss`. |
297
+ | [`<x-badge>`](./docs/x-badge.md) | Small inline label for counts, states, and categories. |
298
+ | [`<x-chip>`](./docs/x-chip.md) | Compact tag component, optionally removable. |
299
+ | [`<x-notification-center>`](./docs/x-notification-center.md) | Notification hub for aggregating and managing in-app notifications. |
300
+ | [`<x-progress>`](./docs/x-progress.md) | Linear progress bar with determinate and indeterminate modes. |
301
+ | [`<x-progress-circle>`](./docs/x-progress-circle.md) | Circular progress indicator for compact spaces. |
302
+ | [`<x-skeleton>`](./docs/x-skeleton.md) | Animated loading placeholder that mirrors content shape. |
303
+ | [`<x-spinner>`](./docs/x-spinner.md) | Inline loading spinner with size and colour variants. |
304
+ | [`<x-toast>`](./docs/x-toast.md) | Single transient notification with enter/exit animations and auto-dismiss. |
305
+ | [`<x-toaster>`](./docs/x-toaster.md) | Toast manager. Positions a queue of `<x-toast>` elements, enforces `max-toasts`, and fires `x-toaster-dismiss`. |
306
+
307
+ ### Navigation (8)
308
+
309
+ | Tag | Description |
310
+ |-----|-------------|
311
+ | [`<x-breadcrumbs>`](./docs/x-breadcrumbs.md) | Hierarchical path trail with separator customisation. |
312
+ | [`<x-menu>`](./docs/x-menu.md) | Vertical menu container coordinating `<x-menu-item>` children. |
313
+ | [`<x-menu-item>`](./docs/x-menu-item.md) | Individual menu entry with icon, label, description, and keyboard support. |
314
+ | [`<x-navbar>`](./docs/x-navbar.md) | Top navigation bar with responsive slot layout. |
315
+ | [`<x-pagination>`](./docs/x-pagination.md) | Page navigation controls with first/previous/next/last and page-size selection. |
316
+ | [`<x-sidebar>`](./docs/x-sidebar.md) | Collapsible side navigation panel with collapse/expand animation. |
317
+ | [`<x-tab>`](./docs/x-tab.md) | Individual tab within an `<x-tabs>` container. |
318
+ | [`<x-tabs>`](./docs/x-tabs.md) | Tab container that coordinates `<x-tab>` children, manages active state, and fires change events. |
319
+
320
+ ### Layout (6)
321
+
322
+ | Tag | Description |
323
+ |-----|-------------|
324
+ | [`<x-card>`](./docs/x-card.md) | Surface container. Variants: `elevated`, `outlined`, `filled`, `ghost`. Interactive mode available. |
325
+ | [`<x-collapse>`](./docs/x-collapse.md) | Expandable/collapsible section with animated height transition. |
326
+ | [`<x-container>`](./docs/x-container.md) | Responsive max-width container with configurable padding. |
327
+ | [`<x-divider>`](./docs/x-divider.md) | Horizontal or vertical visual separator. |
328
+ | [`<x-grid>`](./docs/x-grid.md) | CSS Grid layout component with responsive column configuration. |
329
+ | [`<x-spacer>`](./docs/x-spacer.md) | Flexible spacing element for flexbox and grid layouts. |
330
+
331
+ ### Data (9)
332
+
333
+ | Tag | Description |
334
+ |-----|-------------|
335
+ | [`<x-avatar>`](./docs/x-avatar.md) | User photo or initials display. Shape, size, and status dot variants. |
336
+ | [`<x-avatar-group>`](./docs/x-avatar-group.md) | Overlapping avatar stack for representing multiple users. |
337
+ | [`<x-chart>`](./docs/x-chart.md) | Data visualisation component for common chart types. |
338
+ | [`<x-stat>`](./docs/x-stat.md) | KPI / metric card with value, label, trend, and icon slots. |
339
+ | [`<x-table>`](./docs/x-table.md) | Data grid using CSS subgrid. Supports sorting, single/multi-select, striping, and accessible captions. |
340
+ | [`<x-table-cell>`](./docs/x-table-cell.md) | Table cell for header and data modes, with sort indicator and alignment control. |
341
+ | [`<x-table-row>`](./docs/x-table-row.md) | Table row with interactive selection and `x-table-row-select` event. |
342
+ | [`<x-timeline>`](./docs/x-timeline.md) | Vertical timeline container that coordinates `<x-timeline-item>` children. |
343
+ | [`<x-timeline-item>`](./docs/x-timeline-item.md) | Individual timeline event with time, icon, heading, and body slots. |
344
+
345
+ ### Overlay (7)
346
+
347
+ | Tag | Description |
348
+ |-----|-------------|
349
+ | [`<x-cancel-dialogue>`](./docs/x-cancel-dialogue.md) | Confirmation modal for destructive cancel actions. |
350
+ | [`<x-command-palette>`](./docs/x-command-palette.md) | Keyboard-accessible global search and command interface. |
351
+ | [`<x-context-menu>`](./docs/x-context-menu.md) | Right-click / long-press contextual action menu. |
352
+ | [`<x-drawer>`](./docs/x-drawer.md) | Off-canvas sliding panel, configurable from any edge. |
353
+ | [`<x-dropdown>`](./docs/x-dropdown.md) | Positioned dropdown container for menus and selection. |
354
+ | [`<x-modal>`](./docs/x-modal.md) | Centred dialog with backdrop, focus trap, and `Escape` to close. |
355
+ | [`<x-popover>`](./docs/x-popover.md) | Anchored popover for tooltips, help text, and contextual UI. |
356
+
357
+ ---
358
+
359
+ ## Design Principles
360
+
361
+ **Stateless.** No `atom`, no signal, no reactive state container lives inside a component. Every render is a pure function of the current attributes and properties. Debugging a component means inspecting attributes in DevTools — no hidden state to hunt for.
362
+
363
+ **Standards-only.** BareDOM relies on Custom Elements v1, Shadow DOM v1, and ES modules — all natively supported in modern browsers. There are no polyfills required and no proprietary APIs to learn.
364
+
365
+ **Zero runtime dependency.** Components are compiled to self-contained ES modules. The only JavaScript in your bundle is the component itself. No framework, no runtime library, no utility belt.
366
+
367
+ **Accessible by default.** ARIA roles, live regions, keyboard interaction patterns, focus indicators, and `prefers-reduced-motion` support are written into every component that needs them — not optional add-ons.
368
+
369
+ **Predictable theming.** CSS custom properties follow a single naming convention: `--x-<component>-<property>`. Tokens are set on `:host` and cascade normally. You override them the same way you override any CSS property.
370
+
371
+ ---
372
+
373
+ ## Browser Support
374
+
375
+ BareDOM targets browsers that support Custom Elements v1 and Shadow DOM v1 natively:
376
+
377
+ | Browser | Minimum version |
378
+ |---------|----------------|
379
+ | Chrome / Edge | 67+ |
380
+ | Firefox | 63+ |
381
+ | Safari | 14+ |
382
+
383
+ No polyfills are included or required for these targets.
384
+
385
+ ---
386
+
387
+ ## Component Demo
388
+
389
+ BareDOM ships with a built-in demo that lets you browse and interact with every component in isolation. It is intended for developer convenience when working on the library itself.
390
+
391
+ ```bash
392
+ npm install
393
+ npx shadow-cljs watch app
394
+ ```
395
+
396
+ Then open `http://localhost:8000`. The dev server serves `public/index.html` and hot-reloads on every source change. Each component is demonstrated in its own section with controls for toggling attributes, properties, and variants.
397
+
398
+ ---
399
+
400
+ ## bare-demo — framework-free usage example
401
+
402
+ The `bare-demo/` folder contains a focused ClojureScript application that shows how to consume five BareDOM components — `x-navbar`, `x-sidebar`, `x-button`, `x-modal`, and `x-container` — with **zero framework overhead**.
403
+
404
+ The demo is built on three ideas:
405
+
406
+ - **A ~55-line hiccup renderer.** A small `renderer.cljs` file converts nested ClojureScript vectors into real DOM nodes. There is no virtual DOM, no diffing, and no reactive runtime — just `document.createElement`, `setAttribute`, and `addEventListener`.
407
+ - **A single state atom.** All UI state (`sidebar-open`, `modal-open`, `active-nav`) lives in one `defonce` atom. `mount!` attaches `add-watch` so every `swap!` triggers a full re-render.
408
+ - **CSS custom properties for theming.** Component visuals are overridden entirely in `public/index.html` using `--x-<component>-<property>` rules — no JavaScript involved.
409
+
410
+ **Run it:**
411
+
412
+ ```bash
413
+ npx shadow-cljs watch bare-demo
414
+ ```
415
+
416
+ Then open `http://localhost:8001`.
417
+
418
+ See [`bare-demo/README.md`](./bare-demo/README.md) for a full walkthrough of the renderer, component registration, view syntax, state management, and theming.
419
+
420
+ ---
421
+
422
+ ## Building from Source
423
+
424
+ BareDOM is authored in ClojureScript and compiled with [shadow-cljs](https://shadow-cljs.github.io/docs/UsersGuide.html).
425
+
426
+ ```bash
427
+ # Install dependencies
428
+ npm install
429
+
430
+ # Start development server with hot reload (http://localhost:8000)
431
+ npx shadow-cljs watch app
432
+
433
+ # Run browser-based tests (http://localhost:8021)
434
+ npx shadow-cljs watch test
435
+
436
+ # Build production ESM library to dist/
437
+ npm run build
438
+ ```
439
+
440
+ ---
441
+
442
+ ## License
443
+
444
+ MIT