Styling
Components use Shadow DOM with ::part() selectors and BEM class names for styling flexibility.
Quick Start
Import the optional stylesheet, which styles every component (palette, cheatsheet, settings, context menus, radial menu):
import 'keybinds/styles/palette.css'Its colors follow the page's color-scheme: with :root { color-scheme: light dark } it's light or dark along with the system.
Theme Variables
Every color and font in the stylesheet comes from a custom property. Set them on :root (or on one component) to match your page:
:root {
--keybinds-bg: #fffaf3;
--keybinds-fg: #2b2118;
--keybinds-accent: #b4532a;
--keybinds-font: 'Inter', sans-serif;
}| Variable | Used for | Default |
|---|---|---|
--keybinds-bg | Dialog background | Canvas |
--keybinds-fg | Text | CanvasText |
--keybinds-muted | Secondary text | 60% of fg |
--keybinds-border | Borders, dividers | 16% of fg |
--keybinds-surface | Key caps, buttons | 7% of fg over bg |
--keybinds-accent | Matches, recording | Highlight |
--keybinds-accent-soft | Active row | 18% of accent |
--keybinds-warn | Binding conflicts | #c2410c |
--keybinds-backdrop | Behind dialogs | black at 45% |
--keybinds-shadow | Dialog shadow | |
--keybinds-radius | Dialog corners | 10px |
--keybinds-font, --keybinds-mono | Text, key caps | system fonts |
Selecting Components
Each component marks itself with data-keybinds="<kind>" when it's added to the page: command-palette, cheatsheet, settings, basic-context-menu, context-menu or radial-menu. Select by that rather than by tag name, so styles still apply if the component is registered under another name.
Custom Styles with ::part()
Target shadow DOM elements using CSS ::part():
[data-keybinds="command-palette"]::part(dialog) {
background: #fff;
border-radius: 12px;
}
[data-keybinds="command-palette"]::part(input) {
font-size: 18px;
}
[data-keybinds="command-palette"]::part(item-active) {
background: #0066cc;
color: white;
}Command Palette Parts
| Part | Description |
|---|---|
palette | Root container |
backdrop | Overlay behind dialog |
dialog | Main dialog box |
input | Search input field |
list | Results list (<ul>) |
item | Individual result (<li>) |
item-active | Currently selected item |
item-disabled | Inactive command (failing when) |
item-label | Command label text |
item-category | Category badge |
item-key | Keyboard shortcut (<kbd>) |
empty | "No results" message |
Cheatsheet Parts
| Part | Description |
|---|---|
cheatsheet | Root container |
backdrop | Overlay behind dialog |
dialog | Main dialog box |
group | Category group container |
group-title | Category heading |
list | Commands list (<ul>) |
item | Individual command (<li>) |
item-disabled | Inactive command |
item-label | Command label text |
item-keys | Container for key badges |
item-key | Individual key (<kbd>) |
Settings Parts
| Part | Description |
|---|---|
settings | Root container |
backdrop | Overlay behind dialog |
dialog | Main dialog box |
header | Header container |
title | Title text |
reset-all | Reset All button |
group | Category group container |
group-title | Category heading |
list | Commands list (<ul>) |
item | Individual command (<li>) |
item-label | Command label text |
item-bindings | Container for all bindings |
item-reset | Per-command reset button |
binding | Individual binding span |
binding-recording | Binding in recording state |
binding-keys | Key display container |
binding-key | Individual key (<kbd>) |
binding-remove | Remove (×) button |
binding-release | Press/release switch on a binding (binding-release-on while it is a release) |
item-add | Add binding container |
add-key | Add Key button |
add-mouse | Add Mouse button |
add-gamepad | Add Gamepad button (shown while a gamepad is connected) |
add-axis | Add a source to an axis |
recording-overlay | Recording prompt text |
recording-release | Release toggle in the recording prompt (recording-release-on while on) |
conflict | Conflict warning message |
conflict-accept | Replace button |
conflict-cancel | Cancel button |
Context Menu Parts
| Part | Description |
|---|---|
context-menu | Root container |
backdrop | Overlay behind menu (covers viewport) |
list | Menu list (<ul>) |
item | Individual menu item (<li>) |
item-active | Currently highlighted item |
item-disabled | Inactive command (failing when) |
separator | Category separator between groups |
item-label | Command label text |
item-keys | Container for shortcut keys |
item-key | Individual key (<kbd>) |
BEM Classes
Inside shadow DOM, elements have BEM class names matching their parts:
.palette
.palette__backdrop
.palette__dialog
.palette__input
.palette__list
.palette__item
.palette__item--active
.palette__item--disabled
...These are useful if you're styling via JavaScript or inspecting elements.
Example: Light Theme
keybinds-command-palette::part(backdrop) {
background: rgba(0, 0, 0, 0.3);
}
keybinds-command-palette::part(dialog) {
background: #ffffff;
border: 1px solid #e0e0e0;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1);
}
keybinds-command-palette::part(input) {
color: #333;
border-bottom: 1px solid #e0e0e0;
}
keybinds-command-palette::part(item) {
color: #333;
}
keybinds-command-palette::part(item-active) {
background: #f0f0f0;
}
keybinds-command-palette::part(item-key) {
background: #f5f5f5;
border-color: #ddd;
color: #666;
}Example: Glassmorphic
keybinds-command-palette::part(dialog) {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.2);
}Positioning
Override default positioning:
/* Center vertically */
keybinds-command-palette::part(dialog) {
top: 50%;
transform: translate(-50%, -50%);
}
/* Bottom sheet on mobile */
@media (max-width: 600px) {
keybinds-command-palette::part(dialog) {
top: auto;
bottom: 0;
left: 0;
right: 0;
transform: none;
width: 100%;
max-width: none;
border-radius: 12px 12px 0 0;
}
}