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).
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 todayExpanded by string preprocessing in normalizeMarkdownBlocks.ts:
:::collapsible/:::collapsed [title]→<details class="markdown-collapsible">(+open), single style in index.css.> [!TYPE]→<aside class="markdown-shoutout markdown-shoutout--{type}">in MarkdownPreview.tsx. The type flows straight into the class.normalizeMarkdownBlocks.tsalso has ashoutoutTypeMapthat folds semantic aliases (note/tip→info,caution→warning,danger/fail→error, …) onto the four canonical kinds. CSS already ships--info/--success/--warning/--errorand--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 viashoutoutTypeMap: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 canonicalinfo/success/warning/errorare accepted here too as plain colors).Emit
<details class="markdown-collapsible markdown-collapsible--{resolved}">and add matching CSS, reusing the exact color tokens the shoutout variants use.Resolution:
typeis normalized throughshoutoutTypeMapfirst; iftypeis absent, fall back tocolor; if both are given,typewins (document the precedence). Unknown / missing value → current neutral style (no regression).Why
{attr=…}and not:::collapsed-orangeThere is a planned macro extension point that moves all
:::blocks ontoremark-directive(:::name{attr=val} … :::, shoutouts as the first macro, collapsibles as a fast-follow).remark-directiveexposesnode.attributesnatively, so{type=…}/{color=…}is the form this feature will already speak after that migration. A-orangesuffix would be a throwaway syntax to support or break later. Doing the attribute form now is the forward-compatible step.Scope
{ … }group before the title; minimal tokenizer forkey=value(ignore bare words for now). Consumetype(normalized via the existingshoutoutTypeMap) andcolor; other keys ignored. Feed the resolved variant intoappendCollapsibleBlock, emitmarkdown-collapsible--{variant}.info,success,warning,error,blue,red,green,orange. Unknown / missing → current neutral style. Plain:::collapsed/:::collapsibleunchanged..markdown-collapsible--{variant}rules (border +summaryheader tint), mirroring.markdown-shoutout--*; verify light/dark.type=andcolor=with/without title, alias normalization (type=danger→ error),type+colorprecedence, unknown value → neutral, unknown key ignored, no{…}unaffected,{inside a fenced code block untouched, malformed{…}degrades gracefully.:::orangecallouts).Out of scope
{type=…}/{color=…}— happens with the macro extension point.typeexists, not this issue.style=— stay with the curated palette.remark-directiveadoption / the macro registry itself — separate, larger effort (this issue just picks a syntax that won't collide with it).