Customization guides

Style the components

Customize the search and chat widgets to match your brand.

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",
      },
    },
  }
}

Font sizes

Customize the font sizes that are used throughout the widget. Below are the default font size tokens.

//...
baseSettings: {
  //...
  theme: {
    tokens: {
      fontSizes: {
        '3xs': '0.45rem',
        '2xs': '0.625rem',
        xs: '0.75rem',
        sm: '0.875rem',
        md: '1rem',
        lg: '1.125rem',
        xl: '1.25rem',
        '2xl': '1.5rem',
        '3xl': '1.875rem',
        '4xl': '2.25rem',
        '5xl': '3rem',
        '6xl': '3.75rem',
        '7xl': '4.5rem',
        '8xl': '6rem',
        '9xl': '8rem',
      },
    },
  }
}

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>
<div
  style="display: flex; align-items: center; justify-content: center; height: calc(100vh - 16px);"
>
  <div style="max-height: 600px; height: 100%;">
    <div id="ikp-embedded-chat-target"></div>
  </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>
<div style="display: block; position: relative; height: calc(100vh - 16px);">
  <div
    style="max-height: 600px; height: 100%; position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%);"
  >
    <div id="ikp-embedded-chat-target"></div>
  </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>
<div style="min-height: 600px; height: calc(100vh - 16px);">
  <div
    style="max-width: 750px; max-height: 600px; height: 100%; width: 100%; min-width: 0px;"
  >
    <div id="ikp-embedded-chat-target"></div>
  </div>
</div>

Tip
Tip

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/uikit";
 
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 on hover in chat citations and search results if shouldOpenLinksInNewTab is true.
openLinkInSameTabCustomIconUsed on hover in chat citations and search results if shouldOpenLinksInNewTab is false.
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.

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 InkeepBaseSettings } from "@inkeep/uikit";
 
export const baseSettings: InkeepBaseSettings = {
  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" },
    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" },
  },
  // ...rest of baseSettings
};

Custom CSS and styling

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

InkeepStyleSettings

PropertyTypeDescription
stylesheetUrlsstring[]Array of URLs to stylesheets with style overrides.
stylesheetsReactElement[]Array of <link> or <style> tags with style overrides.

Via stylesheetUrls

Pass the URL(s) of the stylesheet(s). While the URLs can be either relative or absolute, it is recommended to use absolute URLs, such as those from a CDN. If using a relative path please ensure that the file is bundled and published publicly and is accessible on all pages where the widget is rendered.

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

When using the JS Snippet, you can also define the styles inline and encode them as a URL, this is particularly useful if you don't want to create a new stylesheet or if you cannot easily add external stylesheets to your project.

const inkeepStyleString = ".ikp-floating-button { color:  #000000; }";
const encodedStyles = encodeURIComponent(inkeepStyleString);
const stylesheetLink = `data:text/css;charset=UTF-8,${encodedStyles}`;
 
const inkeepEmbeddedChatProps: InkeepEmbeddedChatProps = {
  baseSettings: {
    // ... typeof InkeepBaseSettings
    theme: {
      stylesheetUrls: [stylesheetLink],
    },
  },
  //...
};

Via stylesheets

Alternatively if using the React component, 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 = {
  baseSettings: {
    // ... typeof InkeepBaseSettings
    theme: {
      stylesheets: [
        <link
          key="my-stylesheet-key"
          rel="stylesheet"
          href="cdn.com/path-to-stylesheet.css"
        />,
      ],
    },
  },
  //...
};

You can also inline the styles and pass them to a style tag instead.

const styleOverrides = `
  .ikp-floating-button {
    color:  #000000;
  }
`;
 
// be sure to provide a unique key
const styleTag = <style key="style-tag-1">{styleOverrides}</style>;
 
const inkeepEmbeddedChatProps: InkeepEmbeddedChatProps = {
  baseSettings: {
    // ... typeof InkeepBaseSettings
    theme: {
      stylesheets: [styleTag],
    },
  },
  //...
};

Hosting the stylesheet

Note
Note

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 assets 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 = {
  baseSettings: {
    // ... typeof InkeepBaseSettings
    theme: {
      stylesheetUrls: ["/inkeep.css"],
    },
  },
  //...
};

Gatsby

If using Gatsby, you can create a static folder in the root of your project, then create a css file for the Inkeep widget style overrides, this will then get copied to the public folder, then you can pass the url to the stylesheetUrls prop. For example:

// for this example there is a file in the static folder is called inkeep.css
 
const inkeepEmbeddedChatProps: InkeepEmbeddedChatProps = {
  baseSettings: {
    // ... typeof InkeepBaseSettings
    theme: {
      stylesheetUrls: ["/inkeep.css"],
    },
  },
  //...
};

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-ask-ai-cardsearch bar modal
.ikp-switch-to-chat-iconsearch bar modal
.ikp-search-result-tabssearch results
.ikp-search-result-tabs__listsearch 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-preview-contentsearch results
.ikp-preview-content__highlightsearch results
.ikp-search-result-line__firstsearch results
.ikp-search-result-line__secondsearch results
.ikp-result-card__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
.ikp-switch-view-togglemodal view toggle wrapper
.ikp-switch-view-toggle__buttonmodal view toggle button
.ikp-switch-view-toggle__button--activemodal view toggle button (active)

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;
}