FrameworkJavaScript
Styles API: the class names tools should use
Access CSS class names for styling custom tools and UI elements.
Properties
| Property | Type | Description |
|---|---|---|
block | string | Access CSS class names for styling custom tools and UI elements. |
inlineToolButton | string | Access CSS class names for styling custom tools and UI elements. |
inlineToolButtonActive | string | Access CSS class names for styling custom tools and UI elements. |
input | string | Access CSS class names for styling custom tools and UI elements. |
loader | string | Access CSS class names for styling custom tools and UI elements. |
settingsButton | string | Access CSS class names for styling custom tools and UI elements. |
settingsButtonActive | string | Access CSS class names for styling custom tools and UI elements. |
settingsButtonFocused | string | Access CSS class names for styling custom tools and UI elements. |
settingsButtonFocusedAnimated | string | Access CSS class names for styling custom tools and UI elements. |
button | string | Access CSS class names for styling custom tools and UI elements. |
TypeScript
// Customize the editor from your host app via CSS custom properties —
// no need to target Blok's internal test IDs or data attributes.
// The hooks below are read with fallbacks and never declared by Blok, so
// they inherit from ANY ancestor — a plain container rule works:
.my-editor-container {
/* Cap the content column at a custom width (default: 720px) */
--blok-content-max-width: 650px;
/* Extra start padding on list blocks (default: 0px) */
--blok-list-padding-start: 18px;
/* Checklists follow --blok-list-padding-start unless this is set —
use it to indent checklists independently of other list styles */
--blok-checklist-padding-start: 0px;
/* Gap between a list marker/checkbox and its content (default: 0px) */
--blok-list-gap: 6px;
/* Padding of every block tool wrapper. Fallbacks keep each tool's own
default (7px/7px/2px for most blocks; quotes fall back to 0.2em
vertical, callouts to 5px). Tighten all three for compact read-only
inline rendering — no need to override [data-blok-tool]: */
--blok-block-padding-top: 0;
--blok-block-padding-bottom: 0.2em;
--blok-block-padding-inline: 0;
/* Placeholder color of empty blocks (default: follows --blok-gray-text) */
--blok-placeholder-color: rgba(112, 118, 132, 0.6);
/* Heading typography (defaults mirror the built-in scale) */
--blok-heading-1-font-size: 32px;
--blok-heading-font-weight: 600;
--blok-heading-margin-top: 16px;
--blok-heading-margin-bottom: 16px;
/* Space above embed blocks (default: 8px) */
--blok-embed-margin-top: 16px;
}
// Primary way to override theme tokens: style.tokens in the constructor
// config. Blok injects a per-instance stylesheet that reaches the editor
// AND UI portaled to document.body (popovers, tooltips, top-layer
// elements) automatically — no manual selector targeting needed.
new Blok({
style: {
tokens: {
'--blok-selection': 'rgba(35, 131, 226, 0.28)',
'--blok-popover-bg': '#1f1f1f',
// Surface backgrounds. Most hover/light surfaces follow
// --blok-bg-light; media empty-state cards use --blok-bg-secondary
// with --blok-border-secondary; image/file loading skeletons and
// upload placeholders use --blok-bg-tertiary, which defaults to
// --blok-bg-light. Override the specific token you mean — no need
// to overload --blok-bg-light to reach the skeleton surface.
// NOTE: palette-backed color tokens like these are re-declared by
// Blok on the editor wrapper itself, so set them here (or with a
// CSS selector matching the wrapper, as below) — a declaration on
// an ancestor container is shadowed and does nothing.
'--blok-bg-light': '#eff2f5',
'--blok-bg-secondary': '#f7f8fa',
'--blok-border-secondary': 'rgba(55, 53, 47, 0.09)',
'--blok-bg-tertiary': '#f0f0f0',
},
},
});
// CSS-only alternative: a plain host selector works too — Blok's palette
// is declared at zero specificity via :where(), so this always wins.
// Popovers/menus portal to document.body, so target them explicitly too.
[data-blok-interface],
[data-blok-popover],
[data-blok-top-layer] {
--blok-popover-bg: #1a1a1a;
/* Placeholder color of popover search inputs — wrapper-declared by Blok
(like the palette) and consumed inside body-mounted popovers, so set
it here or via style.tokens, never on an ancestor container: */
--blok-search-input-placeholder: rgba(112, 118, 132, 0.8);
}
// Blok reserves 56px of start gutter automatically in edit mode for the
// floating +/⠿ block controls, collapsing to 0 only when the gutter is
// dead space: chromeless read-only (data-blok-controls-hidden) or
// hideToolbar (data-blok-toolbar-hidden). Plain read-only keeps the
// gutter so in-place mode flips never shift the layout.
// The gutter tokens are declared on the wrapper by Blok (default + state
// collapses), so overrides MUST target the wrapper itself — an ancestor
// container rule is shadowed and does nothing. Set any value, including
// 0px to remove the gutter, or redeclare it to opt back into the
// reserved space while controls are hidden:
.my-editor-container [data-blok-interface] {
--blok-editor-gutter-start: 56px;
--blok-editor-gutter-end: 16px;
}
// Center the content column instead of left-aligning it (default: 'left')
const editor = new Blok({
holder: 'editor',
style: { contentAlign: 'center' },
});
// Flip theme tokens at runtime — e.g. from a host light/dark toggle.
// set() replaces the whole set, so tokens dropped from the new palette
// stop applying. Available immediately; calls before isReady are buffered.
editor.tokens.set({
'--blok-popover-bg': isDark ? '#1f1f1f' : '#ffffff',
'--blok-text-primary': isDark ? '#e6e6e6' : '#1a1a1a',
});
editor.tokens.get(); // -> currently applied tokens
// In React/Vue the same channel is a reactive prop (Angular: [styleTokens])
<BlokEditor style={{ tokens: isDark ? darkTokens : lightTokens }} />
// Opt out of Blok's ::selection repaint and use the native/host-defined
// selection colors instead (recoloring is possible via
// --blok-selection-inline; reverting to the UA default needs this flag)
new Blok({
holder: 'editor',
style: { nativeSelection: true },
});
// Access CSS class names for styling custom tools
const styles = editor.styles;
// Use class names in your custom tool
class MyCustomTool {
constructor({ api }) {
this.api = api;
}
render() {
const wrapper = document.createElement('div');
wrapper.className = this.api.styles.block;
const input = document.createElement('input');
input.className = this.api.styles.input;
const button = document.createElement('button');
button.className = this.api.styles.button;
button.textContent = 'Click me';
wrapper.appendChild(input);
wrapper.appendChild(button);
return wrapper;
}
}
// Available class names:
// - api.styles.block // Base block wrapper
// - api.styles.inlineToolButton // Inline toolbar button
// - api.styles.inlineToolButtonActive // Active inline tool
// - api.styles.input // Input elements
// - api.styles.loader // Loading spinner
// - api.styles.settingsButton // Settings button
// - api.styles.settingsButtonActive // Active settings
// - api.styles.settingsButtonFocused // Focused settings
// - api.styles.settingsButtonFocusedAnimated // Focused settings with click animation
// - api.styles.button // General button