Skip to content
ilinxa/pro-ui

Blackboard

alphav0.2.1

Chalkboard-style team notes board — handwritten ink notes with pens, widths, pins, @mentions, auto-save, and lazy history loading.

Category: Data DisplayUpdated: 2026-08-12Created: 2026-06-18Author: ilinxa

Context

A collaborative handwritten-note wall for dashboards and panels. Notes stream vertically (newest at the bottom) in the author's chosen ink color, chalk width, and handwriting font; the composer auto-saves (no Save button), scrolling up lazy-loads 10 older notes, hovering a note reveals its author inline, authors can @mention teammates and pin notes to a sticky row, and a handwritten red number marks unread notes. The board surface is themeable (color or custom image). Ships as a shadcn-style compound — headless BlackboardRoot + flat parts + standalone primitives + the Blackboard assembly — so a read-only wall falls out by dropping the composer. Portable by design: all persistence, real-time transport, and notifications are the consumer's via callbacks (no network I/O in the library).

Installation

Initialize shadcn (once per project)Seeds lib/utils.ts and components.json. Skip if you've already used any shadcn component.
pnpm dlx shadcn@latest init
Register the @ilinxa namespace (once per project)Add to your components.json. Merge with existing config.
"registries": {
  "@ilinxa": "https://ui.ilinxa.com/r/{name}.json"
}
Install the component
pnpm dlx shadcn@latest add @ilinxa/blackboard

Add -fixtures for dummy data:

pnpm dlx shadcn@latest add @ilinxa/blackboard-fixtures

Preview

Double-click the board to reveal the composer (Esc or ✕ to dismiss). Pick an ink color, chalk width, and font; type @ to mention a teammate; scroll up to lazy-load older notes; the red number marks unread.

Pinned

Standup moved to 10:30 from tomorrow 👋

Maryam
Load older notes

Shipped the media-library smoke fix — green ✅

Ali

@Hessam can you review the blackboard plan?

@youSara

On it — pushing the GATE 2 plan now.

Hessam

Coffee machine on 3rd floor is fixed ☕

Devran

Design review @Maryam @Ali at 4pm in the slate room

Hessam
Double-click to write a note

Demo source

demo.tsxtsx

Usage

When to use

Reach for Blackboard when a team needs a shared, low-ceremony wall — a dark chalkboard you drop into a dashboard or panel where members jot short handwritten notes. Each writer picks an ink color, chalk width, and handwriting font; notes auto-save, the stream lazy-loads older notes on scroll-up, hovering reveals the author, and a handwritten red number marks unread notes. It is not a threaded comment list (comment-thread), a chat panel, or a freeform whiteboard.

Basic example

import { Blackboard } from "@/components/blackboard"

export function TeamBoard({ notes, me, team }) {
  return (
    <div className="h-[520px]">
      <Blackboard
        notes={notes}                 // controlled, oldest → newest
        currentUser={me}
        members={team}                 // drives the @-mention picker
        canWrite
        onPostNote={(draft) => api.post(draft)}      // auto-saves; no Save button
        onLoadOlder={(beforeId, n) => api.older(beforeId, n)}  // 10 on scroll-up
        hasMoreOlder
        onPinNote={(id) => api.pin(id)}
        onMention={(noteId, ids) => api.notify(noteId, ids)}
        lastSeenNoteId={me.lastSeen}
        onSeen={(id) => api.markSeen(id)}
        editableBackground
      />
    </div>
  )
}

Lighter (à la carte)

It ships as a compound. Compose the flat parts directly and drop what you don't need — omitting BlackboardComposer yields a read-only wall and never pulls the writing / mention code:

import {
  BlackboardRoot, BlackboardSurface, BlackboardNoteStream,
} from "@/components/blackboard"

<BlackboardRoot notes={notes} currentUser={me}>
  <BlackboardSurface>
    <BlackboardNoteStream />
  </BlackboardSurface>
</BlackboardRoot>

Notes

  • Portable by design.The library does no network I/O — persistence, real-time transport, and notifications are yours via callbacks. Push inbound notes with the imperative handle's appendNote().
  • Pin is controlled via pinnedNoteIds (or the uncontrolled note.pinned flag); pinned notes lift into a sticky row.
  • Fonts are bundled (Kalam / Caveat / Patrick Hand / Shadows Into Light) and overridable via the fontsprop. “Chalk width” uses real font-weight where the face supports it, a faux stroke otherwise.
  • The board is intentionally dark in both light and dark app themes (chalkboard identity). Type @ in the composer to mention a teammate.

Features

  • Vertical handwritten-note stream with per-note ink color, chalk width, and handwriting font
  • Auto-save (debounced, no Save button) + optimistic posting with reconcile/retry
  • Scroll-up lazy loading (10-note pages) with scroll-anchored, jump-free prepend
  • Inline author-on-hover label + handwritten red unread marker
  • @mentions over a team roster + pin-to-sticky-row, both capability-gated
  • Editable board background (solid color or custom image with legibility overlay)
  • Compound: headless Root + flat à-la-carte parts; drop the composer for a free read-only board

Tags

blackboardchalkboardcollaborationnoteshandwritingmentionsteamfeed

Dependencies

shadcn primitives: button, textarea
npm peer deps: @fontsource/kalam@^5.2.8, @fontsource-variable/caveat@^5.2.8, @fontsource/patrick-hand@^5.2.8, @fontsource/shadows-into-light@^5.2.8, date-fns@^4.1.0, lucide-react@^1.11.0