Documentation

Attributes, slots, events and the class markup each element replaces.

Installation

CDN

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit@1.1.1/notionkit.min.css">
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.0.1/dist/notionkit-elements.min.js"></script>

npm

npm install @jungherz-de/notionkit-elements @jungherz-de/notionkit

import '@jungherz-de/notionkit/notionkit.css';
import '@jungherz-de/notionkit-elements';

Single component

import '@jungherz-de/notionkit-elements/components/nk-btn.js';

Prerequisites

Load notionkit.css on the document and put class="nk-body" on <body>. The shadow roots inherit font, colour and the scoped reset from there; the elements ship no visual CSS of their own. The bundle additionally injects the design tokens as a cascade layer (@layer notionkit-defaults), so a page without the stylesheet still renders, and any unlayered :root { --nk-* } of yours wins.

<html lang="en" data-theme="light">
  <head>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit@1.1.1/notionkit.min.css">
    <script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.0.1/dist/notionkit-elements.min.js"></script>
  </head>
  <body class="nk-body">
    <nk-btn variant="primary">Save</nk-btn>
  </body>
</html>

Hosts are display: contents

Every <nk-*> host is display: contents: it generates no box of its own, so the inner .nk-* element takes part in the parent layout exactly where the class markup would – a button stays inline, a sidebar is a direct flex child of the app, a tree row and its children box are siblings. That is what makes the pixel parity hold. Consequence: style the parent (or the tokens), not the host; hidden on the host still works; getBoundingClientRect() of a host is empty.

<!-- βœ“ spacing on a wrapper you own -->
<div style="margin-top:16px"><nk-btn variant="primary">Save</nk-btn></div>

<!-- βœ— the host has no box; this margin does nothing -->
<nk-btn style="margin-top:16px" variant="primary">Save</nk-btn>

Theming & branding

Set data-theme="light|dark" on <html> – nowhere else. One observer mirrors it into every element. To re-brand, declare tokens on :root in a plain stylesheet: every element follows, in both themes.

<style>
  :root { --nk-accent: #16a34a; }
  [data-theme="dark"] { --nk-accent: #4ade80; }
</style>
<script>document.documentElement.dataset.theme = 'dark';</script>

Forms

Form controls are form-associated custom elements: inside a <form> they appear in FormData, follow reset, honour required and <fieldset disabled>. Outside a form value and events still work, but nothing is submitted.

<form id="f">
  <nk-field label="Display name"><nk-input name="name" required></nk-input></nk-field>
  <nk-field label="Email notifications"><nk-switch name="notify" checked></nk-switch></nk-field>
  <nk-btn type="submit" variant="primary">Save</nk-btn>
</form>
<script>
  f.addEventListener('submit', e => { e.preventDefault(); console.log([...new FormData(f)]); });
</script>

Light-DOM children

Elements that copy their children (nk-select options, breadcrumb crumbs) watch them with a MutationObserver, so a framework that swaps children keeps the element in step. element.refresh() is the escape hatch. The empty string is a valid value.

const sel = document.querySelector('nk-select');
sel.innerHTML = roles.map(r => `<option value="${r.id}">${r.name}</option>`).join('');
// the shadow <select> follows; sel.value is preserved when the option still exists

Passing icons

::slotted() only matches the assigned node itself. Pass an icon as a direct child with the slot name – never wrapped in a container.

<!-- βœ“ the icon is the slotted node -->
<nk-callout><span slot="icon">πŸ“Œ</span>…</nk-callout>

<!-- βœ— wrapped: ::slotted() cannot reach the inner node -->
<nk-callout><span slot="icon"><em>πŸ“Œ</em></span>…</nk-callout>

Overlays

Put nk-modal, nk-cmdk and nk-toast directly under <body>. Inside a transformed or clipping container a fixed overlay is trapped.

Editor

NotionKit ships no editor. nk-block-host is the optical shell; mount TipTap into a light-DOM .nk-block-host with the recipe below (the demo app uses exactly this file). <nk-editor>, a thin TipTap wrapper, follows in v1.1 as an optional import – never part of the core bundle.

<!-- the shell: hover wash, focus ring, drag handle -->
<div class="nk-block-host" id="editor">
  <p>Server-rendered content becomes the initial document.</p>
</div>

<!-- the recipe: TipTap + slash menu + bubble menu + block handle (docs-editor.js) -->
<script type="module" src="docs-editor.js"></script>

docs-editor.js Β· live in the demo app

Forms & controls

Wave 1

<nk-btn> Button

Renders button.nk-btn, or a.nk-btn when href is set. Modifier classes become attributes. A slotted <svg> is sized by the stylesheet – pass it directly, never wrapped.

Wave 1
Save Cancel Delete
<nk-btn variant="primary">Save</nk-btn>
<nk-btn variant="secondary">Cancel</nk-btn>
<nk-btn variant="danger" small>Delete</nk-btn>

Attributes

AttributeTypeDefaultDescription
variantprimary | secondary | danger | danger-solid | topbar | share–Visual variant. topbar and share render .nk-topbar-btn for the top bar.
smallboolean–Compact padding and 12.5px text.
disabledboolean–Disabled; clicks are swallowed.
typebutton | submit | resetbuttonFor submit/reset the surrounding <form> is submitted or reset.
hrefURL–Renders a link instead of a button.

Slots

SlotDescription
(default)Label text and an optional <svg> icon.

Events

EventdetailDescription
click(native, composed)The native click bubbles out of the shadow root.
On a small screen:Unchanged. The button grows with its label; combine with small in dense toolbars.
Replaces.nk-btn.primary.secondary.danger.danger-solid.small.nk-topbar-btn.nk-share-btn

<nk-input> Input

A native <input> inside the shadow root, wired into the surrounding form through ElementInternals: FormData, reset and required validation work as with a plain input.

Wave 1
<nk-input name="name" value="Ada Lovelace" placeholder="Display name"></nk-input>

Attributes

AttributeTypeDefaultDescription
valuestring–Current value; also the reset value.
typetext | email | password | number | date | …textForwarded to the native input.
placeholderstring–Placeholder text.
namestring–Form field name (FormData key).
disabledboolean–Disables the control.
requiredboolean–Marks the field required; validity is mirrored onto the host.
readonlyboolean–Read-only.
wideboolean–Full width (.wide).

Slots

none

Events

EventdetailDescription
nk-change{ value, name }Fired on commit (blur/Enter), like the native change event.
nk-input{ value, name }Fired on every keystroke.

Properties: value name disabled required form validity

Methods: focus() blur() select() checkValidity() reportValidity()

On a small screen:Minimum width 210px; use wide to fill the row.
Replaces.nk-input.wide

<nk-textarea> Textarea

Multi-line sibling of nk-input. The initial value is the value attribute or the element’s text content.

Wave 1
<nk-textarea name="bio" rows="3" placeholder="A sentence about you"></nk-textarea>

Attributes

AttributeTypeDefaultDescription
valuestring–Current value.
placeholderstring–Placeholder text.
rowsnumber–Visible rows.
namestring–Form field name (FormData key).
disabledboolean–Disables the control.
requiredboolean–Required field.
wideboolean–Full width.

Slots

SlotDescription
(default)Initial text (used when value is absent).

Events

EventdetailDescription
nk-change{ value, name }On commit.
nk-input{ value, name }On every keystroke.
On a small screen:Resizes vertically only; wide fills the row.
Replaces.nk-textarea.wide

<nk-select> Select

Light-DOM <option> and <optgroup> children are copied into the shadow <select> and kept in step when a framework swaps them. The empty string is a valid value; a value naming no option leaves the selection alone.

Wave 1
<nk-select name="role" value="editor">
  <option value="viewer">Viewer</option>
  <option value="editor">Editor</option>
  <option value="admin">Admin</option>
</nk-select>

Attributes

AttributeTypeDefaultDescription
valuestring–Selected value.
namestring–Form field name (FormData key).
disabledboolean–Disables the control.
requiredboolean–Required field.
compactboolean–120px minimum width (.compact), e.g. inside a member row.

Slots

SlotDescription
(default)<option> / <optgroup> children – direct children only.

Events

EventdetailDescription
nk-change{ value, name }On selection.

Properties: value selectedIndex options

Methods: refresh()

On a small screen:Uses the native picker of the platform (color-scheme follows the theme).
Replaces.nk-select.compact

<nk-switch> Switch

Renders button.nk-switch[role=switch]; the stylesheet keys the knob on aria-checked, the element does the toggling. Submits value (default on) when checked, nothing otherwise – like a checkbox.

Wave 1
<nk-switch name="notify" checked label="Email notifications"></nk-switch>

Attributes

AttributeTypeDefaultDescription
checkedboolean–On/off state.
namestring–Form field name (FormData key).
disabledboolean–Disables the control.
valuestringonSubmitted value when checked.
labelstring–Accessible name (aria-label).

Slots

none

Events

EventdetailDescription
nk-change{ checked, value, name }On toggle.

Methods: toggle()

On a small screen:34Γ—20px – below the 44px touch target. Give it a label row (nk-field) to enlarge the hit area.
Replaces.nk-switch

<nk-check> Checkbox

A label.nk-check with a custom-drawn checkbox; the label text is slotted, so clicking it toggles the box.

Wave 1
Weekly digest Mentions only
<nk-check name="digest" value="weekly" checked>Weekly digest</nk-check>
<nk-check name="digest" value="mentions">Mentions only</nk-check>

Attributes

AttributeTypeDefaultDescription
checkedboolean–Checked state.
indeterminateboolean–Mixed state (cleared on the next click).
namestring–Form field name (FormData key).
disabledboolean–Disables the control.
valuestringonSubmitted value.
requiredboolean–Must be checked to submit.

Slots

SlotDescription
(default)Label text.

Events

EventdetailDescription
nk-change{ checked, value, name }On toggle.
On a small screen:Row height ~24px; the whole label is the hit area.
Replaces.nk-check

<nk-radio> Radio

Same optics as nk-check with a round mark. Radios with the same name in the same tree and form form one group – across shadow roots, which native radios cannot do. One tab stop per group; arrow keys move, wrap and skip disabled entries. There is deliberately no nk-radio-group.

Wave 1
Concise Balanced Detailed
<nk-radio name="style" value="concise">Concise</nk-radio>
<nk-radio name="style" value="balanced" checked>Balanced</nk-radio>
<nk-radio name="style" value="detailed">Detailed</nk-radio>

Attributes

AttributeTypeDefaultDescription
checkedboolean–Selected; the last checked radio in markup wins.
namestring–Form field name (FormData key).
disabledboolean–Disables the control.
valuestring–Submitted value.
requiredboolean–One of the group must be selected.

Slots

SlotDescription
(default)Label text.

Events

EventdetailDescription
nk-change{ checked, value, name }On selection, also via arrow keys.
On a small screen:As nk-check.
Replaces.nk-check

<nk-slider> Slider

A range input with accent-color from the tokens, plus an optional value readout below.

Wave 1
<nk-slider name="size" min="12" max="18" value="14" unit="px" show-value></nk-slider>

Attributes

AttributeTypeDefaultDescription
valuenumber–Current value.
minnumber–Minimum.
maxnumber–Maximum.
stepnumber–Step.
namestring–Form field name (FormData key).
disabledboolean–Disables the control.
show-valueboolean–Shows the value below the slider.
unitstring–Suffix for the readout (e.g. px).

Slots

none

Events

EventdetailDescription
nk-change{ value, name }On release.
nk-input{ value, name }While dragging.
On a small screen:210px wide; the native thumb is touch-sized by the platform.
Replaces.nk-slider.nk-slider-value

<nk-field> Field row

The settings row: label and description left, control right. Put any control – nk-input, nk-switch, nk-select – in the default slot.

Wave 1
<nk-field label="Display name" desc="Shown next to your comments.">
  <nk-input value="Ada Lovelace"></nk-input>
</nk-field>
<nk-field label="Email notifications">
  <nk-switch checked></nk-switch>
</nk-field>

Attributes

AttributeTypeDefaultDescription
labelstring–Label text.
descstring–Secondary description.

Slots

SlotDescription
(default)The control.
labelRich label content (instead of the attribute).
descRich description.

Events

none

On a small screen:Stays a row; long descriptions wrap under the label.
Replaces.nk-field.f-label.f-desc.f-control

Content elements

Wave 1

<nk-tag> Tag

Semantic status tag. The colour modifier class becomes the color attribute; each pair is tuned per theme.

Wave 1
In progress Done Planned Design
<nk-tag color="blue">In progress</nk-tag> <nk-tag color="green">Done</nk-tag> <nk-tag color="orange">Planned</nk-tag> <nk-tag color="purple">Design</nk-tag>

Attributes

AttributeTypeDefaultDescription
colorblue | green | orange | purple–Colour pair.

Slots

SlotDescription
(default)Tag text.

Events

none

On a small screen:Unchanged.
Replaces.nk-tag.blue.green.orange.purple

<nk-progress> Progress

A 60px bar with an optional label. value/max set the fill; the bar carries role="progressbar".

Wave 1
<nk-progress value="72" label="72%"></nk-progress>

Attributes

AttributeTypeDefaultDescription
valuenumber0Current value.
maxnumber100Maximum.
labelstring–Text after the bar.

Slots

none

Events

none

On a small screen:Unchanged.
Replaces.nk-progress.nk-progress-label

<nk-callout> Callout

One thought that must not be missed. The icon comes from the icon attribute or a slot="icon" node – the node itself, never wrapped.

Wave 1
Core idea: A callout carries one thought that must not be missed.
<nk-callout icon="πŸ’‘"><b>Core idea:</b> A callout carries one thought that must not be missed.</nk-callout>

Attributes

AttributeTypeDefaultDescription
iconstringπŸ’‘Emoji or text icon.

Slots

SlotDescription
(default)Body.
iconIcon node (e.g. <span slot="icon">πŸ“Œ</span>).

Events

none

On a small screen:Unchanged; wraps with the text.
Replaces.nk-callout.c-icon

<nk-divider> Divider

A hairline <hr> with block spacing.

Wave 1
<nk-divider></nk-divider>

Attributes

none

Slots

none

Events

none

On a small screen:Unchanged.
Replaces.nk-divider

<nk-heading> Heading

A section heading. level chooses the real heading element (h1–h4), so the document outline stays honest.

Wave 1
Section heading
<nk-heading>Section heading</nk-heading>

Attributes

AttributeTypeDefaultDescription
level1 | 2 | 3 | 42Heading level.

Slots

SlotDescription
(default)Heading text.

Events

none

On a small screen:Unchanged.
Replaces.nk-heading

<nk-toggle> Toggle block

A <details> block. The summary is rendered inside the element (its marker is a pseudo-element and cannot be styled on slotted content); the body is slotted.

Wave 1
Folded content lives here.
<nk-toggle label="Details" open>Folded content lives here.</nk-toggle>

Attributes

AttributeTypeDefaultDescription
labelstring–Summary text.
openboolean–Expanded state, reflected both ways.

Slots

SlotDescription
(default)Folded content.
labelRich summary content.

Events

EventdetailDescription
nk-toggle{ open }On open/close.
On a small screen:Unchanged.
Replaces.nk-toggle.toggle-body

<nk-todo> To-do

Checkbox line with strike-through when done. Form-associated like nk-check.

Wave 1
Write the docs Ship it
<nk-todo checked>Write the docs</nk-todo>
<nk-todo>Ship it</nk-todo>

Attributes

AttributeTypeDefaultDescription
checkedboolean–Done.
namestring–Form field name (FormData key).
disabledboolean–Disables the control.
valuestringonSubmitted value.

Slots

SlotDescription
(default)Task text.

Events

EventdetailDescription
nk-change{ checked, value, name }On toggle.
On a small screen:Unchanged.
Replaces.nk-todo

<nk-kbd> Key cap

A keyboard key, e.g. in shortcut hints.

Wave 1
⌘ K
<nk-kbd>⌘</nk-kbd> <nk-kbd>K</nk-kbd>

Attributes

none

Slots

SlotDescription
(default)Key label.

Events

none

On a small screen:Unchanged.
Replaces.nk-kbd

<nk-code> Code block

Pre-formatted block with a language badge. Whitespace is kept as written; escape < as &lt;. With highlight, HTML tags and attributes are coloured.

Wave 1
<nk-btn variant="primary">Save</nk-btn>
<nk-code lang="html" highlight>&lt;nk-btn variant="primary"&gt;Save&lt;/nk-btn&gt;</nk-code>

Attributes

AttributeTypeDefaultDescription
langstring–Language badge, top right.
highlightboolean–Colour HTML tags/attributes.

Slots

SlotDescription
(default)The code, as text.

Events

none

On a small screen:Scrolls horizontally instead of wrapping.
Replaces.nk-code.lang.tag.attr

<nk-quote> Quote

A block quote with an optional citation line.

Wave 1
The best interface is the one that gets out of the way.
<nk-quote cite="Unknown">The best interface is the one that gets out of the way.</nk-quote>

Attributes

AttributeTypeDefaultDescription
citestring–Citation text.

Slots

SlotDescription
(default)Quote text.

Events

none

On a small screen:Unchanged.
Replaces.nk-quote.q-cite

App shell & navigation

Wave 2

<nk-app> App shell

The outermost element of a workspace app: a full-height flex row with the sidebar slot left and main.nk-main right. Everything in the default slot – nk-topbar, nk-page – becomes a flex child of the main column.

Wave 2
<nk-app>
  <nk-sidebar slot="sidebar">
    <nk-workspace-switcher slot="workspace" name="MonaHilft"></nk-workspace-switcher>
    <nk-tree>
      <nk-tree-item icon="πŸ”">Search<span slot="end" class="nk-kbd-hint"><nk-kbd>⌘</nk-kbd><nk-kbd>K</nk-kbd></span></nk-tree-item>
      <nk-tree-item icon="🏠" active>Home</nk-tree-item>
      <nk-tree-item icon="πŸ“₯">Inbox</nk-tree-item>
    </nk-tree>
    <nk-tree-item slot="footer" icon="βš™οΈ">Settings</nk-tree-item>
  </nk-sidebar>
  <nk-topbar>
    <nk-breadcrumb><span>πŸ“Š Project overview</span></nk-breadcrumb>
    <nk-btn slot="actions" variant="share">Share</nk-btn>
    <nk-theme-toggle slot="actions"></nk-theme-toggle>
  </nk-topbar>
  <div class="nk-page-scroll"><div class="nk-page" style="padding-top:16px">
    <h1 class="nk-page-title" style="font-size:28px">NotionKit MVP</h1>
    <p class="lead">A calm, document-centric workspace app – built from elements only.</p>
  </div></div>
</nk-app>

Attributes

none

Slots

SlotDescription
sidebarAn nk-sidebar.
(default)Topbar, page – the main column.

Events

none

On a small screen:Below 860px the sidebar is hidden; open it as a drawer with sidebar.open = true.
Replaces.nk-app.nk-main

<nk-sidebar> Sidebar

The left rail: workspace slot on top, a scrolling default slot for the tree, a pinned footer slot. Footer tree items automatically get compact (26px rows). The host is display: contents, so the aside is a direct flex child of the app – exactly like the class markup.

Wave 2
<div style="display:flex;height:100%"><nk-sidebar>
  <nk-workspace-switcher slot="workspace" name="MonaHilft"></nk-workspace-switcher>
  <nk-tree>
    <nk-tree-item icon="🏠" active>Home</nk-tree-item>
    <nk-tree-item icon="πŸ“₯">Inbox</nk-tree-item>
  </nk-tree>
  <nk-tree-item slot="footer" icon="βš™οΈ">Settings</nk-tree-item>
  <nk-tree-item slot="footer" icon="πŸ—‘οΈ">Trash</nk-tree-item>
</nk-sidebar></div>

Attributes

AttributeTypeDefaultDescription
openboolean–Drawer state on small screens (no effect on desktop).

Slots

SlotDescription
workspacenk-workspace-switcher.
(default)The tree (scrolls).
footerPinned bottom rows (Settings, Trash).

Events

EventdetailDescription
nk-toggle{ open }Drawer opened/closed.

Methods: show() close() toggle()

On a small screen:Hidden below 860px. open shows it as an off-canvas drawer with a scrim; Escape and the scrim close it.
Replaces.nk-sidebar.nk-sidebar-scroll.nk-sidebar-footer

<nk-workspace-switcher> Workspace switcher

The row at the very top of the sidebar. A click toggles open and shows whatever sits in the menu slot below it (an nk-menu, from wave 4); outside clicks and Escape close it.

Wave 2
<div style="background:var(--nk-bg-sidebar);border-radius:8px;max-width:260px"><nk-workspace-switcher name="MonaHilft"></nk-workspace-switcher></div>

Attributes

AttributeTypeDefaultDescription
namestring–Workspace name.
avatarstring–Avatar text (default: first letter of the name).
openboolean–Menu shown.

Slots

SlotDescription
avatarCustom avatar node.
menuThe popover content.

Events

EventdetailDescription
nk-toggle{ open }Menu opened/closed.
nk-select(from the menu)Bubbles up from a menu item; the menu closes.

Methods: show() close() toggle()

On a small screen:Unchanged.
Replaces.nk-workspace.avatar.chev

<nk-section-label> Section label

Small uppercase-ish heading between tree sections. With addable a οΌ‹ appears on hover and fires nk-action.

Wave 2
FavouritesProject overview
<div style="background:var(--nk-bg-sidebar);border-radius:8px;max-width:244px;padding:0 8px 6px"><nk-section-label addable>Favourites</nk-section-label><nk-tree-item icon="πŸ“Š">Project overview</nk-tree-item></div>

Attributes

AttributeTypeDefaultDescription
addableboolean–Shows the οΌ‹ on hover.
labelstring–Text (alternative to the slot).

Slots

SlotDescription
(default)Label text.

Events

EventdetailDescription
nk-action{ action: 'add' }οΌ‹ clicked.
On a small screen:Unchanged.
Replaces.nk-section-label.plus

<nk-tree> Tree

Container for nk-tree-items: keeps exactly one item active (listening to nk-select at any depth), gives the whole tree a single tab stop with arrow-key navigation (↑↓ move, β†’ expands or enters, ← collapses or leaves, Home/End), and renders items from tree.data. tree.value is read-only – select programmatically with item.select() or the active attribute. Section labels may sit between items; their οΌ‹ fires nk-action { action: 'add' } without a value.

Wave 2
Favourites Project overview NotionKit MVP Voice-Office-Hub Knowledge base Onboarding Design system
<div style="background:var(--nk-bg-sidebar);border-radius:8px;max-width:244px;padding:6px 8px"><nk-tree>
  <nk-section-label addable>Favourites</nk-section-label>
  <nk-tree-item icon="πŸ“Š" open>Project overview
    <nk-tree-item icon="πŸš€" active>NotionKit MVP</nk-tree-item>
    <nk-tree-item icon="πŸŽ™οΈ">Voice-Office-Hub</nk-tree-item>
  </nk-tree-item>
  <nk-tree-item icon="🧠">Knowledge base
    <nk-tree-item icon="πŸ“„">Onboarding</nk-tree-item>
  </nk-tree-item>
  <nk-tree-item icon="🎨">Design system</nk-tree-item>
</nk-tree></div>

Attributes

AttributeTypeDefaultDescription
manualboolean–Do not move active automatically.

Slots

SlotDescription
(default)nk-tree-item and nk-section-label children.

Events

EventdetailDescription
nk-select{ value, label, href, item }Bubbles from the selected item.
nk-toggle{ open, value }A branch opened/closed.
nk-action{ action, value }Hover action of an item.

Properties: data activeItem value

On a small screen:Rows are 28px; raise the hit area in a touch drawer via the sidebar’s open state styling of your own.
Replaces

<nk-tree-item> Tree item

One row of the page tree – and its children box. Text content is the label, nested nk-tree-items are the children (the arrow appears only then), slot="icon" and slot="end" go where they say. Hover actions οΌ‹/β‹― report through nk-action; a click fires nk-select (cancelable). Outside an nk-tree (sidebar footer) an item marks itself active on click unless the event is cancelled.

Wave 2
Search⌘K Project overview Design system
<div style="background:var(--nk-bg-sidebar);border-radius:8px;max-width:244px;padding:6px 8px">
  <nk-tree-item icon="πŸ”" value="search">Search<span slot="end" class="nk-kbd-hint"><nk-kbd>⌘</nk-kbd><nk-kbd>K</nk-kbd></span></nk-tree-item>
  <nk-tree-item icon="πŸ“Š" active>Project overview</nk-tree-item>
  <nk-tree-item icon="🎨">Design system</nk-tree-item>
</div>

Attributes

AttributeTypeDefaultDescription
iconstring–Emoji/text icon (or slot="icon").
labelstring–Label (alternative to text content).
valuestring–Value reported in events (default: label).
hrefURL–Navigate on select.
activeboolean–Current item.
openboolean–Children expanded.
compactboolean–26px row (footer, settings nav).
no-actionsboolean–Hide the οΌ‹/β‹― hover actions.

Slots

SlotDescription
(default)Label text and nested nk-tree-items.
iconIcon node.
endTrailing content, e.g. <span slot="end" class="nk-kbd-hint"> with nk-kbds (hides the actions).

Events

EventdetailDescription
nk-select{ value, label, href, item }Row clicked / Enter. preventDefault() keeps it from becoming active.
nk-toggle{ open, value }Arrow clicked.
nk-action{ action: 'add' | 'more', value }Hover action clicked.

Properties: label value active open hasChildren

Methods: select() toggle() focus()

On a small screen:28px rows (26px with compact) – below the 44px touch target; the tree does not force a height.
Replaces.nk-tree-item.icon.label.actions.active.compact.nk-tree-children.collapsed.nk-toggle-arrow.open.nk-kbd-hint

<nk-topbar> Top bar

The 45px bar above the page: breadcrumb in the default slot, buttons in the actions slot (right-aligned). Use nk-btn variant="topbar" / "share" and nk-theme-toggle there.

Wave 2
πŸ“Š Project overviewπŸš€ NotionKit MVP Last edited 2 min ago Share ⭐
<div style="border:1px solid var(--nk-border);border-radius:8px;display:flex;flex-direction:column"><nk-topbar>
  <nk-breadcrumb><span>πŸ“Š Project overview</span><span>πŸš€ NotionKit MVP</span></nk-breadcrumb>
  <span slot="actions" class="nk-topbar-btn" style="color:var(--nk-text-tertiary);font-size:12.5px">Last edited 2 min ago</span>
  <nk-btn slot="actions" variant="share">Share</nk-btn>
  <nk-btn slot="actions" variant="topbar">⭐</nk-btn>
  <nk-theme-toggle slot="actions"></nk-theme-toggle>
</nk-topbar></div>

Attributes

none

Slots

SlotDescription
(default)Breadcrumb / title.
actionsButtons on the right.

Events

none

On a small screen:Unchanged; long breadcrumbs truncate.
Replaces.nk-topbar.nk-topbar-actions.nk-topbar-btn.nk-share-btn

<nk-breadcrumb> Breadcrumb

Give it plain <span> or <a> children; they are cloned into the bar with separators between them and the last one marked current (or the child with a current attribute). Text changes, added or removed children are picked up automatically (refresh() only for what the observer cannot see). Clicking a crumb fires nk-select and forwards the click to the original child, so links navigate exactly once.

Wave 2
πŸ“Š Project overviewπŸš€ NotionKit MVP
<nk-breadcrumb><a href="#">πŸ“Š Project overview</a><span>πŸš€ NotionKit MVP</span></nk-breadcrumb>

Attributes

AttributeTypeDefaultDescription
separatorstring/Separator glyph.

Slots

SlotDescription
(default)Crumb children (direct children only, no slot attribute).

Events

EventdetailDescription
nk-select{ index, value, label, href, current }Crumb clicked; preventDefault() stops the forwarded click.

Methods: refresh()

On a small screen:Stays on one line; keep crumbs short.
Replaces.nk-breadcrumb.crumb.sep.current

<nk-theme-toggle> Theme toggle

The β˜€οΈ/πŸŒ™ button. Flips data-theme on <html>, remembers the choice in localStorage, applies a stored or system preference on first connect when <html> has no theme yet, and accepts postMessage({ nkTheme }) from a parent page. apply(theme) does everything a click does: sets, persists and fires nk-change.

Wave 2
<nk-theme-toggle></nk-theme-toggle>

Attributes

AttributeTypeDefaultDescription
storage-keystringnk-themelocalStorage key.
titlestring–Tooltip.

Slots

none

Events

EventdetailDescription
nk-change{ value: 'light' | 'dark' }Theme applied.

Properties: value

Methods: apply(theme)

On a small screen:Unchanged.
Replaces.nk-theme-toggle

Page shell & blocks

Wave 3

<nk-page> Page

The document column: a scrolling wrapper, an optional cover, the 760px page with 64px side padding, and the page icon (rendered here because its slotted twin is keyed on the parent). narrow drops the scroll wrapper for pages that are the document itself.

Wave 3
<div style="display:flex;flex-direction:column;height:100%"><nk-page icon="πŸš€" cover>
  <nk-page-title>NotionKit MVP</nk-page-title>
  <nk-page-actions><span>πŸ‘€ Marcel Karas</span><span>πŸ“… Created 12 May 2026</span><span>🏷️ <nk-tag color="purple">Design system</nk-tag></span></nk-page-actions>
  <p class="lead">A calm, document-centric workspace app – built from elements only.</p>
</nk-page></div>

Attributes

AttributeTypeDefaultDescription
iconstring–Page emoji; click fires nk-action.
coverboolean–Show the token gradient cover.
narrowboolean–No scroll wrapper (landing / docs page).

Slots

SlotDescription
(default)Title, meta, blocks – anything with class="lead" on a <p> becomes the lead paragraph.
coverAn nk-page-cover (instead of the cover attribute).
iconCustom icon node.

Events

EventdetailDescription
nk-action{ action: 'icon', value }Icon clicked (open an emoji picker).
On a small screen:Side padding drops to 24px below 860px.
Replaces.nk-page-scroll.nk-page.nk-page-icon.nk-cover.lead

<nk-page-cover> Page cover

The 200px cover band. Without src it shows the token gradient; with src an image, covered and centred.

Wave 3
<nk-page-cover></nk-page-cover>

Attributes

AttributeTypeDefaultDescription
srcURL–Cover image.

Slots

none

Events

none

On a small screen:Unchanged.
Replaces.nk-cover

<nk-page-title> Page title

The 40px heading. With editable it becomes a plain-text field: Enter commits, blur fires nk-change.

Wave 3
NotionKit MVP
<nk-page-title editable>NotionKit MVP</nk-page-title>

Attributes

AttributeTypeDefaultDescription
editableboolean–Inline editing.
placeholderstring–Shown when empty (editable).
valuestring–Title text (alternative to content).

Slots

SlotDescription
(default)Title text.

Events

EventdetailDescription
nk-change{ value }Edited title committed.

Properties: value

On a small screen:Unchanged; long titles wrap.
Replaces.nk-page-title

<nk-page-actions> Page meta row

The quiet row under the title: owner, date, tags – any inline content, 16px apart.

Wave 3
πŸ‘€ Marcel KarasπŸ“… Created 12 May 2026🏷️ Design system
<nk-page-actions><span>πŸ‘€ Marcel Karas</span><span>πŸ“… Created 12 May 2026</span><span>🏷️ <nk-tag color="purple">Design system</nk-tag></span></nk-page-actions>

Attributes

none

Slots

SlotDescription
(default)Meta items.

Events

none

On a small screen:Wraps naturally.
Replaces.nk-page-meta

<nk-block-host> Block host

The optical shell for editor content: hover wash, focus ring, drop-target line, an optional drag handle. It stays behaviour-neutral – mount your editor into the light DOM; nk-editor (v1.1) will do that for TipTap.

Wave 3

Block content lives here – click to focus.

<nk-block-host handle><p style="margin:0" contenteditable="true">Block content lives here – click to focus.</p></nk-block-host>

Attributes

AttributeTypeDefaultDescription
handleboolean–Render the β Ώ drag handle (shown on hover).
drop-targetboolean–Drop indicator line above the block.

Slots

SlotDescription
(default)Block content / the editor root.

Events

none

On a small screen:The handle sits 26px left of the column and is hidden when there is no room.
Replaces.nk-block-host.nk-block-handle.nk-drop-target

<nk-banner> Banner

A tinted notice row. The colour modifier becomes variant; an action link goes into slot="action" and sits at the right edge.

Wave 3
ℹ️ This page is a component preview – every element follows the same design tokens.Open palette ⚠️ The β€œProject overview” database has 2 overdue entries.View βœ“ All changes have been synced.
<nk-banner variant="info">ℹ️ <span>This page is a <b>component preview</b> – every element follows the same design tokens.</span><span slot="action">Open palette</span></nk-banner>
<nk-banner variant="warning">⚠️ <span>The β€œProject overview” database has 2 overdue entries.</span><span slot="action">View</span></nk-banner>
<nk-banner variant="success">βœ“ <span>All changes have been synced.</span></nk-banner>

Attributes

AttributeTypeDefaultDescription
variantinfo | success | warning–Colour pair.

Slots

SlotDescription
(default)Icon and text.
actionAction link (underlined, right).

Events

none

On a small screen:Wraps; the action drops below the text when needed.
Replaces.nk-banner.info.success.warning.b-action

<nk-empty> Empty state

Dashed box with icon, title, description and whatever call to action you slot in.

Wave 3
οΌ‹ New entry
<nk-empty icon="πŸ—‚οΈ" title="No entries yet" desc="Create the first entry or import existing data."><nk-btn variant="primary" small>οΌ‹ New entry</nk-btn></nk-empty>

Attributes

AttributeTypeDefaultDescription
iconstring–Emoji.
titlestring–Title.
descstring–Description.

Slots

SlotDescription
(default)Call to action.
iconRich icon.
titleRich title.
descRich description.

Events

none

On a small screen:Unchanged.
Replaces.nk-empty.e-icon.e-title.e-desc

<nk-skeleton> Skeleton

Shimmering placeholder lines. lines renders several; widths gives each its own width.

Wave 3
<nk-skeleton height="18" width="60%"></nk-skeleton>
<nk-skeleton lines="3" widths="100%,85%,40%"></nk-skeleton>

Attributes

AttributeTypeDefaultDescription
linesnumber1Number of lines.
heightpx | CSS length13Line height.
widthCSS length–Width for every line.
widthslist–Comma-separated width per line.

Slots

none

Events

none

On a small screen:Unchanged; respects reduced motion.
Replaces.nk-skeleton

<nk-synced> Synced block

Content that appears in several places, framed with a badge.

Wave 3
Our mission: Take real weight off the working day – calm, clear, effective.
<nk-synced badge="⟳ 3 places"><div style="font-size:14px;line-height:1.55"><b>Our mission:</b> Take real weight off the working day – calm, clear, effective.</div></nk-synced>

Attributes

AttributeTypeDefaultDescription
badgestring⟳ syncedBadge text.

Slots

SlotDescription
(default)Content.

Events

none

On a small screen:Unchanged.
Replaces.nk-synced.synced-badge

<nk-tabs> Tabs

A tab strip with panels. nk-tab children are the tabs; elements with slot="panel" and a matching data-tab are the panels – the tabs hide every panel but the active one through hidden. Arrow keys move between tabs.

Wave 3
πŸ“ Notes βœ… Tasks πŸ“Ž Files
Free-form notes on the project – meeting minutes, ideas, rough drafts.
Tasks for this project, linked to the database below.
Attached files and exports.
<nk-tabs value="notes">
  <nk-tab value="notes">πŸ“ Notes</nk-tab>
  <nk-tab value="tasks">βœ… Tasks</nk-tab>
  <nk-tab value="files">πŸ“Ž Files</nk-tab>
  <div slot="panel" data-tab="notes" class="nk-tab-panel">Free-form notes on the project – meeting minutes, ideas, rough drafts.</div>
  <div slot="panel" data-tab="tasks" class="nk-tab-panel">Tasks for this project, linked to the database below.</div>
  <div slot="panel" data-tab="files" class="nk-tab-panel">Attached files and exports.</div>
</nk-tabs>

Attributes

AttributeTypeDefaultDescription
valuestring–Active tab value (default: the tab with active, else the first).

Slots

SlotDescription
(default)nk-tab children.
panelPanels with data-tab.

Events

EventdetailDescription
nk-change{ value }Active tab changed.
nk-select{ value, label }From the clicked tab.

Properties: value

On a small screen:Strip stays on one line; keep labels short.
Replaces.nk-tabs.nk-tab.active.nk-tab-panel

<nk-tab> Tab

One tab of nk-tabs. Standalone it toggles its own active.

Wave 3
πŸ“ Notesβœ… Tasks
<nk-tabs><nk-tab value="a" active>πŸ“ Notes</nk-tab><nk-tab value="b">βœ… Tasks</nk-tab></nk-tabs>

Attributes

AttributeTypeDefaultDescription
valuestring–Value (default: text).
activeboolean–Active.
disabledboolean–Not selectable.

Slots

SlotDescription
(default)Label.

Events

EventdetailDescription
nk-select{ value, label }Clicked / Enter.
On a small screen:Unchanged.
Replaces.nk-tab.active

<nk-segmented> Segmented control

Plain <button value> children stay in the light DOM (the stylesheet’s slotted twins shape them); the element moves .active, handles arrow keys and submits value with the form.

Wave 3
<nk-segmented name="range" value="week"><button value="week">Week</button><button value="month">Month</button><button value="quarter">Quarter</button></nk-segmented>

Attributes

AttributeTypeDefaultDescription
valuestring–Selected value (default: the button with .active, else the first).
namestring–Form field name (FormData key).
disabledboolean–Disables the control.

Slots

SlotDescription
(default)<button value="…"> children.

Events

EventdetailDescription
nk-change{ value, name }Selection changed.
On a small screen:Unchanged.
Replaces.nk-segmented.active

<nk-stats> Stat cards

nk-stats is the row; each nk-stat shows label, value and a trend line coloured by trend.

Wave 3
<nk-stats>
  <nk-stat label="Active pages" value="128" delta="β–² 12 this week" trend="up"></nk-stat>
  <nk-stat label="AI requests" value="847" delta="β–² 23 %" trend="up"></nk-stat>
  <nk-stat label="Open tasks" value="14" delta="β–Ό 5 since yesterday" trend="down"></nk-stat>
</nk-stats>

Attributes

AttributeTypeDefaultDescription
labelstring–(nk-stat) Label.
valuestring–(nk-stat) Big number.
deltastring–(nk-stat) Trend text.
trendup | down–(nk-stat) Colours the delta.

Slots

SlotDescription
(default)(nk-stats) nk-stat children; (nk-stat) slots label, value, delta for rich content.

Events

none

On a small screen:The row wraps below 860px.
Replaces.nk-stats.nk-stat.s-label.s-value.s-delta.up.down

<nk-stat> Stat card

One card; see nk-stats for the row.

Wave 3
<nk-stats><nk-stat label="Active pages" value="128" delta="β–² 12 this week" trend="up"></nk-stat></nk-stats>

Attributes

AttributeTypeDefaultDescription
labelstring–Label.
valuestring–Value.
deltastring–Trend text.
trendup | down–Delta colour.

Slots

SlotDescription
labelRich label.
valueRich value.
deltaRich delta (add class="up" / "down").

Events

none

On a small screen:Unchanged.
Replaces.nk-stat

<nk-avatar-group> Avatar group

Overlapping .mini-avatar children (light DOM, styled by the slotted twins) plus a β€œmore” bubble from the attribute.

Wave 3
MKSLTW5 people have access
<div style="display:flex;align-items:center;gap:12px"><nk-avatar-group more="+2"><span class="mini-avatar" style="background:linear-gradient(135deg,#9065b0,#529cca)">MK</span><span class="mini-avatar" style="background:#448361">SL</span><span class="mini-avatar" style="background:#d9730d">TW</span></nk-avatar-group><span style="font-size:12.5px;color:var(--nk-text-tertiary)">5 people have access</span></div>

Attributes

AttributeTypeDefaultDescription
morestring–Text of the trailing bubble, e.g. +2.

Slots

SlotDescription
(default)<span class="mini-avatar" style="background:…"> children.

Events

none

On a small screen:Unchanged.
Replaces.nk-avatar-group.mini-avatar.more

<nk-mention> Mention

Inline chip for a person (with avatar slot), a page or a date.

Wave 3

SLSara Lindt Β· πŸ“„ Onboarding Β· πŸ“… 20 May

<p style="margin:0;line-height:1.7"><nk-mention type="person"><span slot="avatar" class="mini-avatar" style="background:#448361">SL</span>Sara Lindt</nk-mention> Β· <nk-mention type="page">πŸ“„ Onboarding</nk-mention> Β· <nk-mention type="date">πŸ“… 20 May</nk-mention></p>

Attributes

AttributeTypeDefaultDescription
typeperson | page | date–Kind of mention.

Slots

SlotDescription
avatar.mini-avatar for persons.
(default)Text.

Events

none

On a small screen:Unchanged; never wraps.
Replaces.nk-mention.person.page.date.mini-avatar

<nk-template-btn> Template button

Full-width, left-aligned button on the callout background – β€œinsert a template”. Fires nk-select with value.

Wave 3
Insert week plan Insert meeting minutes Insert retro board
<nk-template-btn icon="πŸ“…" value="week-plan">Insert week plan</nk-template-btn>
<nk-template-btn icon="🀝" value="minutes">Insert meeting minutes</nk-template-btn>
<nk-template-btn icon="πŸ”" value="retro">Insert retro board</nk-template-btn>

Attributes

AttributeTypeDefaultDescription
iconstring–Leading emoji.
valuestring–Reported value (default: text).
disabledboolean–Disabled.

Slots

SlotDescription
(default)Label.

Events

EventdetailDescription
nk-select{ value, label }Clicked.
On a small screen:Unchanged.
Replaces.nk-template-btn

<nk-model-card> Model card

A radio-like card. Cards with the same name form a group; the selected one submits value with the form.

Wave 3
<nk-model-card name="model" value="pro" title="Mona Pro" desc="Best for long documents and research." selected></nk-model-card>
<nk-model-card name="model" value="fast" title="Mona Fast" desc="Quick answers, lower cost."></nk-model-card>

Attributes

AttributeTypeDefaultDescription
titlestring–Name line.
descstring–Description.
namestring–Form field name (FormData key).
disabledboolean–Disables the control.
valuestring–Submitted value.
selectedboolean–Selected.

Slots

SlotDescription
titleRich name line (e.g. with an nk-tag).
descRich description.

Events

EventdetailDescription
nk-change{ value, name, checked }Selected.
nk-select{ value, label }Selected.
On a small screen:Unchanged.
Replaces.nk-model-card.selected.m-radio.m-name.m-desc

<nk-profile-row> Profile row

A 56px gradient avatar with whatever you slot beside it – usually two buttons.

Wave 3
Change photo Remove
<nk-profile-row avatar="MK"><nk-btn variant="secondary" small>Change photo</nk-btn> <nk-btn variant="danger" small>Remove</nk-btn></nk-profile-row>

Attributes

AttributeTypeDefaultDescription
avatarstring–Initials.

Slots

SlotDescription
avatarCustom avatar (e.g. an image).
(default)Content beside the avatar.

Events

none

On a small screen:Unchanged.
Replaces.nk-profile-row.big-avatar

<nk-danger-zone> Danger zone

Red-framed box for destructive settings.

Wave 3
Delete
<nk-danger-zone title="Danger zone"><nk-field label="Delete workspace" desc="Deleting the workspace removes every page."><nk-btn variant="danger-solid" small>Delete</nk-btn></nk-field></nk-danger-zone>

Attributes

AttributeTypeDefaultDescription
titlestring–Red heading.

Slots

SlotDescription
(default)Fields and buttons.

Events

none

On a small screen:Unchanged.
Replaces.nk-danger-zone.dz-title

<nk-member-list> Member list

Rows of nk-member-row; the list marks the last row so it loses its bottom border. Each row shows avatar (initials + color), name, mail and a slot="role" control on the right.

Wave 3
<nk-member-list>
  <nk-member-row name="Sara Lindt" mail="sara@example.com" color="#448361"><nk-select slot="role" compact value="editor"><option value="viewer">Viewer</option><option value="editor">Editor</option><option value="admin">Admin</option></nk-select></nk-member-row>
  <nk-member-row name="Tom Weber" mail="tom@example.com" color="#d9730d"><nk-select slot="role" compact value="viewer"><option value="viewer">Viewer</option><option value="editor">Editor</option><option value="admin">Admin</option></nk-select></nk-member-row>
</nk-member-list>

Attributes

AttributeTypeDefaultDescription
namestring–(row) Name.
mailstring–(row) Mail line.
avatarstring–(row) Initials (default: from the name).
colorCSS color–(row) Avatar background.
lastboolean–(row) No bottom border – set by the list.

Slots

SlotDescription
(default)(list) rows; (row) extra content.
role(row) A control on the right, e.g. nk-select compact.
avatar(row) Custom avatar.

Events

none

On a small screen:Unchanged; the role select shrinks to 120px.
Replaces.nk-member-list.nk-member-row.last.m-mail.mini-avatar

<nk-member-row> Member row

One row; see nk-member-list.

Wave 3
<nk-member-row name="Sara Lindt" mail="sara@example.com" color="#448361" last></nk-member-row>

Attributes

AttributeTypeDefaultDescription
namestring–Name.
mailstring–Mail.
avatarstring–Initials.
colorCSS color–Avatar background.
lastboolean–No bottom border.

Slots

SlotDescription
roleControl on the right.
avatarCustom avatar.
(default)Extra content.

Events

none

On a small screen:Unchanged.
Replaces.nk-member-row

Overlays

Wave 4

<nk-modal> Settings modal

The settings overlay: backdrop, a 960Γ—640 dialog with a nav column and a content column. The nav rows are rendered by the modal from the panes’ label/icon/group, so the 27px rows and the 860px icon rail come straight from the stylesheet. Escape and the backdrop close it; focus moves in and back; the page behind is scroll-locked and inert. Place it directly under <body>.

Wave 4
<nk-modal open>
  <nk-settings-user slot="user" name="Marcel Karas" mail="marcel@monahilft.de"></nk-settings-user>
  <nk-settings-pane name="profile" group="Account" icon="πŸ‘€" label="My profile" title="My profile" active>
    <nk-profile-row avatar="MK"><nk-btn variant="secondary" small>Change photo</nk-btn></nk-profile-row>
    <nk-field label="Display name" desc="Shown next to your comments."><nk-input value="Marcel Karas"></nk-input></nk-field>
    <nk-field label="Email"><nk-input type="email" value="marcel@monahilft.de"></nk-input></nk-field>
  </nk-settings-pane>
  <nk-settings-pane name="appearance" group="Account" icon="🎨" label="Appearance" title="Appearance">
    <nk-field label="Theme"><nk-select><option>Light</option><option>Dark</option><option>System</option></nk-select></nk-field>
  </nk-settings-pane>
  <nk-settings-pane name="members" group="Workspace" icon="πŸ‘₯" label="Members" title="Members">
    <nk-member-list><nk-member-row name="Sara Lindt" mail="sara@example.com" color="#448361"></nk-member-row></nk-member-list>
  </nk-settings-pane>
</nk-modal>

Attributes

AttributeTypeDefaultDescription
openboolean–Shown.
panestring–Name of the active pane (default: the pane with active, else the first).

Slots

SlotDescription
(default)nk-settings-pane children.
usernk-settings-user at the top of the nav.
navExtra nav content below the generated rows (860px rules do not reach slotted elements).

Events

EventdetailDescription
nk-toggle{ open }Opened / closed.
nk-select{ value, label }Pane switched.

Properties: open pane panes

Methods: show(pane?) close() toggle()

On a small screen:Below 860px the nav collapses to a 60px icon rail; the dialog takes 92vw Γ— 86vh.
Replaces.nk-modal-backdrop.open.nk-modal.nk-settings-nav.nk-settings-content

<nk-settings-pane> Settings pane

One pane of the settings modal. label, icon and group feed the modal’s nav; title renders the pane heading. Slotted <h2>/<h3> are styled too.

Wave 4

Email

<nk-settings-pane title="Notifications" active><h3>Email</h3><nk-field label="Email notifications"><nk-switch checked></nk-switch></nk-field></nk-settings-pane>

Attributes

AttributeTypeDefaultDescription
namestring–Identifier used by pane.
labelstring–Nav label (a pane without label gets no nav row).
iconstring–Nav icon.
groupstring–Section label above its nav rows.
titlestring–Pane heading.
activeboolean–Visible (managed by the modal).

Slots

SlotDescription
(default)Fields, headings, anything.

Events

none

On a small screen:Content padding drops to 24px below 860px.
Replaces.nk-settings-pane.active

<nk-settings-user> Settings user

The user card at the top of the settings nav.

Wave 4
<div style="background:var(--nk-bg-sidebar);border-radius:8px;max-width:230px;padding:10px 8px"><nk-settings-user name="Marcel Karas" mail="marcel@monahilft.de"></nk-settings-user></div>

Attributes

AttributeTypeDefaultDescription
namestring–Name.
mailstring–Mail.
avatarstring–Initials (default: from the name).

Slots

SlotDescription
avatarCustom avatar.

Events

none

On a small screen:Below 860px only the avatar remains.
Replaces.nk-settings-user.avatar.u-text.name.mail

<nk-cmdk> Command palette

⌘K. Feed it palette.commands = [{ group, items: [{ id, icon, label, shortcut, keywords, action }] }]; it searches fuzzily over label and keywords, keeps group order, moves the selection with ↑↓, picks with Enter or click (nk-command plus the item’s action), and closes on Escape or the backdrop. The hotkey is mod+k unless changed. Place it directly under <body>.

Wave 4
<nk-cmdk open placeholder="Search or type a command …"></nk-cmdk>
<script>
  document.querySelector('nk-cmdk').commands = [
    { group: 'Pages', items: [
      { id: 'mvp', icon: 'πŸš€', label: 'NotionKit MVP' },
      { id: 'voh', icon: 'πŸŽ™οΈ', label: 'Voice-Office-Hub' },
      { id: 'kb', icon: '🧠', label: 'Knowledge base' },
    ]},
    { group: 'Actions', items: [
      { id: 'new', icon: 'οΌ‹', label: 'Create new page', shortcut: '⌘N' },
      { id: 'theme', icon: 'πŸŒ™', label: 'Toggle theme', shortcut: 'βŒ˜β‡§L' },
      { id: 'settings', icon: 'βš™οΈ', label: 'Open settings', shortcut: '⌘,' },
    ]},
  ];
</script>

Attributes

AttributeTypeDefaultDescription
openboolean–Shown.
hotkeystringmod+kGlobal shortcut, e.g. mod+k, mod+shift+p.
placeholderstring–Input placeholder.

Slots

SlotDescription
footerReplaces the default key hints.

Events

EventdetailDescription
nk-command{ id, item, query }An item was picked; preventDefault() skips item.action.
nk-toggle{ open }Opened / closed.

Properties: commands open query

Methods: show() close() toggle() results() pick(index?)

On a small screen:Full width (96vw) and closer to the top below 860px.
Replaces.nk-cmdk-backdrop.open.nk-cmdk.nk-cmdk-input-row.nk-cmdk-list.nk-cmdk-group.nk-cmdk-item.selected.m-icon.m-shortcut.nk-cmdk-empty.nk-cmdk-footer

<nk-menu> Menu

A 230px context menu. Items are nk-menu-items (type="separator" / "label" for the rest); ↑↓ move, Enter selects, nk-select bubbles up. Usually lives inside nk-pop or the workspace switcher.

Wave 4
Page Rename Duplicate Move to … Delete
<nk-menu>
  <nk-menu-item type="label">Page</nk-menu-item>
  <nk-menu-item icon="✏️" shortcut="⌘E" value="rename">Rename</nk-menu-item>
  <nk-menu-item icon="πŸ“„" shortcut="⌘D" value="duplicate">Duplicate</nk-menu-item>
  <nk-menu-item icon="πŸ“" value="move">Move to …</nk-menu-item>
  <nk-menu-item type="separator"></nk-menu-item>
  <nk-menu-item icon="πŸ—‘οΈ" danger value="delete">Delete</nk-menu-item>
</nk-menu>

Attributes

none

Slots

SlotDescription
(default)nk-menu-item children.

Events

EventdetailDescription
nk-select{ value, label, item }From the chosen item.

Methods: focusFirst()

On a small screen:Unchanged.
Replaces.nk-pop.nk-menu.nk-menu-item.m-icon.m-shortcut.danger.nk-menu-sep.nk-menu-label

<nk-menu-item> Menu item

One row of nk-menu: icon, label, shortcut; danger for destructive actions. type switches to a separator or a group label.

Wave 4
Rename
<nk-menu><nk-menu-item icon="✏️" shortcut="⌘E" value="rename">Rename</nk-menu-item></nk-menu>

Attributes

AttributeTypeDefaultDescription
iconstring–Leading icon.
shortcutstring–Trailing shortcut text.
valuestring–Reported value (default: text).
dangerboolean–Red text.
typeitem | separator | labelitemRow kind.
disabledboolean–Not selectable.

Slots

SlotDescription
(default)Label.
iconIcon node.

Events

EventdetailDescription
nk-select{ value, label, item }Clicked / Enter.
On a small screen:Unchanged.
Replaces.nk-menu-item.danger.nk-menu-sep.nk-menu-label

<nk-pop> Popover

Anchors a floating surface to a trigger. The trigger goes in slot="trigger" and toggles open; outside clicks, Escape and an nk-select from inside close it. Content is wrapped in .nk-pop unless it brings its own surface (nk-menu, nk-emoji-picker) or bare is set.

Wave 4
Options β–Ύ RenameDuplicateDelete
<div style="min-height:220px"><nk-pop open>
  <nk-btn slot="trigger" variant="secondary">Options β–Ύ</nk-btn>
  <nk-menu><nk-menu-item icon="✏️" value="rename">Rename</nk-menu-item><nk-menu-item icon="πŸ“„" value="duplicate">Duplicate</nk-menu-item><nk-menu-item type="separator"></nk-menu-item><nk-menu-item icon="πŸ—‘οΈ" danger value="delete">Delete</nk-menu-item></nk-menu>
</nk-pop></div>

Attributes

AttributeTypeDefaultDescription
openboolean–Shown.
placementbottom-start | bottom-end | top-start | top-endbottom-startWhere the surface opens.
bareboolean–No .nk-pop wrapper.

Slots

SlotDescription
triggerThe button.
(default)The floating content.

Events

EventdetailDescription
nk-toggle{ open }Opened / closed.

Methods: show() close() toggle()

On a small screen:Positioned relative to the trigger; keep it near the viewport edge in mind.
Replaces.nk-pop

<nk-emoji-picker> Emoji picker

Search field, 8-column grid, category strip. Ships with a built-in set (names for search); picker.emojis = [{ char, name, cat }] replaces it. A click fires nk-select { emoji }.

Wave 4
<nk-emoji-picker placeholder="Search…"></nk-emoji-picker>

Attributes

AttributeTypeDefaultDescription
placeholderstring–Search placeholder.
valuestring–Last picked emoji.

Slots

none

Events

EventdetailDescription
nk-select{ emoji, value }Emoji picked.

Properties: emojis value

On a small screen:296px wide; fine on any phone.
Replaces.nk-pop.nk-emoji-search.nk-emoji-grid.nk-emoji-cats.active

<nk-toast> Toast

One inverted pill at the bottom centre. toast.show("Saved") shows it and hides it after duration ms; open is the state.

Wave 4
<nk-toast open duration="0">Settings saved</nk-toast>

Attributes

AttributeTypeDefaultDescription
openboolean–Visible.
durationms2200Auto-hide delay (0 = stay).
iconstringβœ“Leading glyph.

Slots

SlotDescription
(default)Static content (when show() gets no message).

Events

EventdetailDescription
nk-toggle{ open }Shown / hidden.

Properties: open message

Methods: show(message?, { duration }) close()

On a small screen:Unchanged.
Replaces.nk-toast.show

Data & collaboration

Wave 5

<nk-database> Database

The view switcher. Child views (nk-table-view, nk-board-view) become tabs; columns and rows are pushed into every view. view selects the active one; count on a view shows the row count as badge. No fetching: give it data, listen to events.

Wave 5
<nk-database view="table" add-view>
  <nk-table-view name="table" label="β–¦ Table" count new-row sortable></nk-table-view>
  <nk-board-view name="board" label="β–€ Board" group-by="status" new-row></nk-board-view>
</nk-database>
<script>{
  const db = document.currentScript.previousElementSibling;
  db.columns = [
    { key: 'name', label: 'Name', type: 'text', icon: 'πŸ“„', title: true },
    { key: 'status', label: 'Status', type: 'select', icon: 'β—‰', options: [
      { value: 'planned', label: 'Planned', color: 'orange' }, { value: 'progress', label: 'In progress', color: 'blue' }, { value: 'done', label: 'Done', color: 'green' } ] },
    { key: 'owner', label: 'Owner', type: 'person', icon: 'πŸ‘€' },
    { key: 'due', label: 'Due', type: 'date', icon: 'πŸ“…' },
    { key: 'progress', label: 'Progress', type: 'progress', icon: 'β–°' },
  ];
  db.rows = [
    { id: 1, icon: '🧭', name: 'App shell & sidebar', status: 'done', owner: { name: 'Marcel', initials: 'MK', color: '#9065b0' }, due: '08.05.2026', progress: 100 },
    { id: 2, icon: 'πŸ“„', name: 'Page shell & typography', status: 'done', owner: { name: 'Marcel', initials: 'MK', color: '#9065b0' }, due: '10.05.2026', progress: 100 },
    { id: 3, icon: 'πŸ—ƒοΈ', name: 'Database table view', status: 'progress', owner: { name: 'Marcel', initials: 'MK', color: '#9065b0' }, due: '20.05.2026', progress: 65 },
    { id: 4, icon: 'β–€', name: 'Board view & drag-and-drop', status: 'planned', due: '02.06.2026', progress: 0 },
  ];
}</script>

Attributes

AttributeTypeDefaultDescription
viewstring–Name of the active view.
add-viewboolean–Show a οΌ‹ tab (fires nk-action).

Slots

SlotDescription
(default)View elements.

Events

EventdetailDescription
nk-view-change{ view }Tab switched.
nk-action{ action: 'add-view' }οΌ‹ clicked.
nk-select / nk-change / nk-action(from the views)Bubble up from the active view.

Properties: columns rows view views

Methods: refresh()

On a small screen:Tables and boards scroll horizontally; nothing breaks.
Replaces.nk-database.nk-db-tabs.nk-db-tab.active.badge

<nk-table-view> Table view

Renders columns Γ— rows as the NotionKit table. Cells are polymorphic (text, select, multi-select, date, person, checkbox, url, number, progress) and rendered as plain markup by the exported renderPropertyCell() – every cell rule starts with .nk-table, so a cell element of its own would never be styled. Header clicks sort with sortable.

Wave 5
<nk-table-view new-row sortable></nk-table-view>
<script>{
  const db = document.currentScript.previousElementSibling;
  db.columns = [
    { key: 'name', label: 'Name', type: 'text', icon: 'πŸ“„', title: true },
    { key: 'status', label: 'Status', type: 'select', icon: 'β—‰', options: [
      { value: 'planned', label: 'Planned', color: 'orange' }, { value: 'progress', label: 'In progress', color: 'blue' }, { value: 'done', label: 'Done', color: 'green' } ] },
    { key: 'owner', label: 'Owner', type: 'person', icon: 'πŸ‘€' },
    { key: 'due', label: 'Due', type: 'date', icon: 'πŸ“…' },
    { key: 'progress', label: 'Progress', type: 'progress', icon: 'β–°' },
  ];
  db.rows = [
    { id: 1, icon: '🧭', name: 'App shell & sidebar', status: 'done', owner: { name: 'Marcel', initials: 'MK', color: '#9065b0' }, due: '08.05.2026', progress: 100 },
    { id: 2, icon: 'πŸ“„', name: 'Page shell & typography', status: 'done', owner: { name: 'Marcel', initials: 'MK', color: '#9065b0' }, due: '10.05.2026', progress: 100 },
    { id: 3, icon: 'πŸ—ƒοΈ', name: 'Database table view', status: 'progress', owner: { name: 'Marcel', initials: 'MK', color: '#9065b0' }, due: '20.05.2026', progress: 65 },
    { id: 4, icon: 'β–€', name: 'Board view & drag-and-drop', status: 'planned', due: '02.06.2026', progress: 0 },
  ];
}</script>

Attributes

AttributeTypeDefaultDescription
namestring–View name (tab id).
labelstring–Tab label.
badgestring–Tab badge.
countboolean–Row count as badge.
new-rowboolean–Show the add row.
new-row-labelstringοΌ‹ New pageIts text.
sortableboolean–Header click sorts locally.
sort-keystring–Sorted column.
sort-dirasc | desc–Direction.

Slots

none

Events

EventdetailDescription
nk-select{ row, id }Row clicked.
nk-change{ row, key, value }Checkbox cell toggled (row updated in place).
nk-action{ action: 'sort' | 'new-row', key?, value? }Header or add row clicked.

Properties: columns rows data

Methods: refresh()

On a small screen:Scrolls horizontally inside .nk-table-wrap.
Replaces.nk-table-wrap.nk-table.th-icon.row-title.date-cell.person-cell.mini-avatar.nk-new-row

<nk-board-view> Board view

Groups rows by a select column (group-by, default: the first select column) into one column per option. Cards show the title column and the meta-keys (default: dates and progress). Drag a card onto another column: the row’s value changes and nk-change fires.

Wave 5
<nk-board-view group-by="status" new-row></nk-board-view>
<script>{
  const db = document.currentScript.previousElementSibling;
  db.columns = [
    { key: 'name', label: 'Name', type: 'text', icon: 'πŸ“„', title: true },
    { key: 'status', label: 'Status', type: 'select', icon: 'β—‰', options: [
      { value: 'planned', label: 'Planned', color: 'orange' }, { value: 'progress', label: 'In progress', color: 'blue' }, { value: 'done', label: 'Done', color: 'green' } ] },
    { key: 'owner', label: 'Owner', type: 'person', icon: 'πŸ‘€' },
    { key: 'due', label: 'Due', type: 'date', icon: 'πŸ“…' },
    { key: 'progress', label: 'Progress', type: 'progress', icon: 'β–°' },
  ];
  db.rows = [
    { id: 1, icon: '🧭', name: 'App shell & sidebar', status: 'done', owner: { name: 'Marcel', initials: 'MK', color: '#9065b0' }, due: '08.05.2026', progress: 100 },
    { id: 2, icon: 'πŸ“„', name: 'Page shell & typography', status: 'done', owner: { name: 'Marcel', initials: 'MK', color: '#9065b0' }, due: '10.05.2026', progress: 100 },
    { id: 3, icon: 'πŸ—ƒοΈ', name: 'Database table view', status: 'progress', owner: { name: 'Marcel', initials: 'MK', color: '#9065b0' }, due: '20.05.2026', progress: 65 },
    { id: 4, icon: 'β–€', name: 'Board view & drag-and-drop', status: 'planned', due: '02.06.2026', progress: 0 },
  ];
}</script>

Attributes

AttributeTypeDefaultDescription
namestring–View name.
labelstring–Tab label.
group-bystring–Select column key.
title-keystring–Card title column.
meta-keyslist–Comma-separated meta columns.
new-rowboolean–Show οΌ‹ per column.

Slots

none

Events

EventdetailDescription
nk-select{ row, id }Card clicked.
nk-change{ row, key, value }Card dropped into another column.
nk-action{ action: 'new-row', value }οΌ‹ clicked (value = column).

Properties: columns rows data

Methods: move(id, value) refresh()

On a small screen:Columns scroll horizontally.
Replaces.nk-board.active.nk-board-col.nk-board-col-header.count.nk-card.card-title.card-meta

<nk-filter-bar> Filter bar

A toolbar composed from existing classes: filter and sort buttons (nk-action), active filters as removable chips, an optional search field. bar.apply(rows) keeps rows where every chip matches by strict equality (row[key] === value, so use the option value) and the search text appears in any string field (a person’s name); the data logic stays yours.

Wave 5
<nk-filter-bar search placeholder="Search rows …"></nk-filter-bar>
<script>{ document.currentScript.previousElementSibling.filters = [{ key: 'status', value: 'done', label: 'Status: Done', color: 'green' }]; }</script>

Attributes

AttributeTypeDefaultDescription
searchboolean–Show the search field.
placeholderstring–Search placeholder.
no-filterboolean–Hide the filter button.
no-sortboolean–Hide the sort button.

Slots

SlotDescription
(default)Extra controls between chips and search.

Events

EventdetailDescription
nk-change{ filters, search }Chip removed or search typed.
nk-action{ action: 'filter' | 'sort' }Button clicked.

Properties: filters value

Methods: apply(rows)

On a small screen:Wraps onto two lines.
Replaces.nk-btn.secondary.small.nk-tag.nk-input

<nk-comments> Comment thread

A left-ruled thread of nk-comments with an input row. Enter or the button fires nk-submit { text }; appending the new comment is yours.

Wave 5
The board view already feels very close to the original. πŸ‘ AII have flagged the overdue entries and prepared a summary.
<nk-comments placeholder="Comment …" send-label="Send">
  <nk-comment author="Sara Lindt" time="1 hr ago" color="#448361">The board view already feels very close to the original. πŸ‘</nk-comment>
  <nk-comment author="Mona" time="20 min ago" avatar="✨" color="var(--nk-text-tertiary)"><span slot="head" class="nk-tag blue" style="font-size:10.5px">AI</span>I have flagged the overdue entries and prepared a summary.</nk-comment>
</nk-comments>

Attributes

AttributeTypeDefaultDescription
placeholderstring–Input placeholder.
send-labelstringSendButton text.
no-inputboolean–Read-only thread.
disabledboolean–Input disabled.

Slots

SlotDescription
(default)nk-comment children.

Events

EventdetailDescription
nk-submit{ text }New comment typed; preventDefault() keeps the text.

Properties: value

Methods: submit() focus()

On a small screen:Unchanged.
Replaces.nk-comments.nk-comment.mini-avatar.c-head.c-body.nk-comment-input

<nk-comment> Comment

One comment: avatar (initials + color), bold author, time, body. slot="head" adds content after the name.

Wave 5
The board view already feels very close to the original. πŸ‘
<nk-comments no-input><nk-comment author="Sara Lindt" time="1 hr ago" color="#448361">The board view already feels very close to the original. πŸ‘</nk-comment></nk-comments>

Attributes

AttributeTypeDefaultDescription
authorstring–Name.
timestring–Relative time.
avatarstring–Initials/emoji (default: from the author).
colorCSS color–Avatar background.

Slots

SlotDescription
(default)Body.
headAfter the name (tag, badge).
avatarCustom avatar.

Events

none

On a small screen:Unchanged.
Replaces.nk-comment.c-head.c-body

<nk-ai-thread> AI thread

The conversation column: nk-ai-msg children (role="user" gets the gradient avatar), followed by an nk-ai-input-row. Action buttons in slot="actions" fire nk-action { action, value } – both carry the button’s value (or its text).

Wave 5
Summarise the open tasks for this project. Two tasks are open: the table view sits at 65 % (due 20 May), the board with drag and drop is planned.
<nk-ai-thread>
  <nk-ai-msg role="user" name="You" avatar="MK">Summarise the open tasks for this project.</nk-ai-msg>
  <nk-ai-msg role="assistant" name="Mona" badge="Β· AI">Two tasks are open: the <b>table view</b> sits at 65 % (due 20 May), the <b>board with drag and drop</b> is planned.
    <button slot="actions" value="copy">πŸ“‹ Copy</button><button slot="actions" value="rephrase">↻ Rephrase</button><button slot="actions" value="like">πŸ‘</button>
  </nk-ai-msg>
</nk-ai-thread>
<nk-ai-input-row placeholder="Ask Mona something …"></nk-ai-input-row>

Attributes

none

Slots

SlotDescription
(default)nk-ai-msg children.

Events

EventdetailDescription
nk-action{ action }Action button of a message.
On a small screen:Unchanged.
Replaces.nk-ai-thread.nk-ai-msg.user.a-body.a-name.nk-ai-actions.nk-ai-input-row.nk-ai-send

<nk-ai-msg> AI message

One message. role="user" flips the avatar to the gradient; badge is the grey suffix after the name (β€œΒ· AI”); plain <button slot="actions">s form the action row.

Wave 5
Two tasks are open: the table view sits at 65 % (due 20 May), the board with drag and drop is planned.
<nk-ai-thread><nk-ai-msg role="assistant" name="Mona" badge="Β· AI">Two tasks are open: the <b>table view</b> sits at 65 % (due 20 May), the <b>board with drag and drop</b> is planned.<button slot="actions" value="copy">πŸ“‹ Copy</button></nk-ai-msg></nk-ai-thread>

Attributes

AttributeTypeDefaultDescription
roleuser | assistantassistantWho speaks.
namestring–Name line.
badgestring–Grey suffix.
avatarstring–Initials/emoji.
colorCSS color–Avatar background override.

Slots

SlotDescription
(default)Message body (HTML allowed).
actions<button value> children.
avatarCustom avatar.

Events

EventdetailDescription
nk-action{ action, value }Action button clicked.
On a small screen:Unchanged.
Replaces.nk-ai-msg.user.a-body.a-name.nk-ai-actions

<nk-ai-input-row> AI input row

The prompt field with ✨ and a send button. Enter or the button fires nk-submit { text } and clears the field.

Wave 5
<nk-ai-input-row placeholder="Ask Mona something …"></nk-ai-input-row>

Attributes

AttributeTypeDefaultDescription
placeholderstring–Placeholder.
valuestring–Preset text.
disabledboolean–Disabled while the assistant answers.
iconstring✨Leading glyph.

Slots

none

Events

EventdetailDescription
nk-submit{ text }Prompt sent.

Properties: value

Methods: submit() focus()

On a small screen:Unchanged.
Replaces.nk-ai-input-row.nk-ai-send