# Customize themes
URL: /Themes/
## Task
Describe how to build and apply `UiTheme` and `Theme` objects to customize Storyteller colors, typography, layout primitives, player chrome, and Poll and Quiz styling, and how the global, view, and remote themes combine.
## Metadata
- Slug: themes
- Source: public-docs/Themes.md
- Audience: Frontend engineers and designers responsible for Storyteller branding
- Platforms: Web
- Related: StorytellerListView, StorytellerRowView, StorytellerGridView, PrivacyAndTracking
## Overview
- Defines the global theme (`Storyteller.sharedInstance.theme`), a view's theme (`theme` in the view's `configuration`), and the remote theme that Storyteller configures for a tenant or feed.
- Shows setting the global theme after `initialize` resolves and setting a view theme with `view.configuration = { theme }`.
- Explains precedence: the view theme value, then the global theme value, then the default. The view theme merges over the global theme, and a view value equal to the default does not override the global value.
- Explains that every `initialize` call resets the global theme to defaults; a theme in a view's `configuration` is kept.
- Explains that the view's `uiStyle` (`light`, `dark`, `auto`) selects the `light` or `dark` `Theme`; `auto` follows `prefers-color-scheme`.
- Catalogs theme sections (`colors`, `font`, `primitives`, `lists`, `storyTiles`, `player`, `clipPlayer`, `buttons`, `instructions`, `engagementUnits`) with defaults and data types, and marks `player.icons.share`, `engagementUnits.poll.selectedAnswerBorderImage`, and `engagementUnits.poll.showPercentBarBackground` as not used by the Web SDK.
- Documents settings that only the remote theme controls: captions, compact Clip action buttons, and Clip like and share counts, including the version 11.0 caption merge and default changes.
## When To Use
- Consult this guide when aligning Storyteller views with brand guidelines or customizing one view.
- Refer to it when auditing which theme property controls a UI element (for example Poll answer colors or scroll indicators).
- Refer to it when a theme change does not appear: check the `initialize` reset, precedence, and whether the setting belongs to the remote theme.
## Integration Steps
1. Call `initialize` and wait for it to resolve.
2. Create `const theme = new Storyteller.UiTheme({ light: { ... }, dark: { ... } })` or set properties on `theme.light` and `theme.dark`.
3. Assign it with `Storyteller.sharedInstance.theme = theme`. Assign it again after you change a property and after any later `initialize` call.
4. For one view, set `view.configuration = { theme: viewTheme }`. Values that differ from the defaults override the global theme for that view and the player it opens.
5. Adjust base sections (`colors`, `font`, `primitives`) first so dependent properties inherit the values, then fine-tune lists, tiles, players, buttons, instructions, and Polls and Quizzes.
6. Provide custom image URLs for icons or indicators when needed (20 × 20 px action button icons, 48 × 48 px PNG instruction icons).
7. Ask Storyteller to change captions, compact Clip action buttons, or like and share counts in the remote theme.
## API Cheat Sheet
- `new Storyteller.UiTheme({ light, dark })`: Creates a theme object with light and dark `Theme` values.
- `Storyteller.sharedInstance.theme = myTheme`: Applies the global theme and updates existing views. A later property change has no effect until you assign the theme again. Each `initialize` call resets it to defaults.
- `view.configuration = { theme: viewTheme }`: Merges `viewTheme` over the global theme for that view only.
- `uiStyle`: `light`, `dark`, or `auto` (follows `prefers-color-scheme`) selects `theme.light` or `theme.dark`.
- Enums: `Storyteller.Alignment.start|center|end` (tile title and chip alignment), `Storyteller.ButtonAlignment.left|center|right` (`player.actionButton.alignment`), `Storyteller.TextCase.upper|lower|default` (`buttons.textCase`).
- `lists.grid.startInset` and `lists.grid.endInset` (default 16) set the space on the left and right of a grid. `storyTiles.title.fontWeight` (default 700) sets the tile title weight.
- `circularTile.liveChip` and `rectangularTile.liveChip` accept `unreadBackgroundGradient` (replaces `unreadBackgroundColor` on unread chips), `readBorderColor`, and `unreadBorderColor` (one-pixel inner border), all default `null`, for Live and pinned chips. Story content supplies `customLiveChipText` and `pinnedChipText`.
- `instructions.icons`: object with optional `forward`, `back`, `swipe`, `pause` image URLs (default `{}`). Set it on `theme.light.instructions` and `theme.dark.instructions`.
- `clipPlayer.showClipTitle: false`: Hides the Clip title while a supplied long description remains available in expandable details.
- Remote `behavior.player.clipsActionButtonCompactSize`: `true` shows compact action buttons in the Clip details area. The default is `false`. Storyteller sets it for the feed. Versions before 11.0 ignored it.
- Remote `showLikeCount` and `showShareCount`: a feed value overrides the tenant value, then the default `true`. Versions before 11.0 ignored them.
- Captions use the remote `theme.behavior.player.captions` fields. Each valid feed field overrides its tenant field; each padding axis follows the same rule. Defaults: system font stack, 16 px text, natural line height, `#FFFFFF` text, `#171A25` background at 0.65 opacity, 10 px horizontal and 4 px vertical padding, and 8 px corner radius. Zero padding and radius are supported. Each rendered line has its own background with a 2 px gap, and alignment follows LTR or RTL. Versions before 11.0 used the feed caption settings as one object, with 18 px text, a 22 px line height, and a `#000000` background.
- With captions enabled for the content type, the CC button stays available on Clips and supported Story Pages regardless of track presence, loading, or failure. A missing or unavailable track does not interrupt playback. Ads and Poll or Quiz Pages hide the control. Live Clips show the CC button but no caption text. The user's choice applies to Clips and Stories and is stored in the browser only when functional cookies are allowed.
- Clip captions appear after the Clip starts playing and stay visible while paused. Preloaded Clips and Clips not in view hide their captions. Caption text changes as soon as the next cue starts. The Story CC button sits 16 px from the lower-right corner and moves up to 72 px from the bottom on a Page with an action button.
- Major theme sections: `colors`, `font`, `primitives`, `lists`, `storyTiles`, `player`, `clipPlayer`, `buttons`, `instructions`, `engagementUnits`.
## Examples
- Sets the global theme inside `initialize(...).then(...)`.
- Sets a view theme with `configuration = { theme }` to change row tile spacing.
- Recolors built-in instruction icons, and replaces them with custom images on both the light and dark themes.
- Creates a `UiTheme` with constructor values, changes nested properties, and assigns it globally.
## Pitfalls / Notes
- Set the global theme after `initialize` resolves; each `initialize` call, including a user change, resets it.
- Assign the theme again after changing its properties.
- A view theme value equal to the SDK default does not override the global value.
- `UiTheme` can't change remote theme settings (captions, compact Clip action buttons, like and share counts).
- Some properties derive defaults from others; changing a base color may also change chips, indicators, or other elements.
- Image-based overrides expect direct URLs or data strings; HTML strings are not supported.
- `player.icons.share`, `engagementUnits.poll.selectedAnswerBorderImage`, and `engagementUnits.poll.showPercentBarBackground` are not used by the Web SDK.
- Future SDK versions may use a property for more elements.
## Cross-References
- StorytellerListView (Configure views) documents the `theme` and `uiStyle` configuration options.
- StorytellerRowView and StorytellerGridView show where these theme options appear in rows and grids.
- Privacy and Tracking explains `enableFunctionalCookies`, which controls whether the caption choice is stored.
- The Storyteller Web Showcase builds a static theme in `buildBasicTheme`.
## Canonical Reference
# Customize themes
A theme sets the colors, font, spacing, and controls of Storyteller views and
players. You can set a theme in two places:
- The **global theme**, `Storyteller.sharedInstance.theme`, applies to every
view and player on the page.
- A **view's theme**, the `theme` in that view's `configuration`, changes one
view and the player it opens.
Both take a `UiTheme` object. Storyteller also applies a **remote theme**:
theme settings that Storyteller configures for your tenant or for a feed. The
remote theme controls [captions](#closed-captions),
[compact Clip action buttons](#compact-clip-action-buttons), and Clip like and
share counts. You can't change these settings with `UiTheme`.
## Set the global theme
Set the global theme after `initialize` resolves:
```javascript
Storyteller.sharedInstance.initialize('demo-api-key').then(() => {
const myTheme = new Storyteller.UiTheme();
myTheme.light.colors.primary = '#FF2D00';
myTheme.dark.colors.primary = '#FF2D00';
Storyteller.sharedInstance.theme = myTheme;
});
```
The SDK applies the theme when you assign it, and views that already exist
update. If you change a property later, assign the theme again.
## Set a view's theme
To style one view differently, set `theme` in its `configuration`:
```javascript
const storiesRow = new Storyteller.StorytellerStoriesRowView(
'storyteller-stories-row',
['category-id']
);
const rowTheme = new Storyteller.UiTheme();
rowTheme.light.lists.row.tileSpacing = 4;
rowTheme.dark.lists.row.tileSpacing = 4;
storiesRow.configuration = { theme: rowTheme };
```
!!! info "Learn more"
For all view configuration options, see [Configure views](StorytellerListView.md#theme).
The Storyteller Web Showcase builds a static theme in
[`buildBasicTheme`](https://github.com/getstoryteller/storyteller-showcase-web/blob/11.0.0/nextjs/src/helpers/buildBasicTheme.ts#L77).
## Theme precedence
For each `UiTheme` property, the SDK uses the first value it finds:
1. The value in the view's `configuration.theme`
2. The value in the global theme, `Storyteller.sharedInstance.theme`
3. The default value in the tables on this page
The view's theme is merged over the global theme. A view theme value that
equals the default doesn't override the global value.
`initialize` resets the global theme. Each `initialize` call, including a call
after the user changes, sets `Storyteller.sharedInstance.theme` back to the
defaults. Set the global theme after `initialize` resolves, and set it again
after any later `initialize` call. A theme in a view's `configuration` is kept.
The remote theme is separate from `UiTheme`, and `UiTheme` values don't
override it:
- [Captions](#closed-captions): each valid caption field in the feed's remote
theme overrides the same field in the tenant's remote theme. Missing fields
use the tenant value, then the default.
- [Compact Clip action buttons](#compact-clip-action-buttons): the feed's
remote theme turns them on. The default is `false`.
- [Like and share counts](#clip-player): a feed value overrides the tenant
value. The default is `true`.
## Configure a UiTheme {#configuring-a-uitheme}
A `UiTheme` has two properties:
- `light`: the `Theme` used in light mode
- `dark`: the `Theme` used in dark mode
The view's [`uiStyle`](StorytellerListView.md#uistyle) selects which one
applies: `light`, `dark`, or `auto`. With `auto`, the view follows the
browser's `prefers-color-scheme` setting. Set a property in both `light` and
`dark` when it should not change with the color scheme.
## Theme properties {#creating-themes}
The `Theme` object contains every property you can customize.
Some properties take their default value from others. For example, setting
`colors.primary` to `#FF0000` also colors the unread indicator on rectangular
tiles red. The tables mark these properties with "inherits".
Future SDK versions may use a property for more elements.
### Colors
The `colors` property sets the base colors that the SDK uses.
| Property | Default Value | Data Type | Description |
| ----------------- | ------------------------------ | ----------------------------- | ---------------------------------------------------------------------------------------------------- |
| `primary` | `#1C62EB` | `string` - CSS color property | The default accent color used throughout the UI. In general, this should be the primary brand color. |
| `success` | `#3BB327` | `string` - CSS color property | Used to indicate correct answers in Quizzes. |
| `alert` | `#E21219` | `string` - CSS color property | Used to indicate incorrect answers in Quizzes. |
| `white.primary` | `#FFFFFF` | `string` - CSS color property | Used for white text |
| `white.secondary` | `white.primary` at 85% opacity | `string` - CSS color property | Used for light text |
| `white.tertiary` | `white.primary` at 70% opacity | `string` - CSS color property | Used for gray text |
| `black.primary` | `#1A1A1A` | `string` - CSS color property | Used for black text |
| `black.secondary` | `black.primary` at 85% opacity | `string` - CSS color property | Used for light black text |
| `black.tertiary` | `black.primary` at 70% opacity | `string` - CSS color property | Used for gray text |
| `focusIndicator` | `colors.primary` | `string` - CSS color property | Used for the focus outlines of interactive elements |
### Font
Set `font` to a CSS `font-family` value to use a custom font throughout the
SDK. The default value is `inherit`.
### Primitives
The `primitives` object contains base values that the SDK uses throughout.
| Property | Default Value | Data Type | Description |
| -------------- | ------------- | --------- | -------------------------------------------------------------------------------------- |
| `cornerRadius` | `4` | `number` | The corner radius in pixels used for rectangular tiles, buttons, and Poll/Quiz answers |
### Lists
The `lists` property sets the layout of rows and grids.
| Property | Default Value | Data Type | Description |
| ------------------------------------------ | ------------------------------------------------------------------------------ | ----------------------------- | --------------------------------------------------------------------------------------------------------- |
| `lists.backgroundColor` | inherits `colors.white.primary` for `light`, `colors.black.primary` for `dark` | `string` - CSS color property | Used for the outline on the Live chip and the fade at the sides of a row. |
| `lists.row.tileSpacing` | `8` | `number` | The (external) space between each Story Tile in a row |
| `lists.row.startInset` | `12` | `number` | The (external) space before the first Story Tile in a row |
| `lists.row.endInset` | `12` | `number` | The (external) space after the last Story Tile in a row |
| `lists.row.startPadding` | `0` | `number` | The (internal) space before the first Story Tile in a row |
| `lists.row.endPadding` | `0` | `number` | The (internal) space after the last Story Tile in a row |
| `lists.row.showScrollIndicator` | `true` | `boolean` | Whether the scroll indicator should be visible on non-touch screens (it's always hidden on touch screens) |
| `lists.row.scrollIndicatorBackgroundColor` | `white` | `string` - CSS color property | The background color of the scroll indicator |
| `lists.row.scrollIndicatorColor` | `rgba(26, 26, 26, 0.7)` | `string` - CSS color property | The color of the scroll indicator icon. Ignored if `scrollIndicatorIcon` is set |
| `lists.row.scrollIndicatorIcon` | `undefined` | `string` - image URL | URL of a custom scroll indicator icon. HTML strings are not supported. |
| `lists.row.scrollIndicatorFade` | `true` | `boolean` | Used to show/hide the fade overlay on the edges of the Story row |
| `lists.row.scrollIndicatorInlineAlignment` | `inside` | `inside`, `outside` | Whether the scroll arrows should appear on top of the row (`inside`) or next to it (`outside`). |
| `lists.grid.tileSpacing` | `8` | `number` | The space between each Story Tile in a grid, both vertically and horizontally |
| `lists.grid.columns` | `2` | `number` | The number of columns in a grid |
| `lists.grid.topInset` | `12` | `number` | The space before the first row in a grid |
| `lists.grid.bottomInset` | `12` | `number` | The space after the last row in a grid |
| `lists.grid.startInset` | `16` | `number` | The space on the left side of a grid |
| `lists.grid.endInset` | `16` | `number` | The space on the right side of a grid |
### Story tiles
The `storyTiles` property sets the appearance of Story tiles.
| Property | Default Value | Data Type | Description |
| --------------------------------------------------- | -------------------------------------------------------------------------------- | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `chip.textSize` | `11` | `number` | Text size for the New Indicator and Live Indicator |
| `chip.show` | `true` | `boolean` | Used to show/hide the new/live chip |
| `title.textSize` | `11` | `number` | Size of the Story Title on a Tile |
| `title.lineHeight` | `13` | `number` | The line height of the Story Title on a Tile |
| `title.alignment` | `center` | `Alignment` (`Storyteller.Alignment.start`, `.center`, `.end`) | The alignment of the Story Title on a Tile. Possible values are `start`, `center` and `end` |
| `title.fontWeight` | `700` | `number` | The font weight (CSS `font-weight`) of the Story Title on a Tile |
| `circularTile.liveChip.readImage` | `null` | `string` - `
` `src` property | Image to be used in place of default read Live Indicator for circular tiles |
| `circularTile.liveChip.unreadImage` | `null` | `string` - `
` `src` property | Image to be used in place of default unread Live Indicator for circular tiles |
| `circularTile.liveChip.readBackgroundColor` | inherits `colors.black.tertiary` | `string` - CSS color property | Background color of the circular tiles Live Indicator when all Pages have been read |
| `circularTile.liveChip.unreadBackgroundColor` | inherits `colors.alert` | `string` - CSS color property | Background color of the circular tiles Live Indicator when the Story contains unread Pages |
| `circularTile.liveChip.unreadBackgroundGradient` | `null` | `string` - CSS gradient | Background of unread Live and pinned chips on circular tiles. When set, it replaces `unreadBackgroundColor`. See [Live chip gradient and borders](#live-chip-gradient-and-borders) |
| `circularTile.liveChip.readTextColor` | inherits `colors.white.primary` | `string` - CSS color property | Text color of the circular tiles Live Indicator when all Pages have been read |
| `circularTile.liveChip.unreadTextColor` | inherits `colors.white.primary` | `string` - CSS color property | Text color of the circular tiles Live Indicator when the Story contains unread Pages |
| `circularTile.liveChip.readBorderColor` | `null` | `string` - CSS color property | Color of the one-pixel inner border on read Live and pinned chips on circular tiles |
| `circularTile.liveChip.unreadBorderColor` | `null` | `string` - CSS color property | Color of the one-pixel inner border on unread Live and pinned chips on circular tiles |
| `circularTile.title.unreadTextColor` | inherits `colors.black.primary` for `light`, `colors.white.primary` for `dark` | `string` - CSS color property | The text color of the Story Title for a circular tile when the Story is unread |
| `circularTile.title.readTextColor` | inherits `colors.black.tertiary` for `light`, `colors.white.tertiary` for `dark` | `string` - CSS color property | The text color of the Story Title for a circular tile when the Story is read |
| `circularTile.unreadIndicatorColor` | inherits `colors.primary` | `string` - CSS color property or linear-gradient | The color of the ring around a circular tile when the Story is unread |
| `circularTile.readIndicatorColor` | `#C5C5C5` | `string` - CSS color property or linear-gradient | The color of the ring around a circular tile when the Story is read |
| `circularTile.unreadStrokeWidth` | `2` | `number` (in px) | The thickness of the ring around a circular tile when the Story is unread |
| `circularTile.readStrokeWidth` | `1` | `number` (in px) | The thickness of the ring around a circular tile when the Story is read |
| `circularTile.scrollIndicatorBlockAlignment` | `cell` | `cell`, `thumbnail` | Whether the scroll arrows should be centered with the whole cell (including the titles), or with the thumbnail. |
| `rectangularTile.liveChip.readImage` | `null` | `string` - `
` `src` property | Image to be used in place of default read Live Indicator for rectangular tiles |
| `rectangularTile.liveChip.unreadImage` | `null` | `string` - `
` `src` property | Image to be used in place of default unread Live Indicator for rectangular tiles |
| `rectangularTile.liveChip.readBackgroundColor` | inherits `colors.black.tertiary` | `string` - CSS color property | Background color of the rectangular tiles Live Indicator when all Story Pages have been read or the Clip has been viewed |
| `rectangularTile.liveChip.unreadBackgroundColor` | inherits `colors.alert` | `string` - CSS color property | Background color of the rectangular tiles Live Indicator when the Story contains unread Pages or the Clip has not been viewed |
| `rectangularTile.liveChip.unreadBackgroundGradient` | `null` | `string` - CSS gradient | Background of unread Live and pinned chips on rectangular tiles. When set, it replaces `unreadBackgroundColor`. See [Live chip gradient and borders](#live-chip-gradient-and-borders) |
| `rectangularTile.liveChip.readTextColor` | inherits `colors.white.primary` | `string` - CSS color property | Text color of the rectangular tiles Live Indicator when all Story Pages have been read or the Clip has been viewed |
| `rectangularTile.liveChip.unreadTextColor` | inherits `colors.white.primary` | `string` - CSS color property | Text color of the rectangular tiles Live Indicator when the Story contains unread Pages or the Clip has not been viewed |
| `rectangularTile.liveChip.readBorderColor` | `null` | `string` - CSS color property | Color of the one-pixel inner border on read Live and pinned chips on rectangular tiles |
| `rectangularTile.liveChip.unreadBorderColor` | `null` | `string` - CSS color property | Color of the one-pixel inner border on unread Live and pinned chips on rectangular tiles |
| `rectangularTile.title.textColor` | inherits `colors.white.primary` | `string` - CSS color property | The text color of the Story Title for a rectangular tile |
| `rectangularTile.padding` | `8` | `number` | The internal padding for a rectangular Story tile |
| `rectangularTile.chip.alignment` | `end` | `Alignment` (`Storyteller.Alignment.start`, `.center`, `.end`) | Alignment of the New Indicator and Live Indicator in Rectangular Tiles, can be `start`, `center` or `end`. |
| `rectangularTile.unreadIndicator.image` | `null` | `string` - `
` `src` property | An image which can be used in place of the default unread indicator for a rectangular tile |
| `rectangularTile.unreadIndicator.backgroundColor` | inherits `colors.primary` | `string` - CSS color property | The background color of the unread indicator for a rectangular tile |
| `rectangularTile.unreadIndicator.textColor` | inherits `colors.white.primary` | `string` - CSS color property | The text color of the unread indicator for a rectangular tile |
| `rectangularTile.showWebStoriesIcon` | `false` | `boolean` | Set this to true to show a Story icon on rectangular thumbnails |
| `rectangularTile.showGradient` | `true` | `boolean` | Set this to `false` to hide the gradient behind the Story title on rectangular cells |
#### Live chip gradient and borders
The Stories API can supply `customLiveChipText` for a Live Story or
`pinnedChipText` for a pinned Story. The SDK uses that text in the Story tile
chip. These fields come from Story content; they are separate from `UiTheme`.
Use the chip theme properties below to style their background and border on
round or rectangular tiles.
Both `circularTile.liveChip` and `rectangularTile.liveChip` accept these extra
properties:
- `unreadBackgroundGradient`: A CSS gradient string. Its default is `null`. A
set value replaces `unreadBackgroundColor` on unread Live or pinned chips.
- `readBorderColor`: A CSS color for the one-pixel inner border on a read Live
or pinned chip. Its default is `null`.
- `unreadBorderColor`: A CSS color for the one-pixel inner border on an unread
Live or pinned chip. Its default is `null`.


### Player
The `player` property sets options for the Story player.
| Property | Default Value | Data Type | Description |
| --------------------------- | ------------- | --------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `disableUrls` | `false` | `boolean` | Disable the hash URLs when opening a Story. Note that this will also disable sharing. |
| `showStoryIcon` | `true` | `boolean` | Shows the Story icon in the Player |
| `showShareButton` | `true` | `boolean` | Shows the share button in the Player. Setting this to `false` entirely disables sharing in Storyteller |
| `actionButton.icon` | `null` | `string` - image URL | URL of a 20 × 20 px custom icon to display in the action buttons. HTML strings are not supported. |
| `actionButton.showOnMobile` | `true` | `boolean` | Shows the action button on top of the player on small screens. If set to `false`, the action button will only be shown if there is sufficient space to display it underneath the player. |
| `actionButton.alignment` | `center` | `ButtonAlignment` (`Storyteller.ButtonAlignment.left`, `.center`, `.right`) | Sets the alignment of the action button on small screens. Possible values are `left`, `center` and `right`. If there is enough space for the button to sit underneath the player, it will always be centered. |
| `icons.back` | `null` | `string` - image URL or data string | An image to be used in place of the default Clips player back/close icon |
| `icons.share` | `null` | `string` - image URL or data string | Not used by the Web SDK. An image to be used in place of the default share icon |
| `playAllStories` | `false` | `boolean` | Set this to true to stop the player from closing after all unread Stories have been viewed |

### Clips player {#clip-player}
The `clipPlayer` property sets options for the Clips player.
To change the back or close icon at the top left of the Clips player, use
[`player.icons.back`](#player).
| Property | Default Value | Data Type | Description |
| -------------------------- | ------------- | --------- | ------------------------------------------------------------------------------------------ |
| `disableUrls` | `false` | `boolean` | Disable the hash URLs when opening a Clip. Note that this will also disable sharing. |
| `showShareButton` | `true` | `boolean` | Shows the share button in the Player. Setting this to `false` entirely disables sharing. |
| `showLikeButton` | `true` | `boolean` | Shows the like button in the Player. |
| `showFeedTitle` | `true` | `boolean` | Shows the feed title or feed title image in the Clips player header. |
| `showClipTitle` | `true` | `boolean` | Shows the active Clip title in the Clips player metadata. |
| `showNavigationCategories` | `true` | `boolean` | Shows Clip navigation categories and the active category title in the Clips player header. |
The remote theme sets whether the Clips player shows like and share counts. A
feed's `showLikeCount` or `showShareCount` value overrides the tenant value
for that feed. If the feed doesn't set a field, the tenant value applies, and
then the default, `true`. `UiTheme` doesn't include these fields. Before
version 11.0, the SDK ignored them, so tenants whose remote theme already sets
them see the change after the update.
`showClipTitle: false` hides the Clip title. A long description supplied with
the Clip remains available in the [expandable details](StorytellerListView.md#clip-details).
#### Compact Clip action buttons
The remote theme field `behavior.player.clipsActionButtonCompactSize` sets the
size of Clip action buttons. When it is `true`, the Clips player shows smaller
action buttons in the Clip details area. When it is `false`, the buttons span
the width below the Clip. If the remote theme doesn't set it, the value is
`false`.
To change it, ask Storyteller to set it for the feed. Before version 11.0, the
SDK ignored this field, so feeds that already set it show compact buttons
after the update. `UiTheme` still sets the button styles through
[`player.actionButton`](#player) and [`buttons`](#buttons).
### Captions {#closed-captions}
Captions stay off until Storyteller turns them on for Stories, Clips, or both.
The CC button then appears on Clips and on supported Story Pages, even when
the content has no caption track. It stays available while a track loads and
after an empty or failed response. A missing or unavailable track does not
interrupt playback. Ads and Poll or Quiz Pages hide the CC button.
Caption text appears when a Clip or Story Page has a WebVTT track with an
active cue. Clip captions appear after the Clip starts playing and stay
visible while it is paused. Clips that are preloaded or not in view keep their
captions hidden. Live Clips show the CC button but no caption text.
The user's caption choice applies to both Clips and Stories. When functional
cookies are allowed (`enableFunctionalCookies`, see
[Control privacy and tracking](PrivacyAndTracking.md)), the SDK stores the
choice in the browser. Otherwise, the choice lasts until the page reloads.
Story captions appear near the top of each supported Page. Poll and Quiz Pages
hide both the caption text and the CC button. The CC button sits 16 px from
the lower-right corner of the Story. On a Page with an action button, it moves
up to 72 px from the bottom. Caption text changes as soon as the next cue
starts.
Caption styling comes from the remote theme, not from `UiTheme`. Each valid
caption field in the feed's remote theme overrides the same field in the
tenant's remote theme. A missing or invalid feed field uses the tenant value,
then the default in the table below. The horizontal and vertical padding
follow this rule separately.
Version 11.0 changed this behavior. Earlier versions used the feed's caption
settings as one object whenever the feed had them, and their defaults were
18 px text, a 22 px line height, and a `#000000` background. If your captions
relied on those defaults, check them after you update.
Captions align to the start edge of the surrounding text direction: left for
LTR and right for RTL. Each rendered line has its own background, including
lines created by wrapping. The background height includes the text line height
and vertical padding. A 2 px gap separates consecutive backgrounds.
`lineHeight` controls the text area. The SDK adds padding and the gap when it
places the next line. Padding and corner radius accept zero.
| Remote theme field | Default value | Description |
| -------------------- | ------------------- | ---------------------------------------------- |
| `font` | System font stack | Caption font family, with system-font fallback |
| `textSize` | `16` | Font size in pixels |
| `lineHeight` | Natural font height | Line height in pixels |
| `textColor` | `#FFFFFF` | Caption text color |
| `backgroundColor` | `#171A25` | Caption background color |
| `backgroundOpacity` | `0.65` | Background opacity from `0` to `1` |
| `padding.horizontal` | `10` | Left and right padding in pixels |
| `padding.vertical` | `4` | Top and bottom padding in pixels |
| `cornerRadius` | `8` | Background corner radius in pixels |
### Buttons
The `buttons` property sets the style of buttons throughout the SDK.
| Property | Default Value | Data Type | Description |
| ----------------- | ---------------------------------- | --------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| `backgroundColor` | inherits `colors.white.primary` | `string` - CSS color property | The background color of buttons throughout the SDK |
| `textColor` | inherits `colors.black.primary` | `string` - CSS color property | The text color of buttons throughout the SDK |
| `textCase` | `default` | `TextCase` (`Storyteller.TextCase.upper`, `.lower`, `.default`) | Sets the text case for buttons throughout the SDK. Possible values are `upper`, `lower` and `default` |
| `cornerRadius` | inherits `primitives.cornerRadius` | `number` | The corner radius for all buttons throughout the SDK |
### Instructions
The `instructions` property sets the appearance of the instructions screen.
| Property | Default Value | Data Type | Description |
| ------------------------ | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `show` | `true` | `boolean` | Determines whether the Instructions Screen is shown the first time a user opens the Story player. Set to `false` to completely disable the instructions screen. |
| `headingColor` | inherits `colors.black.primary` for `light`, `colors.white.primary` for `dark` | `string` - CSS color property | The color of the heading text on the Instructions Screen |
| `iconColor` | inherits `headingColor` | `string` - CSS color property | The foreground color of the built-in instruction icons |
| `iconHighlightColor` | inherits `colors.primary` | `string` - CSS color property | The highlight color of the built-in instruction icons |
| `subHeadingColor` | inherits `colors.black.secondary` for `light`, `colors.white.secondary` for `dark` | `string` - CSS color property | The color of the subheading text on the Instructions Screen |
| `backgroundColor` | inherits `colors.white.primary` for `light`, `colors.black.primary` for `dark` | `string` - CSS color property | The color of the background of the Instructions Screen |
| `icons` | `{}` | object with optional `forward`, `back`, `swipe`, `pause` image URLs | A set of custom icons to be used for each instruction on the Instructions Screen |
| `button.backgroundColor` | inherits `colors.black.primary` for `light`, `colors.white.primary` for `dark` | `string` - CSS color property | The background color of the button used on the Instructions Screen |
| `button.textColor` | inherits `colors.white.primary` for `light`, `colors.black.primary` for `dark` | `string` - CSS color property | The text color of the button used on the Instructions Screen |
`iconColor` and `iconHighlightColor` recolor every built-in instruction icon.
This includes the pointer icons on non-touch devices and the touch and swipe
icons on touch devices. By default, the icon color follows `headingColor` and
the highlight follows `colors.primary`. These properties don't change the
heading or subheading text colors.
```javascript
const theme = new Storyteller.UiTheme();
theme.light.colors.primary = '#ff2d00'; // Built-in icon highlights inherit this
theme.light.instructions.iconColor = '#2b2929';
theme.dark.instructions.iconColor = '#f5f2f2';
Storyteller.sharedInstance.theme = theme;
```
Use `icons` to replace the image for any instruction. A custom image replaces
the built-in icon and its theme colors for that instruction. Built-in icons
without a custom image still follow the theme colors. Use 48 × 48 px PNG
images:
```javascript
const theme = new Storyteller.UiTheme();
const customIcons = {
forward: './icon-forward-custom.png',
pause: './icon-pause-custom.png',
back: './icon-back-custom.png',
swipe: './icon-swipe-custom.png',
};
theme.light.instructions.icons = customIcons;
theme.dark.instructions.icons = customIcons;
Storyteller.sharedInstance.theme = theme;
```

### Polls and Quizzes (`engagementUnits`) {#engagement-units}
The `engagementUnits` property sets the style of Polls and Quizzes.
| Property | Default Value | Data Type | Description |
| -------------------------------- | -------------------------------- | ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `poll.answerTextColor` | inherits `colors.black.primary` | `string` - CSS color property | The text color used for Poll Answers |
| `poll.percentBarColor` | `#CDD0DC` | `string` - CSS color property | The background color of the percentage bar in Poll Answers |
| `poll.selectedAnswerBorderColor` | inherits `colors.white.tertiary` | `string` - CSS color property | The border color applied to the selected Poll Answer |
| `poll.answeredMessageTextColor` | inherits `colors.white.tertiary` | `string` - CSS color property | The color of the vote count shown to users after they select a Poll Answer |
| `poll.selectedAnswerBorderImage` | `null` | `string` or `null` | Not used by the Web SDK. A border image for the selected Poll Answer. The Web SDK uses `selectedAnswerBorderColor` |
| `poll.showVoteCount` | `true` | `boolean` | Shows the approximate number of Poll Answers after a user selects an answer. If this is set to `false`, the message "Thanks for voting!" is displayed instead |
| `poll.showPercentBarBackground` | `false` | `boolean` | Not used by the Web SDK. Adds a striped background under the percentage bar in Poll Answers |
| `triviaQuiz.correctColor` | inherits `colors.success` | `string` - CSS color property | The color used to show correct answers in Quizzes |
| `triviaQuiz.incorrectColor` | inherits `colors.alert` | `string` - CSS color property | The color used to show incorrect answers in Quizzes |


## Example
```javascript
const theme = new Storyteller.UiTheme({
light: {
colors: {
primary: 'blue',
success: 'green',
},
},
});
// Setting theme by direct property access
theme.light.colors.primary = 'red';
// Applying light/dark mode specific values
theme.light.instructions.headingColor = 'black';
theme.dark.instructions.headingColor = 'white';
Storyteller.sharedInstance.theme = theme;
```