Add the selector to a Next.js site
Ce guide est écrit à partir de la documentation propre de Next.js. Nous ne l'avons pas encore exécuté sur un vrai site, donc si une étape ne correspond pas à ce que vous voyez, dites-le nous et nous corrigerons le guide.
Written from how Next.js works rather than from an install we did ourselves. What we have confirmed on a real Next.js site is the part that matters: a server rendered tag boots correctly and the selector survives hydration.
Copy the snippet from Settings, then Selector, in your project. It carries your
project id in data-ut-tenant, so paste it rather than retyping it.
Where the snippet goes
It belongs in the shared layout, never in an individual route. In a single route the selector appears on that one page and nowhere else.
App Router. File: app/layout.tsx
Render it as an ordinary element inside <body>:
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
{children}
<script
src="https://translate.ultimsuite.com/ut/v1.js"
defer
data-ut-tenant="YOUR-PROJECT"
/>
</body>
</html>
);
}
Pages Router. File: pages/_document.tsx
next/document's <Head> is safe here: that document renders on the server and is
never hydrated.
import { Html, Head, Main, NextScript } from 'next/document';
export default function Document() {
return (
<Html lang="en">
<Head>
<script
src="https://translate.ultimsuite.com/ut/v1.js"
defer
data-ut-tenant="YOUR-PROJECT"
/>
</Head>
<Main />
<NextScript />
</Html>
);
}
Prefer a plain tag over next/script. Its default afterInteractive strategy injects
the tag from the browser after hydration, so the selector appears later than it needs to
and may never appear at all if hydration fails. If you do use next/script, keep
data-ut-tenant on it: the script reads its own tag to know which project it belongs to.
The trap on Next.js
A menu that only exists once it is open. The common shape:
{open && <MobileNav />}
The whole menu, and anything you place inside it, is absent from the served HTML and enters the DOM only when a visitor opens it. A selector placed in there ships on zero pages. It looks correct when you inspect the DOM with the menu open, which is why it is easy to miss. We hit this on our own site.
Render the container always and hide it while closed:
<MobileNav open={open} />
display: none is fine, the selector still renders inside and appears when the menu
opens. If you hide it with max height or opacity so it can animate, add inert and
aria-hidden while closed, or every link inside stays in the tab order and in screen
reader output while the menu looks shut.
To place the selector inside a menu, try the picker first (Settings, then Selector, and open your menu inside the picker before clicking the spot). If the position does not hold, use the placement element from the "Paste an element" method and put it at the exact spot in your nav component:
<div data-ut-selector="your-selector-id" />
A second, milder trap: do not wrap the tag in an explicit <head> element you write
yourself. React can render it into the server HTML and then insert it again while
hydrating, leaving two tags on the live page. Nothing breaks, the script starts once
however many tags load it and mounts one selector per configured position, so it is
untidy rather than harmful. The examples above avoid it.
How to know it worked
Open the deployed site and view the page source, then search for ut/v1.js. One match
means it is live. Check the deployed site rather than your local one, since a missing
selector is usually a tag that never made it into the deployed build.
The check on the Selector settings screen asks your site directly and answers plainly.
Because a hydration duplicate does not appear in view source, check the running page too. In the browser console:
document.querySelectorAll("script[src*='/ut/v1.js']").length
Expect 1. If you get 2, remove the explicit head wrapper and check again.