Repository navigation
docs: document SSR / Hydration guidelines for Meta-Frameworks (TanStack Start, Remix, Nuxt) #498
Description
Proposed Documentation Updates
Note this is related to #500
Part 1: Redirecting the Existing FAQ Entry
The current FAQ entry will be made brief and direct readers straight to the comprehensive integration blueprint to ensure a clean navigation experience.
Target File: site/docs/faq.md
### Can I use AgnosticUI with SSR / SSG meta-frameworks?
Yes, but because AgnosticUI leverages highly optimized Lit-based Web Components, their browser-native lifecycle requires consideration inside server-rendered environments to prevent hydration errors.
For concrete setup guides and code blueprints covering TanStack Start, Remix, and Nuxt, see our dedicated [SSR & Meta-Frameworks Integration Guide](/docs/ssr.html).Part 2: Documentation Tree Hierarchy Placement
The new guide will live directly beneath the existing installation sub-sections for visibility.
Target Path: site/docs/ssr.md
Sidebar Navigation
├── Quick Start
│ ├── Installation
│ │ ├── ...
│ │ └── Framework Support
│ │ └── SSR & Meta-Frameworks (Add New Route Link Here)
Part 3: Dedicated SSR Guide Content
This copy replaces the initial draft with clean layout snippets and incorporates a dedicated section on value tracking and controlled states within isolated environments.
Target File: site/docs/ssr.md
# Server-Side Rendering (SSR) & Meta-Frameworks
Using AgnosticUI within server-rendered frameworks requires client-only isolation to prevent structural hydration mismatches caused by browser-native Lit Web Components initializing before hydration completes.
## The Solution: Client-Only Isolation
Isolate components to initialize exclusively on the client side after the browser mounts. Refer to the framework-specific blocks below to safely handle boundaries:
### 🚀 TanStack Start
Wrap your AgnosticUI components using TanStack's built-in `<ClientOnly>` component, providing a lightweight skeleton placeholder as a fallback:
```tsx
import { ClientOnly } from "@tanstack/react-router";
import { ReactSelect } from "./components/ag/Select/react/ReactSelect";
export default function MyComponent() {
return (
<ClientOnly fallback={<div className="animate-pulse bg-slate-200 h-9 rounded" />}>
<ReactSelect label="Options" name="my-select">
<option value="1">Option 1</option>
</ReactSelect>
</ClientOnly>
);
}💿 Remix / React Router v7
Use the community standard <ClientOnly> wrapper from remix-utils/client-only:
import { ClientOnly } from "remix-utils/client-only";
import { ReactSelect } from "./components/ag/Select/react/ReactSelect";
export default function MyComponent() {
return (
<ClientOnly fallback={<div>Loading...</div>}>
{() => (
<ReactSelect label="Options" name="my-select">
<option value="1">Option 1</option>
</ReactSelect>
)}
</ClientOnly>
);
}🟢 Nuxt (Vue 3)
Vue and Nuxt feature native support for client-side isolation using the built-in <ClientOnly> tag:
<template>
<ClientOnly>
<VueSelect label="Options" name="my-select">
<option value="1">Option 1</option>
</VueSelect>
<template #fallback>
<div>Loading...</div>
</template>
</ClientOnly>
</template>Controlled State & Value Management in ReactSelect
Because ReactSelect compiles down to a custom Web Component container generated by @lit/react, it does not feature a standard React-controlled value property on its wrapper.
If you are piping external route query parameters or state variables directly down into the selector dropdown, you must manage selections declaratively via the child <option> tags using React's native selected property inside your <ClientOnly> wrapper.
<ClientOnly fallback={<div className="h-[38px] bg-slate-100 animate-pulse rounded" />}>
<ReactSelect
label="Filter Categories"
labelHidden={true}
name="categoryFilter"
onChange={(e: any) => handleFilterChange(e.detail.value)}
>
<option value="" selected={currentFilter === ""}>
All Categories
</option>
{categories.map((cat) => (
<option
key={cat.id}
value={cat.name}
selected={currentFilter === cat.name}
>
{cat.name}
</option>
))}
</ReactSelect>
</ClientOnly>Best Practices for Your Project
- SPAs & Dashboards: If your application sits behind an authentication wall or acts as a Single Page App dashboard where SEO is not a priority, you can often disable SSR globally or per-route within your framework config to bypass hydration guards entirely.
- Public Pages & SEO: For high-traffic, public-facing landing pages where search engine indexing is critical, we recommend utilizing native semantic HTML elements for basic inputs (buttons, text fields) and reserving AgnosticUI for complex interactive components on the page.
Activity