Skip to content

[Feature Request]: Color variants for collapsible blocks (via directive attributes) #1522

Description

@perber

Context

From Discussion #1438. Collapsible blocks (:::collapsible / :::collapsed, #1344 / #1382) render in one neutral style. The ask: give them the color options callouts have (e.g. an orange collapsible to grab attention).

How ::: blocks work today

Expanded by string preprocessing in normalizeMarkdownBlocks.ts:

  • :::collapsible / :::collapsed [title] → <details class="markdown-collapsible"> (+ open), single style in index.css.
  • Any other type → > [!TYPE] → <aside class="markdown-shoutout markdown-shoutout--{type}"> in MarkdownPreview.tsx. The type flows straight into the class. normalizeMarkdownBlocks.ts also has a shoutoutTypeMap that folds semantic aliases (note/tip → info, caution → warning, danger/fail → error, …) onto the four canonical kinds. CSS already ships --info/--success/--warning/--error and --blue/--red/--green/--orange, so colored callouts already work (:::orange, :::blue, …) — just undocumented. Colored collapsibles don't.

Proposal

Add an optional color to the collapsible open line using directive-attribute syntax, not a compound type. Support two attributes:

  • type= — semantic kind, same vocabulary as shoutouts: info, success, warning, error (plus the existing aliases via shoutoutTypeMap: note, tip, caution, danger, fail, …). Defines the color, and is the natural hook if collapsibles later get an icon / default heading treatment like shoutout cards.
  • color= — raw palette color with no semantics: blue, red, green, orange (and the canonical info/success/warning/error are accepted here too as plain colors).
:::collapsed{type=warning} Deployment steps
Body…
:::

:::collapsible{color=blue} Notes
Body…
:::

Emit <details class="markdown-collapsible markdown-collapsible--{resolved}"> and add matching CSS, reusing the exact color tokens the shoutout variants use.

Resolution: type is normalized through shoutoutTypeMap first; if type is absent, fall back to color; if both are given, type wins (document the precedence). Unknown / missing value → current neutral style (no regression).

Why {attr=…} and not :::collapsed-orange

There is a planned macro extension point that moves all ::: blocks onto remark-directive (:::name{attr=val} … :::, shoutouts as the first macro, collapsibles as a fast-follow). remark-directive exposes node.attributes natively, so {type=…} / {color=…} is the form this feature will already speak after that migration. A -orange suffix would be a throwaway syntax to support or break later. Doing the attribute form now is the forward-compatible step.

Scope

  • normalizeMarkdownBlocks.ts: extend the open-line parse to accept a trailing { … } group before the title; minimal tokenizer for key=value (ignore bare words for now). Consume type (normalized via the existing shoutoutTypeMap) and color; other keys ignored. Feed the resolved variant into appendCollapsibleBlock, emit markdown-collapsible--{variant}.
  • Accepted variants = the curated set already in CSS: info, success, warning, error, blue, red, green, orange. Unknown / missing → current neutral style. Plain :::collapsed / :::collapsible unchanged.
  • index.css: .markdown-collapsible--{variant} rules (border + summary header tint), mirroring .markdown-shoutout--*; verify light/dark.
  • normalizeMarkdownBlocks.test.ts: type= and color= with/without title, alias normalization (type=danger → error), type + color precedence, unknown value → neutral, unknown key ignored, no {…} unaffected, { inside a fenced code block untouched, malformed {…} degrades gracefully.
  • No i18n (no user-facing strings). If a markdown help/docs page exists, document the attributes there (and the already-working :::orange callouts).

Out of scope

  • Migrating callouts/shoutouts to {type=…} / {color=…} — happens with the macro extension point.
  • Icons / default headings on colored collapsibles — possible fast-follow once type exists, not this issue.
  • Arbitrary hex colors / inline style= — stay with the curated palette.
  • Full remark-directive adoption / the macro registry itself — separate, larger effort (this issue just picks a syntax that won't collide with it).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions