- canon/standards/contribution-convention_v0.1.md: master spec for BR/FR/EP/UPR artifact types, directory layout, frontmatter schema, ID schemes (EP-DOMAIN-NNN for extension points), status lifecycle, and relationship to State Hub - canon/standards/contrib-templates/: four template files (br, fr, ep, upr) - contrib/upstream-prs/2026-02-26--observablehq--framework--toc-sidebar-inject.md: first real UPR artifact — proposes injectTocTop() to Observable Framework Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
100 lines
3.5 KiB
Markdown
100 lines
3.5 KiB
Markdown
---
|
|
id: upr-2026-02-26--observablehq--framework--toc-sidebar-inject
|
|
type: upr
|
|
target_org: observablehq
|
|
target_repo: framework
|
|
title: "Add injectTocTop() utility for injecting elements into the TOC sidebar"
|
|
status: draft
|
|
domain: custodian
|
|
related_workstream: contribution-tracking-sbom
|
|
state_hub_contribution_id: null
|
|
created: "2026-02-26"
|
|
updated: "2026-02-28"
|
|
local_component_path: "state-hub/dashboard/src/components/toc-sidebar.js"
|
|
target_upstream_file: "src/client/toc.ts"
|
|
upstream_pr_url: null
|
|
---
|
|
|
|
# Upstream PR: Add injectTocTop() utility for injecting elements into the TOC sidebar
|
|
|
|
## Summary
|
|
|
|
Propose adding an `injectTocTop(id, element)` utility to Observable Framework
|
|
that allows dashboard pages to prepend arbitrary HTML elements at the top of the
|
|
automatically-generated table-of-contents sidebar. This enables KPI cards, live
|
|
status indicators, and other contextual widgets to live alongside the page's
|
|
section links.
|
|
|
|
## Motivation
|
|
|
|
Observable Framework generates a TOC sidebar from headings automatically, but
|
|
provides no standard way to inject content into it from page JavaScript. As a
|
|
result, every project that wants sidebar widgets must implement its own DOM
|
|
manipulation workaround.
|
|
|
|
By upstreaming a small, focused utility, the community gets a stable API for
|
|
sidebar injection that doesn't depend on Observable Framework's internal DOM
|
|
structure.
|
|
|
|
## Local Component
|
|
|
|
**Path in this repo**: `state-hub/dashboard/src/components/toc-sidebar.js`
|
|
**Origin story**: Created 2026-02-26 during implementation of the Decisions KPI
|
|
dashboard (State Hub v0.2). The component provides two utilities:
|
|
- `injectTocTop(id, element)`: remove-then-prepend to the TOC aside element
|
|
- `withDocHelp(element, docPath)`: attaches a `?` button that opens a doc page
|
|
as an iframe overlay
|
|
|
|
## Target Upstream Location
|
|
|
|
**Repo**: `observablehq/framework`
|
|
**File**: `src/client/toc.ts` (or a new `src/client/toc-inject.ts`)
|
|
|
|
## Draft PR Body
|
|
|
|
```markdown
|
|
## Summary
|
|
|
|
Add `injectTocTop(id, element)` — a small utility for injecting custom elements
|
|
at the top of the Observable Framework table-of-contents sidebar.
|
|
|
|
## Motivation
|
|
|
|
Dashboard pages frequently need contextual widgets (KPI boxes, live status
|
|
indicators, navigation aids) that belong alongside the TOC, not in the page
|
|
content flow. Currently this requires each project to directly manipulate the
|
|
`#observablehq-toc` DOM element, coupling page code to an internal DOM detail.
|
|
|
|
`injectTocTop` provides a stable API for this pattern:
|
|
|
|
```js
|
|
import {injectTocTop} from "observablehq:toc";
|
|
|
|
const myWidget = html`<div class="kpi-box">...</div>`;
|
|
injectTocTop("my-kpi-box", myWidget);
|
|
```
|
|
|
|
## Changes
|
|
|
|
- Add `injectTocTop(id: string, element: HTMLElement): void` to Framework's
|
|
client runtime
|
|
- Export from the `observablehq:toc` module (or equivalent public API)
|
|
- Add documentation page: "Customising the sidebar"
|
|
|
|
## Testing
|
|
|
|
- [ ] Unit test: `injectTocTop` prepends element to `#observablehq-toc aside`
|
|
- [ ] Unit test: calling again with same `id` removes old element before
|
|
inserting new one (idempotent)
|
|
- [ ] Integration test: injected element appears above TOC links in rendered page
|
|
```
|
|
|
|
## Notes
|
|
|
|
- The local implementation (`toc-sidebar.js`) uses `querySelector('#observablehq-toc aside')`
|
|
— this should be replaced with a stable API reference once upstreamed.
|
|
- The `withDocHelp` utility in the same file is a separate feature; this PR
|
|
focuses solely on `injectTocTop`.
|
|
- Observable Framework issue tracker should be checked for any existing
|
|
discussion of sidebar customisation before opening a new issue.
|