Skip to main content
After this guide, the widget uses your colors, button, and header in both light and dark mode. Use the options first and CSS only for what they don’t cover: the widget renders inside a shadow root that your stylesheets never touch. Each option is described in the configuration reference. Before you begin
  • The widget installed and working, per the quickstart.
  • Your brand color as a CSS color value and, optionally, a 16 × 16 px icon at a public HTTPS URL.
1

Pin or follow the theme

theme defaults to "auto", which follows the end user’s operating-system preference; pin it when your site has one look.
2

Brand the button

buttonColor sets the background, buttonText the label, and buttonIcon an image URL that replaces the Lua logo. Emoji go in the text, never in the icon.
popupButtonStyles are inline styles, so use camelCase keys and plain values; a background here wins over buttonColor. Without buttonColor, the button uses the theme’s primary color, which no option sets; change that only with CSS in the shadow root (last step).
3

Place the button

position picks a corner, popupButtonPositionalContainerStyles adjusts the offsets, and draggable: true lets end users move the button when it covers something on the page.
4

Style the header

chatTitle and chatTitleHeaderStyles cover the header bar; chatHeaderSubtitle controls the “Powered by” line under it.
5

Optional: inject CSS into the shadow root

The widget mounts an open shadow root on #lua-shadow-root (#lua-shadow-root-embedded in embedded mode). After init() resolves, append a <style> element to it.
Class names in the deployed build: .lua-pop-widget on the fixed container, .lua-pop-button, .lua-pop-chat, .lua-pop-chat-header, .lua-close-button, and .lua-pop-chat-mobile-fullscreen on screens under 640 px and on phones and tablets. The composer is .lua-pop-input-region and its textarea has the id lua-pop-chat-input. Message bubbles carry .chat-message-bubble with .chat-message-bubble-user or .chat-message-bubble-agent, and rendered Markdown sits in .chat-markdown-content.
Class names are not a stable API, and the hosted script has no version pin: lua-pop.umd.js is replaced on every widget release. Keep shadow-root CSS small and recheck it after releases.
6

Verify

Reload the page, open the widget, and switch your operating system between light and dark mode. The button, the header, and any injected rules hold in both.

If it isn’t working

Page CSS cannot cross the shadow boundary. Use the options from the earlier steps, or inject a <style> into the shadow root as in the last step.
A background in popupButtonStyles overrides it. Set one or the other.
With draggable: true, the spot an end user chose is stored in their browser under the localStorage key luapop:pos:<agentId> and wins over position. Remove the key to reset it.

Next steps

Widget configuration

Every display option with its default.

Frameworks

Mount and clean up in React, Next.js, Vue, Angular, and Svelte.