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.
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.jsonA 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-editingin edit mode), anolnamed "Sections".section-board-section(li,data-section,data-dragging): drag handle, title (your heading level), tag, Edit and Remove.section-board-content: the content,inertwhile 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
| Prop | Type | Notes |
|---|---|---|
sections | BoardSection[] | { id, title, badge?, prompt?, model?, settings?, content? }. |
onChange | (sections) => void | The whole list after a reorder, edit or removal. Without it the board is read only. |
editing | boolean | Edit mode. Default false. |
models | { value, label? }[] | The models offered. An unset model means your default. |
columns | 1 | 2 | Two columns from sm. Default 1. |
onAdd | () => void | Shows Add section in edit mode. |
renderContent | (section) => ReactNode | What a section shows. Default section.content. |
headingAs | ElementType | Section title level. Default h3. |
labels | Partial<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.
Related
dashboard-board, repeater, ai-model-picker, copilot-chat.
Lab
AI Agents › Section Board: Default, Two columns, Read only, Empty, Arabic.