@barefootjs/cli 0.1.0

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 (45) hide show
  1. package/dist/docs/core/README.md +84 -0
  2. package/dist/docs/core/adapters/adapter-architecture.md +262 -0
  3. package/dist/docs/core/adapters/csr.md +78 -0
  4. package/dist/docs/core/adapters/custom-adapter.md +357 -0
  5. package/dist/docs/core/adapters/go-template-adapter.md +269 -0
  6. package/dist/docs/core/adapters/hono-adapter.md +199 -0
  7. package/dist/docs/core/adapters.md +37 -0
  8. package/dist/docs/core/advanced/code-splitting.md +142 -0
  9. package/dist/docs/core/advanced/compiler-internals.md +331 -0
  10. package/dist/docs/core/advanced/error-codes.md +261 -0
  11. package/dist/docs/core/advanced/ir-schema.md +65 -0
  12. package/dist/docs/core/advanced/performance.md +115 -0
  13. package/dist/docs/core/advanced/xyflow-browser-bundle.md +69 -0
  14. package/dist/docs/core/advanced.md +11 -0
  15. package/dist/docs/core/components/children-slots.md +150 -0
  16. package/dist/docs/core/components/component-authoring.md +207 -0
  17. package/dist/docs/core/components/context-api.md +236 -0
  18. package/dist/docs/core/components/portals.md +192 -0
  19. package/dist/docs/core/components/props-type-safety.md +97 -0
  20. package/dist/docs/core/components/styling.md +37 -0
  21. package/dist/docs/core/components.md +19 -0
  22. package/dist/docs/core/core-concepts/ai-native.md +83 -0
  23. package/dist/docs/core/core-concepts/backend-freedom.md +31 -0
  24. package/dist/docs/core/core-concepts/how-it-works.md +147 -0
  25. package/dist/docs/core/core-concepts/mpa-style.md +36 -0
  26. package/dist/docs/core/core-concepts/reactivity.md +35 -0
  27. package/dist/docs/core/core-concepts.md +28 -0
  28. package/dist/docs/core/introduction.md +87 -0
  29. package/dist/docs/core/llms.txt +53 -0
  30. package/dist/docs/core/quick-start.mdx +160 -0
  31. package/dist/docs/core/reactivity/create-effect.md +125 -0
  32. package/dist/docs/core/reactivity/create-memo.md +91 -0
  33. package/dist/docs/core/reactivity/create-signal.md +128 -0
  34. package/dist/docs/core/reactivity/on-cleanup.md +67 -0
  35. package/dist/docs/core/reactivity/on-mount.md +70 -0
  36. package/dist/docs/core/reactivity/props-reactivity.md +91 -0
  37. package/dist/docs/core/reactivity/untrack.md +69 -0
  38. package/dist/docs/core/reactivity.md +28 -0
  39. package/dist/docs/core/rendering/client-directive.md +82 -0
  40. package/dist/docs/core/rendering/fragment.md +43 -0
  41. package/dist/docs/core/rendering/jsx-compatibility.md +163 -0
  42. package/dist/docs/core/rendering.md +14 -0
  43. package/dist/index.js +25490 -0
  44. package/dist/tokens.json +74 -0
  45. package/package.json +37 -0
@@ -0,0 +1,91 @@
1
+ ---
2
+ title: createMemo
3
+ description: Creates a cached derived value that recomputes only when its dependencies change.
4
+ ---
5
+
6
+ # createMemo
7
+
8
+ Creates a cached derived value. Recomputes only when its dependencies change.
9
+
10
+ ```ts
11
+ import { createMemo } from '@barefootjs/client'
12
+
13
+ const getter = createMemo<T>(fn: () => T): Memo<T>
14
+ ```
15
+
16
+ Returns a read-only getter typed as `Memo<T>` (alias for `Reactive<() => T>`).
17
+
18
+
19
+ ## Basic Usage
20
+
21
+ ```tsx
22
+ const [count, setCount] = createSignal(2)
23
+ const doubled = createMemo(() => count() * 2)
24
+
25
+ doubled() // 4
26
+ setCount(5)
27
+ doubled() // 10
28
+ ```
29
+
30
+
31
+ ## When to Use
32
+
33
+ Use `createMemo` when you have a **derived value** that:
34
+
35
+ - Depends on one or more signals
36
+ - Is used in multiple places (avoids recalculating)
37
+ - Involves a non-trivial computation
38
+
39
+ ```tsx
40
+ const [todos, setTodos] = createSignal<Todo[]>([])
41
+ const [filter, setFilter] = createSignal<'all' | 'active' | 'done'>('all')
42
+
43
+ const filteredTodos = createMemo(() => {
44
+ const list = todos()
45
+ switch (filter()) {
46
+ case 'active': return list.filter(t => !t.done)
47
+ case 'done': return list.filter(t => t.done)
48
+ default: return list
49
+ }
50
+ })
51
+
52
+ // Used in multiple effects and JSX expressions
53
+ createEffect(() => console.log(filteredTodos().length))
54
+ ```
55
+
56
+ For simple expressions used once, a memo is unnecessary:
57
+
58
+ ```tsx
59
+ // No memo needed
60
+ <p>{count() * 2}</p>
61
+ ```
62
+
63
+
64
+ ## Chaining Memos
65
+
66
+ Memos can depend on other memos:
67
+
68
+ ```tsx
69
+ const [count, setCount] = createSignal(1)
70
+ const doubled = createMemo(() => count() * 2)
71
+ const quadrupled = createMemo(() => doubled() * 2)
72
+
73
+ createEffect(() => {
74
+ console.log(quadrupled()) // 4
75
+ })
76
+
77
+ setCount(3) // Logs: 12 (3 → 6 → 12)
78
+ ```
79
+
80
+ Each memo in the chain only recomputes when its direct dependencies change.
81
+
82
+
83
+ ## Memo vs Effect
84
+
85
+ | | `createMemo` | `createEffect` |
86
+ |---|---|---|
87
+ | Returns a value | Yes (getter function) | No |
88
+ | Triggers other effects | Yes (acts as a signal) | No |
89
+ | Used for | Derived data | Side effects (DOM, fetch, logging) |
90
+
91
+ Internally, `createMemo` is sugar over `createSignal` + `createEffect`. A memo behaves like a read-only signal to the rest of the reactive system.
@@ -0,0 +1,128 @@
1
+ ---
2
+ title: createSignal
3
+ description: Creates a reactive getter/setter pair for managing state.
4
+ ---
5
+
6
+ # createSignal
7
+
8
+ Creates a reactive value. Returns a getter/setter pair.
9
+
10
+ ```ts
11
+ import { createSignal } from '@barefootjs/client'
12
+
13
+ const [getter, setter] = createSignal<T>(initialValue: T)
14
+ ```
15
+
16
+ **Type:**
17
+
18
+ ```tsx
19
+ type Reactive<T> = T & { readonly __reactive: true }
20
+
21
+ type Signal<T> = [
22
+ Reactive<() => T>, // getter (carries Reactive brand)
23
+ (valueOrFn: T | ((prev: T) => T)) => void // setter
24
+ ]
25
+ ```
26
+
27
+ The getter carries the `Reactive<T>` phantom brand — a compile-time marker for reactive expression detection. No runtime cost.
28
+
29
+
30
+ ## Basic Usage
31
+
32
+ ```tsx
33
+ const [count, setCount] = createSignal(0)
34
+
35
+ // Read — call the getter
36
+ count() // 0
37
+
38
+ // Write — pass a value
39
+ setCount(5)
40
+ count() // 5
41
+
42
+ // Write — pass an updater function
43
+ setCount(n => n + 1)
44
+ count() // 6
45
+ ```
46
+
47
+ The getter is a **function call** — `count()`, not `count`. This is how the reactivity system tracks dependencies.
48
+
49
+
50
+ ## Equality Check
51
+
52
+ The setter uses `Object.is` to compare values. Identical values do not trigger effects:
53
+
54
+ ```tsx
55
+ const [name, setName] = createSignal('Alice')
56
+ setName('Alice') // No effect runs — value unchanged
57
+ ```
58
+
59
+ For objects and arrays, this means you need a new reference to trigger an update:
60
+
61
+ ```tsx
62
+ const [todos, setTodos] = createSignal([{ text: 'Buy milk' }])
63
+
64
+ // ❌ Mutating the same array — no update
65
+ const list = todos()
66
+ list.push({ text: 'Walk dog' })
67
+ setTodos(list) // Same reference, Object.is returns true
68
+
69
+ // ✅ New array — triggers update
70
+ setTodos([...todos(), { text: 'Walk dog' }])
71
+ ```
72
+
73
+
74
+ ## With Effects
75
+
76
+ Reading a signal inside an effect subscribes the effect to changes:
77
+
78
+ ```tsx
79
+ const [count, setCount] = createSignal(0)
80
+
81
+ createEffect(() => {
82
+ console.log('Count is:', count()) // Runs whenever count changes
83
+ })
84
+
85
+ setCount(1) // Logs: "Count is: 1"
86
+ setCount(2) // Logs: "Count is: 2"
87
+ ```
88
+
89
+
90
+ ## With JSX
91
+
92
+ Signal getters in JSX expressions create fine-grained DOM updates:
93
+
94
+ ```tsx
95
+ "use client"
96
+ import { createSignal } from '@barefootjs/client'
97
+
98
+ export function Counter() {
99
+ const [count, setCount] = createSignal(0)
100
+
101
+ return (
102
+ <div>
103
+ <p>{count()}</p>
104
+ <button onClick={() => setCount(n => n + 1)}>+1</button>
105
+ </div>
106
+ )
107
+ }
108
+ ```
109
+
110
+ The compiler generates an effect that updates only the `<p>` text content when `count` changes — the rest of the DOM is untouched.
111
+
112
+
113
+ ## Type Inference
114
+
115
+ Type is inferred from the initial value:
116
+
117
+ ```tsx
118
+ const [count, setCount] = createSignal(0) // Signal<number>
119
+ const [name, setName] = createSignal('Alice') // Signal<string>
120
+ const [visible, setVisible] = createSignal(false) // Signal<boolean>
121
+ ```
122
+
123
+ For union types or complex types, specify the type parameter:
124
+
125
+ ```tsx
126
+ const [user, setUser] = createSignal<User | null>(null)
127
+ const [filter, setFilter] = createSignal<'all' | 'active' | 'done'>('all')
128
+ ```
@@ -0,0 +1,67 @@
1
+ ---
2
+ title: onCleanup
3
+ description: Registers a cleanup function that runs when the owning effect re-runs or the component is destroyed.
4
+ ---
5
+
6
+ # onCleanup
7
+
8
+ Registers a cleanup function. Called when the owning effect re-runs or the component is destroyed.
9
+
10
+ ```tsx
11
+ import { onCleanup } from '@barefootjs/client'
12
+
13
+ onCleanup(fn: () => void): void
14
+ ```
15
+
16
+
17
+ ## Basic Usage
18
+
19
+ ```tsx
20
+ createEffect(() => {
21
+ const timer = setInterval(() => console.log('tick'), 1000)
22
+ onCleanup(() => clearInterval(timer))
23
+ })
24
+ ```
25
+
26
+ On re-run, the cleanup function runs first, clearing the previous interval before creating a new one.
27
+
28
+
29
+ ## Multiple Cleanups
30
+
31
+ `onCleanup` can be called multiple times. Cleanups execute in reverse order (last registered, first called):
32
+
33
+ ```tsx
34
+ createEffect(() => {
35
+ const controller = new AbortController()
36
+ onCleanup(() => controller.abort())
37
+
38
+ const listener = () => setHash(window.location.hash)
39
+ window.addEventListener('hashchange', listener)
40
+ onCleanup(() => window.removeEventListener('hashchange', listener))
41
+ })
42
+ // On cleanup: removeEventListener runs first, then abort
43
+ ```
44
+
45
+
46
+ ## With `onMount`
47
+
48
+ `onCleanup` works inside `onMount` for one-time setup/teardown:
49
+
50
+ ```tsx
51
+ onMount(() => {
52
+ const handleResize = () => setWidth(window.innerWidth)
53
+ window.addEventListener('resize', handleResize)
54
+ onCleanup(() => window.removeEventListener('resize', handleResize))
55
+ })
56
+ ```
57
+
58
+
59
+ ## Where It Works
60
+
61
+ `onCleanup` must be called within a reactive context:
62
+
63
+ - Inside `createEffect`
64
+ - Inside `onMount`
65
+ - During component initialization
66
+
67
+ Calling it outside these contexts has no effect.
@@ -0,0 +1,70 @@
1
+ ---
2
+ title: onMount
3
+ description: Runs a callback once when the component initializes, without tracking signal dependencies.
4
+ ---
5
+
6
+ # onMount
7
+
8
+ Runs once when the component initializes. Signal accesses inside are **not** tracked.
9
+
10
+ ```tsx
11
+ import { onMount } from '@barefootjs/client'
12
+
13
+ onMount(fn: () => void): void
14
+ ```
15
+
16
+
17
+ ## Basic Usage
18
+
19
+ ```tsx
20
+ onMount(() => {
21
+ console.log('Component initialized')
22
+ })
23
+ ```
24
+
25
+ Unlike `createEffect`, this function never re-runs. It executes once at initialization time.
26
+
27
+
28
+ ## Common Patterns
29
+
30
+ ### Browser state
31
+
32
+ ```tsx
33
+ onMount(() => {
34
+ const hash = window.location.hash
35
+ setFilter(hash === '#/active' ? 'active' : 'all')
36
+ })
37
+ ```
38
+
39
+ ### Event listeners
40
+
41
+ ```tsx
42
+ onMount(() => {
43
+ const handleHashChange = () => setFilter(getFilterFromHash())
44
+ window.addEventListener('hashchange', handleHashChange)
45
+ onCleanup(() => window.removeEventListener('hashchange', handleHashChange))
46
+ })
47
+ ```
48
+
49
+ ### Focus
50
+
51
+ ```tsx
52
+ onMount(() => {
53
+ inputElement.focus()
54
+ })
55
+ ```
56
+
57
+
58
+ ## How It Works
59
+
60
+ `onMount` is equivalent to `createEffect(() => untrack(fn))`. The function runs inside an effect context (so `onCleanup` works), but `untrack` prevents dependency tracking.
61
+
62
+
63
+ ## `onMount` vs `createEffect`
64
+
65
+ | | `onMount` | `createEffect` |
66
+ |---|---|---|
67
+ | Runs on init | Yes | Yes |
68
+ | Re-runs on signal change | No | Yes |
69
+ | Tracks dependencies | No | Yes |
70
+ | Supports `onCleanup` | Yes | Yes |
@@ -0,0 +1,91 @@
1
+ ---
2
+ title: Props Reactivity
3
+ description: How prop access patterns determine whether reactive updates propagate in BarefootJS components.
4
+ ---
5
+
6
+ # Props Reactivity
7
+
8
+ **How you access props determines whether updates propagate.** The compiler wraps dynamic prop expressions in getters.
9
+
10
+
11
+ ## Direct Access — Reactive
12
+
13
+ `props.xxx` maintains reactivity. Each access calls the underlying getter:
14
+
15
+ ```tsx
16
+ function Display(props: { value: number }) {
17
+ createEffect(() => {
18
+ console.log(props.value) // Re-runs when parent updates value
19
+ })
20
+ return <span>{props.value}</span>
21
+ }
22
+ ```
23
+
24
+
25
+ ## Destructuring — Captures Once
26
+
27
+ Destructuring calls the getter once and stores the result. The value does not update:
28
+
29
+ ```tsx
30
+ function Display({ value }: { value: number }) {
31
+ createEffect(() => {
32
+ console.log(value) // Stale — captured at component init
33
+ })
34
+ return <span>{value}</span>
35
+ }
36
+ ```
37
+
38
+ The compiler emits `BF043` when it detects props destructuring in a client component:
39
+
40
+ ```
41
+ warning[BF043]: Props destructuring breaks reactivity
42
+
43
+ --> src/components/Display.tsx:1:18
44
+ |
45
+ 1 | function Display({ value }: { value: number }) {
46
+ | ^^^^^^^^^
47
+ |
48
+ = help: Access props via `props.value` to maintain reactivity
49
+ ```
50
+
51
+ Suppress with `@bf-ignore` when capturing intentionally (e.g., initial values):
52
+
53
+ ```tsx
54
+ // @bf-ignore props-destructuring
55
+ function Counter({ initial }: { initial: number }) {
56
+ const [count, setCount] = createSignal(initial)
57
+ return <button onClick={() => setCount(n => n + 1)}>{count()}</button>
58
+ }
59
+ ```
60
+
61
+
62
+ ## When Destructuring Is Safe
63
+
64
+ Destructuring is safe for **initial values** of local state and for values that never change (`id`, static labels).
65
+
66
+
67
+ ## Summary
68
+
69
+ | Pattern | Reactive? | Use when |
70
+ |---------|-----------|----------|
71
+ | `props.value` | Yes | You need live updates from parent |
72
+ | `const { value } = props` | No | Value is used once (e.g., initial state) |
73
+ | `createSignal(props.value)` | `props.value` is reactive, signal is independent | Creating local state from a prop |
74
+
75
+
76
+ ## How It Works
77
+
78
+ The compiler transforms dynamic prop expressions into getters:
79
+
80
+ ```tsx
81
+ // Parent
82
+ <Child value={count()} />
83
+
84
+ // Compiled props object
85
+ { get value() { return count() } }
86
+ ```
87
+
88
+ - `props.value` → calls getter → calls `count()` → dependency tracked
89
+ - `const { value } = props` → calls getter once → stores the number → no further tracking
90
+
91
+ This is the same model as SolidJS. If you are coming from React, this is the key behavioral difference.
@@ -0,0 +1,69 @@
1
+ ---
2
+ title: untrack
3
+ description: Executes a function without tracking signal dependencies in the current reactive context.
4
+ ---
5
+
6
+ # untrack
7
+
8
+ Executes a function without tracking signal dependencies.
9
+
10
+ ```tsx
11
+ import { untrack } from '@barefootjs/client'
12
+
13
+ untrack<T>(fn: () => T): T
14
+ ```
15
+
16
+ Returns the value produced by `fn`.
17
+
18
+
19
+ ## Basic Usage
20
+
21
+ ```tsx
22
+ const [count, setCount] = createSignal(0)
23
+ const [name, setName] = createSignal('Alice')
24
+
25
+ createEffect(() => {
26
+ // count() IS tracked — this effect re-runs when count changes
27
+ console.log('count:', count())
28
+
29
+ // name() is NOT tracked — changing name alone won't trigger this effect
30
+ console.log('name:', untrack(() => name()))
31
+ })
32
+
33
+ setCount(1) // Effect re-runs
34
+ setName('Bob') // Effect does NOT re-run
35
+ ```
36
+
37
+
38
+ ## When to Use
39
+
40
+ ### Read without subscribing
41
+
42
+ ```tsx
43
+ createEffect(() => {
44
+ // Re-run only when items change, not when sortOrder changes
45
+ const sorted = [...items()].sort(untrack(() => sortOrder()) === 'asc' ? compare : reverseCompare)
46
+ setDisplayList(sorted)
47
+ })
48
+ ```
49
+
50
+ ### Log without dependencies
51
+
52
+ ```tsx
53
+ createEffect(() => {
54
+ const value = computedResult()
55
+ console.log('Updated at:', untrack(() => new Date().toISOString()))
56
+ })
57
+ ```
58
+
59
+ ### Break circular dependencies
60
+
61
+ `untrack` breaks cycles where two signals depend on each other through effects:
62
+
63
+ ```tsx
64
+ createEffect(() => {
65
+ const a = signalA()
66
+ const b = untrack(() => signalB()) // Read B without tracking
67
+ setResult(a + b)
68
+ })
69
+ ```
@@ -0,0 +1,28 @@
1
+ ---
2
+ title: Reactivity
3
+ description: Fine-grained reactive primitives inspired by SolidJS, including signals, effects, memos, and lifecycle hooks.
4
+ ---
5
+
6
+ # Reactivity
7
+
8
+ All reactive primitives are imported from `@barefootjs/client`:
9
+
10
+ ```tsx
11
+ "use client"
12
+ import { createSignal, createEffect, createMemo, onMount, onCleanup, untrack } from '@barefootjs/client'
13
+ ```
14
+
15
+ ## API Reference
16
+
17
+ | API | Description |
18
+ |-----|-------------|
19
+ | [`createSignal`](./reactivity/create-signal.md) | Create a reactive value |
20
+ | [`createEffect`](./reactivity/create-effect.md) | Run side effects when dependencies change |
21
+ | [`createMemo`](./reactivity/create-memo.md) | Create a cached derived value |
22
+ | [`onMount`](./reactivity/on-mount.md) | Run once on component initialization |
23
+ | [`onCleanup`](./reactivity/on-cleanup.md) | Register cleanup for effects and lifecycle |
24
+ | [`untrack`](./reactivity/untrack.md) | Read signals without tracking dependencies |
25
+
26
+ ## Guides
27
+
28
+ - [Props Reactivity](./reactivity/props-reactivity.md) — How props stay reactive, and when destructuring breaks it
@@ -0,0 +1,82 @@
1
+ ---
2
+ title: /* @client */ Directive
3
+ description: Mark JSX expressions for client-only evaluation when the compiler cannot translate them to server templates.
4
+ ---
5
+
6
+ # /* @client */ Directive
7
+
8
+ Marks a JSX expression for **client-only evaluation**. The server renders a placeholder; the browser evaluates the expression at runtime.
9
+
10
+ ```tsx
11
+ {/* @client */ expression}
12
+ ```
13
+
14
+
15
+ ## When to Use
16
+
17
+ The compiler emits `BF021` for expressions it cannot translate to a marked template. `/* @client */` resolves the error by opting into client-only evaluation.
18
+
19
+ ```
20
+ error[BF021]: Expression cannot be compiled to marked template
21
+
22
+ --> src/components/Dashboard.tsx:15:10
23
+ |
24
+ 15 | {items().reduce((sum, x) => sum + x.price, 0)}
25
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
26
+ |
27
+ = help: Add /* @client */ to evaluate this expression on the client only
28
+ ```
29
+
30
+ See [JSX Compatibility — Limitations](./jsx-compatibility.md#limitations) for the full list of unsupported patterns.
31
+
32
+
33
+ ## How It Works
34
+
35
+ The compiler skips template generation for the expression. The server outputs a comment marker; the client JS evaluates it:
36
+
37
+ **Server output:**
38
+
39
+ ```html
40
+ <!--bf-client:s2--><!--/-->
41
+ ```
42
+
43
+ **Client JS:**
44
+
45
+ ```js
46
+ // @client: s2
47
+ createEffect(() => {
48
+ updateClientMarker(__scope, 's2', todos().filter(t => !t.done).length)
49
+ })
50
+ ```
51
+
52
+
53
+ ## Examples
54
+
55
+ ### Unsupported patterns
56
+
57
+ ```tsx
58
+ // Nested higher-order methods
59
+ {/* @client */ items().filter(x => x.tags().filter(t => t.active).length > 0)}
60
+
61
+ // Unsupported array methods
62
+ {/* @client */ items().reduce((sum, x) => sum + x.price, 0)}
63
+ ```
64
+
65
+ ### Explicit client-only evaluation
66
+
67
+ Even for patterns the compiler supports, you can use `/* @client */` to skip server evaluation. The [TodoApp example](https://github.com/piconic-ai/barefootjs/blob/main/integrations/shared/components/TodoApp.tsx) uses this approach:
68
+
69
+ ```tsx
70
+ // These expressions CAN compile without @client, but the developer
71
+ // chose client-only evaluation here
72
+ checked={/* @client */ todos().every(t => t.done)}
73
+
74
+ <strong>{/* @client */ todos().filter(t => !t.done).length}</strong>
75
+ ```
76
+
77
+ Compare with the [TodoAppSSR version](https://github.com/piconic-ai/barefootjs/blob/main/integrations/shared/components/TodoAppSSR.tsx), which omits `/* @client */` and lets the compiler generate marked template equivalents for the same expressions.
78
+
79
+
80
+ ## Trade-off
81
+
82
+ `/* @client */` means **no server-rendered content** for the expression — users see a placeholder until client JS loads. Omit the directive when the compiler can generate a template equivalent to get server-rendered initial values.
@@ -0,0 +1,43 @@
1
+ ---
2
+ title: Fragment
3
+ description: Using fragments to render children without a wrapper element, including transparent fragment behavior.
4
+ ---
5
+
6
+ # Fragment
7
+
8
+ Fragments (`<>...</>`) are supported. They render children without a wrapper element.
9
+
10
+ ```tsx
11
+ <>
12
+ <h1>Title</h1>
13
+ <p>Description</p>
14
+ </>
15
+ ```
16
+
17
+
18
+ ## Transparent Fragments
19
+
20
+ A fragment that passes through `children` is treated as transparent — the compiler skips it and processes the children directly:
21
+
22
+ ```tsx
23
+ <>{children}</>
24
+ <>{props.children}</>
25
+ ```
26
+
27
+ No extra hydration markers are generated for transparent fragments.
28
+
29
+
30
+ ## Fragments and Hydration
31
+
32
+ Fragments don't produce a DOM node. For conditional fragments, the compiler uses HTML comment markers as boundaries:
33
+
34
+ ```html
35
+ <!--bf-cond-start:s0-->
36
+ <h1>Title</h1>
37
+ <p>Description</p>
38
+ <!--bf-cond-end:s0-->
39
+ ```
40
+
41
+ The client runtime uses these comment markers to locate and swap the fragment content when the condition changes.
42
+
43
+ For component roots that return a fragment, each direct child element is marked with `bf-s` so the runtime can find them during hydration.