Lit is the default adapter. If you don't pass --adapter when creating a project, you get Lit.
pnpm create @beatzball/litro my-app --adapter lit
The client entry (app.ts) must import hydration support first:
// app.ts
import '@lit-labs/ssr-client/lit-element-hydrate-support.js'; // MUST be first
import '@beatzball/litro/runtime/LitroOutlet.js';
import '@beatzball/litro/runtime/LitroLink.js';
import { routes } from './routes.generated.js';
const outlet = document.querySelector('litro-outlet');
if (outlet) outlet.routes = routes;
Pages are LitElement subclasses exported as the default export. The filename determines the route.
// pages/index.ts
import { html } from 'lit';
import { customElement } from 'lit/decorators.js';
import { LitroPage } from '@beatzball/litro/runtime';
import { definePageData } from '@beatzball/litro';
export const pageData = definePageData(async (event) => {
return { message: 'Hello from the server!' };
});
@customElement('page-home')
export class HomePage extends LitroPage {
override async fetchData() {
const res = await fetch('/api/hello');
return res.json();
}
render() {
const data = this.serverData as { message: string } | null;
return html`<h1>${data?.message ?? 'Loading...'}</h1>`;
}
}
export default HomePage;
Lit SSR uses @lit-labs/ssr to render components as Declarative Shadow DOM (DSD). The server streams <template shadowrootmode="open"> elements that the browser parses natively. On the client, @lit-labs/ssr-client hydrates the existing shadow trees — attaching event listeners without re-rendering.
The HTML output includes a DSD polyfill inline script for browsers that don't yet support shadowrootmode.
Lit components use Shadow DOM for style encapsulation. Styles defined via static styles or css tagged templates are scoped to the component — they don't leak out and global CSS doesn't leak in.
import { css } from 'lit';
@customElement('page-about')
export class AboutPage extends LitElement {
static styles = css`
:host { display: block; padding: 2rem; }
h1 { color: #1a1a2e; }
`;
// ...
}
The Lit adapter configures Nitro to:
@lit-labs/ssr and @lit-labs/ssr-client for edge deployment compatibilityexperimentalDecorators: true for esbuild (Lit's decorators use the legacy TC39 proposal)These are handled automatically when using --adapter lit.
::part() for cross-boundary styling.static override properties = { ... } instead of @property() on plain fields to avoid TC39 Stage 3 decorator issues with Vite/esbuild. See the Decisions log for details.window, document, or localStorage at module evaluation time. Guard browser-only code in lifecycle methods.