noteloom

Theming & styling

<NoteloomEditor> auto-injects noteloom's own default theme — a minimal, Notion/Linear-adjacent look — as a single <style> tag in <head> the moment it mounts. There's nothing to import and nothing to configure: install the package, render an editor, and it's already styled. (The granular <EditorProvider> underneath does the actual injecting — NoteloomEditor just forwards theme/className/style/getBlockClassName straight to it, so everything below applies identically either way.)

The default theme is new since 0.1.1; per-block class names (getBlockClassName, below) landed in 0.1.2. Earlier versions shipped no default styling at all — every .be-* class was left entirely to the host app.

Retheme it

The default theme reads every color, radius, shadow, and font from --noteloom-* CSS custom properties defined on :root. Override any of them in your own stylesheet, loaded after noteloom's (ordinary CSS cascade — no build step needed):

css
:root {
  --noteloom-accent: #16a34a;      /* swap the indigo accent for green */
  --noteloom-radius-md: 4px;       /* sharper corners */
  --noteloom-font: 'Inter', sans-serif;
}
PropertyControls
--noteloom-fontBase font stack.
--noteloom-text / -text-muted / -text-faintText color scale.
--noteloom-bg / -bg-subtle / -bg-hoverSurface colors.
--noteloom-borderDefault border color.
--noteloom-accent / -accent-text / -accent-soft / -accent-soft-hoverPrimary accent (selection, active states, links).
--noteloom-danger / -danger-softDestructive actions (delete buttons, warnings).
--noteloom-radius-sm / -md / -lg / -xlCorner radius scale.
--noteloom-shadowPopover/menu/modal elevation.
--noteloom-code-bg / -code-textCode block colors.

These variables are deliberately defined on :root, not scoped to a wrapper element — several pieces of the editor (Select's popover, SlashMenu, FloatingToolbar, the table header menu, the block gutter/range menus, Modal) are portaled to document.body, so they aren't DOM descendants of wherever you render the editor itself — scoping to a wrapper class would silently fail to reach them.

Dark mode

The default theme follows prefers-color-scheme automatically. To control it explicitly instead (e.g. your own light/dark toggle rather than the OS setting), set data-theme="dark" or data-theme="light" on any ancestor element (typically <html>) — an explicit attribute always wins over the media query.

Scoping overrides to one editor instance

Pass className and/or style to <NoteloomEditor> to wrap children in one <div className="be-root ..."> — the natural hook for scoping --noteloom-* overrides (or full custom CSS) to just that editor, when a page renders more than one:

jsx
<NoteloomEditor editor={editor} className="my-editor" />
css
.my-editor { --noteloom-accent: #16a34a; }

No wrapper <div> is added unless you pass one of these props — existing usage that doesn't need it is completely unaffected.

Per-block class names

getBlockClassName(block), if given, is the per-block counterpart — every block component appends whatever string it returns onto its own root element's class list, so you can target individual blocks by type, id, or any of their props, not just the editor as a whole:

jsx
<NoteloomEditor
  editor={editor}
  getBlockClassName={(block) => (block.type === 'callout' ? 'my-callout' : '')}
/>

Opting out entirely

Pass theme="none" and nothing gets injected — you take full responsibility for styling every .be-* class yourself. Useful when you want a completely custom look with no default to override, or need to control exactly when CSS loads (e.g. a specific <link> order, or an SSR/CSP setup where runtime <style> injection isn't allowed) — the same theme is also published standalone at noteloom/style.css for that case:

jsx
import 'noteloom/style.css'; // optional — control load order yourself

<NoteloomEditor editor={editor} theme="none" />

This site's own editor (the Playground and Notes pages) takes exactly this route: a top-level @import 'noteloom/style.css' in its global stylesheet, loaded once, ahead of the rest of the site's own Tailwind-based CSS — plus theme="none" on every <EditorProvider> so the runtime auto-injection never duplicates it. It's the package's own real default theme, not a hand-rolled approximation — the same file described in this page.

See API reference for the full prop list, or Getting started for the minimal setup.