Skip to content

feat(apollo-wind): compact density for the chat primitives - #1403

Draft
BenGSchulz wants to merge 1 commit into
feat/apollo-wind-chat-primitive-gapsfrom
feat/apollo-wind-chat-compact-density
Draft

BenGSchulz wants to merge 1 commit into
feat/apollo-wind-chat-primitive-gapsfrom
feat/apollo-wind-chat-compact-density

Conversation

@BenGSchulz

Copy link
Copy Markdown
Contributor

Summary

MST-16573, part of the Wind chat epic MST-16172. Stacked on #1402 (chat primitive gaps), which is stacked on #1400 (math fences). This is the last PR of the apollo-wind stack.

Material's spacing.compactMode shrinks the chat's type and spacing. The Wind chat marks compact mode with data-density="compact" on its root. The apollo-wind chat primitives now follow that attribute on any ancestor, with no prop plumbing.

Mechanism and contract

  • Tailwind's in-data-[density=compact]: variant, which compiles to :where(*[data-density="compact"]) & (checked with Tailwind 4.1.17, the build's version, and 4.3.0, the test runner's).
  • A host className on the root wins in both densities. Root-level sizes read CSS variables whose fallbacks are today's values, for example gap-(--markdown-gap,0.75rem) text-(length:--markdown-font-size,0.875rem) leading-(--markdown-leading,1.625), and the compact variant only sets the variables (in-data-[density=compact]:[--markdown-gap:0.5rem]). A host class such as gap-1 replaces the variable-reading class through cn() (tailwind-merge groups them; tested), so the compact value has nothing to change. The Wind chat's MessageContent className="gap-0" and Markdown className="gap-1 text-xs leading-4" keep working.
  • Default computed styles are unchanged (checked in Storybook: Markdown 14px on 22.75px with a 12px gap, code 13px on 20.8px, bubble 14px on 22.75px, message content gap 10px).
  • Nested elements a className cannot reach (Markdown headings and lists, the thinking icon, the avatar offsets) use the variant directly.
  • ChatComposer: without a density prop it is compact under any compact ancestor, like the CSS variant. Only that ancestor's attribute is watched; an ancestor that gains the attribute later is picked up on the next render. The prop wins.
  • ThinkingIndicator and Citation take their sm look in compact only when no size is given.

Material to Wind mapping

Element Material default to compact Wind default Wind compact
Markdown p, li, th, td, em, strong, link fontSizeM 14/20 to fontSizeS 12/16 14px on 22.75px 12px on 18px
h1 H3Bold 24/32 to H4Bold 20/24 text-xl text-lg
h2 H3Bold to H4Bold text-lg text-base
h3 H3Bold to H4Bold text-base text-sm
h4, h5, h6 LBold 16/24 to MBold 14/20 text-sm text-xs
Markdown block, list, quote spacing unchanged (24px) gap 12px, lists 4px, quotes 8px, paragraphs in li 8px gap 8px, lists 2px, quotes 6px, paragraphs in li 6px (Wind's choice)
Code block source 14px to 12px, rendered on an 18px line 13px on 20.8px 12px on 18px
Code block header unchanged unchanged unchanged
Message text (primaryFontToken) M 14 to S 12 14px on 20px 12px on 16px
BubbleContent text M to S 14px on 22.75px 12px on 18px, padding unchanged
Gap between messages in a group (messageSpacing) 32 to 8 MessageGroup 8px 4px
Gap between a message's parts (messageGroupGap) 16 to 8 MessageContent 10px 5px, avatar offsets follow
Citation M to Xs (10px) 11px pill the sm pill (10px), no size given
Loading text (ThinkingIndicator) M to S 14px, 16px icon 12px, 14px icon, no size given
Source items M to S; icon 24 to 18 14px; 16px icon 12px; icon unchanged (already below Material's compact 18px)
ChatComposer compact rows and paddings density prop follows the ancestor; prop wins

Ticket claims corrected

The brief asked for a shorter code block header and smaller copy button, reduced bubble padding, smaller MessageActions controls, and possibly smaller ToolCall, DisclosureTree and Attachment gaps. Material's compact mode does none of these:

  • Material's code block header and its buttons do not read compactMode; only the code font changes.
  • Material's message box padding does not depend on compactMode; only the type and the two message gaps change.
  • MessageActions defaults to 3xs, not md, and Material's action bar ignores compact mode.
  • Material's tool call, tree and attachment chips do not read compactMode.

So these stay unchanged.

Wind-only choices

  • Compact body leading is 18px, not Material's 16px: Wind's comfortable leading is already looser than Material's (22.75 against 20), and 18px keeps that ratio.
  • Markdown block, list and quote spacing tightens in compact; Material keeps its spacing.
  • Code blocks inside a ToolCall follow the compact ancestor like any CodeBlock, which Material's do not; documented in ToolCall's JSDoc (a compact debug panel gains from it).

What the Wind chat needs to do

Nothing for compact beyond the data-density attribute it already sets on its root. It may drop the density prop it passes to the composer.

Stories

  • Chat/Patterns Embedded has a compact arg (off by default, so the default canvas is unchanged) that sets data-density="compact" on the panel and lets the footer composer take its density from the panel.
  • New Markdown/CompactDensity (default and compact side by side, with a wide table and a long code line) and CodeBlock/CompactDensity.

Tests

  • Markdown and CodeBlock render inside a compact ancestor and compile their classes with Tailwind: the base classes read the variables with the comfortable fallbacks, and the compact variant sets them under :where(*[data-density="compact"]).
  • A host gap-1 text-xs leading-4 on Markdown and gap-0 on MessageContent replace the variable-reading classes inside a compact ancestor.
  • tailwind-merge groups gap-(--x,…), text-(length:--x,…), leading-(--x,…) and h-(--x,…) with their plain counterparts.
  • Message, Bubble, Citation and ThinkingIndicator compact classes inside a compact ancestor, with an explicit size opting out; the avatar's compact offsets order after the comfortable ones.
  • ChatComposer: compact from an ancestor, followed when the attribute changes, picked up on rerender when an ancestor gains it, compact even with a nearer comfortable, and the prop wins.
  • Storybook at 360px: Embedded compact and Markdown/CompactDensity do not overflow (tables and code scroll inside their blocks), axe clean; also checked in dark, light-hc, dark-hc and future-light (the legacy dark contrast and Prism token contrast findings exist without compact too).
  • Biome on touched files, tsc --noEmit, the full apollo-wind suite and pnpm --filter @uipath/apollo-wind build.

🤖 Generated with Claude Code

Material's spacing.compactMode shrinks the chat's type and spacing, and
the Wind chat marks compact mode with data-density="compact" on its
root. The chat primitives now follow that attribute on any ancestor,
with no prop plumbing.

Root-level sizes read CSS variables whose fallbacks are today's values
(gap-(--markdown-gap,0.75rem) and so on), and an in-data-[density=compact]
variant sets the variables. A host className on the root replaces the
variable-reading class, so it wins in both densities, and the default
computed styles are unchanged. Nested elements (headings, lists, the
thinking icon, avatar offsets) use the variant directly.

- Markdown: body, lists and tables 14px to 12px, each heading one step
  down. Wind's own choices: an 18px line (Material uses 16px; this keeps
  the comfortable ratio) and tighter block, list and quote spacing
  (Material keeps 24px).
- CodeBlock: source 13px on 20.8px to 12px on 18px, as Material's
  compact code renders, through two variables since the Prism style is
  inline. The header stays, as in Material. Code blocks in a ToolCall
  shrink too, which Material's do not.
- Message and Bubble: text 14px to 12px, gaps between a group's messages
  and a message's parts halved, avatar offsets adjusted. Bubble padding
  stays, as in Material.
- ThinkingIndicator and Citation: the sm look when no size is given.
- Sources: items 14px to 12px.
- ChatComposer: compact under any compact ancestor when no density prop
  is given; the prop wins. Only that ancestor's attribute is watched.

MessageActions, ToolCall, DisclosureTree and Attachment are otherwise
unchanged: Material's compact mode does not touch their counterparts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

Dependency License Review

  • ✅ 1947 package(s) scanned
  • ✅ No license issues found
  • ⚠️ 2 package(s) excluded (see details below)
License distribution
License Packages
MIT 1713
ISC 91
Apache-2.0 56
BSD-3-Clause 28
BSD-2-Clause 23
BlueOak-1.0.0 8
MPL-2.0 4
MIT-0 3
CC0-1.0 3
MIT OR Apache-2.0 2
(MIT OR Apache-2.0) 2
Unlicense 2
LGPL-3.0-or-later 1
Python-2.0 1
CC-BY-4.0 1
(MPL-2.0 OR Apache-2.0) 1
Unknown 1
Artistic-2.0 1
(WTFPL OR MIT) 1
(BSD-2-Clause OR MIT OR Apache-2.0) 1
CC-BY-3.0 1
0BSD 1
(MIT OR CC0-1.0) 1
MIT AND ISC 1
Excluded packages
Package Version License Reason
@img/sharp-libvips-linux-x64 1.3.4 LGPL-3.0-or-later LGPL pre-built binary, not linked
khroma 2.1.0 Unknown MIT per GitHub repo, missing license field in package.json

This branch was successfully deployed

4 active deployments
preview/apollo-vertex — 018ee7c1 Deployed Oct 17, 2026 by github-actions[bot]
preview/apollo-docs — 018ee7c1 Deployed Oct 17, 2026 by github-actions[bot]
preview/apollo-design — 018ee7c1 Deployed Oct 17, 2026 by github-actions[bot]
preview/apollo-landing — 018ee7c1 Deployed Oct 17, 2026 by github-actions[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant