Skip to content
FrameworkJavaScript

Styles API: the class names tools should use

Access CSS class names for styling custom tools and UI elements.

Properties

PropertyTypeDescription
blockstringAccess CSS class names for styling custom tools and UI elements.
inlineToolButtonstringAccess CSS class names for styling custom tools and UI elements.
inlineToolButtonActivestringAccess CSS class names for styling custom tools and UI elements.
inputstringAccess CSS class names for styling custom tools and UI elements.
loaderstringAccess CSS class names for styling custom tools and UI elements.
settingsButtonstringAccess CSS class names for styling custom tools and UI elements.
settingsButtonActivestringAccess CSS class names for styling custom tools and UI elements.
settingsButtonFocusedstringAccess CSS class names for styling custom tools and UI elements.
settingsButtonFocusedAnimatedstringAccess CSS class names for styling custom tools and UI elements.
buttonstringAccess 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