Разработчику

Фреймворки

Куда вставить две строки в Next.js, Nuxt, React, Vue, Angular, WordPress, Tilda и Битрикс.

На странице

В любом стеке нужны те же две строки (Установка на сайт). Скрипт и элемент добавляются по одному разу, в общий шаблон всех страниц. Замените your-project на id проекта.

Обычный HTML

Вставьте строки перед </body> на каждой странице или в шаблоне, из которого они собираются:

HTML
  <script type="module" src="https://api.tolkly.io/widget.js"></script>
  <tolkly-chat endpoint="https://api.tolkly.io" project="your-project"></tolkly-chat>
</body>

С другими серверными шаблонами — так же: layout Blade в Laravel, base.html в Django, application.html.erb в Rails. Строки идут перед </body> базового layout.

Next.js (App Router)

Корневой layout не пропадает при переходах между страницами. Поставьте чат туда:

TSX
// app/layout.tsx
import Script from 'next/script'
import type { ReactNode } from 'react'

export default function RootLayout({ children }: { children: ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <tolkly-chat endpoint="https://api.tolkly.io" project="your-project"></tolkly-chat>
        <Script type="module" src="https://api.tolkly.io/widget.js" strategy="afterInteractive" />
      </body>
    </html>
  )
}
  • next/script передаёт type="module" в тег скрипта, который добавляет.
  • С afterInteractive виджет запускается после гидрации страницы.
  • React 19 выводит custom element с атрибутами в том виде, как они написаны.
  • Добавьте объявление типа ниже, иначе TypeScript не примет <tolkly-chat>.

Next.js (Pages Router)

_app оборачивает каждую страницу и не размонтируется при переходах:

TSX
// pages/_app.tsx
import type { AppProps } from 'next/app'
import Script from 'next/script'

export default function App({ Component, pageProps }: AppProps) {
  return (
    <>
      <Component {...pageProps} />
      <tolkly-chat endpoint="https://api.tolkly.io" project="your-project"></tolkly-chat>
      <Script type="module" src="https://api.tolkly.io/widget.js" strategy="afterInteractive" />
    </>
  )
}

TypeScript и JSX

Типы React 19 берут intrinsic elements из React.JSX. Объявите тег один раз в любом файле .d.ts, который входит в ваш tsconfig.json, например в tolkly.d.ts:

TypeScript
import type { DetailedHTMLProps, HTMLAttributes } from 'react'

type TolklyChatProps = DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement> & {
  endpoint?: string
  project?: string
  name?: string
  greeting?: string
  handoff?: string
  teaser?: string
  position?: 'left' | 'right'
  theme?: 'site' | 'system' | 'light' | 'dark'
  'send-icon'?: 'arrow' | 'plane' | 'forward'
  collapse?: string
  'data-identity'?: string
}

declare module 'react' {
  namespace JSX {
    interface IntrinsicElements {
      'tolkly-chat': TolklyChatProps
    }
  }
}

import делает файл модулем. Благодаря этому declare module 'react' дополняет типы React, а не заменяет их. HTMLAttributes уже включает lang, nonce, style и className.

Не передавайте open и inline в JSX. Если у элемента есть DOM-свойство с тем же именем, React 19 записывает prop в это свойство. А у <tolkly-chat> есть метод open() и свойство inline только для чтения. Пишите эти атрибуты в index.html или вызывайте open({ focus: false }) у элемента из эффекта.

Nuxt 3

Подключите скрипт в nuxt.config.ts и сообщите Vue, что тег — это custom element:

TypeScript
// nuxt.config.ts
export default defineNuxtConfig({
  app: {
    head: {
      script: [{ src: 'https://api.tolkly.io/widget.js', type: 'module' }],
    },
  },
  vue: {
    compilerOptions: {
      isCustomElement: (tag) => tag.startsWith('tolkly-'),
    },
  },
})

Затем поставьте элемент в app.vue, вне <NuxtPage>:

Vue
<template>
  <NuxtLayout>
    <NuxtPage />
  </NuxtLayout>
  <tolkly-chat endpoint="https://api.tolkly.io" project="your-project"></tolkly-chat>
</template>

React на Vite

Вставьте обе строки в index.html, перед </body>, вне элемента #root, в который рисует React. Код React менять не нужно. Если хотите выводить <tolkly-chat> из JSX, выводите его один раз в корневом компоненте и добавьте объявление типа.

Vue 3 на Vite

Вставьте обе строки в index.html, перед </body>, вне элемента #app. Если хотите использовать тег в шаблоне Vue, сообщите компилятору, что это custom element:

TypeScript
// vite.config.ts
import vue from '@vitejs/plugin-vue'
import { defineConfig } from 'vite'

export default defineConfig({
  plugins: [
    vue({
      template: {
        compilerOptions: { isCustomElement: (tag) => tag.startsWith('tolkly-') },
      },
    }),
  ],
})

Angular

Вставьте обе строки в src/index.html, перед </body>, вне корневого элемента приложения. Не добавляйте скрипт в scripts файла angular.json. Тогда он попадёт в сборку как обычный скрипт и не запустится.

Если хотите использовать тег в шаблоне компонента, разрешите там custom elements:

TypeScript
import { Component, CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  schemas: [CUSTOM_ELEMENTS_SCHEMA],
})
export class AppComponent {}

WordPress

Вставьте строки прямо перед </body> в footer.php вашей темы. Берите дочернюю тему, чтобы обновление не стёрло вставку. Или добавьте их через functions.php темы:

PHP
add_action('wp_footer', function () {
    echo '<script type="module" src="https://api.tolkly.io/widget.js"></script>';
    echo '<tolkly-chat endpoint="https://api.tolkly.io" project="your-project"></tolkly-chat>';
});

Нет доступа к файлам темы? Подойдёт любой плагин, который добавляет свой код перед </body> на всех страницах. Затем очистите кэш страниц, если он есть.

Tilda

Добавьте обе строки в блок HTML-кода (T123). Поставьте блок в подвал, общий для всех страниц, или на каждую страницу, где нужен чат. Затем опубликуйте страницы заново.

1С-Битрикс

Вставьте строки прямо перед </body> в footer.php шаблона сайта. Он лежит в /local/templates/<template>/footer.php или /bitrix/templates/<template>/footer.php. Если шаблон кэшируется, затем очистите кэш сайта.