unite()

unite() reaches a reactive variable declared in another file.

No imports, no prop drilling, no context provider, no store boilerplate.

Every let in a file is already published under a namespace taken from that file's path, and unite() names the one you want.

source
<!-- pages/demo.html -->
<script>
let counter = 5
let theme = 'dark'
</script>

<p>Counter: {counter}</p>
source
<!-- pages/other.html -->
<script>
let counter = unite(demo.counter)  // Gets counter from demo.html
let theme = unite(demo.theme)      // Gets theme from demo.html
</script>

<button onclick="counter++">Increment</button>
<p>Theme: {theme}</p>

There is one variable, not a copy: writing to counter in either file updates both.

A consumer's write reaches whatever backs the original too, so uniting a storage() or url() variable still persists it.

Namespaces

The namespace is the file's path, without the extension:

File Namespace Reached as
pages/demo.html demo unite(demo.counter)
pages/demo/index.html demo unite(demo.counter)
pages/admin/dashboard.html admin.dashboard unite(admin.dashboard.theme)
components/Button.html Button unite(Button.size)
components/ui/Modal.html ui.Modal unite(ui.Modal.settings)

A Worked Example

A theme owned by the layout, persisted to localStorage, and toggled from a component that knows nothing about the layout:

source
<!-- pages/layout.html -->
<script>
let theme = storage('light')
</script>

<div class="{theme}">
  <slot />
</div>
source
<!-- components/ThemeToggle.html -->
<script>
let theme = unite(layout.theme)
</script>

<button onclick="theme = theme === 'light' ? 'dark' : 'light'">
  Toggle Theme
</button>

The toggle's write lands in the layout's variable, the layout re-renders, and storage() saves it.

Neither file imports the other.

A united value outlives its declaring component: a page that re-mounts adopts the live value instead of resetting it. A variable nobody unites is ordinary local state and re-initialises as usual.

Type Safety

A Vite plugin generates namespace declarations, so unite() autocompletes and type-checks:

source
// vite.config.ts
import { namespaceCodegenPlugin } from 'jafjs/vite'

export default defineConfig({
  plugins: [
    namespaceCodegenPlugin()  // Generates src/generated/namespaces.d.ts
  ]
})

There is no provide() / inject() in JAF. Share across files with unite(), or pass props down. If you are writing a library and want its variable names kept out of the app's namespaces, call unite.set("my-lib").