Guides

Server and Client Components

Keep data access on the server while adding reusable UI and interactive controls.

Combine server-rendered UI with interactive Client Components without moving data access into the browser. The example pairs a greeting component with a counter. It shows where each kind of component belongs.

Choose a component for the task

TaskUse
Read services and render dataA Page or EFFRONT.Component
Handle clicks, input, or local stateA Client Component
Submit data to the serverA Server Function

Keep data access on the server. Add Client Components only where users interact with the page.

Reuse server-rendered UI

In src/entry.effront.tsx from Routes, define Welcome. Then replace HomePage:

// src/entry.effront.tsx: add before HomePage.
const Welcome = EFFRONT.Component.make({
  render: ({ name }: { readonly name: string }) => Effect.succeed(<p>Hello, {name}.</p>),
});

// Replace HomePage.
const HomePage = EFFRONT.Page.make({
  render: () => Effect.succeed(<Welcome name="Ada" />),
});

Open / to see Hello, Ada. For data-backed UI, read application services inside the Effect returned by render.

Add an interactive control

Create src/components/counter.tsx with "use client" as its first statement:

"use client";

import { useState } from "react";

export function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount((value) => value + 1)}>Count: {count}</button>;
}

Import it in src/entry.effront.tsx. Then replace HomePage again:

// src/entry.effront.tsx: add to the imports.
import { Counter } from "./components/counter";

// Replace HomePage.
const HomePage = EFFRONT.Page.make({
  render: () =>
    Effect.succeed(
      <>
        <Welcome name="Ada" />
        <Counter />
      </>,
    ),
});

Open /. Click Count: 0 to increase the counter. Effront renders the Welcome component on the server.

Refer to React's "use client" reference for the boundary rules.