Skip to content

Add the widget to a React or Next.js app

Mount the widget with one component, drive it with a hook, and get typed attributes in Vue and Svelte.

Last updated

The @helpai/elements package comes with a React kit: a component that adds the widget and a hook that drives it from any component. It works with server rendering, includes its TypeScript types, and needs React 18 or later.

1. Install the package#

bash
npm install @helpai/elements

2. Add the widget once, in your root layout#

tsx
// app/layout.tsx (Next.js App Router)
import { HelpAI } from '@helpai/elements/react';

type Props = { children: React.ReactNode };

export default function RootLayout({ children }: Props) {
  return (
    <html lang='en'>
      <body>
        {children}
        <HelpAI
          publicKey='agent_pk_...'
          aiAgentDeploymentId='...'
          theme='host'
        />
      </body>
    </html>
  );
}

Copy the public key and deployment ID from the deployment's Install tab. <HelpAI /> takes every widget option as a prop, the same as init(): theme, launcher, userToken, widgetId and more. It draws nothing itself: the widget appears once the page is running in the browser, a changed prop updates it in place, and removing the component removes the widget.

In the App Router, a server layout can only pass plain values. To use callback props such as onOpen or onMessage, render <HelpAI /> from a 'use client' component of your own.

3. Drive it from any component#

tsx
'use client';

import { useHelpAI } from '@helpai/elements/react';

export function PricingHelp() {
  const { ask, open, state } = useHelpAI();
  return (
    <>
      <button onClick={() => ask('Which plan fits us?')}>
        Ask about plans
      </button>
      <button onClick={() => open({ to: 'help' })}>
        Help ({state.unread} unread)
      </button>
    </>
  );
}

useHelpAI() returns state, ask, open, close, reset and track, and re-renders your component when the state changes. The calls work the same as in Control the widget with JavaScript. Before <HelpAI /> has mounted they do nothing; state.ready turns true once they act.

Import everything from @helpai/elements/react, types included, so every component talks to the same widget.

Signed-in users and a second widget#

  • Signed-in users: pass a function that fetches your token as userToken. Keep it the same function for the same user; removing the prop signs them out. See Verify signed-in users.
  • Two widgets: give each <HelpAI widgetId='support' … /> its own id, and read it with useHelpAI('support'). See Run two widgets on one page.

Vue, Svelte and other frameworks#

Use the <web-ai-chat> element. Register it once:

ts
import '@helpai/elements/web-component';

With server rendering, such as Nuxt or SvelteKit, import it only in browser code: a Nuxt plugin whose file name ends in .client.ts, or onMount in SvelteKit, with await import('@helpai/elements/web-component'). The element can't be defined on the server.

Then add its types once, so your editor checks every attribute:

ts
// Vue 3. For Svelte 5: /jsx/svelte. For React 19: /jsx/react
import type {} from '@helpai/elements/jsx/vue';

Vue also needs web-ai-chat marked as a custom element. With Vite:

js
// vite.config.js
import vue from '@vitejs/plugin-vue';

export default {
  plugins: [
    vue({
      template: {
        compilerOptions: {
          isCustomElement: (tag) => tag === 'web-ai-chat',
        },
      },
    }),
  ],
};

On the element, wait with await element.ready and listen with element.on(…). Listeners end when the element leaves the page.

Was this helpful?

Still need help?

Ask the community