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.
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 -->
<divstyle="margin-top:16px"><nk-btnvariant="primary">Save</nk-btn></div>
<!-- β the host has no box; this margin does nothing -->
<nk-btnstyle="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.
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.
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 => `<optionvalue="${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><spanslot="icon">π</span>β¦</nk-callout>
<!-- β wrapped: ::slotted() cannot reach the inner node -->
<nk-callout><spanslot="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 -->
<divclass="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) -->
<scripttype="module" src="docs-editor.js"></script>
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.
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.
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-textareaname="bio" rows="3" placeholder="A sentence about you"></nk-textarea>
<textareaclass="nk-textarea" name="bio" rows="3" placeholder="A sentence about you"></textarea>
Attributes
Attribute
Type
Default
Description
value
string
β
Current value.
placeholder
string
β
Placeholder text.
rows
number
β
Visible rows.
name
string
β
Form field name (FormData key).
disabled
boolean
β
Disables the control.
required
boolean
β
Required field.
wide
boolean
β
Full width.
Slots
Slot
Description
(default)
Initial text (used when value is absent).
Events
Event
detail
Description
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.
120px minimum width (.compact), e.g. inside a member row.
Slots
Slot
Description
(default)
<option> / <optgroup> children β direct children only.
Events
Event
detail
Description
nk-change
{ value, name }
On selection.
Properties:valueselectedIndexoptions
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.
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.
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
Display name
Shown next to your comments.
Email notifications
<nk-fieldlabel="Display name" desc="Shown next to your comments.">
<nk-inputvalue="Ada Lovelace"></nk-input>
</nk-field>
<nk-fieldlabel="Email notifications">
<nk-switch checked></nk-switch>
</nk-field>
<divclass="nk-field">
<div><divclass="f-label">Display name</div><divclass="f-desc">Shown next to your comments.</div></div>
<divclass="f-control"><inputclass="nk-input" value="Ada Lovelace"></div>
</div>
<divclass="nk-field">
<div><divclass="f-label">Email notifications</div></div>
<divclass="f-control"><buttonclass="nk-switch" role="switch" aria-checked="true"></button></div>
</div>
Attributes
Attribute
Type
Default
Description
label
string
β
Label text.
desc
string
β
Secondary description.
Slots
Slot
Description
(default)
The control.
label
Rich label content (instead of the attribute).
desc
Rich 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.
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.
π‘
Core idea: A callout carries one thought that must not be missed.
<nk-callouticon="π‘"><b>Core idea:</b> A callout carries one thought that must not be missed.</nk-callout>
<divclass="nk-callout"><spanclass="c-icon">π‘</span><div><b>Core idea:</b> A callout carries one thought that must not be missed.</div></div>
Attributes
Attribute
Type
Default
Description
icon
string
π‘
Emoji or text icon.
Slots
Slot
Description
(default)
Body.
icon
Icon 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>
<hrclass="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
Section heading
<nk-heading>Section heading</nk-heading>
<h2class="nk-heading">Section heading</h2>
Attributes
Attribute
Type
Default
Description
level
1 | 2 | 3 | 4
2
Heading level.
Slots
Slot
Description
(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.
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.
The best interface is the one that gets out of the way.Unknown
<nk-quotecite="Unknown">The best interface is the one that gets out of the way.</nk-quote>
<blockquoteclass="nk-quote">The best interface is the one that gets out of the way.<citeclass="q-cite">Unknown</cite></blockquote>
Attributes
Attribute
Type
Default
Description
cite
string
β
Citation text.
Slots
Slot
Description
(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.
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.
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.
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
FavouritesProject overview
NotionKit MVPVoice-Office-HubKnowledge base
OnboardingDesign system
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.
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 MVPLast edited 2 min agoShareβ
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.
Crumb children (direct children only, no slot attribute).
Events
Event
detail
Description
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.
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
<divstyle="display:flex;flex-direction:column;height:100%"><nk-pageicon="π" cover>
<nk-page-title>NotionKit MVP</nk-page-title>
<nk-page-actions><span>π€ Marcel Karas</span><span>π Created 12 May 2026</span><span>π·οΈ <nk-tagcolor="purple">Design system</nk-tag></span></nk-page-actions>
<pclass="lead">A calm, document-centric workspace app β built from elements only.</p>
</nk-page></div>
<divstyle="display:flex;flex-direction:column;height:100%"><divclass="nk-page-scroll"><divclass="nk-cover"></div><divclass="nk-page">
<divclass="nk-page-icon">π</div>
<h1class="nk-page-title">NotionKit MVP</h1>
<divclass="nk-page-meta"><span>π€ Marcel Karas</span><span>π Created 12 May 2026</span><span>π·οΈ <spanclass="nk-tag purple">Design system</span></span></div>
<pclass="lead">A calm, document-centric workspace app β built from elements only.</p>
</div></div></div>
Attributes
Attribute
Type
Default
Description
icon
string
β
Page emoji; click fires nk-action.
cover
boolean
β
Show the token gradient cover.
narrow
boolean
β
No scroll wrapper (landing / docs page).
Slots
Slot
Description
(default)
Title, meta, blocks β anything with class="lead" on a <p> becomes the lead paragraph.
cover
An nk-page-cover (instead of the cover attribute).
icon
Custom icon node.
Events
Event
detail
Description
nk-action
{ action: 'icon', value }
Icon clicked (open an emoji picker).
On a small screen:Side padding drops to 24px below 860px.
The quiet row under the title: owner, date, tags β any inline content, 16px apart.
Wave 3
π€ Marcel Karasπ Created 12 May 2026π·οΈ Design system
π€ Marcel Karasπ Created 12 May 2026π·οΈ Design system
<nk-page-actions><span>π€ Marcel Karas</span><span>π Created 12 May 2026</span><span>π·οΈ <nk-tagcolor="purple">Design system</nk-tag></span></nk-page-actions>
<divclass="nk-page-meta"><span>π€ Marcel Karas</span><span>π Created 12 May 2026</span><span>π·οΈ <spanclass="nk-tag purple">Design system</span></span></div>
Attributes
none
Slots
Slot
Description
(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.
β Ώ
Block content lives here β click to focus.
<nk-block-host handle><pstyle="margin:0" contenteditable="true">Block content lives here β click to focus.</p></nk-block-host>
<divclass="nk-block-host"><spanclass="nk-block-handle">β Ώ</span><pstyle="margin:0" contenteditable="true">Block content lives here β click to focus.</p></div>
Attributes
Attribute
Type
Default
Description
handle
boolean
β
Render the β Ώ drag handle (shown on hover).
drop-target
boolean
β
Drop indicator line above the block.
Slots
Slot
Description
(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.
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.
βΉοΈ 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-bannervariant="info">βΉοΈ <span>This page is a <b>component preview</b> β every element follows the same design tokens.</span><spanslot="action">Open palette</span></nk-banner>
<nk-bannervariant="warning">β οΈ <span>The βProject overviewβ database has 2 overdue entries.</span><spanslot="action">View</span></nk-banner>
<nk-bannervariant="success">β <span>All changes have been synced.</span></nk-banner>
<divclass="nk-banner info">βΉοΈ <span>This page is a <b>component preview</b> β every element follows the same design tokens.</span><spanclass="b-action">Open palette</span></div>
<divclass="nk-banner warning">β οΈ <span>The βProject overviewβ database has 2 overdue entries.</span><spanclass="b-action">View</span></div>
<divclass="nk-banner success">β <span>All changes have been synced.</span></div>
Attributes
Attribute
Type
Default
Description
variant
info | success | warning
β
Colour pair.
Slots
Slot
Description
(default)
Icon and text.
action
Action 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
ποΈ
No entries yet
Create the first entry or import existing data.
<nk-emptyicon="ποΈ" title="No entries yet" desc="Create the first entry or import existing data."><nk-btnvariant="primary" small>οΌ New entry</nk-btn></nk-empty>
<divclass="nk-empty"><divclass="e-icon">ποΈ</div><divclass="e-title">No entries yet</div><divclass="e-desc">Create the first entry or import existing data.</div><buttonclass="nk-btn primary small">οΌ New entry</button></div>
Attributes
Attribute
Type
Default
Description
icon
string
β
Emoji.
title
string
β
Title.
desc
string
β
Description.
Slots
Slot
Description
(default)
Call to action.
icon
Rich icon.
title
Rich title.
desc
Rich 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.
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.
β³ 3 places
Our mission: Take real weight off the working day β calm, clear, effective.
<nk-syncedbadge="β³ 3 places"><divstyle="font-size:14px;line-height:1.55"><b>Our mission:</b> Take real weight off the working day β calm, clear, effective.</div></nk-synced>
<divclass="nk-synced"><spanclass="synced-badge">β³ 3 places</span><divstyle="font-size:14px;line-height:1.55"><b>Our mission:</b> Take real weight off the working day β calm, clear, effective.</div></div>
Attributes
Attribute
Type
Default
Description
badge
string
β³ synced
Badge text.
Slots
Slot
Description
(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.
π Notesβ Tasksπ Files
Free-form notes on the project β meeting minutes, ideas, rough drafts.
<nk-tabsvalue="notes">
<nk-tabvalue="notes">π Notes</nk-tab>
<nk-tabvalue="tasks">β Tasks</nk-tab>
<nk-tabvalue="files">π Files</nk-tab>
<divslot="panel" data-tab="notes" class="nk-tab-panel">Free-form notes on the project β meeting minutes, ideas, rough drafts.</div>
<divslot="panel" data-tab="tasks" class="nk-tab-panel">Tasks for this project, linked to the database below.</div>
<divslot="panel" data-tab="files" class="nk-tab-panel">Attached files and exports.</div>
</nk-tabs>
<divclass="nk-tabs">
<spanclass="nk-tab active">π Notes</span>
<spanclass="nk-tab">β Tasks</span>
<spanclass="nk-tab">π Files</span>
</div>
<divclass="nk-tab-panel">Free-form notes on the project β meeting minutes, ideas, rough drafts.</div>
Attributes
Attribute
Type
Default
Description
value
string
β
Active tab value (default: the tab with active, else the first).
Slots
Slot
Description
(default)
nk-tab children.
panel
Panels with data-tab.
Events
Event
detail
Description
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.
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.
<nk-stats><nk-statlabel="Active pages" value="128" delta="β² 12 this week" trend="up"></nk-stat></nk-stats>
<divclass="nk-stats"><divclass="nk-stat"><divclass="s-label">Active pages</div><divclass="s-value">128</div><divclass="s-delta up">β² 12 this week</div></div></div>
Attributes
Attribute
Type
Default
Description
label
string
β
Label.
value
string
β
Value.
delta
string
β
Trend text.
trend
up | down
β
Delta colour.
Slots
Slot
Description
label
Rich label.
value
Rich value.
delta
Rich 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
MKSLTW+2
5 people have access
<divstyle="display:flex;align-items:center;gap:12px"><nk-avatar-groupmore="+2"><spanclass="mini-avatar" style="background:linear-gradient(135deg,#9065b0,#529cca)">MK</span><spanclass="mini-avatar" style="background:#448361">SL</span><spanclass="mini-avatar" style="background:#d9730d">TW</span></nk-avatar-group><spanstyle="font-size:12.5px;color:var(--nk-text-tertiary)">5 people have access</span></div>
<divstyle="display:flex;align-items:center;gap:12px"><divclass="nk-avatar-group"><spanclass="mini-avatar" style="background:linear-gradient(135deg,#9065b0,#529cca)">MK</span><spanclass="mini-avatar" style="background:#448361">SL</span><spanclass="mini-avatar" style="background:#d9730d">TW</span><spanclass="mini-avatar more">+2</span></div><spanstyle="font-size:12.5px;color:var(--nk-text-tertiary)">5 people have access</span></div>
A radio-like card. Cards with the same name form a group; the selected one submits value with the form.
Wave 3
Mona Pro
Best for long documents and research.
Mona Fast
Quick answers, lower cost.
<nk-model-cardname="model" value="pro" title="Mona Pro" desc="Best for long documents and research." selected></nk-model-card>
<nk-model-cardname="model" value="fast" title="Mona Fast" desc="Quick answers, lower cost."></nk-model-card>
<divclass="nk-model-card selected"><divclass="m-radio"></div><div><divclass="m-name">Mona Pro</div><divclass="m-desc">Best for long documents and research.</div></div></div>
<divclass="nk-model-card"><divclass="m-radio"></div><div><divclass="m-name">Mona Fast</div><divclass="m-desc">Quick answers, lower cost.</div></div></div>
<nk-danger-zonetitle="Danger zone"><nk-fieldlabel="Delete workspace" desc="Deleting the workspace removes every page."><nk-btnvariant="danger-solid" small>Delete</nk-btn></nk-field></nk-danger-zone>
<divclass="nk-danger-zone"><divclass="dz-title">Danger zone</div><divclass="nk-field"><div><divclass="f-label">Delete workspace</div><divclass="f-desc">Deleting the workspace removes every page.</div></div><divclass="f-control"><buttonclass="nk-btn danger-solid small">Delete</button></div></div></div>
Attributes
Attribute
Type
Default
Description
title
string
β
Red heading.
Slots
Slot
Description
(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.
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>.
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>.
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.
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.
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 }.
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.
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.
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.
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.
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.
SL
Sara Lindt Β· 1 hr ago
The board view already feels very close to the original. π
β¨
MonaAI Β· 20 min ago
I have flagged the overdue entries and prepared a summary.
<nk-commentsplaceholder="Comment β¦" send-label="Send">
<nk-commentauthor="Sara Lindt" time="1 hr ago" color="#448361">The board view already feels very close to the original. π</nk-comment>
<nk-commentauthor="Mona" time="20 min ago" avatar="β¨" color="var(--nk-text-tertiary)"><spanslot="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>
<divclass="nk-comments">
<divclass="nk-comment"><spanclass="mini-avatar" style="background:#448361">SL</span><div><divclass="c-head"><b>Sara Lindt</b> Β· 1 hr ago</div><divclass="c-body">The board view already feels very close to the original. π</div></div></div>
<divclass="nk-comment"><spanclass="mini-avatar" style="background:var(--nk-text-tertiary)">β¨</span><div><divclass="c-head"><b>Mona</b><spanclass="nk-tag blue" style="font-size:10.5px">AI</span> Β· 20 min ago</div><divclass="c-body">I have flagged the overdue entries and prepared a summary.</div></div></div>
<divclass="nk-comment-input"><inputclass="nk-input" placeholder="Comment β¦"><buttonclass="nk-btn primary small">Send</button></div>
</div>
Attributes
Attribute
Type
Default
Description
placeholder
string
β
Input placeholder.
send-label
string
Send
Button text.
no-input
boolean
β
Read-only thread.
disabled
boolean
β
Input disabled.
Slots
Slot
Description
(default)
nk-comment children.
Events
Event
detail
Description
nk-submit
{ text }
New comment typed; preventDefault() keeps the text.
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. π
SL
Sara Lindt Β· 1 hr ago
The board view already feels very close to the original. π
<nk-comments no-input><nk-commentauthor="Sara Lindt" time="1 hr ago" color="#448361">The board view already feels very close to the original. π</nk-comment></nk-comments>
<divclass="nk-comments"><divclass="nk-comment"><spanclass="mini-avatar" style="background:#448361">SL</span><div><divclass="c-head"><b>Sara Lindt</b> Β· 1 hr ago</div><divclass="c-body">The board view already feels very close to the original. π</div></div></div></div>
Attributes
Attribute
Type
Default
Description
author
string
β
Name.
time
string
β
Relative time.
avatar
string
β
Initials/emoji (default: from the author).
color
CSS color
β
Avatar background.
Slots
Slot
Description
(default)
Body.
head
After the name (tag, badge).
avatar
Custom 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.
MK
You
Summarise the open tasks for this project.
β¨
Mona Β· AI
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-msgrole="user" name="You" avatar="MK">Summarise the open tasks for this project.</nk-ai-msg>
<nk-ai-msgrole="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.
<buttonslot="actions" value="copy">π Copy</button><buttonslot="actions" value="rephrase">β» Rephrase</button><buttonslot="actions" value="like">π</button>
</nk-ai-msg>
</nk-ai-thread>
<nk-ai-input-rowplaceholder="Ask Mona something β¦"></nk-ai-input-row>
<divclass="nk-ai-thread">
<divclass="nk-ai-msg user"><spanclass="mini-avatar">MK</span><divclass="a-body"><divclass="a-name">You</div>Summarise the open tasks for this project.</div></div>
<divclass="nk-ai-msg"><spanclass="mini-avatar">β¨</span><divclass="a-body"><divclass="a-name">Mona <span>Β· AI</span></div>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.<divclass="nk-ai-actions"><button>π Copy</button><button>β» Rephrase</button><button>π</button></div></div></div>
</div>
<divclass="nk-ai-input-row"><spanstyle="font-size:14px">β¨</span><inputplaceholder="Ask Mona something β¦"><buttonclass="nk-ai-send">β</button></div>
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.
β¨
Mona Β· AI
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-msgrole="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.<buttonslot="actions" value="copy">π Copy</button></nk-ai-msg></nk-ai-thread>
<divclass="nk-ai-thread"><divclass="nk-ai-msg"><spanclass="mini-avatar">β¨</span><divclass="a-body"><divclass="a-name">Mona <span>Β· AI</span></div>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.<divclass="nk-ai-actions"><button>π Copy</button></div></div></div></div>