@vanelsas/baredom 0.1.0-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.
- package/CHANGELOG.md +30 -0
- package/LICENSE +21 -0
- package/README.md +444 -0
- package/dist/base.js +352 -0
- package/dist/x-alert.js +20 -0
- package/dist/x-avatar-group.js +12 -0
- package/dist/x-avatar.js +18 -0
- package/dist/x-badge.js +12 -0
- package/dist/x-breadcrumbs.js +15 -0
- package/dist/x-button.js +17 -0
- package/dist/x-cancel-dialogue.js +20 -0
- package/dist/x-card.js +8 -0
- package/dist/x-chart.js +45 -0
- package/dist/x-checkbox.js +12 -0
- package/dist/x-chip.js +10 -0
- package/dist/x-collapse.js +13 -0
- package/dist/x-command-palette.js +33 -0
- package/dist/x-container.js +7 -0
- package/dist/x-context-menu.js +20 -0
- package/dist/x-copy.js +26 -0
- package/dist/x-currency-field.js +22 -0
- package/dist/x-date-picker.js +37 -0
- package/dist/x-divider.js +11 -0
- package/dist/x-drawer.js +13 -0
- package/dist/x-dropdown.js +12 -0
- package/dist/x-fieldset.js +7 -0
- package/dist/x-file-download.js +9 -0
- package/dist/x-form-field.js +16 -0
- package/dist/x-form.js +11 -0
- package/dist/x-grid.js +8 -0
- package/dist/x-menu-item.js +11 -0
- package/dist/x-menu.js +13 -0
- package/dist/x-modal.js +14 -0
- package/dist/x-navbar.js +13 -0
- package/dist/x-notification-center.js +10 -0
- package/dist/x-pagination.js +17 -0
- package/dist/x-popover.js +13 -0
- package/dist/x-progress-circle.js +12 -0
- package/dist/x-progress.js +11 -0
- package/dist/x-radio.js +13 -0
- package/dist/x-search-field.js +17 -0
- package/dist/x-select.js +12 -0
- package/dist/x-sidebar.js +27 -0
- package/dist/x-skeleton.js +8 -0
- package/dist/x-slider.js +17 -0
- package/dist/x-spacer.js +6 -0
- package/dist/x-spinner.js +7 -0
- package/dist/x-stat.js +10 -0
- package/dist/x-stepper.js +17 -0
- package/dist/x-switch.js +12 -0
- package/dist/x-tab.js +9 -0
- package/dist/x-table-cell.js +26 -0
- package/dist/x-table-row.js +11 -0
- package/dist/x-table.js +16 -0
- package/dist/x-tabs.js +12 -0
- package/dist/x-text-area.js +20 -0
- package/dist/x-timeline-item.js +25 -0
- package/dist/x-timeline.js +10 -0
- package/dist/x-toast.js +26 -0
- package/dist/x-toaster.js +9 -0
- package/package.json +276 -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
|
+
[](https://www.npmjs.com/package/@vanelsas/baredom)
|
|
6
|
+
[](./LICENSE)
|
|
7
|
+
[](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules)
|
|
8
|
+
[](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.0-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
|