facebook / facebook/astryx

XDSHeading/XDSText: no responsive `type`/`size` prop — fluid display headlines require a hand-written @media override

Open
#2,580 1 comment 0 reactions 1 assignee Claimed by @rubyycheung View on GitHub
component enhancement
Dominant language
TypeScript
Stars
13k
Forks
1.1k
Avg merge
1d 15h
Merged PRs (30d)
690

Description

## Summary

Neither `XDSHeading` nor `XDSText` can express a **breakpoint-dependent type/size** (e.g. `display-2` on desktop, `display-3` on mobile). Their `type`/`size` props are scalar. So any template that wants a responsive display headline must hand-write a `@media` `fontSize` override via StyleX, which costs Custom CSS points under the template rubric and re-derives values the design tokens already define.

## Repro

`packages/cli/templates/pages/centered-hero/page.tsx` (and identically `gallery-hero/page.tsx`):

```ts
const styles = stylex.create({
titleResponsive: {
fontSize: {
default: 'var(--text-display-2-size)',
'@media (max-width: 640px)': 'var(--text-display-3-size)',
},
},
});
```
…applied as `xstyle` on the headline because there's no prop for it:
```tsx

```

Verified the full prop tables: `XDSHeading.type` is `'display-1' | 'display-2' | 'display-3'` (scalar) and `XDSText.type` is `'body' | 'large' | 'label' | 'supporting' | 'code'` (scalar). No responsive/object form, no fluid option.

## Impact

Responsive display headlines are a common pattern (hero/landing templates). Today every such template carries an off-rubric `@media fontSize` block. This is shared by at least `centered-hero` and `gallery-hero`.

## Proposed fix (either)

1. **Responsive object form** for `type`/`size`, mirroring how some XDS props already accept breakpoint maps:
```tsx

```
2. **Fluid display tokens** — make `--text-display-1/2/3-size` `clamp()`-based so display headings scale fluidly with the viewport and the breakpoint swap becomes unnecessary. (`clamp()` is StyleX-supported per CLAUDE.md.)

Either removes the need for the hand-written media query in templates.

## Related, smaller gap (separate but adjacent)

While here: there's also no **directional spacing prop** on layout primitives — `XDSSection.padding` is uniform and `XDSVStack` has no padding prop, so "top-only" spacing (e.g. a hero's top inset) also requires a one-line `paddingTop` custom style. Mentioning for context; can split into its own issue if preferred.

## Context

Found polishing the `centered-hero` page template toward a perfect template-rubric score. Everything else was fixable with pure components (adopting `XDSAspectRatio` for the image, `XDSHeading` for the headline); this responsive-type override is the one genuinely unavoidable custom CSS.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.