Appearance

Task patterns

Small, shared compositions for real work. Content, storage, permissions, and business rules stay with the app.
Appearance
Sample workspace

Campaign review

Review the message and its sources before release.
Sample retrieval state
Bring your people. Make a memory.
Evergreen sample copy. No live offer, schedule, or price.
Verified sample orders: 0
Current retail price: unavailable
Source: local demonstration fixture
Sample retries: 0

AppearanceControl

Offer Light, Dark, and System in app settings. The control is a labeled radio group with native semantics and arrow-key navigation on web. Pass its value to ThemeProvider. Keep a deliberate Light default until a stored preference exists; System follows operating-system changes.
const [appearance, setAppearance] = useState<Appearance>("light"); <ThemeProvider appearance={appearance}> <AppearanceControl value={appearance} onValueChange={setAppearance} /> </ThemeProvider>
The host owns persistence: browser storage with a failure fallback on web; the app’s existing preference store on native. A persistence failure must leave the current selection usable. Scope preview themes independently. Paint safe areas, status bars, portals, and install/offline shells too.

PageHeader

Give a page one clear title, a short description, and its next action. Optional eyebrow copy names context rather than replacing the title. The actions wrap below the title on small screens. Use level 1 for the page or a lower level inside an existing hierarchy.
<PageHeader title="Order requests" description="Review unpaid buyer requests." actions={<Button onPress={refresh}>Refresh requests</Button>} />

AsyncState

Represent ready, loading, empty, error, and offline explicitly. Preserve entered work and any useful cached content. Pass sourceLabel and freshnessLabel when showing retained information. A timestamp alone cannot prove a result current. The component never converts missing data into zero or infers Open from published hours.
<AsyncState status={offline ? "offline" : "ready"} title="Offline · showing saved orders" sourceLabel="Source: Core · saved locally" freshnessLabel="Saved at 10:30 AM · current state unverified" onRetry={reload}> <OrderList orders={savedOrders} /> </AsyncState>
Use retry only when it can do something. Empty explains how to begin; error explains recovery; offline identifies what still works. Avoid a spinner for the entire page when only one region is loading. A known zero is a value. Unknown, stale, unavailable, and expired each need their own text.

Business patterns

Stand information: name, verified address, directions, published dates/hours and timezone, then separate staff-reported status. Product information: original image, product identity, qualified retail price and relevant availability. Bulk: case price and size stay distinct from retail; requests remain unpaid until the owning workflow records otherwise.
Campaigns: one message, approved artwork, verified destination, current terms, eligibility, dates/timezone and owner. Expired campaigns lose redemption actions. A missing or unverified fact stays absent or clearly unavailable.