[RFC] Platform-aware Astryx — web + native mobile contract, docs, and Expo integration
- 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
Assessment
This issue has not been assessed yet.