The theme object

The theme object is part of the baseSettings and can be used to customize the widgets to fit your brand’s style. It allows you to overrides variables that we use throughout our styling.

Fonts

Specify which fonts should be applied to the body, headings, or code (mono) elements. For example:

//...
baseSettings: {
  //...
  theme: {
    tokens: {
      fonts: {
        heading: "'Space Grotesk'",
        body: "'Inter'",
        mono: "'Space Mono', monospace",
      },
    },
  }
}

Colors

The widget ships with a neutral gray scheme and derives accent colors from the primaryBrandColor (passed into baseSettings), but these colors can be overridden with your own colors if you wish. Here is an example:

//...
baseSettings: {
  //...
  theme: {
    tokens: {
      colors: {
        // grays for light mode
        'gray.50': '#f8f9fa',
        'gray.100': '#f1f3f5',
        'gray.200': '#eceef0',
        'gray.300': '#e6e8eb',
        'gray.400': '#dfe3e6',
        'gray.500': '#BDC2C7',
        'gray.600': '#889096',
        'gray.700': '#687076',
        'gray.800': '#36424A',
        'gray.900': '#11181c',
        // grays for dark mode
        'grayDark.50': '#ededed',
        'grayDark.100': '#a0a0a0',
        'grayDark.200': '#7e7e7e',
        'grayDark.300': '#707070',
        'grayDark.400': '#505050',
        'grayDark.500': '#3e3e3e',
        'grayDark.600': '#343434',
        'grayDark.700': '#2e2e2e',
        'grayDark.800': '#282828',
        'grayDark.900': '#1c1c1c',
      },
    },
    primaryColors: {  // by default, derived from primaryBrandColor
      textColorOnPrimary: '#11181c',
      textBold: '#141d20',
      textSubtle: '#354a51',
      lighter: '#e5feff',
      light: '#85f0ff',
      lightSubtle: '#f1f8fa',
      medium: '#26d6ff', // primaryBrandColor
      strong: '#00b5dd',
      stronger: '#006881',
      hitContentPreview: '#00b5dd',
      hitContentPreviewHover: '#006881',
      textColorOnPrimary: 'white',
    },
  }
}

Z-indices

Customizing the zIndex tokens is usually not necessary but can be helpful if there is an element on your site with a high z-index that is being rendered on top of one of the widgets or modal. Below are the default token values. It is a good idea to update the rest of z-index tokens relative to the one you need to change, for example if changing modal to 2000 make sure to also bump popover to 2100, skipLink to 2200 etc.

//...
baseSettings: {
  //...
  theme: {
    tokens: {
      zIndex: {
        hide: -1,
        auto: 'auto',
        base: 0,
        docked: 10,
        dropdown: 1000,
        sticky: 1100,
        banner: 1200,
        overlay: 1300,
        modal: 1400,
        popover: 1500,
        skipLink: 1600,
        toast: 1700,
        tooltip: 1800,
      },
    }
  }
}

The Search Bar component has two variants to chose from subtle and emphasized, the default is subtle. There are also four size variants to chose from expand, compact, shrink, or medium, the default is compact. The Docusaurus package defaults to shrink.

To change the variant and size:

//...
baseSettings: {
  //...
  theme: {
    components: {
      SearchBarTrigger: {
        defaultProps: {
          size: 'expand', // 'expand' 'compact' 'shrink' 'medium'
          variant: 'emphasized', // 'emphasized' 'subtle'
        },
      },
    }
  }
}

Embedded Chat

Theme variants

The Embedded Chat component has two styling variants: container-with-shadow and no-shadow, the default is container-with-shadow. There are also four size variants: shrink-vertically, expand, default, or full-viewport, the default is default.

To change the variant and size:

//...
baseSettings: {
  //...
  theme: {
    components: {
      AIChatPageWrapper: {
        defaultProps: {
          size: 'shrink-vertically', // 'shrink-vertically' 'expand', 'default', 'full-viewport'
          variant: 'no-shadow', // 'no-shadow' or 'container-with-shadow'
        },
      },
    }
  }
}

Centering and sizing

The embedded chat is sized relative to it’s container. By default, it expands to a certain max width and heights that preserve a reasonable aspect ratio for different breakpoints and tries to center itself relative to its parent. So it’s properly centered, consider wrapping it in parents that have the below stylings.

With a display='flex' parent

<div style={{ // parent
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
    height: 'calc(100vh - 16px)',
  }}>
  <div style={{ // container
    maxHeight: '600px',
    height: '100%',
   }}>
    <EmbeddedChat {...embeddedChatProps} />
  <div>
</div>


With a display='block' parent

<div style={{ // parent
    display: 'block',
    position: 'relative',
    height: 'calc(100vh - 16px)',
  }}>
  <div style={{ // container
    maxHeight: '600px',
    height: '100%',
    position: 'absolute',
    top: '50%',
    left: '50%',
    transform: 'translate(-50%,-50%)',
  }}>
    <EmbeddedChat {...embeddedChatProps} />
  <div>
</div>


Customizing dimensions (using size='expand')

<div style={{ // parent
    minHeight: '600px',
    height: 'calc(100vh - 16px)',
  }}>
  <div style={{ // container
    maxWidth: '750px',
    maxHeight: '600px',
    height: '100%',
    width: '100%',
    minWidth: '0px',
   }}>
    <EmbeddedChat {...embeddedChatProps} />
  <div>
</div>

We recommend setting the height for the container div to height: min(80vh, 800px);

Syntax highlighting theme

By default, the Prism syntax highlighting theme we use is oneLight in light mode and vsDark in dark mode. To use a different theme, you can provide it in the theme.syntaxHighlighter prop.

For example, to use the dracula theme:

import { themes } from "prism-react-renderer";

const inkeepProps = {
  theme: {
    syntaxHighlighter: {
      lightTheme: themes.dracula, // theme used in light mode
      darkTheme: themes.dracula, // theme used in dark mode
    },
  },
};

You can use published Prism themes or create your own.

Dark mode

Controlling the color mode

By default, the widgets will be rendered in light mode, to change the color mode use the forcedColorMode prop in the colorMode object of the baseSettings.

//..
baseSettings: {
  // ...
  colorMode: {
    forcedColorMode: 'dark', // options: 'light' or dark'
  }
}

System color mode

To use the user’s system preference color mode, set the enableSystem prop to true (by default it is false) in the colorMode object of baseSettings.

 baseSettings: {
  //...
  colorMode: {
      enableSystem: true,
    }
  }

Customize the icons

Bot avatar

The bot avatar can be customized by passing the botAvatarSrcUrl and / or botAvatarDarkSrcUrl (avatar to be used in dark mode) property to the aiChatSettings. If botAvatarDarkSrcUrl is not provided botAvatarSrcUrl will be used in dark mode as well.

User avatar

The user avatar can be customized by passing the userAvatarSrcUrl to the aiChatSettings.

import { type InkeepAIChatSettings } from "@inkeep/widgets";

export const aiChatSettings: InkeepAIChatSettings = {
  botAvatarSrcUrl: "http://example.com/bot-avatar.png",
  botAvatarDarkSrcUrl: "http://example.com/bot-avatar-dark-mode.png",
  userAvatarSrcUrl: "http://example.com/user-avatar.png",
  // ...rest of aiChatSettings
};

Custom icons

These icons can be used by passing a dictionary called customIcons in the baseSettings. See example.

PropertyTypeDescription
searchCustomIconSearch icon in search bar.
thumbsUpCustomIconThumbs up icon.
thumbsDownCustomIconThumbs down icon.
messageCopyCustomIconCopy message icon.
codeCopyCustomIconCopy code icon in code header.
openLinkInNewTabCustomIconUsed in the search result content header and on hover in the chat citations.
openLinkInSameTabCustomIconUsed on hover in chat citations if shouldOpenLinksInNewTab is false.
linkIndicatorCustomIconLink icon next to search result.
newLineCustomIconArrow icon in front of search result.
breadcrumbSeparatorCustomIconBreadcrumb separator icon.
switchToSearchCustomIconSwitch to search icon.
switchToChatCustomIconSwitch to chat icon.
chatSubmitCustomIconChat submit icon.
closeCustomIconClose icon.
infoCustomIconInfo icon next to the disclaimer and chat mode toggle.
commandCustomIconCommand icon in search bar.
enterCustomIconEnter key icon (for switch to chat).

CustomIcon

Can either be builtIn or custom

PropertyTypeDescription
builtInAvailableBuiltInIconsPass in the name of an icon that is already included in the widgets package.
customstringURL of icon image.

If the url for a custom icon is a .svg file it will be rendered as an <svg>, all other file types will be rendered using an <img> tag.

Custom icons example

import { type InkeepWidgetBaseSettings } from "@inkeep/widgets";

export const baseSettings: InkeepWidgetBaseSettings = {
  customIcons: {
    search: { builtIn: "IoSearch" }, // ex. using builtIn
    thumbsUp: { custom: "/path/to/thumbs-up.svg" }, // ex. using custom
    thumbsDown: { custom: "/path/to/thumbs-down.svg" },
    messageCopy: { custom: "/path/to/message-copy.svg" },
    codeCopy: { custom: "/path/to/code-copy.svg" },
    openLinkInNewTab: { custom: "path/to/open-link-in-new-tab.svg" },
    openLinkInSameTab: { custom: "path/to/open-link-in-same-tab.svg" },
    linkIndicator: { custom: "path/to/link-indicator.svg" },
    newLine: { custom: "path/to/new-line.svg" },
    breadcrumbSeparator: { custom: "path/to/breadcrumb-separator.svg" },
    switchToSearch: { custom: "/path/to/switch-to-search.svg" },
    switchToChat: { custom: "/path/to/switch-to-chat.svg" },
    chatSubmit: { custom: "/path/to/chat-submit.svg" },
    close: { custom: "/path/to/close.svg" },
    info: { custom: "/path/to/info.svg" },
    command: { custom: "/path/to/command.svg" },
    enter: { custom: "/path/to/enter.svg" },
  },
  // ...rest of baseSettings
};

Custom CSS and styling

Additional customization can be done via CSS stylesheets. Because the Inkeep widgets are isolated via a shadom DOM, any custom styling must be passed to the widget configuration in order for them to be applied.

Via stylesheetUrls

Pass the url(s) of the stylesheet(s):

const inkeepEmbeddedChatProps: InkeepEmbeddedChatProps = {
  stylesheetUrls: ["cdn.com/path-to-stylesheet.css"],
  baseSettings: {
    // ... typeof InkeepWidgetBaseSettings
  },
  //...
};

The urls can be relative or absolute.

Via stylesheets

Alternatively if using React, you may instead pass an array of <link> or <style> tags to the stylesheets property. Please ensure that each element has a unique key. For example:

const inkeepEmbeddedChatProps: InkeepEmbeddedChatProps = {
  stylesheets: [
    <link
      key="my-stylesheet-key"
      rel="stylesheet"
      href="cdn.com/path-to-stylesheet.css"
    />,
  ],
  baseSettings: {
    // ... typeof InkeepWidgetBaseSettings
  },
  //...
};

Hosting the stylesheet

Please ensure that stylesheets are in valid, publicly accessible URLs and correctly load. If a stylesheet does not load, the Inkeep widgets will not render.

You can host your stylesheet in a CDN or include it as part of the public assetts exposed in an existing application.

For example:

If using Next.js, you can create a css file within the public folder and then pass that url to the stylesheetUrls prop. For example:

// for this example there is a file in the public folder is called inkeep.css

const inkeepEmbeddedChatProps: InkeepEmbeddedChatProps = {
  stylesheetUrls: ["/inkeep.css"],
  baseSettings: {
    // ... typeof InkeepWidgetBaseSettings
  },
  //...
};

Class names

Below is a list of class names and their corresponding component part:

Main widget containers

classNameElement
.ikp-ai-chat-page-wrapperEmbeddedChat
.ikp-search-bar-trigger__containerSearchBar
.ikp-floating-buttonChatButton
.ikp-modal-widget__containerModal
classNameElement
.ikp-search-bar-trigger__wrappersearch bar trigger
.ikp-search-bar-trigger__containersearch bar trigger
.ikp-search-bar-trigger__iconsearch bar trigger
.ikp-search-bar-trigger__search-iconsearch bar trigger
.ikp-search-bar-trigger__kbdsearch bar trigger
.ikp-kbd-shortcut-iconsearch bar trigger
.ikp-search-bar-stand-alone__search-iconsearch bar modal
.ikp-search-bar-stand-alone__search-inputsearch bar modal
.ikp-search-bar-stand-alonesearch bar modal
.ikp-switch-to-chat-buttonsearch bar modal
.ikp-switch-to-chat-button__shortcutsearch bar modal
.ikp-switch-to-chat-iconsearch bar modal
.ikp-enter-iconsearch bar modal
.ikp-search-result-tabssearch results
.ikp-search-result-tabs__listsearch results
.ikp-search-result-tabsearch results
.ikp-search-result-tabsearch results
.ikp-search-result-tab__contentsearch results
.ikp-search-result-content__breadcrumbssearch results
.ikp-search-result-content__headersearch results
.ikp-heading-tree__titledocumentation results
.ikp-heading-tree__listdocumentation results
.ikp-heading-tree__itemdocumentation results
.ikp-heading-tree__headingdocumentation results
.ikp-new-line-icondocumentation results
.ikp-preview-contentsearch results
.ikp-preview-content__highlightsearch results
.ikp-preview-content-header__headingsearch results
.ikp-preview-content-header__titlesearch results
.ikp-link-indicator-iconsearch results
.ikp-open-link-in-new-tab-iconsearch results
.ikp-open-link-in-same-tab-iconsearch results
.ikp-taglinesearch footer

AI chat

classNameElement
.ikp-ai-chat-page-wrapperai chat
.ikp-ai-chat__scrollable-page-wrapperai chat
.ikp-ai-chat__headerai chat
.ikp-ai-chat__header-toolbarai chat
.ikp-ai-chat__scrollable-page-contentai chat
.ikp-ai-chat__scrollable-page-content__innerai chat
.ikp-messages__wrappermessages
.ikp-messages__errormessages
.ikp-message__wrappermessage
.ikp-message__divider-wrappermessage
.ikp-message__dividermessage
.ikp-chat-bubble__wrapperchat bubble
.ikp-chat-bubble__user-messagechat bubble (user)
.ikp-chat-bubble__bot-messagechat bubble (bot)
.ikp-chat-bubble__message-content-wrapperchat bubble
.ikp-chat-bubble__user-message-content-wrapperchat bubble
.ikp-chat-bubble__user-message-contentchat bubble
.ikp-chat-bubble__message-actionschat bubble
.ikp-chat-bubble__message-actions-copychat bubble
.ikp-thumbs-up-down__wrapperthumbs up and down
.ikp-thumbs-up__buttonthumbs up button
.ikp-thumbs-up-iconthumbs up icon
.ikp-thumbs-down__buttonthumbs down button
.ikp-thumbs-down-iconthumbs down icon
.ikp-message-headerai chat
.ikp-message-header__avatar-boxai chat
.ikp-bot-avatar__boxai chat
.ikp-quick-questions__labelquick questions
.ikp-quick-question-button__wrapperquick questions
.ikp-quick-question-button__highlightquick questions
.ikp-quick-question-buttonquick questions
.ikp-ai-chat__disclaimerdisclaimer
.ikp-ai-chat__disclaimer-labeldisclaimer
.ikp-disclaimer-icondisclaimer
.ikp-ai-chat-footer__content-wrapperchat footer
.ikp-ai-chat-footer__contentchat footer
.ikp-ai-chat-footerchat footer
.ikp-ai-chat-footer__footerchat footer
.ikp-ai-chat__message-box-wrappermessage box
.ikp-ai-chat__message-boxmessage box
.ikp-ai-chat__message-box-rowmessage box
.ikp-ai-chat__send-iconsubmit chat icon
.ikp-ai-chat__message-inputmessage input
.ikp-ai-chat__send-buttonsubmit chat button
.ikp-taglinechat footer
.ikp-get-help__buttonget help
.ikp-get-help__menuget help
.ikp-get-help__menu-itemget help
.ikp-get-help__menu-item-linkget help
.ikp-ai-chat__toolbarai chat modal
.ikp-ai-chat__toolbar-headerai chat modal
.ikp-switch-to-search-buttonai chat modal
.ikp-switch-to-search-iconai chat modal
.ikp-citation-sources-headerai chat
.ikp-result-cardresult card
.ikp-result-card--focusedresult card (focused state)
.ikp-result-card__containerresult card
.ikp-result-card__container--focusedresult card (focused state)
.ikp-result-card__bodyresult card
.ikp-result-card__contentresult card
.ikp-result-card__content-textresult card
.ikp-result-card__iconai chat
.ikp-result-card__hover-iconai chat
.ikp-search-result-line__firstresult card
.ikp-search-result-line__secondresult card
.ikp-bread-crumb-separatorresult card
.ikp-codeblock-containercode block
.ikp-codeblock-headercode block
.ikp-codeblock-header__language-wrappercode block
.ikp-codeblock-header__languagecode block
.ikp-codeblock-header__copy-button-wrappercode block
.ikp-codeblock-header__copy-buttoncode block
.ikp-copy-code-iconcode block
.ikp-codeblock-highlighter-wrappercode block
.ikp-codeblock-highlightercode block
.ikp-content-parser__supmessage content
.ikp-content-parser__sup-linkmessage content
.ikp-content-parser__textmessage content
.ikp-content-parser__olmessage content
.ikp-content-parser__limessage content
.ikp-content-parser__codemessage content
.ikp-loading__dotsai chat
.ikp-loading__dotai chat
.ikp-loading__status-textai chat

Chat button

classNameElement
.ikp-floating-buttonchat button
.ikp-floating-button-boxchat button
.ikp-chat-button__textchat button
.ikp-bot-avatar__boxchat button
classNameElement
.ikp-modal-widget__containermodal container
.ikp-modal-widget__contentmodal content
.ikp-modal__backdropmodal overlay

Using Inkeep CSS variables

Inkeep CSS variables can be utilized within stylesheets to customize elements. For example, the Chat Button uses a dark gray color by default. You can use the .ikp-floating-button and any of the pre-defined theme color tokens or any color of your choice to customize it:

.ikp-floating-button {
  background: var(--ikp-colors-inkeep-primary-medium);
}

Dark mode style overrides

To apply a specific style for dark mode only, utilize the [data-theme='dark'] attribute. For example:

[data-theme="dark"] .ikp-floating-button {
  background: #353e52;
}