Nasaq

Section Board

An ordered set of sections, each generated by a prompt, a model and a few settings. View mode shows the content; edit mode reorders by drag or keyboard and edits each section in a dialog.

PreviewOpen ↗

Code

const [sections, setSections] = useState<BoardSection[]>(initial);const [editing, setEditing] = useState(false);<SectionBoard  sections={sections}  editing={editing}  models={[{ value: "fast", label: "Fast" }, { value: "deep", label: "Deep reasoning" }]}  columns={2}  onChange={(next) => {    setSections(next);    void api.saveSections(next);  }}  onAdd={() => setSections((s) => [...s, { id: crypto.randomUUID(), title: "New section" }])}  renderContent={(s) => <Markdown>{generated[s.id]}</Markdown>}/>;

AI Agents · beta

Live examples and controls: Section Board in the lab.

Install

npx shadcn@latest add https://docs.nasaqui.com/r/section-board.json

A page made of sections that an AI writes: a daily briefing, a report, a generated landing page. Each section has a prompt, a model and a few free settings. Readers see only the content. Editors switch on editing to reorder the sections, change how each is generated, or remove one.

When to use

  • Pages whose parts are generated from prompts and which the owner tunes over time.

When not to use

  • A grid of widgets with sizes and typed settings: use DashboardBoard.
  • Reordering form rows: use Repeater.

Import

import { SectionBoard, type BoardSection } from "@fadymondy/nasaq";

Quick start

const [sections, setSections] = useState<BoardSection[]>(initial);
const [editing, setEditing] = useState(false);

<SectionBoard
  sections={sections}
  editing={editing}
  models={[{ value: "fast", label: "Fast" }, { value: "deep", label: "Deep reasoning" }]}
  columns={2}
  onChange={(next) => {
    setSections(next);
    void api.saveSections(next);
  }}
  onAdd={() => setSections((s) => [...s, { id: crypto.randomUUID(), title: "New section" }])}
  renderContent={(s) => <Markdown>{generated[s.id]}</Markdown>}
/>;

Anatomy

  • data-slot="section-board" (data-editing in edit mode), an ol named "Sections".
  • section-board-section (li, data-section, data-dragging): drag handle, title (your heading level), tag, Edit and Remove.
  • section-board-content: the content, inert while editing so it cannot be tabbed into as cards move.
  • section-board-prompt: in edit mode, the model and the first line of the prompt.
  • The editor dialog: title, tag, prompt, model (with a "Default model" choice), and key/value settings rows (section-board-setting).
  • An empty state when there are no sections.

API

PropTypeNotes
sectionsBoardSection[]{ id, title, badge?, prompt?, model?, settings?, content? }.
onChange(sections) => voidThe whole list after a reorder, edit or removal. Without it the board is read only.
editingbooleanEdit mode. Default false.
models{ value, label? }[]The models offered. An unset model means your default.
columns1 | 2Two columns from sm. Default 1.
onAdd() => voidShows Add section in edit mode.
renderContent(section) => ReactNodeWhat a section shows. Default section.content.
headingAsElementTypeSection title level. Default h3.
labelsPartial<SectionBoardLabels>Text overrides.

Helpers

From section-board-logic.ts, pure: sectionSettingRows(settings) and sectionSettingsFromRows(rows) convert between the settings object and editable rows (keys trimmed, empty keys dropped, a repeated key keeps its last value); duplicateSectionSettingKeys(rows) finds keys used twice; boardSectionChanged(a, b) compares the editable parts. Types BoardSection, BoardSectionModel, BoardSettingRow.

Accessibility

  • Each section is a list item named by its title. Reorder by dragging the handle, or focus it and press the arrow keys, Home or End; the new position is announced ("News is now at position 2 of 4"), as are saves and removals.
  • Icon buttons have names that include the section ("Edit News", "Remove News") and tooltips.
  • The editor is a dialog with labelled fields. A missing title and repeated setting keys are reported in words with role="alert"; Save stays off until something changed.

RTL & i18n

English and Arabic strings are built in. Titles, prompts and content use dir="auto"; setting keys stay left to right. The layout uses logical sides, so it mirrors in Arabic. Positions use the locale's digits.

Styling & tokens

Sections are bg-card with border-border and rounded-card; a dragged section gets border-nq-focus and shadow-floating. The prompt line uses font-mono and text-muted-foreground.

Do / Don't

  • Do keep ids stable; they key the content you generate.
  • Do save in onChange, or collect changes and save when the person leaves edit mode.
  • Don't put interactive content in a section and expect it to work in edit mode; it is inert there.

dashboard-board, repeater, ai-model-picker, copilot-chat.

Lab

AI Agents › Section Board: Default, Two columns, Read only, Empty, Arabic.

On this page