Skip to content
Vincle

Loading…

    Server-side JSX renderer

    Your views in JSX.
    Your app in HTML.

    Compose typed, async components in your existing server. Start with an HTML response, then let slower parts of the page arrive when they are ready.

    Terminal window
    npm install @vincle/core
    From JSX to HTMLTypeScript
    hello.tsx
    import { renderToString } from "@vincle/core";
    function App({ name }: { name: string }) {
    return <h1>Hello, {name}!</h1>;
    }
    const page = <App name="world" />;
    const html = await renderToString(page);
    <h1>Hello, world!</h1>

    The rendered output is a plain HTML string.

    Supported runtimes
    • Node.js 22+
    • Bun
    • Deno
    • Cloudflare Workers

    Start with one view.
    Grow with your page.#

    Keep your server and routing. Choose how much rendering behavior each page needs.

    Defer the slow parts

    Add @vincle/flow to send the page shell first, then deliver deferred HTML fragments.

    Stream a fragment

    The page can arrive before the results.#

    Keep the heading visible while an async component loads. With flow, a fallback fills the space until its HTML is ready.

    Choose how it is delivered: natively, or through an HTMX or Turbo adapter.

    Follow the complete example
    results-page.tsx
    import { Defer, renderToStream } from "@vincle/flow";
    import { NativeAdapter } from "@vincle/flow/adapters";
    async function findResults() {
    return [{ title: "Getting started", href: "/guide/getting-started/installation" }];
    }
    async function Results() {
    const items = await findResults();
    return (
    <ul>
    {items.map((item) => (
    <li>
    <a href={item.href}>{item.title}</a>
    </li>
    ))}
    </ul>
    );
    }
    function Page() {
    return (
    <main>
    <h1>Search results</h1>
    <Defer fallback={<p>Loading results…</p>}>
    <Results />
    </Defer>
    </main>
    );
    }
    const stream = renderToStream(() => <Page />, NativeAdapter);

    The Results component stays the same. The page opts into deferred rendering.

    Built into the renderer.#

    Typed views, predictable rendering, and explicit HTML boundaries.

    View source on GitHub