# React and Next.js

> Load the Taggor snippet in a Next.js or React app and place a component.

## Install the snippet once

**Next.js (App Router):** load it with `next/script` in the root layout:

```tsx title="app/layout.tsx"
import Script from "next/script";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <Script src="https://cdn.taggorcdn.com/s/<site-key>.js" strategy="lazyOnload" />
      </body>
    </html>
  );
}
```

`lazyOnload` loads the script when the browser is idle and is meant for widgets; `afterInteractive` is
Next.js's default (next/script, `https://nextjs.org/docs/app/api-reference/components/script`, read 2026-11-09).

**A React app without Next.js:** paste the plain tag in the HTML file the app starts from (`index.html` in
Vite):

```html title="index.html"
<script async src="https://cdn.taggorcdn.com/s/<site-key>.js"></script>
```

## Place the component

Write the tag in a component like any element. A prop of text, number or boolean is an attribute; a list or an
object is the element's property, and an event is `addEventListener`: the recipes and the differences between
React 18 and 19 are in [Components in React, Vue and Angular](https://taggor.dev/docs/framework-interop.md). In the App Router, the
file that holds the tag and uses hooks starts with `"use client"`.

## Limits

- The server's HTML carries the tag; the component appears once the Taggor script runs in the browser. Put a
  fallback inside the tag ([Fallback content](https://taggor.dev/docs/fallback.md)).
- Hydration does not warn about the shadow root the component creates.

## Common problems

- **A list prop shows as empty.** React 19 sets it as an attribute when the tag is not defined yet:
  use a `ref` and an effect.
- **A `price-list:select` event never fires.** The `:` in the name; use `addEventListener` on a `ref`.

## How we checked

The matrix runs the components on a Next.js 16 App Router static export hydrated by React and on a Vite React 19
single-page app, in Chromium, Firefox and WebKit and two mobile emulations. Not checked: the snippet in
`next/script` was checked as text and not run inside a Next.js app that uses it.
