Theming
Every color the Angular components draw comes from a --listens-* CSS custom property. The kit ships a light and a dark value for each one and switches between them on its own, so you only set the tokens you want to change.
Change a color
Set the token on :root in your global stylesheet, src/styles.css. The kit's own styles sit in a cascade layer, @layer listens, and plain CSS always beats a layer, so your value wins without !important.
src/styles.css
:root {
/* Labels and content while the mic is open. */
--listens-accent: #7c3aed;
/* Focus, highlighted options, and checkbox, radio and slider fills. */
--listens-interactive: #7c3aed;
}
Keep :root rules in styles.css. Angular scopes a component's own styles to
that component's elements, so a :root rule in a component stylesheet never
matches.
A value set this way applies in light and dark mode alike. To give dark mode its own value, see different colors in light and dark.
Light and dark mode
The components, the listening bar and the popup follow the device's light or dark setting automatically. To switch them yourself, set data-listens-theme to "dark" or "light" on the <html> element, and remove it to follow the device again. The components only read the attribute there, so it has no effect on an inner element.
document.documentElement.setAttribute('data-listens-theme', 'dark');
The Angular setup has a dark mode switch built from a <listens-toggle>, so people can tap it or say "dark mode".
Different colors in light and dark
Dark mode turns on in two ways: the device is set to dark, or your app sets data-listens-theme="dark". Cover both with the same selectors the kit uses:
src/styles.css
:root {
--listens-accent: #7c3aed;
}
/* The device is dark, and the app hasn't forced light. */
@media (prefers-color-scheme: dark) {
:root:not([data-listens-theme='light']) {
--listens-accent: #a78bfa;
}
}
/* The app forced dark. */
:root[data-listens-theme='dark'] {
--listens-accent: #a78bfa;
}
Theme one part of a page
Custom properties are inherited, so a token set on any element reaches every component inside it, including through Angular's style scoping. Give a section a class and set its tokens there, in styles.css or in that component's own styles:
checkout.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-checkout',
template: `
<section class="checkout">
<!-- …every component in here uses the green -->
</section>
`,
styles: `
.checkout {
--listens-accent: #0a7c42;
--listens-interactive: #0a7c42;
--listens-success: #0a7c42;
}
`,
})
export class Checkout {}
This also keeps a section light on a dark page, or dark on a light one: set the whole palette on it, using the values in the token reference.
Style one component
Tokens restyle every component at once. To change just one, give it a class. Angular components have no className input; the ordinary class attribute does the same job, and Angular keeps the kit's own classes beside yours. Because tokens are inherited, a class can retheme that one component:
src/styles.css
.danger-toggle {
--listens-success: #e53935;
}
<listens-toggle
class="danger-toggle"
label="Delete my data"
command="delete my data"
/>
To restyle a component's parts, target the kit's CSS classes, which plain CSS also overrides without a fight. Each component's page lists its classes, state attributes and tokens under Styling hooks, for example the label button's. Those parts belong to the kit's components, so put rules for them in styles.css, where Angular's scoping doesn't apply.
The listening bar and popup
The bar and the popup have their own stylesheet, with frosted light and dark backgrounds, so the tokens don't change them. They follow the device and data-listens-theme like the components do. Their colors are inputs instead: waveColor on both, and backgroundColor and textColor on the popup. See the listening bar and popup page.
Token reference
The web kits share these tokens, so the same CSS restyles Angular and React.
| Token | Light | Dark |
|---|---|---|
| Listening signal | ||
--listens-accentLabels and content while the mic is open. The one color every control shares. | #ff0000 | #ff0000 |
| Text | ||
--listens-textPrimary control text. | #222222 | #ededed |
--listens-text-secondaryValues and secondary readouts. | #444444 | #c2c2c2 |
--listens-labelField labels. | #666666 | #a6a6a6 |
--listens-text-mutedIdle toggle button text and “no results” messages. | #888888 | #8f8f8f |
--listens-text-subtleIcons, empty states, delete buttons and disabled text. | #999999 | #7d7d7d |
--listens-text-strongThe strongest emphasis, such as the selected ring. | #000000 | #ffffff |
--listens-on-accentText and icons on an accent fill. | #ffffff | #ffffff |
--listens-placeholderInput placeholders. | #9a9a9a | #7d7d7d |
| Surfaces and borders | ||
--listens-surfaceInputs, menus, list items and cards. | #ffffff | #2a2a2a |
--listens-borderDefault borders and input outlines. | #d0d0d0 | #4a4a4a |
--listens-border-subtleFaint dividers. | #e0e0e0 | #3a3a3a |
--listens-button-borderThe soft edge around buttons. | rgba(0, 0, 0, 0.12) | rgba(255, 255, 255, 0.13) |
--listens-button-faceButton fill. | #efefef | #6b6b6b |
--listens-on-buttonText on a button fill. | #222222 | #ffffff |
--listens-menu-hairlineThe edge of the combobox menu. | rgba(0, 0, 0, 0.05) | rgba(255, 255, 255, 0.12) |
--listens-ringThe selection ring’s shadow. | rgba(0, 0, 0, 0.2) | rgba(255, 255, 255, 0.28) |
| Interactive | ||
--listens-interactiveFocus, highlighted options, and checkbox, radio and slider fills. | #007aff | #0a84ff |
--listens-successThe toggle’s track when on. | #4caf50 | #46c463 |
--listens-trackThe toggle’s track when off. | #dddddd | #555555 |
--listens-toggle-thumbThe toggle’s thumb. | #ffffff | #f0f0f0 |
--listens-segment-onA checked toggle button’s fill. | #64b5f6 | #0a84ff |
--listens-segment-on-borderA checked standalone toggle button’s border. | #2196f3 | #409cff |
--listens-dangerDestructive hovers, such as delete. | #e53935 | #ff6b6b |