canonrs-server 0.1.0

CanonRS server-side rendering support
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
---
component: Accordion
layer: UI
status: Stable
since: v1.0
last_review: 2025-01-18
ownership: canonrs
keywords:
  - design system
  - dioxus
  - ssr
  - accordion
  - disclosure
  - enterprise ui
path_primitive: /opt/docker/monorepo/packages-rust/rs-design/src/primitives/accordion.rs
path_ui: /opt/docker/monorepo/packages-rust/rs-design/src/ui/accordion/
---

# Accordion

## 1. Conceptual Introduction

The Accordion is a **UI component** that provides ergonomic composition of collapsible content sections in an exclusive (single-open) interaction pattern. It serves as the canonical enterprise solution for FAQ pages, documentation navigation, settings panels, and structured information disclosure.

The Accordion exists in the **UI layer** because it provides:
- Default behavior (exclusive single-open)
- Ergonomic API with sensible defaults
- Semantic intent (collapsible structured content)
- Composition of primitives without business logic

**What it is NOT:**
- Not a primitive (it composes primitives)
- Not a runtime behavior (no browser APIs)
- Not a styling layer (delegates to CSS via data-attributes)
- Not a navigation component (use Tabs for horizontal navigation)

---

## 2. Architectural Responsibility (Contract)

### Responsibility

The Accordion UI component:
- **Composes** `AccordionPrimitive`, `AccordionItem`, `AccordionTrigger`, and `AccordionContent`
- **Declares** exclusive open behavior via `data-collapsible` attribute
- **Exposes** ergonomic API with `default_value` and `collapsible` props
- **Emits** SSR-safe HTML with data-attributes for runtime hydration
- **Guarantees** semantic structure and accessibility contracts

### Non-Responsibility

The Accordion UI component explicitly does NOT:
- ❌ Execute browser APIs (clipboard, focus, keyboard)
- ❌ Manage state imperatively (state lives in DOM via data-attributes)
- ❌ Apply CSS classes or inline styles
- ❌ Register global event listeners
- ❌ Perform side effects or mutations

**Side effects are PROHIBITED.**  
All runtime behavior is delegated to the Shell Runtime JS layer.

---

## 3. Position in CanonRS Ecosystem

The Accordion participates in the canonical CanonRS flow:
```text
Page/Block (usage)
  ↓
UI Component (Accordion) — ergonomic API, composition
  ↓
Primitives (AccordionPrimitive, AccordionItem, etc.) — HTML + data-attributes
  ↓
SSR Render — static HTML emitted
  ↓
Shell Runtime JS — event delegation, state management
  ↓
Browser API — DOM manipulation, ARIA, keyboard navigation
  ↓
CSS — styling via [data-accordion-*] selectors
```

**SSR Context:**
- Accordion renders complete HTML structure on server
- No client-side JS required for initial render
- Runtime JS hydrates interactive behavior on client

**Hydration:**
- Shell Runtime reads `data-collapsible` and `data-default-value`
- Attaches delegated event listeners to `[data-accordion-trigger]`
- Manages `data-state="open|closed"` on `[data-accordion-item]`

---

## 4. Tokens Applied

The Accordion UI component does **not directly apply tokens**—it delegates to CSS.  
The CSS layer (`style/ui/accordion.css`) consumes the following token families:

### Layout Tokens
- `--space-sm` (accordion gap)
- `--space-md` (trigger padding, content padding)

### Typography Tokens
- `--font-family-sans`
- `--font-size-sm`
- `--font-weight-medium`
- `--line-height-normal`

### Color Tokens
- `--color-fg-default` (text color)
- `--color-fg-muted` (icon color)
- `--color-bg-muted` (hover/active background)
- `--color-border-muted` (item separator)

### Border & Radius Tokens
- `--border-width-hairline`
- `--radius-sm`

### State Tokens
- `--state-hover-opacity`
- `--state-active-opacity`
- `--state-focus-opacity`

### Accordion Family Tokens (Defined in CSS)
- `--accordion-gap`
- `--accordion-trigger-padding`
- `--accordion-content-padding`
- `--accordion-icon-size`
- `--accordion-icon-rotation-open`
- `--accordion-icon-svg` (themeable icon)

**Token Resolution:**  
UI component emits data-attributes → CSS applies tokens → Browser renders.

---

## 5. Technical Structure (How It Works)

### SSR Render Phase

The Accordion component renders to static HTML:
```html
<div data-accordion="" data-collapsible="false" data-default-value="item-1">
  <div data-accordion-item="">
    <button data-accordion-trigger="" type="button">
      Section Title
    </button>
    <div data-accordion-content="">
      <div>Content goes here</div>
    </div>
  </div>
</div>
```

**Key contracts:**
- `data-accordion` marks root container
- `data-collapsible="true|false"` controls whether all items can be closed
- `data-default-value="id"` specifies initially open item
- `data-accordion-trigger` marks interactive button
- `data-accordion-content` marks collapsible region

### Runtime Hydration Phase

Shell Runtime JS:
1. Queries `[data-accordion]` elements
2. Reads `data-collapsible` and `data-default-value` attributes
3. Sets initial `data-state="open|closed"` on items
4. Attaches delegated click handler to `[data-accordion-trigger]`
5. Manages exclusive open behavior (closes siblings on trigger click)

### CSS Styling Phase

CSS selectors target data-attributes:
```css
[data-accordion-item][data-state="open"] [data-accordion-content] {
  grid-template-rows: 1fr; /* expand */
}

[data-accordion-trigger]::after {
  background-image: var(--accordion-icon-svg);
  transform: rotate(0deg);
}

[data-accordion-item][data-state="open"] [data-accordion-trigger]::after {
  transform: rotate(var(--accordion-icon-rotation-open));
}
```

**No classes. No inline styles. Only data-attributes.**

---

## 6. Execution Flow
```text
1. SSR Render (Server)
      Accordion component executes
      Composes primitives with data-attributes
      Emits static HTML

2. HTML Delivery (Network)
      Browser receives HTML
      Renders static structure (no interactivity yet)

3. Shell Runtime Hydration (Client)
      Runtime JS executes
      Reads data-accordion attributes
      Sets initial data-state based on default_value
      Attaches event delegation

4. User Interaction
      User clicks [data-accordion-trigger]
      Event delegation catches click
      Runtime toggles data-state on item
      CSS reacts to [data-state] change
      Browser animates content expansion
```

**Critical:** State lives in DOM (`data-state`), not in JS memory.  
This ensures SSR compatibility and simplifies debugging.

---

## 7. Canonical Use Cases

### FAQ Page
```rust
use rs_design::ui::Accordion;

rsx! {
    Accordion {
        default_value: "faq-1".to_string(),
        collapsible: true,
        
        AccordionItem {
            AccordionTrigger { "What is CanonRS?" }
            AccordionContent {
                p { "CanonRS is an enterprise design system..." }
            }
        }
        
        AccordionItem {
            AccordionTrigger { "How does SSR work?" }
            AccordionContent {
                p { "SSR renders HTML on the server..." }
            }
        }
    }
}
```

### Settings Panel (Non-Collapsible)
```rust
Accordion {
    default_value: "general".to_string(),
    collapsible: false, // Always one section open
    
    AccordionItem {
        AccordionTrigger { "General Settings" }
        AccordionContent { /* settings form */ }
    }
    
    AccordionItem {
        AccordionTrigger { "Privacy Settings" }
        AccordionContent { /* privacy form */ }
    }
}
```

### Documentation Navigation
```rust
Accordion {
    default_value: None, // All closed initially
    collapsible: true,
    
    AccordionItem {
        AccordionTrigger { "Getting Started" }
        AccordionContent { /* guide content */ }
    }
}
```

---

## 8. Anti-Patterns (PROHIBITED)

### ❌ Anti-Pattern 1: Imperative State Management
```rust
// WRONG — trying to manage state in component
let mut open_item = use_signal(|| "item-1");

Accordion {
    // This violates SSR-safety and CanonRS architecture
    on_change: move |item| open_item.set(item)
}
```

**Why it breaks:**
- State belongs in DOM via `data-state`
- Component layer has no business logic
- Breaks SSR hydration contract

**Correct approach:**  
Let Shell Runtime manage state via data-attributes.

---

### ❌ Anti-Pattern 2: Direct Browser API Usage
```rust
// WRONG — accessing window in UI component
#[component]
pub fn Accordion(...) -> Element {
    use_effect(move |_| {
        window().document().query_selector(...); // FORBIDDEN
    });
}
```

**Why it breaks:**
- UI components must be SSR-safe
- No `window()`, `document()`, or `web_sys` allowed
- Violates layer separation

**Correct approach:**  
Shell Runtime handles all browser APIs.

---

### ❌ Anti-Pattern 3: Inline Styles or Classes
```rust
// WRONG — applying classes or styles directly
rsx! {
    AccordionPrimitive {
        class: "bg-gray-100 rounded-lg", // FORBIDDEN
        style: "padding: 1rem", // FORBIDDEN
    }
}
```

**Why it breaks:**
- Primitives emit data-attributes only
- CSS layer owns all styling
- Breaks token system and theming

**Correct approach:**  
Emit `data-accordion` and let CSS handle styling.

---

### ❌ Anti-Pattern 4: Multiple Accordions Without Context
```rust
// WRONG — nesting accordions without semantic reason
Accordion {
    AccordionItem {
        AccordionTrigger { "Parent" }
        AccordionContent {
            Accordion { // Nested accordion — usually wrong
                AccordionItem { ... }
            }
        }
    }
}
```

**Why it breaks:**
- Cognitive overload
- Confusing navigation
- Violates enterprise UX patterns

**Correct approach:**  
Use flat structure or switch to Tree/Disclosure for nested navigation.

---

## 9. SSR, Hydration, and Runtime

### SSR Impact

**Server-Side:**
- Accordion renders complete HTML structure
- All `data-*` attributes present in initial HTML
- No JavaScript required for structure
- Initial state determined by `default_value` prop

**Benefits:**
- SEO-friendly (content visible to crawlers)
- Fast First Contentful Paint
- Works without JavaScript (graceful degradation)

**Constraints:**
- Cannot use browser APIs during SSR
- Cannot access `window`, `document`, `localStorage`
- Must emit pure HTML

---

### Hydration Process

1. **HTML Delivery:** Browser receives static HTML with `data-accordion` attributes
2. **CSS Application:** Browser applies `accordion.css` styles
3. **Runtime Load:** Shell Runtime JS executes
4. **State Initialization:** Runtime reads `data-default-value`, sets `data-state="open"` on matching item
5. **Event Delegation:** Runtime attaches single click handler to document for `[data-accordion-trigger]`
6. **Interactive:** Component is now fully interactive

**Hydration Contract:**
- Runtime never re-renders HTML
- Runtime only mutates `data-state` attribute
- CSS reacts to state changes

---

### Runtime Global Constraints

**AutoReload Behavior:**
- AutoReload during dev can break script order
- Shell Runtime must be inline in SSR (Canon Rule #103)
- External scripts may load out of order

**Mitigation:**
- Critical runtime JS inlined in `<head>`
- Non-critical behavior degrades gracefully
- Never depend on external script load timing

**Hot Reload:**
- Accordion preserves state across hot reloads
- `data-state` persists in DOM
- No state loss during development

---

## 10. Conformance Checklist

- [x] SSR-safe (no browser APIs in component)
- [x] No imperative JS (no `use_effect`, `window()`, `document()`)
- [x] Uses tokens (indirectly via CSS)
- [x] All tokens documented in section 4
- [x] Anti-patterns documented with explanations
- [x] Canon Rules cited in section 11
- [x] Execution flow documented
- [x] Use cases provided
- [x] Hydration contract explicit
- [x] Runtime constraints documented

---

## 11. Canon Rules Applied

### Canon Rules Applied

- **Canon Rule #102 — Runtime JS Is Shell Infrastructure**  
  Accordion delegates all browser interaction to Shell Runtime, never executing imperative JS in the component layer.

- **Canon Rule #103 — Critical Runtime JS Must Be Inline in SSR**  
  Accordion hydration depends on Shell Runtime being available immediately; inline runtime ensures no race conditions.

- **Canon Rule #104 — AutoReload Breaks Script Order Guarantees**  
  Accordion state persists in DOM (`data-state`) to survive AutoReload script re-execution during development.

- **Canon Rule #107 — Primitives Are SSR-Safe Structural Components**  
  Accordion composes SSR-safe primitives that emit only HTML and data-attributes, never browser-dependent logic.

- **Canon Rule #108 — UI Components Provide Ergonomic Composition**  
  Accordion exists in the UI layer to provide default behavior (`collapsible`, `default_value`) and reduce boilerplate in application code.

- **Canon Rule #109 — State Lives in DOM, Not Memory**  
  Accordion state is declared via `data-state` attribute, making it inspectable, debuggable, and SSR-compatible.

- **Canon Rule #110 — CSS Targets Data-Attributes, Never Classes**  
  Accordion styling uses `[data-accordion-*]` selectors exclusively, ensuring token-based theming and avoiding Tailwind/utility class pollution.

---

**End of Documentation**