facebook / facebook/astryx

Add playground defaults and slotElements to all component docs

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

Description

## Context

PR #2005 added two new fields to the component doc system:

1. **`playground.defaults`** on `BaseDoc` — initial prop values for the interactive playground preview
2. **`slotElements`** on `PropDoc` — declares what XDS components a ReactNode prop typically accepts

Currently only 4 components have playground defaults (Button, Badge, Card, EmptyState) and 2 props have slotElements (Button.icon, Button.endContent). Every other component needs to be updated.

## What needs to happen

Every `.doc.mjs` file in `packages/core/src/` needs:

### 1. `slotElements` on ReactNode props

For each prop with `type: 'ReactNode'` or `type: 'ReactElement<...>'`, decide:

**Add `slotElements`** when the prop expects specific XDS components:
```js
{
name: 'icon',
type: 'ReactNode',
description: 'Leading icon.',
slotElements: [{__element: 'XDSIcon', props: {icon: 'check', size: 'sm'}}],
}
```

**Skip `slotElements`** (leave as-is) when:
- The prop accepts plain **text** (label, title, description, name) — the playground already renders a text input for these
- The prop is a **render function** (`(item: T) => ReactNode`) — not an element slot
- The prop is a **compound component entry** (names starting with `XDS` or `use` in compound docs) — these are documentation of sub-components, not interactive props
- The prop is **`children`** on a generic container — too many possible values to enumerate
- The prop is internal (`element` for imperative APIs, `layerNode` for portals)

### Common slot patterns

| Prop name | Typical `slotElements` |
|-----------|------------------------|
| `icon`, `startIcon`, `endIcon`, `sendIcon`, `stopIcon`, `pressedIcon`, `selectedIcon` | `[{__element: 'XDSIcon', props: {icon: 'check', size: 'sm'}}]` |
| `endContent` (on buttons/inputs) | `[{__element: 'XDSIcon', props: {icon: 'chevronDown', size: 'sm'}}, {__element: 'XDSBadge', props: {label: '3'}}]` |
| `startContent` | `[{__element: 'XDSIcon', props: {icon: 'check', size: 'sm'}}]` |
| `actions` | `[{__element: 'XDSButton', props: {label: 'Action', variant: 'secondary'}}]` |
| `status` (on Avatar) | `[{__element: 'XDSStatusDot', props: {variant: 'online'}}]` |
| `banner` (on AppShell) | `[{__element: 'XDSBanner', props: {title: 'Info', status: 'info'}}]` |
| `headerEndContent` | `[{__element: 'XDSButton', props: {label: 'Action', variant: 'ghost', size: 'sm'}}]` |

The `props` in each ElementDescriptor should be the **minimal viable props** to render a recognizable instance — just enough for the playground user to see what the slot does.

### 2. `playground.defaults` on BaseDoc

Add sensible starting state so the component renders meaningfully in the playground:

```js
playground: {
defaults: {
// Primitives
label: 'Click me',
variant: 'primary',
// ElementDescriptors for slot content
children: {
__element: 'XDSVStack', props: {gap: 2}, children: [
{__element: 'XDSHeading', props: {level: 3}, children: 'Title'},
{__element: 'XDSText', props: {type: 'body'}, children: 'Content'},
],
},
},
}
```

**When to add playground defaults:**
- Component needs `children` to render anything visible (Card, Dialog, Section, Layout, etc.)
- Component has required props that benefit from a more descriptive default than the auto-generated one (`label: 'label'` → `label: 'Click me'`)
- Component renders empty/broken without specific prop combinations

**When to skip:**
- Simple components that render fine with auto-generated defaults (Switch, Spinner, Divider)
- Hooks (no visual preview)
- Components where the showcase already demonstrates the ideal state

### 3. Priority order

High priority (render broken without defaults):
- All container components: Card, Dialog, Section, Layout, AppShell, Popover, HoverCard
- All list-like components: List, CheckboxList, RadioList, TabList, Breadcrumbs, SideNav, TopNav
- Form components: Field, FormLayout

Medium priority (render but look empty):
- Banner, EmptyState, Toast, Toolbar
- Chat components (ChatMessage, ChatComposer, etc.)

Low priority (render fine already):
- Button, Badge, Switch, Spinner, TextInput, etc.
- Hooks and utilities

## Scope

~60 component doc files, ~140 ReactNode props needing `slotElements` decisions, ~30-40 components needing playground defaults.

## Reference

- Type definitions: `packages/core/src/docs-types.ts` (ElementDescriptor, PlaygroundConfig, PropDoc.slotElements)
- Existing examples: Button.doc.mjs, Card.doc.mjs, Badge.doc.mjs, EmptyState.doc.mjs
- Playground consumer: `apps/docsite/src/components/component-detail/InteractivePreview.tsx`
- Element resolver: `apps/docsite/src/components/component-detail/PlaygroundPropsTable.tsx`

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.