A lightweight, customizable Vue 3 chat widget for embedding Tock AI bots into any web page or app.
Try the Tock Vue Kit (and the Tock Vue Kit Editor) on the demo page
- Run a Tock Bot in API mode
- Vue.js: v3.4+ (peer dependency)
- Browser support: Modern browsers (Chrome, Firefox, Safari, Edge)
This repository does not include a package-lock.json file.
Since Tock Vue Kit is designed as a widget/library for integration into various projects, we avoid locking dependency versions to prevent conflicts with host environments.
Key dependencies (e.g., Vue.js) are defined as peerDependencies and must be provided by the host project. This ensures compatibility with your existing setup.
For users:
- Run
npm installto generate your ownpackage-lock.jsonlocally. - Use
npm cifor deterministic installations in CI/CD environments. - Refer to the integration examples for guidance on required peer dependencies.
For contributors:
- The
package-lock.jsonfile is excluded via.gitignore. - Always test your changes with
npm installbefore committing.
As of v2.0.0, this widget no longer bundles or automatically loads bootstrap-icons via CDN.
You must now include your preferred icon library manually in your project:
Add this to your HTML <head>:
<link
rel="stylesheet"
href="https://unpkg.com/[email protected]/font/bootstrap-icons.css"
/>Install the package:
npm install bootstrap-iconsThen import it in your project:
import "bootstrap-icons/font/bootstrap-icons.css";This change allows you to use any icon library of your choice (e.g., Font Awesome, Material Icons, etc.) instead of being locked into bootstrap-icons.
Include js and css files:
<script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>
<link
rel="stylesheet"
href="https://unpkg.com/[email protected]/dist/style.css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/[email protected]/font/bootstrap-icons.min.css"
/>
<script
crossorigin
src="https://unpkg.com/[email protected]/dist/tock-vue-kit.iife.js"
></script>
<!-- Next line can be omitted if no Latex formula is expected in bot responses -->
<link
rel="stylesheet"
href="https://unpkg.com/[email protected]/dist/katex.min.css"
/>Display the chat widget in desired target:
<div id="chat-wrapper"></div>
<script>
TockVueKit.renderChat(
document.getElementById("chat-wrapper"),
"<TOCK_BOT_API_URL>"
);
</script>Create a simple index.html file:
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>
<link
rel="stylesheet"
href="https://unpkg.com/[email protected]/font/bootstrap-icons.min.css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/[email protected]/dist/style.css"
/>
<script src="https://unpkg.com/[email protected]/dist/tock-vue-kit.iife.js"></script>
</head>
<body>
<div id="chat-wrapper"></div>
<script>
TockVueKit.renderChat(
document.getElementById("chat-wrapper"),
"https://your-tock-bot-api-url.com"
);
</script>
</body>
</html>npm install tock-vue-kit bootstrap-iconsIn the desired component:
<script setup lang="ts">
import { onMounted, ref } from "vue";
import "tock-vue-kit/dist/style.css";
import "bootstrap-icons/font/bootstrap-icons.css";
import { renderChat } from "tock-vue-kit";
const chatTarget = ref<HTMLElement>();
onMounted(() => {
renderChat(chatTarget.value!, "<TOCK_BOT_API_URL>");
});
</script>
<template>
<div ref="chatTarget"></div>
</template>
<style scoped>
/* Any scoped styling... */
</style>
<!-- Use unscoped styling to visualy customize the Tvk widget -->
<style>
:root {
--tvk_colors_brand-hue: 214;
--tvk_colors_brand-lightness: 42%;
--tvk_colors_brand-saturation: 40%;
--tvk_colors_dark_neutral: white;
--tvk_colors_dark_text1: white;
--tvk_colors_dark_text2: white;
--tvk_wrapper_height: calc(98vh - 6em);
}
</style>If Latex formulas are expected in bot responses, include the katex css file as well.
For example, directly in the component :
<style lang="scss">
@import url("https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css");
</style>Or by installing the library locally:
npm install katexAnd then by including the css in your imports :
import "katex/dist/katex.min.css";Install the dependency:
npm install tock-vue-kit bootstrap-iconsIn the desired component:
import {
Component,
ElementRef,
ViewChild,
ViewEncapsulation,
} from "@angular/core";
import { renderChat } from "tock-vue-kit";
import "tock-vue-kit/dist/style.css";
import "bootstrap-icons/font/bootstrap-icons.css";
@Component({
selector: "app-my-component",
standalone: true,
template: `<div #chatTarget></div>`,
styles: `
:root {
--tvk_colors_brand-hue: 214;
--tvk_colors_brand-lightness: 42%;
--tvk_colors_brand-saturation: 40%;
--tvk_colors_light_background: hsl(var(--tvk_colors_brand-hue) 50% 90%);
--tvk_colors_dark_neutral: white;
--tvk_colors_dark_text1: white;
--tvk_colors_dark_text2: white;
--tvk_wrapper_height: calc(100vh - 5em);
--tvk_wrapper_max-height: calc(100vh - 5em);
}
`,
encapsulation: ViewEncapsulation.None,
})
export class MyComponentComponent {
@ViewChild("chatTarget") chatTarget!: ElementRef<HTMLDivElement>;
ngAfterViewInit() {
renderChat(this.chatTarget.nativeElement, "<TOCK_BOT_API_URL>");
}
}If Latex formulas are expected in bot responses, include the katex css file as well.
For example, by localy installing the katex library:
npm install katexAnd then including katex css file in your angular.json :
"projects": {
"YOUR_PROJECT": {
...
"architect": {
"build": {
...
"options": {
...
"styles": [
...
"node_modules/katex/dist/katex.min.css"
],
...Install the dependency:
npm install tock-vue-kit bootstrap-iconsIn a css file, define your visual customizations of the widget (styles.css by example):
:root {
--tvk_colors_brand-hue: 214;
--tvk_colors_brand-lightness: 42%;
--tvk_colors_brand-saturation: 40%;
--tvk_colors_light_background: hsl(var(--tvk_colors_brand-hue) 50% 90%);
--tvk_colors_dark_neutral: white;
--tvk_colors_dark_text1: white;
--tvk_colors_dark_text2: white;
--tvk_wrapper_height: calc(100vh - 5em);
--tvk_wrapper_max-height: calc(100vh - 5em);
}Finally in the desired component:
import { useRef, useEffect } from "react";
import { renderChat } from "tock-vue-kit";
import "tock-vue-kit/dist/style.css";
import "bootstrap-icons/font/bootstrap-icons.css";
import "./styles.css";
function App() {
const chatTarget = useRef(null);
useEffect(() => {
renderChat(chatTarget.current, "<TOCK_BOT_API_URL>");
});
return <div ref={chatTarget}></div>;
}
export default App;If Latex formulas are expected in bot responses, include the katex css file as well https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css.
Install the dependency:
npm install tock-vue-kit bootstrap-iconsIn the desired component:
<style>
:root {
--tvk_colors_brand-hue: 214;
--tvk_colors_brand-lightness: 42%;
--tvk_colors_brand-saturation: 40%;
--tvk_colors_light_background: hsl(var(--tvk_colors_brand-hue) 50% 90%);
--tvk_colors_dark_neutral: white;
--tvk_colors_dark_text1: white;
--tvk_colors_dark_text2: white;
--tvk_wrapper_height: calc(98vh - 6em);
}
</style>
<script>
import { onMount } from "svelte";
import { renderChat } from "tock-vue-kit";
import "tock-vue-kit/dist/style.css";
import "bootstrap-icons/font/bootstrap-icons.css";
/** @type {HTMLDivElement} */
let chatTarget;
onMount(() => {
renderChat(chatTarget, "<TOCK_BOT_API_URL>");
});
</script>
<div bind:this="{chatTarget}"></div>If Latex formulas are expected in bot responses, include the katex css file as well https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css.
To optimize the size of our library and cater to the diverse needs of our users, we have chosen not to include the KaTeX CSS by default. Since the display of LaTeX formulas is not a required feature for all users, this approach helps reduce the overall weight of the library.
If you need the LaTeX formula display functionality, you can easily include the KaTeX CSS in your project by adding the following line to your HTML file or importing it into your CSS:
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/[email protected]/dist/katex.min.css"
/>This will enable the display of mathematical formulas while giving you control over the resources loaded in your application.
The /dist folder includes optimized builds for different environments:
| File | Format | Usage |
|---|---|---|
tock-vue-kit.iife.js |
IIFE | Direct inclusion in HTML via <script>. Exposes TockVueKit globally. |
tock-vue-kit.umd.js |
UMD | Works with require (CommonJS) and import (ESM). Compatible with most bundlers. |
tock-vue-kit.js |
ESM | Modern projects (Vite, Webpack 5+, Rollup). Use with import. |
tock-vue-kit.cjs |
CJS | Node.js or legacy bundlers (Webpack 4, Browserify). Use with require. |
style.css |
CSS | Required for widget styling. Include via <link rel="stylesheet">. |
TockVueKit.renderChat(element,tockBotApiUrl,customizationOptions)
The first argument of TockVueKit.renderChat method is the element where to render the widget. The element must be present in the document and provided as a HTMLElement reference.
The second argument is the url of the Tock instance to communicate with. This can be found in Tock Studio in Settings > Configurations, Relative REST path field (add the hosting domain of the Tock instance before the given path).
The third argument hosts the widget's customization options. See below.
Customization options are functional options of the widget. For visual widget customization, see Visual customization below. Customization options are provided in the form of an object that can contain the following optional attributes:
Tock Vue Kit Editor offers an easy way to define customization options (See demo page, click Editor switch then see Preferences and Wording tabs)
Options relating to the persistence in localStorage of messages exchanged by the user with the Tock instance:
| Property name | Description | Type | Default |
|---|---|---|---|
| enabled | Enable/disable persistence of conversation history in the browser's localStorage. When disabled, messages are not saved between page refreshes. | boolean | false |
| prefix | Unique prefix for localStorage keys to prevent conflicts when multiple bots are used on the same domain. If undefined, a default prefix is used. (Conditions: localStorage.enabled) | string | undefined |
| maxNumberMessages | Maximum number of messages to retain in localStorage. When this limit is reached, oldest messages are automatically removed. (Conditions: localStorage.enabled) | number | 20 |
Example :
TockVueKit.renderChat(
document.getElementById("<TARGET_ELEMENT_ID>"),
"<TOCK_BOT_API_URL>",
{
localStorage : {
enabled : true,
prefix : 'myprefix',
maxNumberMessages : 15
}
}
);Parameters for the initial setup and first interactions with the bot:
| Property name | Description | Type | Default |
|---|---|---|---|
| extraHeaders | Additional HTTP header key/value pairs to be supplied in requests. Warning : Tock server configuration required. | Record<string, string> |
undefined |
| welcomeMessage | Initial bot message to be displayed to the user at startup. It will not be sent to the bot and will be stored in local storage, if any. | string | undefined |
| openingMessage | Initial user message to be sent to the bot at startup to trigger a welcome sequence. It will not be displayed to the user and will not be stored in local storage, if any. | string | undefined |
Example :
TockVueKit.renderChat(
document.getElementById("<TARGET_ELEMENT_ID>"),
"<TOCK_BOT_API_URL>",
{
"initialization": {
"extraHeaders": {
"my-header-name": "My header value",
"other-header-name": "other header value"
},
"welcomeMessage": "Hi, how can i help you today ?"
}
}
)Customization options for the chat interface and user experience:
| Property name | Description | Type | Default |
|---|---|---|---|
| messages | Messages options | Messages | |
| questionBar | QuestionBar options | QuestionBar |
| Property name | Description | Type | Default |
|---|---|---|---|
| hideIfNoMessages | Hide the messages container when there are no messages to display. Useful for cleaner UI when chat is first loaded. | boolean | true |
| clearOnNewRequest | When enabled, clears previous conversation history each time the user sends a new message. Creates a fresh context for each new user input. | boolean | false |
| parseBotResponsesMarkdown | When enabled, bot responses containing Markdown are rendered as HTML with proper formatting (including code syntax highlighting, LaTeX, and MathML support). When disabled, responses are shown as plain text. | boolean | true |
| message | Message options | Message | |
| footNotes | FootNotes options | FootNotes | |
| feedback | Feedback options | Feedback |
| Property name | Description | Type | Default |
|---|---|---|---|
| hideUserMessages | If true, user messages are not displayed. | boolean | false |
| header | Header options | Header |
| Property name | Description | Type | Default |
|---|---|---|---|
| display | Display a header above message. | boolean | true |
| avatar | Avatar options | Avatar | |
| label | Label options | Label |
| Property name | Description | Type | Default |
|---|---|---|---|
| display | Display source references for RAG (Retrieval-Augmented Generation) responses. Sources appear as footnotes below the bot's answer. | boolean | true |
| requireSourcesContent | When enabled, retrieves and displays the actual content of source documents in addition to just the titles/links. Increases API load but provides more context. (Conditions: preferences.messages.footNotes.display) | boolean | false |
| parseContentMarkdown | Apply Markdown formatting to source document content when requireSourcesContent is enabled. Converts Markdown to HTML with syntax highlighting. (Conditions: preferences.messages.footNotes.display, preferences.messages.footNotes.requireSourcesContent) | boolean | true |
| clampSourceContent | Limit the displayed length of source document content to prevent overly long footnotes. The actual number of lines is controlled by clampSourceContentNbLines. (Conditions: preferences.messages.footNotes.display, preferences.messages.footNotes.requireSourcesContent) | boolean | true |
| clampSourceContentNbLines | Maximum number of lines to display for each source document when clampSourceContent is enabled. Set to 0 to show complete content. (Conditions: preferences.messages.footNotes.display, preferences.messages.footNotes.requireSourcesContent, preferences.messages.footNotes.clampSourceContent) | number | 2 |
| displayOnMessageSide | Display sources in a side panel next to the message instead of below it. Provides better separation between answer and sources but requires more horizontal space. (Conditions: preferences.messages.footNotes.display) | boolean | false |
| condensedDisplay | Display source links as numbered references only (without titles). More compact but less informative. Has no effect when requireSourcesContent is enabled. (Conditions: preferences.messages.footNotes.display, !preferences.messages.footNotes.requireSourcesContent) | boolean | false |
| Property name | Description | Type | Default |
|---|---|---|---|
| enabled | Show thumbs up/down buttons below bot messages to allow users to provide feedback on response quality. | boolean | false |
| thumbsUpIcon | CSS class for the thumbs-up icon. Uses Bootstrap Icons by default. Can be replaced with any icon library class. | string | bi bi-hand-thumbs-up |
| thumbsDownIcon | CSS class for the thumbs-down icon. Uses Bootstrap Icons by default. Can be replaced with any icon library class. | string | bi bi-hand-thumbs-down |
| Property name | Description | Type | Default |
|---|---|---|---|
| clearTypedCharsOnSubmit | Clear the input field after the user submits a message. When disabled, the submitted text remains in the input field for potential editing. | boolean | true |
| maxUserInputLength | Maximum number of characters allowed in user messages. Longer messages are truncated to this limit before being sent to the bot. | number | 500 |
| clearHistory | ClearHistory options | ClearHistory | |
| submit | Submit options | Submit |
| Property name | Description | Type | Default |
|---|---|---|---|
| display | Display a button that allows users to clear the current conversation history and start fresh. | boolean | true |
| icon | CSS class for the clear history icon. Uses Bootstrap Icons by default. Only displayed if no custom image is provided. (Conditions: preferences.questionBar.clearHistory.display) | string | bi bi-trash-fill |
| image | Custom image for the clear history button. Overrides the default icon if provided. (Conditions: preferences.questionBar.clearHistory.display) | ImageDef | undefined |
| Property name | Description | Type | Default |
|---|---|---|---|
| icon | CSS class for the submit button icon. Uses Bootstrap Icons by default. Only displayed if no custom image is provided. | string | bi bi-send-fill |
| image | Custom image for the submit button. Overrides the default icon if provided. | ImageDef | undefined |
Complex type definitions used in the configuration:
Option object for ImageDef.
| Property name | Description | Type |
|---|---|---|
| src | Src of the image (url or svg data image) | string |
| width | Width in which to display the image. | string |
| height | Height in which to display the image. | string |
Example :
TockVueKit.renderChat(
document.getElementById("<TARGET_ELEMENT_ID>"),
"<TOCK_BOT_API_URL>",
{
"preferences": {
"messages": {
"hideIfNoMessages": false,
"message": {
"header": {
"avatar": {
"userImage": {
"src": "https://my-url.com/my-file.png",
"width": "1em",
"height": "1em"
}
},
"label": {
"display": false
}
}
},
"footNotes": {
"requireSourcesContent": true,
"clampSourceContentNbLines": "4"
}
},
"questionBar": {
"submit": {
"icon": "bi bi-arrow-right-circle-fill"
}
}
}
}
)Text labels and messages displayed in the interface (can be customized for internationalization):
| Property name | Description | Type | Default |
|---|---|---|---|
| connectionErrorMessage | Message displayed to users when the connection to the bot service fails. | string | An unexpected error occurred. Please try again later. |
| messages | Messages options | Messages | |
| questionBar | QuestionBar options | QuestionBar |
| Property name | Description | Type | Default |
|---|---|---|---|
| message | Message options | Message | |
| feedback | Feedback options | Feedback |
| Property name | Description | Type | Default |
|---|---|---|---|
| header | Header options | Header | |
| footnotes | Footnotes options | Footnotes |
| Property name | Description | Type | Default |
|---|---|---|---|
| labelUser | Label displayed next to user messages in the conversation header. | string | You |
| labelBot | Label displayed next to bot messages in the conversation header. | string | Bot |
| Property name | Description | Type | Default |
|---|---|---|---|
| sources | Label prefix for the list of sources in RAG responses. | string | Sources: |
| showMoreLink | Text for the link that expands truncated source content. | string | > Show more |
| Property name | Description | Type | Default |
|---|---|---|---|
| confirmationMessage | Message shown to user after successfully submitting feedback. | string | Thank you for your feedback! |
| errorMessage | Message shown to user if feedback submission fails. | string | An error occurred while submitting your feedback. Please try again later. |
| thumbsUpTitle | Tooltip text displayed when hovering over the thumbs-up button. | string | I like this answer |
| thumbsDownTitle | Tooltip text displayed when hovering over the thumbs-down button. | string | I don't like this answer |
| thumbsUpAriaLabel | Accessibility label for the thumbs-up button for screen readers. | string | Thumbs up feedback button |
| thumbsDownAriaLabel | Accessibility label for the thumbs-down button for screen readers. | string | Thumbs down feedback button |
| Property name | Description | Type | Default |
|---|---|---|---|
| clearHistory | Text label for the clear history button. Leave empty to use icon only. | string | `` |
| clearHistoryTitle | Tooltip text displayed when hovering over the clear history button. | string | Clear discussion and history |
| clearHistoryAriaLabel | Accessibility label for the clear history button for screen readers. | string | Clear discussion and history button |
| submit | Text label for the submit button. Leave empty to use icon only. | string | `` |
| submitAriaLabel | Accessibility label for the submit button for screen readers. | string | Submit button |
| input | Input options | Input |
| Property name | Description | Type | Default |
|---|---|---|---|
| placeholder | Placeholder text shown in the input field when empty. Guides users on what to type. | string | Ask me a question... |
Example :
TockVueKit.renderChat(
document.getElementById("<TARGET_ELEMENT_ID>"),
"<TOCK_BOT_API_URL>",
{
"wording": {
"messages": {
"message": {
"header": {
"labelUser": "Vous"
},
"footnotes": {
"sources": "Sources :",
"showMoreLink": "> Voir plus"
}
}
},
"questionBar": {
"clearHistoryAriaLabel": "Effacer la discussion et l'historique",
"input": {
"placeholder": "Posez moi une question..."
},
"submitAriaLabel": "Bouton d'envoi"
},
"connectionErrorMessage": "Une erreur est survenue. Merci de réessayer dans quelques instants."
}
}
)Most of the css rules that shape the widget are defined by css variables.
Each of these variables has a default value, which you are free to redefine according to your needs. Use your DevTools to identify the variables to overload or take a look at the Tock Vue Kit Editor via its demo page. The css variables are prefixed with the string “--tvk” so as not to unintentionally impact the page hosting the widget.
Tock Vue Kit Editor offers an easy way to define and export css variables customization (See demo page, click Editor switch then see Styling and Output tabs)
You can redefine the desired css variables in a number of ways:
Redefine desired css variables in the source of the page hosting the widget, anywhere after inclusion of the css file.
Example :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>My Website</title>
<script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>
<script src="https://unpkg.com/[email protected]/dist/tock-vue-kit.iife.js"></script>
<link
rel="stylesheet"
href="https://unpkg.com/[email protected]/dist/style.css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/[email protected]/font/bootstrap-icons.min.css"
/>
<style>
:root {
--tvk_colors_brand-hue: 214;
--tvk_colors_brand-lightness: 42%;
--tvk_colors_brand-saturation: 40%;
--tvk_colors_dark_neutral: white;
--tvk_colors_dark_text1: white;
--tvk_colors_dark_text2: white;
--tvk_wrapper_height: calc(98vh - 6em);
}
</style>
</head>
<body>
<main>
<h1>Welcome to My Website</h1>
<div id="chat-wrapper"></div>
</main>
<script>
TockVueKit.renderChat(
document.getElementById("chat-wrapper"),
"<TOCK_BOT_API_URL>"
);
</script>
</body>
</html>Create a separate css file where you redefine css variables and include this file in source, after inclusion of main css file.
Example :
Main html page
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>My Website</title>
<script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>
<script src="https://unpkg.com/[email protected]/dist/tock-vue-kit.iife.js"></script>
<link
rel="stylesheet"
href="https://unpkg.com/[email protected]/dist/style.css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/[email protected]/font/bootstrap-icons.min.css"
/>
<link href="my-visual-customization.css" rel="stylesheet" />
</head>
<body>
<main>
<h1>Welcome to My Website</h1>
<div id="chat-wrapper"></div>
</main>
<script>
TockVueKit.renderChat(
document.getElementById("chat-wrapper"),
"<TOCK_BOT_API_URL>"
);
</script>
</body>
</html>Separate customization file (my-visual-customization.css in this example)
:root {
--tvk_colors_brand-hue: 214;
--tvk_colors_brand-lightness: 42%;
--tvk_colors_brand-saturation: 40%;
--tvk_colors_dark_neutral: white;
--tvk_colors_dark_text1: white;
--tvk_colors_dark_text2: white;
--tvk_wrapper_height: calc(98vh - 6em);
}If necessary, you can inject css variable overloads with javascript at runtime.
Example :
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>My Website</title>
<script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>
<script src="https://unpkg.com/[email protected]/dist/tock-vue-kit.iife.js"></script>
<link
rel="stylesheet"
href="https://unpkg.com/[email protected]/dist/style.css"
/>
<link
rel="stylesheet"
href="https://unpkg.com/[email protected]/font/bootstrap-icons.min.css"
/>
</head>
<body>
<main>
<h1>Welcome to My Website</h1>
<div id="chat-wrapper"></div>
</main>
<script>
TockVueKit.renderChat(
document.getElementById("chat-wrapper"),
"<TOCK_BOT_API_URL>"
);
const styling = {
"--tvk_colors_brand-hue": "214",
"--tvk_colors_brand-lightness": "42%",
"--tvk_colors_brand-saturation": "40%",
"--tvk_colors_dark_background":
"hsl(var(--tvk_colors_brand-hue) 50% 20%)",
"--tvk_colors_dark_neutral": "white",
"--tvk_colors_dark_text1": "white",
"--tvk_colors_dark_text2": "white",
"--tvk_colors_light_background":
"hsl(var(--tvk_colors_brand-hue) 50% 90%)",
"--tvk_wrapper_height": "calc(98vh - 6em)",
};
let root = document.documentElement;
Object.entries(styling).forEach((style) => {
root.style.setProperty(style[0], style[1]);
});
</script>
</body>
</html>If you need to modify the widget's appearance in greater depth, use your own version of the "dist/style.css" file, which you can then customize as you see fit.
The Tock Vue Kit implements a sophisticated HSL-based theming system with some key principles. Take a look at the demo page of the Tock Vue Kit Editor to better understand this mechanism.
- Foundation variables for brand customization using HSL
- Dual-variable system for light/dark themes
- Theme-agnostic variables for component usage (
--tvk_colors_*) - Automatic color generation from base HSL values
These base variables define your brand identity and automatically generate all other theme colors. By modifying these 3 values, you change the overall appearance of your interface.
/* Brand foundation - generates all derived colors */
--tvk_colors_brand-hue: 210; /* 0-360 color wheel position */
--tvk_colors_brand-saturation: 80%; /* 0-100% color intensity */
--tvk_colors_brand-lightness: 50%; /* 0-100% color brightness */The system automatically generates light and dark variants from the foundation variables. These are prefixed with light* and dark* for precise theme customization.
/* Light mode vars - automatically generated from base variables */
--tvk_colors_light_brand: hsl(
var(--tvk_colors_brand-hue) var(--tvk_colors_brand-saturation) var(--tvk_colors_brand-lightness)
);
--tvk_colors_light_surface1: var(--tvk_colors_light_brand);
--tvk_colors_light_text1: hsl(
var(--tvk_colors_brand-hue) var(--tvk_colors_brand-saturation) 100%
);
--tvk_colors_light_surface2: hsl(var(--tvk_colors_brand-hue) 10% 99%);
--tvk_colors_light_text2: hsl(var(--tvk_colors_brand-hue) 30% 30%);
/* Dark mode vars - also automatically generated */
--tvk_colors_dark_brand: hsl(
var(--tvk_colors_brand-hue) var(--tvk_colors_brand-saturation) var(--tvk_colors_brand-lightness)
);
--tvk_colors_dark_surface1: var(--tvk_colors_dark_brand);
--tvk_colors_dark_text1: hsl(var(--tvk_colors_brand-hue) 10% 85%);
--tvk_colors_dark_surface2: hsl(var(--tvk_colors_brand-hue) 1% 15%);
--tvk_colors_dark_text2: hsl(var(--tvk_colors_brand-hue) 5% 65%);These variables automatically adapt to the current theme (light or dark) to ensure smooth theme switching.
[data-theme="light"] {
--tvk_colors_brand: var(--tvk_colors_light_brand);
--tvk_colors_surface1: var(--tvk_colors_light_surface1);
--tvk_colors_text1: var(--tvk_colors_light_text1);
--tvk_colors_surface2: var(--tvk_colors_light_surface2);
--tvk_colors_text2: var(--tvk_colors_light_text2);
}
[data-theme="dark"] {
--tvk_colors_brand: var(--tvk_colors_dark_brand);
--tvk_colors_surface1: var(--tvk_colors_dark_surface1);
--tvk_colors_text1: var(--tvk_colors_dark_text1);
--tvk_colors_surface2: var(--tvk_colors_dark_surface2);
--tvk_colors_text2: var(--tvk_colors_dark_text2);
}Themes are controlled via HTML attributes, allowing explicit and consistent theme switching.
<!-- Light theme (default) -->
<html data-theme="light"></html><!-- Dark theme -->
<html data-theme="dark"></html><!-- Bootstrap compatibility -->
<html data-bs-theme="dark"></html>Important: The kit intentionally does not automatically respond to prefers-color-scheme to maintain consistency with the hosting website's theme behavior.
For effective theme customization:
1 - Always modify theme-specific variables (--tvk_colors_light_* and --tvk_colors_dark_*) rather than theme-agnostic variables (--tvk_colors_*).
2 - Use the HSL system to maintain color consistency between themes:
:root {
/* Recommended customization - modify light/dark variables */
--tvk_colors_light_surface1: hsl(
var(--tvk_colors_brand-hue) calc(var(--tvk_colors_brand-saturation) - 20%)
90%
);
--tvk_colors_dark_surface1: hsl(
var(--tvk_colors_brand-hue) calc(var(--tvk_colors_brand-saturation) - 10%)
20%
);
}3 - Avoid directly modifying theme-agnostic variables like --tvk_colors_surface1 as this bypasses the automatic theme switching system.
4 - For specific cases, you can directly override a component property:
:root {
/* Example of direct override (use sparingly) */
--tvk_message_answer_user_background: #e8f5e8;
}5 - Always test your customizations in both themes to ensure visual consistency.
\:root {
/* Brand foundation - all colors derive from these */
--tvk_colors_brand-hue: 210; /* Blue */
--tvk_colors_brand-saturation: 80%;
--tvk_colors_brand-lightness: 50%;
/* Feedback colors */
--tvk_colors_good-hue: 120; /* Green */
--tvk_colors_bad-hue: 0; /* Red */
/* Custom surface colors using HSL */
--tvk_colors_light_surface1: hsl(
var(--tvk_colors_brand-hue) calc(var(--tvk_colors_brand-saturation) - 20%)
90%
);
--tvk_colors_dark_surface1: hsl(
var(--tvk_colors_brand-hue) calc(var(--tvk_colors_brand-saturation) - 10%)
20%
);
/* Message bubble customization using theme variables */
--tvk_message_answer_user_background: var(--tvk_colors_surface1);
--tvk_message_answer_bot_background: var(--tvk_colors_background);
}\:root {
/* Direct color override example */
--tvk_message_answer_user_background: #e8f5e8;
/* Using theme variables for other properties */
--tvk_message_answer_user_color: var(--tvk_colors_text1);
--tvk_message_answer_user_border: 1px solid var(--tvk_colors_neutral-dim);
}- Start with foundation variables before overriding specific components
- Use HSL-based definitions for consistent color relationships
- Leverage theme-agnostic variables (--tvkcolors*) in your components
- Maintain sufficient contrast (minimum 4.5:1 for normal text)
- Document your customizations in a separate CSS file
- Test in both themes if implementing dark mode
- Consistent theming across all components
- Easy maintenance through centralized variable management
- Flexible branding without component modification
- Automatic dark/light switching via HTML attributes
- Future-proof design that accommodates new components
- HSL-based system ensures color harmony across themes
Pull requests are welcome! For any kind of change, please open an issue first.
- See the
demobranch of this repository for more information.
For bugs or feature requests, please open an issue.