Customizing the widget’s look
The widget ships with sensible defaults that work on light backgrounds. You can override any of that from your own site’s CSS — the widget honors a small set of CSS custom properties (variables) plus a set of Shadow DOM parts for cases where the variables aren’t specific enough.
You don’t need to do any of this. The widget looks fine untouched. But if your site has a strong brand you want the widget to inherit, or you’re running a dark theme, here’s how.
How customization works
The widget renders inside a Shadow DOM. That means your page’s global CSS can’t leak into the widget by accident — and, conversely, the widget’s internal styles can’t leak into your page. Two mechanisms cross that boundary intentionally:
- CSS custom properties (variables) — set them on your page (or on the
<ask-pod-widget>element itself) and the widget reads them from inside the Shadow DOM - CSS Shadow Parts (
::part()) — for elements explicitly labeled with apart=""attribute inside the widget, you can target them from outside using the::part()selector
Variables cover 90% of what customers want (colors, radius, font). Parts cover the rest.
Quick example
Say you’re a church with a warm brown-red brand color, using a serif on your site, and you want the widget to match.
Add this to your site’s global stylesheet:
ask-pod-widget {
--podsaid-accent: #8b3a1e;
--podsaid-accent-fg: #fff8f2;
--podsaid-font: 'EB Garamond', Georgia, serif;
--podsaid-radius: 4px;
} That’s it. The widget now uses your brand color for tabs, buttons, and focus states; renders body text in your serif; and uses squared-off corners instead of the default rounded ones.
CSS variables — the full list
Set any of these on the <ask-pod-widget> element (or anywhere they cascade from, like :root) to override the defaults.
Colors
| Variable | Default | Controls |
|---|---|---|
--podsaid-bg | transparent | Widget frame background |
--podsaid-fg | inherit | Main text color |
--podsaid-accent | #E05A2B | Active tab underline, primary buttons, focus rings, links |
--podsaid-accent-fg | currentColor | Text color on accent-colored backgrounds (e.g. Send button) |
--podsaid-muted | 60% of currentColor | Secondary text (dates, char counters, footer copy) |
--podsaid-surface | 6% of currentColor | Subtle secondary background (stat tiles, controls background) |
--podsaid-border | 15% of currentColor | Borders between tabs, around inputs, dividers |
--podsaid-error | #c00 | Error text and error state |
--podsaid-input | inherits from --podsaid-surface | Input field background |
--podsaid-input-fg | inherits from --podsaid-fg | Input field text |
The four “N% of currentColor” defaults use color-mix(in srgb, currentColor N%, transparent) — which means they automatically adapt to whatever text color they cascade under. If your page uses light text on a dark background, the widget’s borders and surfaces adapt without you doing anything.
Layout and sizing
| Variable | Default | Controls |
|---|---|---|
--podsaid-radius | 8px | Border radius on inputs, cards, tiles |
--podsaid-pane-height | 480px | Height of the main pane (chat/search area). Set to 100% if you want the widget to fill a bounded container |
Typography
| Variable | Default | Controls |
|---|---|---|
--podsaid-font | system-ui, sans-serif | Font family for all widget text |
Shadow Parts — targeting specific elements
When a CSS variable isn’t specific enough (say you want the Send button a different shape from other buttons), the widget exposes these named parts:
| Part | Element it targets |
|---|---|
widget | The outer widget container |
feed-header | The feed identity strip (avatar + name + info) above the tabs |
tabs | The tab container |
tab | Each individual tab (Ask, Search) |
pane | The active pane (chat or search) |
search-input | The search text input |
search-submit | The Search button |
chat-input | The chat textarea |
chat-send | The Send button |
result | Each search result row |
turn | Each chat turn (question or answer) |
citation | Each citation card inside an assistant answer |
Target from your global CSS with ::part():
/* Make just the Send button pill-shaped */
ask-pod-widget::part(chat-send) {
border-radius: 999px;
padding-inline: 1.25rem;
}
/* Highlight the active tab differently */
ask-pod-widget::part(tab) {
text-transform: uppercase;
letter-spacing: 0.08em;
font-size: 0.75rem;
}
/* Give search results a subtle card look */
ask-pod-widget::part(result) {
background: #fdfbf7;
border-left: 3px solid var(--podsaid-accent, #E05A2B);
} One catch: you can’t target descendants of a part with plain descendant selectors. ::part(result) p { ... } won’t work — the selector needs to end at the part boundary. If you need finer control, add another part attribute in a follow-up, or use CSS variables cascaded through the part.
Common recipes
Dark mode
@media (prefers-color-scheme: dark) {
ask-pod-widget {
--podsaid-bg: #0f172a;
--podsaid-fg: #f1f5f9;
--podsaid-accent: #f97316;
--podsaid-accent-fg: #0f172a;
--podsaid-border: rgba(255, 255, 255, 0.15);
--podsaid-surface: rgba(255, 255, 255, 0.06);
}
} Because the widget uses color-mix for --podsaid-muted, --podsaid-border, and --podsaid-surface, you often only need to set --podsaid-fg and --podsaid-accent for a dark theme — the derived colors adapt automatically.
Fill a full-height sidebar
If you’re embedding in a fixed-height sidebar container (e.g. a right-side widget slot), tell the widget to fill it:
.my-sidebar ask-pod-widget {
--podsaid-pane-height: 100%;
display: block;
height: 100%;
} Match a church’s Google-Fonts pairing
<!-- Load the fonts once at the top of your <head> -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link href="https://fonts.googleapis.com/css2?family=Merriweather:wght@400;700&display=swap" rel="stylesheet"> ask-pod-widget {
--podsaid-font: 'Merriweather', Georgia, serif;
} The widget’s Shadow DOM inherits the font because font resources on the page cascade in.
Brand-color the launcher without changing anything else
ask-pod-widget {
--podsaid-accent: #2c6e49;
--podsaid-accent-fg: white;
} Since the Send button, active tab underline, and focus ring all read from --podsaid-accent, one variable change updates all of them consistently.
When customization doesn’t take effect
- You forgot the widget renders in Shadow DOM. Rules like
ask-pod-widget button { ... }don’t work — you can’t reach inside from outside. Use variables or::part(). - You set the variable on a parent that isn’t in the widget’s inheritance chain. Safest: set on
ask-pod-widgetitself, or on:root. - The variable name is misspelled. They’re all
--podsaid-*, not--pod-said-*or--podsaid_*. Autocomplete in your editor helps. - A more-specific selector inside the widget wins. Rare, but the widget’s internal styles sometimes use
!importantwhen the layout would otherwise break. If a variable seems ignored, DevTools → Elements → click the shadow root → inspect the specific element to see what rule won.
What’s stable
Variable and part names are considered public API for the widget. Additions come in minor versions; renames or removals only in major versions. See the widget’s stability principles for the policy.
Related
- WordPress — pastes the snippet; your global CSS reaches it
- Squarespace — Code Block for the snippet, Custom CSS for the customization
- Next.js — put your customization CSS in a global stylesheet imported from your root layout
- Allowed origins — the security allowlist