> ## Documentation Index
> Fetch the complete documentation index at: https://knitkit.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Using knitkit in React: RemoteComponent and lazyRemote

> Mount federated remote components in a React host using <RemoteComponent>, lazyRemote, and <RemoteFragment> from @knitkit/react.

The `@knitkit/react` package gives you a set of React primitives that sit on top of knitkit's
runtime `loadRemote()`. Rather than calling `loadRemote` yourself and wiring up `React.lazy`,
`Suspense`, and an error boundary by hand, you use `<RemoteComponent>` for the common case, or
`lazyRemote()` when you need to own the boundary setup yourself. `<RemoteFragment>` covers a
third scenario: embedding a server- or framework-agnostic HTML fragment inside a React host
without any React sharing.

## Install

```bash theme={null}
npm i @knitkit/react
```

`@knitkit/react` lists `react` as a peer dependency. It works with React 18 and later.

***

<Warning>
  You must call `registerRemotes()` from `@knitkit/runtime` **before** any `<RemoteComponent>`
  (or `lazyRemote`) renders. Attempting to load a remote whose manifest has not been registered
  will throw `KNIT_ERR_UNKNOWN_REMOTE`. Place your `registerRemotes` call in your app entry
  point, before any lazy boundaries can trigger.
</Warning>

***

## `<RemoteComponent>`

`<RemoteComponent>` is the highest-level primitive. It wraps `lazyRemote`, `React.Suspense`,
and `<RemoteErrorBoundary>` into a single component so you can drop a federated remote into
your tree with one JSX line. The remote's exposed module **must default-export a React
component** — knitkit wraps whatever it receives in `{ default: mod }` for the lazy factory.

### Props

<ParamField path="name" type="string" required>
  The federated specifier in `"<remoteName>/<exposeKey>"` format, e.g.
  `"checkout/CartWidget"`. This matches the remote name you passed to `registerRemotes` and
  the key in that remote's `exposes` map.
</ParamField>

<ParamField path="fallback" type="ReactNode">
  Rendered while the remote module is loading (passed to the inner `<Suspense fallback>`).
  Defaults to `null`, so the slot is simply empty during loading if you omit it.
</ParamField>

<ParamField path="errorFallback" type="ReactNode | ((error: Error) => ReactNode)">
  Rendered when loading or rendering the remote throws. Pass a function to receive the caught
  `Error` and render a contextual message. Defaults to `null`.
</ParamField>

<ParamField path="onError" type="(error: Error) => void">
  Called once when an error is caught by the inner `<RemoteErrorBoundary>`. Use this for
  logging or telemetry without replacing the rendered fallback.
</ParamField>

Any additional props you place on `<RemoteComponent>` are forwarded directly to the remote
component once it loads.

### Example

```tsx theme={null}
import { RemoteComponent } from "@knitkit/react";

function Cart() {
  return (
    <RemoteComponent
      name="checkout/CartWidget"
      fallback={<Spinner />}
      errorFallback={(err) => <p>Could not load cart: {err.message}</p>}
      onError={(err) => analytics.track("remote_error", { error: err.message })}
      sku="ABC-123"
      quantity={2}
    />
  );
}
```

In this example `sku` and `quantity` are forwarded to the `CartWidget` component that the
`checkout` remote exports as its default export.

***

## `lazyRemote(specifier)`

`lazyRemote` gives you a `React.lazy`-compatible component backed by `loadRemote`. Use it
when you want full control over the `<Suspense>` boundary, the error boundary strategy, or
when you need to render the same remote component in multiple locations without paying for
separate lazy instances — `lazyRemote` caches the lazy wrapper by specifier so React does
not re-create and re-suspend on every render.

Choose `lazyRemote` over `<RemoteComponent>` when you need to:

* Share a single boundary across multiple remote slots
* Compose the remote inside an existing Suspense tree you already own
* Apply a different error boundary library (e.g. `react-error-boundary`)

```tsx theme={null}
import { Suspense } from "react";
import { lazyRemote, clearRemoteCache } from "@knitkit/react";

const CartWidget = lazyRemote("checkout/CartWidget");
const ProfileMenu = lazyRemote("profile/NavMenu");

function Shell() {
  return (
    <Suspense fallback={<PageSkeleton />}>
      <CartWidget sku="ABC-123" />
      <ProfileMenu userId="u_42" />
    </Suspense>
  );
}
```

`@knitkit/react` also exports `clearRemoteCache(specifier?)` — call it without an argument to
flush all cached lazy wrappers, or pass a specifier to evict one entry. This is useful if a
remote previously failed to load and you want to retry it.

```tsx theme={null}
import { clearRemoteCache } from "@knitkit/react";

function RetryButton({ specifier }: { specifier: string }) {
  return (
    <button onClick={() => clearRemoteCache(specifier)}>
      Retry
    </button>
  );
}
```

***

## `<RemoteFragment>`

`<RemoteFragment>` embeds a remote HTML fragment — the response of a plain HTTP `fetch` — into
your React host using `dangerouslySetInnerHTML`. Because nothing is shared between the fragment
server and your React app, there is no risk of hook-call conflicts or version mismatches.

Use `<RemoteFragment>` when:

* A remote team ships a server-rendered HTML fragment (e.g. from a Vue, Astro, or plain
  Express server)
* You want a clear client boundary with no shared JavaScript
* You are embedding a widget that owns its own bootstrap script separately

<Note>
  `<RemoteFragment>` embeds **static HTML**. Any `<script>` tags inside the fragment HTML do
  **not** execute. For interactive fragments that need their own JavaScript, have the remote
  ship a self-contained bootstrap (a `<script src="...">` in the fragment pointing at the
  remote's own bundle) or use an iframe. For edge-side stream stitching, see `@knitkit/edge`.
</Note>

### Props

<ParamField path="src" type="string" required>
  The URL of the remote fragment endpoint. knitkit `fetch`es this URL and injects the
  response text as inner HTML.
</ParamField>

<ParamField path="fallback" type="ReactNode">
  Rendered while the fragment is loading. Defaults to `null`.
</ParamField>

<ParamField path="errorFallback" type="ReactNode | ((error: Error) => ReactNode)">
  Rendered when the fetch fails or returns a non-OK status. Pass a function to receive the
  error.
</ParamField>

<ParamField path="as" type="keyof JSX.IntrinsicElements">
  The container element tag. Defaults to `"div"`.
</ParamField>

<ParamField path="init" type="RequestInit">
  Passed directly to `fetch()`. Use this to set custom headers, credentials, or an abort
  signal.
</ParamField>

### Example

```tsx theme={null}
import { RemoteFragment } from "@knitkit/react";

function PromoBar() {
  return (
    <RemoteFragment
      src="https://marketing.example.com/fragments/promo-bar"
      as="section"
      fallback={<div className="promo-skeleton" />}
      errorFallback={<></>}
      init={{ credentials: "include" }}
    />
  );
}
```

***

## `<RemoteErrorBoundary>`

`<RemoteErrorBoundary>` is the error boundary that `<RemoteComponent>` uses internally. You
can use it directly when you want a standalone boundary around **multiple** remote components
or around a subtree that mixes remote and local components.

### Props

<ParamField path="children" type="ReactNode" required>
  The React subtree to protect. Any error thrown by a child during rendering is caught by
  this boundary.
</ParamField>

<ParamField path="fallback" type="ReactNode | ((error: Error) => ReactNode)">
  Rendered when any child throws. A function receives the caught `Error`.
</ParamField>

<ParamField path="onError" type="(error: Error) => void">
  Called once when an error is caught. Use it for logging or telemetry.
</ParamField>

### Example

```tsx theme={null}
import { RemoteErrorBoundary, lazyRemote } from "@knitkit/react";
import { Suspense } from "react";

const CartWidget  = lazyRemote("checkout/CartWidget");
const RecoWidget  = lazyRemote("recommendations/Carousel");

function Sidebar() {
  return (
    <RemoteErrorBoundary
      fallback={(err) => <aside>Sidebar unavailable: {err.message}</aside>}
      onError={(err) => console.error("[remote]", err)}
    >
      <Suspense fallback={<SidebarSkeleton />}>
        <CartWidget />
        <RecoWidget />
      </Suspense>
    </RemoteErrorBoundary>
  );
}
```

<Tip>
  Prefer one `<RemoteErrorBoundary>` per logical UI zone (e.g. sidebar, header, main content)
  rather than wrapping every individual remote. This keeps failure granular enough to be useful
  without adding boundary boilerplate everywhere.
</Tip>
