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.21.0/notionkit.min.css">
<script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.21.0/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';

<!-- build-free: map NotionKit's sheet once, the files import it -->
<script type="importmap">{ "imports": { "@jungherz-de/notionkit/notionkit-styles.js": "/node_modules/@jungherz-de/notionkit/notionkit-styles.js" } }</script>

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.21.0/notionkit.min.css">
    <script src="https://cdn.jsdelivr.net/npm/@jungherz-de/notionkit-elements@1.21.0/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>

Languages

The texts the elements bring along – button labels, placeholders, the names a screen reader announces – come in English and German. The language is the element’s own: its nearest lang attribute, across shadow roots, else <html lang>. An attribute on the element wins, for a label with a meaning of its own. setStrings() adds or replaces texts, for every language or for one, and the elements on the page take them at once; your own NkElement reads them with this.str(key). Percentages follow the language as Intl writes them – 45 % in German.

<html lang="de">  <!-- the elements speak German: Kopieren, Heute, οΌ‹ Neue Seite … -->

<script type="module">
  import { setStrings } from '@jungherz-de/notionkit-elements';
  setStrings({ newPage: 'οΌ‹ New course' });       // every language
  setStrings({ copy: 'Copier' }, 'fr');           // a language of its own
</script>

<!-- an attribute wins -->
<nk-copy-field value="https://…" copy-label="Copy link"></nk-copy-field>

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-sheet, nk-peek, nk-cmdk, nk-toast and a floating nk-menu directly under <body>. Inside a transformed or clipping container a fixed overlay is trapped. Give an overlay you open from a URL hash another id than the hash: the browser scrolls to the fragment target and takes the focus the overlay just gave.

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. Stretched across a column – a full-width button on a sign-in page – it keeps its label centred.

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 | tool | sidebar–Visual variant. topbar and share render .nk-topbar-btn for the top bar. tool renders .nk-db-tool, a tool in the database toolbar (slot="tools" of nk-database). sidebar is the ☰ .nk-topbar-btn.nk-sidebar-toggle: shown below 860px only, a click opens the nk-sidebar of its app as a drawer and sets aria-expanded.
activeboolean–A tool in effect – a set filter – takes the accent (variant="tool").
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-db-tool.active.nk-sidebar-toggle

<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 – inside a panel never wider than the tile; use wide to fill the row.
Replaces.nk-input.wide

<nk-copy-field> Copy field

A value to take along – a link, an address, a key – as tall as an input, with Copy inside on the right: it writes the clipboard and says β€œCopied” in green for a moment; where the clipboard is not allowed, the value is shown and selected for ⌘C. secret masks it behind Show/Hide, Copy still copies the real value. value set as a property is not reflected, so a key never lands in the markup. Each button carries an icon beside its word: on a phone, and with icons anywhere, the icon stands in for the word – two overlapping squares, an eye, a check in green for the moment after – and a masked key keeps a dozen characters more. The word stays the button’s name, and while the icons show, its tooltip for nk-tooltip.

Wave 1
<div style="max-width:340px"><nk-copy-field value="https://monahilft.notionkit.app" copy-label="Copy"></nk-copy-field></div>
<div style="max-width:340px;margin-top:10px"><nk-copy-field value="ntn_4f2a9c1e8b7d6a5f3e2c" secret mono copy-label="Copy" show-label="Show"></nk-copy-field></div>
<div style="max-width:340px;margin-top:10px"><nk-copy-field value="ntn_4f2a9c1e8b7d6a5f3e2c" secret mono icons copy-label="Copy" show-label="Show"></nk-copy-field></div>

Attributes

AttributeTypeDefaultDescription
valuestring–The value.
secretboolean–Masked, with Show/Hide.
iconsboolean–Icons instead of words at every width, not only on a phone.
monoboolean–Monospace – addresses, keys, code.
wrapboolean–A long value breaks instead of an ellipsis.
wideboolean–Fills the row.
copy-labelstringCopy Β· KopierenButton text.
copied-labelstringCopied Β· KopiertText for the moment after.
show-labelstringShow Β· ZeigenReveal (secret).
hide-labelstringHide Β· VerbergenMask again.

Slots

none

Events

EventdetailDescription
nk-action{ action: 'copy', value, ok }Copy clicked; ok is false where the clipboard refused.

Properties: value secret icons

Methods: copy()

On a small screen:Keeps to its column – inside a panel even below its 210px: the value is cut, never the actions. The actions are icons, with the words as their names and tooltips.
Replaces.nk-copy-field.cf-value.cf-btn.copied.mono.wrap.wide.icons

<nk-image-picker> Image picker

A picture for a person or a workspace, on NotionKit’s profile row: round, or square for a workspace icon, with Upload / Change and Remove beside it. From GlassKit Elements: the file is decoded with its EXIF rotation, drawn no larger than max and handed over as a data URL in nk-change – upload it yourself; an unreadable file fires nk-error. JPEG is drawn on white; type="image/png" keeps transparency. src as a property is not reflected, so megabytes never land in the DOM.

Wave 1
<nk-image-picker initials="AL" choose-label="Upload image"></nk-image-picker>
<nk-image-picker square src="/favicon.svg" change-label="Change image" remove-label="Remove"></nk-image-picker>

Attributes

AttributeTypeDefaultDescription
srcURL / data URL–Starting picture.
initialsstring–Shown without a picture.
squareboolean–Rounded square – a workspace icon.
maxpx512Longest edge after scaling.
typeMIMEimage/jpegOutput format.
quality0–10.82JPEG / WebP quality.
acceptstringimage/*File dialog filter.
labelstring–Names the group.
choose-labelstringUpload image Β· Bild hochladenWithout a picture.
change-labelstringChange image Β· Bild Γ€ndernWith a picture.
remove-labelstringRemove Β· EntfernenRemove button.

Slots

none

Events

EventdetailDescription
nk-change{ dataUrl, width, height, size }A picture chosen – or removed, with an empty dataUrl.
nk-error{ message, name }The file cannot be decoded.

Properties: src square

Methods: choose()

On a small screen:Unchanged; the actions stay beside the picture.
Replaces.nk-profile-row.big-avatar.square.pr-actions.pr-remove

<nk-calendar> Date picker

Notion’s date picker as one element (NotionKit 1.9.0): a month with Today and β€Ή β€Ί, the keys, bounds and a form value. The value is a day (YYYY-MM-DD); with range an interval start/end, picked in two clicks in either order; with time a day and a time (YYYY-MM-DDTHH:MM). weeks puts the ISO calendar week in front of each row (β€œKW” in German), weekend greys the days not worked, the days property adds holidays (off with a label) and up to three marks per day in the nine colours – deadlines, milestones. Days outside min/max are announced as unavailable and cannot be picked. Arrows move by a day or a week, Home/End to the ends of the week, PageUp/PageDown by a month (with Shift a year), Enter or Space picks; one day is in the tab order. Month names, weekdays and the first day of the week come from the page’s language; week-start="1" fixes Monday. With floating sheet it is a popover that show(anchor) opens under a property or a cell, and a bottom sheet on a phone; a pick closes it. Put a floating one directly under <body>: an open nk-dialog, nk-modal or nk-sheet leaves it usable, so it opens from a field in a dialog as well.

Wave 1
<div style="display:flex;gap:16px;flex-wrap:wrap;align-items:flex-start">
<div class="nk-pop"><nk-calendar name="due" value="2026-06-02T09:30" time clearable weeks week-start="1" weekend="6,0" today="2026-06-17" today-label="Today" time-label="Time" clear-label="Clear" days='{"2026-06-04":{"off":true,"label":"Corpus Christi"},"2026-06-02":{"marks":["blue"]},"2026-06-11":{"marks":["orange","red"]},"2026-06-24":{"marks":["green"]}}'></nk-calendar></div>
<div class="nk-pop"><nk-calendar name="sprint" range value="2026-06-08/2026-06-12" weeks week-start="1" weekend="6,0" today="2026-06-17" today-label="Today" days='{"2026-06-04":{"off":true,"label":"Corpus Christi"}}'></nk-calendar></div>
</div>

Attributes

AttributeTypeDefaultDescription
valueYYYY-MM-DD | start/end | …THH:MM–The day, the range or the day and time; also the reset value.
monthYYYY-MM–The month shown first; default the value’s, else today’s.
minYYYY-MM-DD–First day that can be picked.
maxYYYY-MM-DD–Last day that can be picked.
rangeboolean–Two picks make a range start/end.
timeboolean–A time field under the month – single days only.
clearableboolean–A Clear button under the month.
weeksboolean–The ISO calendar week in front of each row.
week-start0–6IntlFirst day of the week: 0 Sunday, 1 Monday …
weekendlist–Weekdays not worked, greyed – 6,0.
daysJSON–Per day { off, label, marks }; also the property.
todayYYYY-MM-DD–Another today – for tests and docs.
localeBCP 47langLanguage of the names and the week.
floatingboolean–A popover over the page: show(anchor), close().
sheetboolean–Floating: a bottom sheet on a phone.
openboolean–Floating: shown.
alignend | startendFloating: right or left edge on the anchor’s.
labelstring–Names the month group for screen readers.
today-labelstringToday Β· HeuteToday button.
prev-labelstringPrevious month Β· Voriger MonatNames β€Ή.
next-labelstringNext month Β· NΓ€chster MonatNames β€Ί.
week-labelstringW Β· KWHead of the week column.
time-labelstringTime Β· UhrzeitNames the time field.
clear-labelstringClear Β· LeerenClear button.
namestring–Form field name (FormData key).
disabledboolean–Disables the control.
requiredboolean–A value is required; validity is set on the host.

Slots

none

Events

EventdetailDescription
nk-change{ value, start, end, time }The value changed: a day picked – for a range the second one –, a new time, or Clear. The same day again is no change.
nk-month{ month }Another month shown.
nk-toggle{ open }Floating: opened or closed.

Properties: value start end month days open form validity

Methods: show(anchor) close() toggle(anchor) focusDay() checkValidity()

On a small screen:Floating with sheet: a bottom sheet with 44px cells, a thumb’s width; seven days and the week column still fit a 390px screen.
Replaces.nk-calendar.weeks.cal-head.cal-title.cal-nav.cal-grid.cal-wd.cal-week.cal-day.out.off.today.selected.start.end.in-range.cal-marks.cal-foot.nk-pop.floating.sheet.open

<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. A value – attribute or property – whose option is not there yet waits and is applied once the option arrives, over the browser’s preselection of the first option, unless someone has chosen another in the meantime; settling on it fires no nk-change.

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.
wideboolean–Full width (.nk-select.wide).

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
PlannedIn progress
<div style="display:flex;gap:20px;flex-wrap:wrap;align-items:center"><nk-switch name="notify" checked label="Email notifications"></nk-switch>
<nk-switch name="planned" checked>Planned</nk-switch><nk-switch name="progress">In progress</nk-switch><nk-switch name="done" text="Done" checked></nk-switch></div>

Attributes

AttributeTypeDefaultDescription
checkedboolean–On/off state.
namestring–Form field name (FormData key).
disabledboolean–Disables the control.
valuestringonSubmitted value when checked.
textstring–Visible text beside the switch (alternative to the default slot).
labelstring–Accessible name (aria-label) when there is no visible text.

Slots

SlotDescription
(default)Visible text beside the switch; part of the hit area. Without it the element renders the bare button.

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-switch-label

<nk-check> Checkbox

A label.nk-check with a custom-drawn checkbox; the label text is slotted, so clicking it toggles the box. indeterminate shows a dash (NotionKit 1.21.0) – for a box over a group partly chosen.

Wave 1
All Weekly digest Mentions only
<nk-check indeterminate>All</nk-check>
<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.
textstring–Label text (alternative to the default slot).

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.
textstring–Label text (alternative to the default slot).

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. stacked puts the label above a full-width control (textareas, long descriptions) and sets wide on the control for you; compact shrinks the label to 12px tertiary text. Inside nk-fields both are on by default.

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>
<nk-field label="Short bio" stacked>
  <nk-textarea rows="2" placeholder="A sentence about you"></nk-textarea>
</nk-field>

Attributes

AttributeTypeDefaultDescription
labelstring–Label text.
descstring–Secondary description.
stackedboolean–Label above a full-width control.
compactboolean–Small tertiary label, no row padding.

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. Use stacked where the control needs the whole width.
Replaces.nk-field.f-label.f-desc.f-control.stacked.compact

<nk-fields> Field grid

Several short fields in one row: a grid of minmax(150px, 1fr) columns that wraps as the width allows. Every nk-field inside renders itself stacked and compact – a 12px label above a full-width control – so nothing collides.

Wave 1
<nk-fields>
  <nk-field label="Display name"><nk-input value="Ada Lovelace"></nk-input></nk-field>
  <nk-field label="Email"><nk-input value="ada@acme.com"></nk-input></nk-field>
  <nk-field label="Role"><nk-select value="editor"><option value="viewer">Viewer</option><option value="editor">Editor</option></nk-select></nk-field>
</nk-fields>

Attributes

AttributeTypeDefaultDescription
fitboolean–The fields share the row instead of keeping 150px columns – two fields in a wide dialog are two halves.

Slots

SlotDescription
(default)nk-field children.

Events

none

On a small screen:Wraps to one or two columns on its own; no breakpoint needed.
Replaces.nk-fields.fit

Content elements

Wave 1

<nk-tag> Tag

The select option as Notion draws it, in its nine colours. The colour modifier class becomes the color attribute; without one it is the grey tag. Each pair is tuned per theme.

Wave 1
Not started Archive Planned Review Done In progress Design Idea Blocked
<nk-tag>Not started</nk-tag> <nk-tag color="brown">Archive</nk-tag> <nk-tag color="orange">Planned</nk-tag> <nk-tag color="yellow">Review</nk-tag> <nk-tag color="green">Done</nk-tag> <nk-tag color="blue">In progress</nk-tag> <nk-tag color="purple">Design</nk-tag> <nk-tag color="pink">Idea</nk-tag> <nk-tag color="red">Blocked</nk-tag>

Attributes

AttributeTypeDefaultDescription
colorgray | brown | orange | yellow | green | blue | purple | pink | red–Colour pair; grey without it.

Slots

SlotDescription
(default)Tag text.

Events

none

On a small screen:Unchanged.
Replaces.nk-tag.gray.brown.orange.yellow.green.blue.purple.pink.red

<nk-progress> Progress

A 60px bar with an optional label. value/max set the fill; the bar carries role="progressbar". wide fills its row, and in a flex column – a panel – it stays a 6px bar. With a label the bar and its label form one .nk-progress-row: the label sits beside the bar, on its middle, in a panel too, where the host – display: contents – would let them stand one under the other.

Wave 1

Progress

<nk-progress value="72" label="72%"></nk-progress>
<div class="nk-panel" style="margin-top:12px"><h3>Progress</h3><nk-progress value="40" label="40%" wide></nk-progress></div>

Attributes

AttributeTypeDefaultDescription
valuenumber0Current value.
maxnumber100Maximum.
labelstring–Text after the bar.
wideboolean–Fills its row – a property value, a panel; in a flex row the label stays beside it.

Slots

none

Events

none

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

<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-bookmark> Bookmark

Notion’s link block, filled from what you know of the page – og:title, og:description, og:image: title, two lines of description and the address with its icon on the left, the image on the right in a third, 240px at most. title is the heading, never a tooltip; without it the host name stands in. url shows an address other than href. Opens in a new tab unless target says otherwise; a part without a value is left out.

Wave 1
<div style="max-width:600px"><nk-bookmark href="https://notionkit.jungherz.com" title="NotionKit – the calm workspace look as CSS" desc="NotionKit is a pure CSS component library in the Notion idiom: sidebar, page tree, document shell, database views, settings and AI surfaces." favicon="/favicon.svg" cover="/covers/notionkit-og.jpg"></nk-bookmark></div>

Attributes

AttributeTypeDefaultDescription
hrefURL–The link.
titlestring–Title – og:title.
descstring–Description, two lines – og:description.
faviconURL–The site’s icon, 16px.
coverURL–Preview image – og:image.
urlstring–The address shown (default: href).
targetstring_blankLink target.

Slots

none

Events

EventdetailDescription
click(native)The link is a plain <a>.

Properties: title href

On a small screen:The image keeps its third and is cropped at the centre; title and address end in an ellipsis.
Replaces.nk-bookmark.bm-text.bm-title.bm-desc.bm-url.bm-favicon.bm-cover

<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

AttributeTypeDefaultDescription
peek-insetboolean–The main column makes room for the side peek – <nk-peek inset> sets it while open.

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.peek-inset

<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. collapsible adds Notion’s Β« beside the workspace row, shown while the pointer is over the sidebar: on the desktop it collapses the sidebar – it slides out, the main column takes the width, nothing in it takes focus – and <nk-btn variant="sidebar"> in the topbar shows and brings it back; ⌘\ or Ctrl+\ toggles it. collapsed is the state, nk-collapse the moment to keep it.

Wave 2
<div style="display:flex;height:100%"><nk-sidebar collapsible collapse-label="Close 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).
collapsibleboolean–Shows the Β« that collapses it on the desktop, and ⌘\.
collapsedboolean–Collapsed on the desktop (no effect on a phone).
collapse-labelstringClose sidebar · Seitenleiste schließenName and tooltip of the «.

Slots

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

Events

EventdetailDescription
nk-toggle{ open }Drawer opened/closed.
nk-collapse{ collapsed }Collapsed / expanded on the desktop.

Properties: open collapsed

Methods: show() close() toggle() collapse() expand() toggleCollapsed()

On a small screen:Hidden below 860px. open shows it as a drawer over the page with a scrim – NotionKit’s own rules since 1.7.0 (.nk-sidebar.open, .nk-sidebar-backdrop), the same as the class markup’s; <nk-btn variant="sidebar"> in the topbar is the ☰ that opens it. Escape and the scrim close it. The drawer slides in over 240ms and the scrim fades, closing runs backwards – CSS only (transition-behavior: allow-discrete + @starting-style; older browsers switch hard, reduced motion snaps). In landscape the drawer grows by the left safe-area inset, so its rows clear the Dynamic Island.
Replaces.nk-sidebar.nk-sidebar-head.nk-sidebar-collapse.nk-sidebar-scroll.nk-sidebar-footer.nk-sidebar-backdrop.open.collapsed

<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 44px 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, and <span class="nk-topbar-meta"> for passive text such as β€œEdited 2 min ago”.

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-meta">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:Below 860px only the last crumb stays and ends in an ellipsis, nk-topbar-meta hides, and the actions keep to one line – as in Notion’s mobile app.
Replaces.nk-topbar.nk-topbar-actions.nk-topbar-btn.nk-topbar-meta.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(mode) does everything a click does: sets, persists and fires nk-change.
modes="auto light dark" adds a third state: auto follows prefers-color-scheme, live, and is what no stored value means – so the inline script before first paint keeps working and a choice made without modes still counts. A click then goes from auto to the theme not on screen, to the other one, back to auto, so every click but the last changes something. The glyph shows the mode (nk-theme-glyph, sun and moon diagonally for auto) instead of the next theme, the title names the mode and the next one, and another tab's choice arrives through the storage event. Two states stay the default, where nothing about this element changes.

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

Attributes

AttributeTypeDefaultDescription
modesstringlight darkThe states offered, e.g. auto light dark; without auto among them nothing changes.
storage-keystringnk-themelocalStorage key; auto is no entry.
theme-colorboolean–Keeps <meta name="theme-color"> in step: while a theme is fixed every bar carries that theme's colour – the page's own, never invented.
titlestring–Tooltip; replaces the built-in text.

Slots

none

Events

EventdetailDescription
nk-change{ value: 'auto' | 'light' | 'dark', theme: 'light' | 'dark' }Mode applied; theme is what is on screen (without auto both are the theme).

Properties: value theme mode modes

Methods: apply(mode) nextMode() themeFor(mode)

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

<nk-tab-bar> Tab bar (mobile)

The thumb-reachable twin of the sidebar for phones and installed PWAs. Put it last inside nk-app: it is slotted into the main column below the scrolling page, so it never moves and no bottom padding is needed. Keeps the nk-tab-bar-item whose value is value active (listening to nk-select); a drawer item opens the sidebar instead. A value no item has – a page without a tab of its own, opened from the drawer – marks the drawer item, as iOS marks β€œMore”; without one no item is active. Needs NotionKit CSS 1.2.0.

Wave 2
Home Inbox Search Settings More
<div style="max-width:390px;border:1px solid var(--nk-border);border-radius:12px;overflow:hidden"><nk-tab-bar always value="inbox">
  <nk-tab-bar-item icon="🏠" value="home">Home</nk-tab-bar-item>
  <nk-tab-bar-item icon="πŸ“₯" value="inbox">Inbox</nk-tab-bar-item>
  <nk-tab-bar-item icon="πŸ”" value="search">Search</nk-tab-bar-item>
  <nk-tab-bar-item icon="βš™οΈ" value="settings">Settings</nk-tab-bar-item>
  <nk-tab-bar-item icon="☰" drawer>More</nk-tab-bar-item>
</nk-tab-bar></div>

Attributes

AttributeTypeDefaultDescription
valuestring–Active item value (default: the item with active, else the first); a value no item has marks the drawer item.
alwaysboolean–Visible at every width, not only below 860px.
fixedboolean–Pinned to the viewport bottom instead of sitting in the column – for standalone PWAs; a spacer keeps its height (--nk-tab-bar-height + safe area) in the flow.
floatingboolean–A fixed capsule with rounded corners instead of the full-width bar.
labelstring–aria-label of the nav.

Slots

SlotDescription
(default)nk-tab-bar-item children, up to five.

Events

EventdetailDescription
nk-change{ value }Active item changed.
nk-select{ value, label, href, item, drawer }Bubbles from the tapped item; cancelable.

Properties: value items

On a small screen:This is where it lives: hidden above 860px (the sidebar is the navigation there), shown below. always shows it at every width – previews, phone frames. The bottom padding is the larger of 6px and env(safe-area-inset-bottom); in landscape the side padding grows to the left/right insets.
Replaces.nk-tab-bar.nk-tab-bar-spacer.always.fixed.floating

<nk-tab-bar-item> Tab bar item

One destination of nk-tab-bar: an icon over a short label. A tap emits nk-select (cancelable), then moves the bar’s value; with href it navigates afterwards. drawer turns it into the β€œMore” item that opens the nearest nk-sidebar as a drawer and never becomes active. Standalone it toggles its own active.

Wave 2
HomeInbox
<div style="max-width:390px;border:1px solid var(--nk-border);border-radius:12px;overflow:hidden"><nk-tab-bar always><nk-tab-bar-item icon="🏠" value="home" active>Home</nk-tab-bar-item><nk-tab-bar-item icon="πŸ“₯" value="inbox">Inbox</nk-tab-bar-item></nk-tab-bar></div>

Attributes

AttributeTypeDefaultDescription
iconstring–Emoji or glyph (alternative: slot="icon").
valuestring–Value (default: the label).
labelstring–Label text (alternative to the default slot).
hrefstring–Navigates after nk-select.
activeboolean–The current destination (aria-current="page").
drawerboolean–Opens the sidebar drawer instead of becoming active.
disabledboolean–Not selectable.

Slots

SlotDescription
(default)Label.
iconIcon node instead of the attribute.

Events

EventdetailDescription
nk-select{ value, label, href, item, drawer }Tapped; cancelable.

Methods: select() focus()

On a small screen:Made for the thumb: 20px icon, 10.5px label, the whole column is the hit area.
Replaces.nk-tab-bar-item.icon.label.active

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. With a cover the icon overlaps its bottom edge; a cover without an icon leaves the page its top padding, so the title never touches the picture.

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.
fullboolean–Page option β€œFull width”: the column fills the window instead of stopping at 760px.
smallboolean–Page option β€œSmall text”: document text 14px instead of 16px; headings, lead, prose and editor follow.
coverboolean–Shows the cover strip; the icon then overlaps its bottom edge and the page drops its top padding (the stylesheet’s covered state, also set for a slotted nk-page-cover). Without it the icon sits in 24px top padding, fully visible.
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.full.small

<nk-page-cover> Page cover

The cover band, as tall as the token --nk-cover-height (200px) – on :root, or on the element for one cover: style="--nk-cover-height: clamp(200px, 30vh, 300px)" comes close to Notion’s 30vh. Without src it shows the token gradient; with src a picture – an <img> inside the band, cropped rather than stretched. position moves the crop, as Notion’s β€œReposition” does.

Wave 3
<nk-page-cover src="/covers/meadow.svg"></nk-page-cover>

Attributes

AttributeTypeDefaultDescription
srcURL–Cover picture.
positionCSS object-positioncenterWhere the crop sits.

Slots

none

Events

none

On a small screen:Unchanged; lower --nk-cover-height if the band eats too much of a short screen.
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-props> Page properties

The properties under the title of a database page, the pattern Notion is known for: a list of nk-prop rows. The rows are hosts with display: contents, so each renders as a row of this list – no markup of their own around them. flush drops the outer margin meant for the flow under a title, for a list inside a panel or a flex column.

Wave 3
In progress ALAda Lovelace 2 June 2026 Design systemCSS
<nk-props style="max-width:520px">
  <nk-prop label="Status" icon="β—‰"><nk-tag color="blue">In progress</nk-tag></nk-prop>
  <nk-prop label="Owner" icon="πŸ‘€"><nk-avatar size="small" color="purple">AL</nk-avatar>Ada Lovelace</nk-prop>
  <nk-prop label="Due" icon="πŸ“…">2 June 2026</nk-prop>
  <nk-prop label="Tags" icon="🏷️"><nk-tag color="purple">Design system</nk-tag><nk-tag>CSS</nk-tag></nk-prop>
  <nk-prop label="Progress" icon="β–°"><nk-progress value="65" label="65 %" wide></nk-progress></nk-prop>
</nk-props>

Attributes

AttributeTypeDefaultDescription
flushboolean–No outer margin.

Slots

SlotDescription
(default)nk-prop children.

Events

none

On a small screen:Below 860px each property stacks: the name above its value. In a column narrower than 380px the value moves under its name as well.
Replaces.nk-props.flush

<nk-prop> Page property

One property: the name with its type icon in a 160px column, the value beside it, 34px with the hover wash on both halves. The value is the element’s content – tags, an avatar and a name, a date, <nk-progress wide>. A click fires nk-action with the half that was hit, the moment Notion opens the property’s editor. text lets a value that is text – a sentence, an address, a model name with a tag – flow as text instead of setting its parts one under the other. The value keeps at least 220px: in a column narrower than 380px it moves under its name.

Wave 3
2 June 2026support+design@notionkit.example.com Β· Verified
<nk-props style="max-width:520px"><nk-prop label="Due" icon="πŸ“…">2 June 2026</nk-prop><nk-prop label="Address" icon="βœ‰οΈ" text>support+design@notionkit.example.com Β· <nk-tag color="green">Verified</nk-tag></nk-prop></nk-props>

Attributes

AttributeTypeDefaultDescription
labelstring–Property name.
iconstring–Type icon.
textboolean–The value flows as text.

Slots

SlotDescription
(default)The value.
iconIcon node.

Events

EventdetailDescription
nk-action{ action: 'name' | 'value', label }Name or value clicked.
On a small screen:Stacks below 860px, and in a column narrower than 380px.
Replaces.nk-prop.p-name.p-icon.p-value.text

<nk-panels> Panels

A grid of nk-panels: columns of at least 200px that share the row. The panels are hosts with display: contents, so each is a cell of this grid. flush drops the outer margin, for a grid inside a flex column with a gap of its own.

Wave 3

2 min ago

Yesterday

Three pages changed, one comment is waiting for an answer.

<nk-panels>
  <nk-panel href="#" cover="/covers/aurora.svg" icon="πŸš€" title="NotionKit MVP"><p>2 min ago</p></nk-panel>
  <nk-panel href="#" cover="/covers/dunes.svg" icon="πŸ“š" title="Knowledge base"><p>Yesterday</p></nk-panel>
  <nk-panel title="Weekly review"><p>Three pages changed, one comment is waiting for an answer.</p></nk-panel>
</nk-panels>

Attributes

AttributeTypeDefaultDescription
flushboolean–No outer margin.

Slots

SlotDescription
(default)nk-panel children.

Events

none

On a small screen:Falls to one column as soon as two 200px columns no longer fit.
Replaces.nk-panels.flush

<nk-panel> Panel

A neutral surface for content that belongs together – the cards on Notion’s Home, the boxes in its settings. title is the heading (never a tooltip); the content goes in as <p>s and blocks. cover without a value draws the gradient band, with a URL a picture; icon overlaps the cover as on a page – a page tile. With href the panel is a link. slot="end" sits at the right edge of the title – a state as a tag, a button – as Notion’s settings boxes show a connection, and moves under the title where both do not fit. The cover is --nk-panel-cover-height tall (64px) – set it on :root or on one panel. Inputs, selects and copy fields inside never run past the panel’s edge, however narrow the tile.

Wave 3

2 min ago

In progress

Three pages changed, one comment is waiting for an answer.

<div style="max-width:360px;display:grid;gap:12px"><nk-panel href="#" cover icon="πŸš€" title="NotionKit MVP"><p>2 min ago</p></nk-panel>
<nk-panel title="Weekly review"><nk-tag slot="end" color="blue">In progress</nk-tag><p>Three pages changed, one comment is waiting for an answer.</p></nk-panel></div>

Attributes

AttributeTypeDefaultDescription
titlestring–Heading.
iconstring–Page icon.
coverURL | empty–Cover band: empty for the gradient, a URL for a picture.
hrefURL–Makes the panel a link.
targetstring–Link target.

Slots

SlotDescription
(default)Content: <p>, a prose block, a progress bar.
endBeside the title, at its right edge: a tag, a button.

Events

none

On a small screen:Takes the width of its grid cell.
Replaces.nk-panel.nk-cover.nk-page-icon.p-head.p-end

<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; the action – a <button> – 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. ⚠️ The β€œProject overview” database has 2 overdue entries. βœ“ All changes have been synced. β›” The connection to Notion was lost.
<nk-banner variant="info">ℹ️ <span>This page is a <b>component preview</b> – every element follows the same design tokens.</span><button slot="action" type="button">Open palette</button></nk-banner>
<nk-banner variant="warning">⚠️ <span>The β€œProject overview” database has 2 overdue entries.</span><button slot="action" type="button">View</button></nk-banner>
<nk-banner variant="success">βœ“ <span>All changes have been synced.</span></nk-banner>
<nk-banner variant="danger">β›” <span>The connection to Notion was lost.</span></nk-banner>

Attributes

AttributeTypeDefaultDescription
variantinfo | success | warning | danger–Tint.

Slots

SlotDescription
(default)Icon and text.
actionThe action – a <button>, shown as underlined text on the right.

Events

none

On a small screen:Below 860px the action moves under the text instead of squeezing it into a narrow column.
Replaces.nk-banner.info.success.warning.danger.b-action

<nk-empty> Empty state

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

Wave 3
οΌ‹ New entryImport
<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-btn variant="secondary" small>Import</nk-btn></nk-empty>

Attributes

AttributeTypeDefaultDescription
iconstring–Emoji.
titlestring–Title. Read once and taken off the host, so it never shows as a tooltip.
descstring–Description.

Slots

SlotDescription
(default)Call to action – several buttons sit in a centred row, 8px apart.
iconRich icon.
titleRich title.
descRich description.

Events

none

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

<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⟳ synced · ⟳ synchronisiertBadge 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. scroll keeps many tabs in one row that scrolls sideways, scrollbar hidden, and holds the active tab in view – after the first layout, on every change and when the row’s width changes.

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).
scrollboolean–One row that scrolls sideways and keeps the active tab in view.

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 scroll

On a small screen:The strip stays on one line; one longer than the screen takes scroll.
Replaces.nk-tabs.nk-tab.active.nk-tab-panel.scroll

<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. With scroll the chosen option stays in view: after the first layout, on every change and when the row’s width changes, the row – never the page – scrolls the least distance, right to left as well.

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>
<div style="max-width:300px;margin-top:12px"><nk-segmented name="filter" value="all" scroll><button value="all">All</button><button value="attention">⚠️ Attention</button><button value="failed">Failed</button><button value="read">Read</button><button value="ignored">Ignored</button></nk-segmented></div>
<div style="max-width:300px;margin-top:12px"><nk-segmented name="filter2" value="all" wrap><button value="all">All</button><button value="attention">⚠️ Attention</button><button value="failed">Failed</button><button value="read">Read</button><button value="ignored">Ignored</button></nk-segmented></div>

Attributes

AttributeTypeDefaultDescription
valuestring–Selected value (default: the button with .active, else the first).
scrollboolean–Horizontally scrollable row, scrollbar hidden.
wrapboolean–Segments wrap onto further rows.
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:One row by default, which five filter options overflow on a phone: scroll keeps one thumb-swipeable row capped at the parent width (scrollbar hidden), wrap breaks it onto further rows.
Replaces.nk-segmented.active.scroll.wrap

<nk-steps> Steps

A short flow – connecting an account, setting up a model – calm and vertical: a numbered circle per step joined by a hairline, done steps with a check on the green tag, the current one ringed in the accent and marked aria-current="step". current counts from 1; one past the last marks every step done, and next() moves on. The steps attribute is a comma-separated list; the property also takes { label, desc } objects for a line under the label. A state in such an object – done, skipped or open – wins over the order, for a wizard that lets a step be skipped while a later one is done; a skipped step shows a dashed ring around a dash. selectable makes each label a button: a click or Enter fires nk-select { index, value, step } – index counts from 1, like current – and, unless cancelled, makes that step current. A step with href shows its label as a link, with or without selectable – to open a chapter in a new tab or copy its address. A plain click, and Enter, fire the same nk-select; cancel it and the browser stays, for a router of your own. A middle click or one with Cmd, Ctrl, Shift or Alt fires nothing and does what a link does. horizontal sets the steps in one row above a wizard.

Wave 3
<nk-steps label="Connect your own model" current="2"></nk-steps>
<script>{ document.currentScript.previousElementSibling.steps = [{ label: 'Choose a provider', desc: 'Anthropic' }, 'Enter the API key', 'Test the connection']; }</script>
<div style="margin-top:16px"><nk-steps id="stepsWizard" label="Connect your own model" current="3" horizontal selectable></nk-steps></div>
<script>{ document.getElementById('stepsWizard').steps = [{ label: 'Choose a provider', state: 'done', href: '#nk-steps' }, { label: 'Enter the API key', desc: 'skipped', state: 'skipped' }, 'Test the connection']; }</script>

Attributes

AttributeTypeDefaultDescription
stepslist–Comma-separated step labels.
currentnumber1The current step, from 1.
labelstring–The list’s accessible name.
selectableboolean–Labels are buttons that jump to their step.
horizontalboolean–One row above a wizard.

Slots

none

Events

EventdetailDescription
nk-select{ index, value, step }A step clicked (with selectable, or its link with a plain click or Enter); cancel it to stay.

Properties: steps current selectable horizontal

Methods: next() select(index)

On a small screen:Vertical steps stay as they are. horizontal keeps its row below 860px, with every mark but only the current step’s label.
Replaces.nk-steps.nk-step.st-mark.st-desc.done.current.skipped.st-label.horizontal

<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. Pass .mini-avatar, not .nk-avatar: the document rule of .nk-avatar sets its own 24px, and for slotted nodes the document wins over the group’s 26px.

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,var(--nk-decor-purple),var(--nk-decor-blue))">MK</span><span class="mini-avatar" style="background:var(--nk-color-green)">SL</span><span class="mini-avatar" style="background:var(--nk-color-orange)">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-avatar> Avatar

A person or a workspace: initials, an emoji or a photo in a circle. size small (20px), default 24px, large (32px), xlarge (56px); color one of Notion’s nine names or any CSS background, without it the avatar gradient; square for a workspace icon. Without content the initials come from name; with src a photo fills the circle and name becomes its alt text. Initials from name are the first letter or digit of each word: β€œPlaner (Dev)” β†’ PD, β€œAnna-Lena GroΓŸβ€ β†’ AG.

Wave 3
TWALSLMKA
<div style="display:flex;align-items:center;gap:10px"><nk-avatar size="small" color="blue">TW</nk-avatar><nk-avatar>AL</nk-avatar><nk-avatar color="green">SL</nk-avatar><nk-avatar size="large" color="orange">MK</nk-avatar><nk-avatar size="xlarge" color="purple" name="Ada Lovelace"></nk-avatar><nk-avatar size="large" square>A</nk-avatar></div>

Attributes

AttributeTypeDefaultDescription
sizesmall | large | xlarge–Size; default 24px.
colorcolour name | CSS–gray, brown, orange, yellow, green, blue, purple, pink, red – or any CSS background.
squareboolean–Corners instead of a circle.
namestring–Initials when empty; alt text of the photo.
srcURL–Photo.

Slots

SlotDescription
(default)Initials or an emoji.

Events

none

On a small screen:Unchanged. A fixed size, so a row of avatars never reflows.
Replaces.nk-avatar.small.large.xlarge.square.green.blue.orange.purple

<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. Read once and taken off the host, so it never shows as a tooltip.
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. Read once and taken off the host, so it never shows as a tooltip.

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="green" last></nk-member-row>

Attributes

AttributeTypeDefaultDescription
namestring–Name.
mailstring–Mail.
avatarstring–Initials.
colorcolour name | CSS–Avatar colour: one of the nine names (gray … red) or any CSS background; without it the avatar gradient.
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-sheet> Sheet

Notion’s mobile surface for menus, properties and more – the phone’s twin of the modal, with its contract: show(), close(), toggle(); Escape and the backdrop close it; focus moves in and back; the page behind is scroll-locked and inert. The panel rises from the bottom edge with a grabber, title sits under it and names the dialog. Rows inside are 40px, a thumb’s height. Choosing a row does not close the sheet – nk-select bubbles out and the app decides. For a menu that is a popover on the desktop and a sheet on the phone, use <nk-menu floating sheet>. Place it directly under <body>.

Wave 4
<nk-sheet open title="More">
  <nk-tree manual>
    <nk-section-label>Favourites</nk-section-label>
    <nk-tree-item icon="πŸš€">NotionKit MVP</nk-tree-item>
    <nk-tree-item icon="πŸŽ™οΈ">Voice-Office-Hub</nk-tree-item>
    <nk-section-label>Workspace</nk-section-label>
    <nk-tree-item icon="🧠">Knowledge base</nk-tree-item>
    <nk-tree-item icon="πŸ—‘οΈ">Trash</nk-tree-item>
  </nk-tree>
</nk-sheet>

Attributes

AttributeTypeDefaultDescription
openboolean–Shown.
titlestring–Heading under the grabber and the dialog’s name – never a tooltip.

Slots

SlotDescription
(default)The content: an nk-tree, menu items, fields.

Events

EventdetailDescription
nk-toggle{ open }Opened / closed.

Properties: open title

Methods: show() close() toggle()

On a small screen:Made for the phone: full width, above the tab bar, bottom padding from the safe area; the content scrolls inside the sheet. On larger screens at most 640px wide, centred.
Replaces.nk-sheet-backdrop.open.nk-sheet.sh-grabber.sh-title

<nk-peek> Side peek

Notion’s side peek: a database row opens at the right edge, full height, next to the table, which stays usable – no scrim, nothing inert. The bar carries Β» to close and your actions (slot="actions"); the body is the page – nk-page-title (32px here), nk-props, a .nk-prose, nk-comments. show() slides it in and moves focus to it; Β», Escape and a click elsewhere close it, and a click that calls show() again – another row – only swaps the content. Clicks inside other overlays leave it open. Place it directly under <body>. resizable gives it Notion’s drag on the left edge, inset moves the page aside instead of covering it.

Wave 4
<nk-peek open resizable resize-label="Resize" label="Database Table-View">
  <nk-btn slot="actions" variant="topbar" aria-label="Open as page"><svg viewBox="0 0 24 24" aria-hidden="true"><path d="M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7"/></svg></nk-btn>
  <nk-page-title>πŸ—ƒοΈ Database Table-View</nk-page-title>
  <nk-props>
    <nk-prop label="Status" icon="β—‰"><nk-tag color="blue">In progress</nk-tag></nk-prop>
    <nk-prop label="Due" icon="πŸ“…">20.05.2026</nk-prop>
  </nk-props>
  <div class="nk-prose"><p>Table, board and list read the same rows; filters and sort act on all three.</p></div>
</nk-peek>

Attributes

AttributeTypeDefaultDescription
openboolean–Shown.
labelstring–The dialog’s name – the entry’s title.
close-labelstringClose · SchließenName of ».
resizableboolean–The left edge makes it wider or narrower – pointer and arrow keys; the width is the token --nk-peek-width on :root.
widthpx560Sets the width, within min and max.
minpx380Narrowest.
maxpxwindow βˆ’ 320Widest.
resize-labelstringResize Β· Breite Γ€ndernName of the edge.
insetboolean–While open on the desktop, the page’s nk-app makes room instead of lying under it – for a chart whose bars must stay visible.

Slots

SlotDescription
(default)The page: title, properties, prose, comments.
actionsButtons beside Β» – open as page, share.

Events

EventdetailDescription
nk-toggle{ open }Opened / closed.
nk-resize{ width }A drag or a key changed the width – the moment to keep it.

Properties: open width

Methods: show() close() toggle()

On a small screen:Below 860px a bottom sheet over a dimmed page, title in 28px – and modal there: the page is inert and scroll-locked, a tap on the dimmed page closes it.
Replaces.nk-peek-backdrop.open.nk-peek.pk-resize.active.pk-bar.pk-body

<nk-dialog> Dialog

A question or a short form – β€œMove to trash?”, the name of a new view, the link between two tasks – with the contract of nk-modal and nk-sheet: show(), close(), toggle(), nk-toggle; Escape – captured, before a peek, a menu or a modal behind it – and the backdrop close it; focus moves in, to an [autofocus] element or the first field or button, and back; the page behind is inert and scroll-locked. It lies above the modal and the sheet. title is the heading, the default slot the text or the fields, slot="actions" the buttons, the confirming one last. A button in slot="actions" with a value closes it with that value, one anywhere inside with data-close too – another button with a value, an option of nk-segmented say, leaves it open – and so does the submit of a <form method="dialog"> inside; before it closes, nk-close fires and can be cancelled – the place to check an input. alert for a question, wide (560px) for a form. show(from) hands focus back to from – the β‹― of a menu that closed. Place it directly under <body>. While it is open the page behind is inert, but floating menus and date pickers under <body> – and the tooltip and toast – stay usable, so a field in the dialog can open one.

Wave 4
<nk-dialog open alert title="Move β€œNotionKit MVP” to trash?">
  The page and its sub-pages can be restored from Trash for 30 days.
  <nk-btn slot="actions" variant="secondary" value="">Cancel</nk-btn>
  <nk-btn slot="actions" variant="danger-solid" value="trash">Move to trash</nk-btn>
</nk-dialog>

Attributes

AttributeTypeDefaultDescription
openboolean–Shown.
titlestring–Heading and the dialog’s name – never a tooltip.
alertboolean–An alertdialog, described by its text.
wideboolean–560px instead of 440px.

Slots

SlotDescription
(default)The text or the fields.
actionsThe buttons, right; a value closes with it.

Events

EventdetailDescription
nk-close{ value }About to close – cancel it to keep it open.
nk-toggle{ open }Opened / closed.

Properties: open returnValue title

Methods: show(from) close(value) toggle()

On a small screen:Below 860px a bottom sheet with a grabber, the buttons stacked across the width, the confirming one on top.
Replaces.nk-dialog-backdrop.open.nk-dialog.wide.dl-title.dl-body.dl-actions

<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. Read once and taken off the host, so it never shows as a tooltip.
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. Inside nk-pop or the workspace switcher it is part of their surface. With floating it is a menu over the page of its own, NotionKit’s .nk-pop.floating: menu.show(button) opens it under the button, right edges aligned (align="start": left edges), and it fades in like the palette. A tap outside closes it and reaches nothing else; Escape and a chosen item close it, a switch row keeps it open. Opened from the keyboard, focus moves to the first item and back when it closes. Put it directly under <body>, like the other overlays. Floating, it opens upwards where the window ends below and there is more room above, and a menu longer than the room scrolls inside; in an nk-modal or nk-dialog it sits right as well, and opened from one of them it stays usable – an open dialog, modal or sheet leaves floating menus alone.

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

AttributeTypeDefaultDescription
floatingboolean–A menu over the page: fixed, closed until open, fades in.
sheetboolean–Below 860px a bottom sheet (with floating).
openboolean–Shown (with floating).
alignend | startendWhich edges show(anchor) aligns.

Slots

SlotDescription
(default)nk-menu-item children.

Events

EventdetailDescription
nk-select{ value, label, item }From the chosen item.
nk-toggle{ open }A floating menu opened / closed.

Properties: open items

Methods: show(anchor?) close() toggle(anchor?) focusFirst()

On a small screen:With sheet the floating menu is a bottom sheet below 860px – full width, a grabber, 40px rows, the page dimmed – whatever position show() wrote: one markup, two presentations, as Notion’s mobile app opens every menu.
Replaces.nk-pop.nk-menu.nk-menu-item.m-icon.m-shortcut.danger.nk-menu-sep.nk-menu-label.floating.sheet.open

<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, or to a row with a switch on the right – β€œSmall text” in Notion’s page menu: a click flips checked and fires nk-change, so the menu stays open. type="check" puts a βœ“ where the shortcut stands, as in a filter menu – for a choice of several: a click flips checked and fires nk-change { value, checked } instead of nk-select, and the menu stays open.

Wave 4
RenameSmall text
<nk-menu><nk-menu-item icon="✏️" shortcut="⌘E" value="rename">Rename</nk-menu-item><nk-menu-item type="switch" icon="πŸ”‘" value="small" checked>Small text</nk-menu-item></nk-menu>

Attributes

AttributeTypeDefaultDescription
iconstring–Leading icon.
shortcutstring–Trailing shortcut text.
valuestring–Reported value (default: text).
dangerboolean–Red text.
typeitem | separator | label | switch | checkitemRow kind.
checkedboolean–The switch is on, the check shows (type="switch" / "check").
disabledboolean–Not selectable.

Slots

SlotDescription
(default)Label.
iconIcon node.

Events

EventdetailDescription
nk-select{ value, label, item }Clicked / Enter.
nk-change{ value, checked, item }A switch or check row flipped.
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, above every overlay; over a tab bar at the bottom of the screen it rises 12px above the bar. toast.show("Saved") shows it and hides it after duration ms; open is the state. With an action – show("Moved to trash", { action: { label: "Undo", value: "undo" } }) or a <button slot="action"> – it is Notion’s toast with a button and an Γ—: it stays until one of them is used, unless show() names a duration, and waits while the pointer or the focus is on it. The action fires nk-action and, unless cancelled, closes it; Escape closes it while the focus is inside.

Wave 4
<nk-toast open duration="0" icon="πŸ—‘οΈ">Moved to trash<button slot="action" value="undo">Undo</button></nk-toast>

Attributes

AttributeTypeDefaultDescription
openboolean–Visible.
durationms2200Auto-hide delay (0 = stay); a toast with an action stays unless show() names one.
iconstringβœ“Leading glyph.

Slots

SlotDescription
(default)Static content (when show() gets no message).
actionA button for the action; its value goes out with nk-action.

Events

EventdetailDescription
nk-toggle{ open }Shown / hidden.
nk-action{ action, value, label }The action used; cancel it to keep the toast.

Properties: open message

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

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

<nk-tooltip> Tooltip

Notion’s hover hint in the toast’s colours, a shortcut muted beside it. One <nk-tooltip> without for serves every element with data-tooltip (and data-tooltip-key) on the page, inside shadow roots too – a whole toolbar in one element, and it follows pointer and keyboard from one such element to the next within the same shadow root; with for it belongs to one element and shows its own content and shortcut. It appears after delay ms (400) under the pointer and at once on keyboard focus, never on touch; leaving – the window too –, a press, blur, scrolling and Escape hide it. It sits 6px below its target and centred, above it where the window ends, 8px inside the window – placeNear in util/floating.js. show(target, text, shortcut) takes an element or a rect, for what has no element of its own: the bars of a chart. The target’s aria-describedby names it while it shows. Hover the buttons. A tooltip shown with show(rect, …) stays until hide(), the pointer on another [data-tooltip], a press or Escape; the wheel hides it too, also inside a shadow root. A line break in the text is kept.

β‹― ⭐ ☰
Open sidebar
<div style="display:flex;gap:16px;align-items:center;padding:4px 0 44px">
  <nk-btn variant="topbar" aria-label="Style, export and more" data-tooltip="Style, export and more">β‹―</nk-btn>
  <nk-btn variant="topbar" aria-label="Add to Favourites" data-tooltip="Add to Favourites">⭐</nk-btn>
  <nk-btn variant="topbar" id="ttSidebar" aria-label="Open sidebar">☰</nk-btn>
</div>
<nk-tooltip></nk-tooltip>
<nk-tooltip for="ttSidebar" shortcut="⌘\">Open sidebar</nk-tooltip>

Attributes

AttributeTypeDefaultDescription
forid–The one element it belongs to; without it, every [data-tooltip].
shortcutstring–With for: the shortcut beside the text.
delayms400Wait under the pointer.
placementbottom | topbottomPreferred side.

Slots

SlotDescription
(default)With for: the text.

Events

none

Properties: open

Methods: show(target, text, shortcut) hide()

On a small screen:No hover on a phone: it shows nothing on touch.
Replaces.nk-tooltip.open.tt-key

Data & collaboration

Wave 5

<nk-database> Database

The view switcher with Notion’s toolbar: child views (nk-table-view, nk-board-view, nk-list-view) become the tabs on the left, slot="tools" holds the view’s tools on the right – <nk-btn variant="tool"> for Filter, Sort and search, then β€œNew” – and slot="filters" the nk-filter-bar under them. 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
Filter Sort New
<nk-database view="table" add-view>
  <nk-btn slot="tools" variant="tool" active>Filter</nk-btn>
  <nk-btn slot="tools" variant="tool">Sort</nk-btn>
  <nk-btn slot="tools" variant="primary" small>New</nk-btn>
  <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: 'β–°' },
    { key: 'effort', label: 'Effort (h)', type: 'number', icon: '#', locale: 'en', format: { minimumFractionDigits: 1 } },
  ];
  db.rows = [
    { id: 1, icon: '🧭', name: 'App shell & sidebar', status: 'done', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '08.05.2026', progress: 100, effort: 6, cover: '/covers/aurora.svg' },
    { id: 2, icon: 'πŸ“„', name: 'Page shell & typography', status: 'done', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '10.05.2026', progress: 100, effort: 4.5, cover: '/covers/dunes.svg' },
    { id: 3, icon: 'πŸ—ƒοΈ', name: 'Database table view', status: 'progress', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '20.05.2026', progress: 65, effort: 12.5, cover: '/covers/meadow.svg' },
    { id: 4, icon: 'β–€', name: 'Board view & drag-and-drop', status: 'planned', due: '02.06.2026', progress: 0, effort: 8, cover: '/covers/tide.svg' },
  ];
}</script>

Attributes

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

Slots

SlotDescription
(default)View elements.
toolsThe tools right of the tabs: <nk-btn variant="tool">, a small primary β€œNew”.
filtersUnder the toolbar: nk-filter-bar.

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:The tabs scroll sideways when the row gets narrow; the tools keep their place. Tables and boards scroll horizontally; nothing breaks.
Replaces.nk-database.nk-db-toolbar.nk-db-tabs.nk-db-tab.active.badge.add.tools

<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. A number column stands right-aligned in figures of equal width, formatted by its locale and format (Intl.NumberFormat options); a person’s color takes one of the nine names. A column of type actions (NotionKit 1.12.0) sets buttons in each row from column.actions – [{ action, label, icon, danger, disabled, tooltip }] –, and a row’s value – a list of action names – picks which of them it shows; a click fires nk-action { action, row, id, anchor } instead of selecting the row. A url value may be { href, label, target }: a link of your own, to another page of the app, with its own text. A text value may be { text, desc, color, tooltip } (NotionKit 1.15.0): a quiet second line, one of Notion’s nine text colours – orange for an error –, the whole text in a tooltip. Sorting goes by the value, not the text shown: dates by their time, selects by the order of their options, empty cells last; sortKey on a column sorts by another field of the row, a sort in a cell’s object by that value. A date column with format – 'short', 'relative' or the options of Intl.DateTimeFormat – shows ISO dates and date-times formatted in its locale. A checkbox column with selectAll: true (1.21.0) is a selection column: its header is a checkbox – empty, a dash for some rows, a check for all – that sorts nothing; a click or Space sets the column for every row the view has (a dash selects all, as in Notion) and fires one nk-change { key, value, all: true, rows }. What β€œall” means beyond these rows – more pages, a filter on the server – stays with the app. Its name comes from the texts (selectAll).

Wave 5
<nk-table-view new-row sortable></nk-table-view>
<script>{
  const db = document.currentScript.previousElementSibling;
  db.columns = [
    { key: 'selected', type: 'checkbox', selectAll: true },
    { 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: 'β–°' },
    { key: 'effort', label: 'Effort (h)', type: 'number', icon: '#', locale: 'en', format: { minimumFractionDigits: 1 } },
    { key: 'actions', type: 'actions', actions: [{ action: 'open', label: 'Open' }, { action: 'archive', label: 'Archive', danger: true }] },
  ];
  db.rows = [
    { id: 1, icon: '🧭', name: { text: 'App shell & sidebar', desc: 'Three open questions' }, status: 'done', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '08.05.2026', progress: 100, effort: 6, cover: '/covers/aurora.svg', selected: true },
    { id: 2, icon: 'πŸ“„', name: 'Page shell & typography', status: 'done', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '10.05.2026', progress: 100, effort: 4.5, cover: '/covers/dunes.svg' },
    { id: 3, icon: 'πŸ—ƒοΈ', name: 'Database table view', status: 'progress', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '20.05.2026', progress: 65, effort: 12.5, cover: '/covers/meadow.svg', selected: true },
    { id: 4, icon: 'β–€', name: 'Board view & drag-and-drop', status: 'planned', due: '02.06.2026', progress: 0, effort: 8, actions: ['open'], cover: '/covers/tide.svg' },
  ];
}</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 page Β· οΌ‹ Neue SeiteIts text.
sortableboolean–Header click sorts locally.
sort-keystring–Sorted column.
sort-dirasc | desc–Direction.
wrapboolean–Cell text may break (Notion's "wrap column").

Slots

none

Events

EventdetailDescription
nk-select{ row, id, key, cell }Row clicked.
nk-change{ row, key, value } Β· selectAll: { key, value, all: true, rows }Checkbox cell toggled (row updated in place); from a selectAll header once for every row.
nk-action{ action: 'sort' | 'new-row' | an actions column's action, key?, value?, row?, id?, anchor? }Header, add row or a row’s button clicked.

Properties: columns rows data

Methods: refresh()

On a small screen:Scrolls horizontally inside .nk-table-wrap.
Replaces.nk-table-wrap.nk-table.wrap.th-icon.row-title.date-cell.person-cell.nk-avatar.num.row-actions.actions.select-all.nk-check.td-text.td-desc.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: 'β–°' },
    { key: 'effort', label: 'Effort (h)', type: 'number', icon: '#', locale: 'en', format: { minimumFractionDigits: 1 } },
  ];
  db.rows = [
    { id: 1, icon: '🧭', name: 'App shell & sidebar', status: 'done', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '08.05.2026', progress: 100, effort: 6, cover: '/covers/aurora.svg' },
    { id: 2, icon: 'πŸ“„', name: 'Page shell & typography', status: 'done', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '10.05.2026', progress: 100, effort: 4.5, cover: '/covers/dunes.svg' },
    { id: 3, icon: 'πŸ—ƒοΈ', name: 'Database table view', status: 'progress', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '20.05.2026', progress: 65, effort: 12.5, cover: '/covers/meadow.svg' },
    { id: 4, icon: 'β–€', name: 'Board view & drag-and-drop', status: 'planned', due: '02.06.2026', progress: 0, effort: 8, cover: '/covers/tide.svg' },
  ];
}</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-list-view> List view

The third database view: one line per row – icon and title, the meta-keys on the right (default: the select and date columns, in column order). Dates and text stand as text, selects as tags, a person as avatar and name. Rows fire nk-select; new-row adds the add row.

Wave 5
<nk-list-view meta-keys="due,status"></nk-list-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: 'β–°' },
    { key: 'effort', label: 'Effort (h)', type: 'number', icon: '#', locale: 'en', format: { minimumFractionDigits: 1 } },
  ];
  db.rows = [
    { id: 1, icon: '🧭', name: 'App shell & sidebar', status: 'done', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '08.05.2026', progress: 100, effort: 6, cover: '/covers/aurora.svg' },
    { id: 2, icon: 'πŸ“„', name: 'Page shell & typography', status: 'done', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '10.05.2026', progress: 100, effort: 4.5, cover: '/covers/dunes.svg' },
    { id: 3, icon: 'πŸ—ƒοΈ', name: 'Database table view', status: 'progress', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '20.05.2026', progress: 65, effort: 12.5, cover: '/covers/meadow.svg' },
    { id: 4, icon: 'β–€', name: 'Board view & drag-and-drop', status: 'planned', due: '02.06.2026', progress: 0, effort: 8, cover: '/covers/tide.svg' },
  ];
}</script>

Attributes

AttributeTypeDefaultDescription
namestring–View name.
labelstring–Tab label.
title-keystring–Title column.
meta-keyslist–Comma-separated columns on the right.
new-rowboolean–Show the add row.
new-row-labelstringοΌ‹ New page Β· οΌ‹ Neue SeiteIts text.

Slots

none

Events

EventdetailDescription
nk-select{ row, id }Row clicked or Enter.
nk-action{ action: 'new-row' }Add row clicked.

Properties: columns rows data

Methods: refresh()

On a small screen:Stays one line per row: the title ends in an ellipsis, the properties keep their place.
Replaces.nk-list.nk-list-item.l-icon.l-title.l-meta

<nk-calendar-view> Calendar view

The fourth database view (NotionKit 1.9.0): a month, the rows as cards on their dates. date-key names the date column (default: the first one) – YYYY-MM-DD or D.M.YYYY, a range on its start. Today sits on a red pill, days of other months are washed; weeks puts the calendar week in front, weekend washes the days not worked. A card fires nk-select like a row of the table; Today and β€Ή β€Ί change the month (nk-month). In nk-database it is a tab like the others and shows the same rows.

Wave 5
<nk-calendar-view date-key="due" month="2026-05" today="2026-05-20" weeks week-start="1" today-label="Today"></nk-calendar-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: 'β–°' },
    { key: 'effort', label: 'Effort (h)', type: 'number', icon: '#', locale: 'en', format: { minimumFractionDigits: 1 } },
  ];
  db.rows = [
    { id: 1, icon: '🧭', name: 'App shell & sidebar', status: 'done', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '08.05.2026', progress: 100, effort: 6, cover: '/covers/aurora.svg' },
    { id: 2, icon: 'πŸ“„', name: 'Page shell & typography', status: 'done', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '10.05.2026', progress: 100, effort: 4.5, cover: '/covers/dunes.svg' },
    { id: 3, icon: 'πŸ—ƒοΈ', name: 'Database table view', status: 'progress', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '20.05.2026', progress: 65, effort: 12.5, cover: '/covers/meadow.svg' },
    { id: 4, icon: 'β–€', name: 'Board view & drag-and-drop', status: 'planned', due: '02.06.2026', progress: 0, effort: 8, cover: '/covers/tide.svg' },
  ];
}</script>

Attributes

AttributeTypeDefaultDescription
namestringcalendarView name.
labelstring–Tab label.
date-keystring–Date column.
title-keystring–Title column.
monthYYYY-MM–The month shown; default today’s.
weeksboolean–The ISO calendar week in front of each row.
week-start0–6IntlFirst day of the week: 0 Sunday, 1 Monday …
weekendlist–Weekdays not worked, washed – 6,0.
todayYYYY-MM-DD–Another today – for tests and docs.
localeBCP 47langLanguage of the names and the week.
today-labelstringToday Β· HeuteToday button.
prev-labelstringPrevious month Β· Voriger MonatNames β€Ή.
next-labelstringNext month Β· NΓ€chster MonatNames β€Ί.
week-labelstringW Β· KWHead of the week column.

Slots

none

Events

EventdetailDescription
nk-select{ row, id }Card clicked or Enter.
nk-month{ month }Another month shown.

Properties: columns rows data month

Methods: refresh()

On a small screen:Keeps seven columns; the days get lower (64px) and the cards smaller.
Replaces.nk-calendar-view.weeks.cv-head.cv-title.cal-nav.cv-grid.cv-wd.cv-week.cv-day.out.off.today.cv-num.cv-item

<nk-gallery-view> Gallery view

The fifth database view: the rows as cards with a picture on top, in a grid that fills the row – Notion’s gallery, for a course catalog or a reading list. cover-key names the row field with the picture’s URL (default: cover); a row without one shows the cover gradient, no-cover leaves the pictures out. The picture stands in 2:1, cropped to fill; fit shows it whole, for logos. size small, medium or large sets the card size – columns from 180, 260 or 340px. Cards show the title and the meta-keys (default: the select and date columns) and fire nk-select on a click, Enter or Space; new-row adds the add card. href-key names the row field with a card’s address: such a card is a link, <a class="nk-card" href> in a .card-item that carries the list item’s role – to open a course in a new tab or copy its address. A plain click, and Enter, fire the same nk-select; cancel it and the browser stays. A middle click or one with Cmd, Ctrl, Shift or Alt fires nothing and does what a link does.

Wave 5
<nk-gallery-view meta-keys="status,due" new-row></nk-gallery-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: 'β–°' },
    { key: 'effort', label: 'Effort (h)', type: 'number', icon: '#', locale: 'en', format: { minimumFractionDigits: 1 } },
  ];
  db.rows = [
    { id: 1, icon: '🧭', name: 'App shell & sidebar', status: 'done', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '08.05.2026', progress: 100, effort: 6, cover: '/covers/aurora.svg' },
    { id: 2, icon: 'πŸ“„', name: 'Page shell & typography', status: 'done', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '10.05.2026', progress: 100, effort: 4.5, cover: '/covers/dunes.svg' },
    { id: 3, icon: 'πŸ—ƒοΈ', name: 'Database table view', status: 'progress', owner: { name: 'Marcel', initials: 'MK', color: 'purple' }, due: '20.05.2026', progress: 65, effort: 12.5, cover: '/covers/meadow.svg' },
    { id: 4, icon: 'β–€', name: 'Board view & drag-and-drop', status: 'planned', due: '02.06.2026', progress: 0, effort: 8, cover: '/covers/tide.svg' },
  ];
}</script>

Attributes

AttributeTypeDefaultDescription
namestring–View name.
labelstring–Tab label.
cover-keystringcoverRow field with the picture’s URL.
no-coverboolean–Cards without pictures.
sizesmall | medium | largemediumCard size.
fitboolean–Show a picture whole instead of cropped.
title-keystring–Title column.
meta-keyslist–Comma-separated columns under the title.
href-keystring–Row field with the card’s address; such a card is a link.
new-rowboolean–Show the add card.
new-row-labelstringοΌ‹ New page Β· οΌ‹ Neue SeiteIts text.

Slots

none

Events

EventdetailDescription
nk-select{ row, id, value }Card clicked, Enter or Space; a link card with a plain click or Enter – cancel it to stay.
nk-action{ action: 'new-row' }Add card clicked.

Properties: columns rows data

Methods: refresh()

On a small screen:The grid drops columns by itself – one card per row on a phone, no breakpoint involved.
Replaces.nk-gallery.small.large.fit.nk-card.card-item.nk-cover.card-title.card-meta.nk-new-row

<nk-filter-bar> Filter bar

The filters in effect as NotionKit’s filter pills – .active with an accent tint, a Γ— to remove each, a quiet add pill at the end – with no inline style. In slot="filters" of nk-database the row sits under the toolbar. A pill’s label fires nk-action { action: "edit" }, the add pill { action: "add" }, each with the clicked button as anchor for menu.show(anchor). bar.apply(rows) keeps rows where every filter matches by strict equality (row[key] === value, so use the option value) – or differs with op: "is-not" – and the search text appears in any string field (a person’s name); the data logic stays yours. Its own Filter and Sort tools and the search field are there for a bar without a database toolbar. It keeps its own copy of filters: the array you pass is never changed, a removed pill is reported in nk-change.

Wave 5
<nk-filter-bar add no-filter no-sort remove-label="Remove filter"></nk-filter-bar>
<script>{ document.currentScript.previousElementSibling.filters = [{ key: 'status', value: 'done', op: 'is-not', label: 'Status: Open' }]; }</script>

Attributes

AttributeTypeDefaultDescription
addboolean–Show the add pill.
add-labelstringοΌ‹ FilterIts text.
no-filterboolean–Hide the Filter tool.
no-sortboolean–Hide the Sort tool.
filter-labelstringFilterText of the Filter tool.
sort-labelstringSort Β· SortierenText of the Sort tool.
remove-labelstringRemove filter Β· Filter entfernenThe ×’s name, followed by the pill’s text.
searchboolean–Show the search field.
placeholderstring–Search placeholder.

Slots

SlotDescription
(default)Extra pills or controls between the pills and the search.

Events

EventdetailDescription
nk-change{ filters, search }A filter removed or the search typed.
nk-action{ action: 'edit' | 'add' | 'filter' | 'sort', index?, filter?, anchor }A pill or a tool clicked.

Properties: filters value

Methods: apply(rows)

On a small screen:The pills wrap onto further rows.
Replaces.nk-filter-row.nk-filter-pill.active.add.fp-remove.nk-db-tool.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-labelstringSend Β· SendenButton 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="green">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).
colorcolour name | CSS–Avatar colour: one of the nine names or any CSS background; without it the avatar gradient.

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
What is still open on this page?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" bubble>What is still open on this page?</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></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.
bubbleboolean–The message as a grey bubble without avatar or name; with role="user" on the right, as Notion’s AI chat shows your own question.

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.bubble.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