facebook / facebook/astryx

[RFC] Platform-aware Astryx — web + native mobile contract, docs, and Expo integration

Open
#3,912 3 comments 5 reactions 0 assignees View on GitHub
component design documentation enhancement needs-scoping needs:design-review
Dominant language
TypeScript
Stars
13k
Forks
1.1k
Avg merge
1d 15h
Merged PRs (30d)
690

Description

## Summary

Astryx currently has a strong web component system and unusually good agent-facing docs (`ComponentDoc`, dense CLI output, generated agent context). But if the goal is for Astryx components to target **both web and mobile at an Expo-level quality bar**, we need to make platform support a first-class part of the architecture — not just make the existing DOM components responsive.

Expo's durable pattern is worth copying:

- one public JS/TS API contract
- platform-specific implementations behind that contract (`ios` / `android` / `web`)
- visible platform support metadata in docs
- setup tooling/config plugins for native project requirements
- honest caveats when behavior differs by platform

Astryx should define the equivalent contract before we start calling anything "mobile support."

## Problem

Today the product boundary is ambiguous:

- `@astryxdesign/core` is a React DOM/web implementation.
- `browser-support` documents web platform tiers, but not component-level native/mobile support.
- Component docs have useful guidance (`usage`, `bestPractices`, `anatomy`, `props`, `theming`, `playground`), but no standard platform/considerations taxonomy.
- There is no first-class `@astryxdesign/native` renderer for React Native/Expo.
- There is no first-class `@astryxdesign/expo` config plugin/setup package.
- The CLI cannot answer "how does `Button` behave on iOS?" or "which components are supported on Android?"

The failure mode is predictable: consumers will either assume "responsive web" means "mobile" or attempt to reuse DOM-specific components in native contexts where the behavior, accessibility model, layout primitives, and platform APIs are different.

This is already visible around layered/hover surfaces: #3885 exists because `Tooltip` / `HoverCard` have no touch path. Native mobile raises the same issue more broadly — not every web pattern has a 1:1 mobile equivalent, and pretending otherwise would make the docs less honest than Expo's.

## Proposed direction (to be scoped)

### 1. Split the design contract from the renderer packages

Keep the design language shared, but do not force one implementation to serve every platform.

```txt
@astryxdesign/tokens shared token source / generated artifacts
@astryxdesign/core React DOM / web renderer
@astryxdesign/native React Native / Expo renderer
@astryxdesign/expo Expo setup + config plugin bridge
@astryxdesign/cli platform-aware docs, init, parity checks
```

The shared contract should own names, design intent, tokens, docs schema, accessibility expectations, platform status, and parity expectations. Renderer packages should own platform-specific behavior.

### 2. Add platform support metadata to component docs

Every public component should be able to state support explicitly:

```ts
type Platform = 'web' | 'mobile-web' | 'ios' | 'android';

type PlatformSupport = {
status: 'stable' | 'beta' | 'alpha' | 'unsupported' | 'planned';
notes?: string[];
};
```

Example rendered output:

| Component | Web | Mobile web | iOS | Android | Notes |
| --- | --- | --- | --- | --- | --- |
| Button | stable | stable | beta | beta | Native touch target differs |
| TextInput | stable | stable | beta | beta | Keyboard behavior differs |
| Popover | stable | partial | unsupported | unsupported | Use Sheet/Dialog on mobile |
| Table | stable | partial | unsupported | unsupported | Use List/Card pattern on mobile |

### 3. Add a typed `considerations` model, not just a prose section

Expo's caveats are useful but scattered (`Known issues`, `Platform differences`, warning callouts, `@platform` tags). Astryx can do better by making them structured:

```ts
type Consideration = {
type:
| 'accessibility'
| 'keyboard'
| 'touch'
| 'platform'
| 'browser'
| 'server-client'
| 'performance'
| 'security'
| 'privacy'
| 'theming'
| 'composition'
| 'limitation'
| 'known-issue'
| 'migration';
severity?: 'info' | 'warning' | 'danger';
title: string;
body: string;
platforms?: Platform[];
workaround?: string;
};
```

This should render consistently in the docsite and CLI, and it should be available to agents via dense output.

### 4. Start with a native-safe foundation set

Do not start by porting overlays, tables, or complex menus. Start with components whose native/mobile semantics are clear:

- Theme / provider
- Text / Heading
- Stack / HStack / VStack / Center
- Icon
- Button / IconButton
- Card
- Badge / StatusDot
- Avatar
- Spinner / ProgressBar
- TextInput / TextArea
- Switch / CheckboxInput / RadioList
- simple List / Item

Defer or explicitly mark unsupported/alternate-pattern components:

- Tooltip / HoverCard
- Popover / DropdownMenu / ContextMenu
- Table
- Typeahead / CommandPalette
- complex overlay stacks

### 5. Add Expo-specific setup as an integration package

Astryx should not become "an Expo plugin." Astryx is the design system; Expo is the app/runtime platform. The clean integration is an Expo config plugin/setup package:

```json
{
"expo": {
"plugins": [
[
"@astryxdesign/expo",
{
"theme": "neutral",
"fonts": true,
"icons": true
}
]
]
}
}
```

Initial responsibilities to scope:

- font loading / registration
- theme + color-scheme bridge
- safe-area defaults
- Expo Router link adapter
- icon asset/registry setup if needed
- native config only where components actually require it

### 6. Teach the CLI to answer platform questions

Expected commands:

```bash
npx astryx init --platform expo
npx astryx component Button --platform web
npx astryx component Button --platform ios
npx astryx component --list --platform android
npx astryx parity
npx astryx doctor --platform expo
```

The CLI should make unsupported states obvious instead of letting consumers discover them by trial and error.

## Open questions for scoping

1. **What does "mobile" mean for Astryx?** Mobile web only, native iOS/Android, or both? The architecture above assumes both and treats them separately.
2. **API shape:** do we prefer one cross-platform event prop (`onAction`) or idiomatic platform aliases (`onClick` on web, `onPress` on native)? Likely answer: shared intent prop plus platform-native aliases where needed.
3. **Visual parity vs behavioral parity:** Expo succeeds by being honest that platforms differ. Astryx should aim for one design language and equivalent behavior, not pixel-perfect sameness.
4. **Token pipeline:** what is the source of truth for tokens, and what artifacts should be generated for CSS vars, StyleX, React Native objects, Tailwind, and docs?
5. **Expo plugin scope:** what setup belongs in `@astryxdesign/expo` versus plain runtime providers/components?
6. **Unsupported web patterns:** what are the recommended mobile alternatives for Tooltip, HoverCard, Popover, DropdownMenu, and Table?
7. **Testing bar:** what is the minimum matrix before declaring a component `stable` on iOS/Android?

## Acceptance criteria (draft)

- [ ] Decision recorded on whether Astryx is targeting mobile web only, native iOS/Android, or both.
- [ ] `ComponentDoc` schema supports platform support metadata.
- [ ] `ComponentDoc` schema supports typed considerations/caveats that can be filtered by platform.
- [ ] CLI can list/read components by platform and show unsupported/partial states.
- [ ] A parity matrix exists for core components across web / mobile-web / iOS / Android.
- [ ] Package direction is documented for `@astryxdesign/native` and `@astryxdesign/expo`.
- [ ] A native-safe starter set is agreed before advanced components are attempted.
- [ ] Expo example/spike proves the setup path for at least Theme, Text, Stack, Button, Card, Icon, TextInput, and Switch.
- [ ] Accessibility expectations are documented per platform for the starter set.

## Non-goals

- Auto-porting current DOM components into React Native.
- Claiming mobile support because web components are responsive.
- Making every component available on every platform.
- Pixel-perfect sameness between web and native.
- Solving complex overlays/tables before the foundation set is working.

## Why this is worth doing

Expo's quality bar is not "same code everywhere" — it is **one mental model with explicit platform implementations and honest caveats**. Astryx already has a strong docs/CLI foundation. Adding platform-aware docs, a native renderer plan, and an Expo integration path would let us scale that same model to web + mobile without misleading consumers about what is actually supported.

Related: #3885 (touch access for HoverCard/Tooltip), #3675 (Sheet API + mobile swipe questions), #3755 (adoption DX / setup guardrails).

_Filed via Navi on behalf of @thedjpetersen after read-only comparison of Expo, Astryx, and internal XDS docs._

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.