React Native integration
Toned shares portable declarations and resolves native style fields. Your application supplies its renderer, concrete primitives and an explicit host adapter. The native host module alone does not establish a working or certified React Native integration.
1. Define portable parts
npm install @toned/core @toned/reactimport { stylesheet } from './system'
export const cardStyles = stylesheet({
Root: { surface: 'card', padding: 4 },
Title: { $kind: 'text', text: 'title' },
})The sheet takes its tokens from the application's system:
import { defineSystem, defineToken } from '@toned/core'
export const ui = defineSystem({
id: 'native-example',
tokens: {
surface: defineToken({
values: ['card'] as const,
resolve: () => ({ backgroundColor: '#fff' }),
}),
padding: defineToken({
values: [2, 4] as const,
resolve: step => ({ padding: step * 4 }),
}),
text: defineToken({
values: ['title'] as const,
resolve: () => ({ color: '#172033', fontSize: 20 }),
}),
},
})
export const { stylesheet } = uiThe token resolvers return concrete values that both platforms accept. If you reach for the $style escape hatch, shared declarations use the portable property intersection. Explicit platform blocks can widen styles for that platform. Native rejects unsupported CSS fields and values; a web-only cursor or CSS variable is not automatically translated into a native equivalent. Theme resolvers must supply concrete native values.
2. Declare the application host
// Integration-owned adapter.
import { Dimensions, Image, Pressable, Text, View } from 'react-native'
import { defineReactNativeHost } from '@toned/core/stylesheet'
import type { ReactHost } from '@toned/react'
import { nativeHost as native } from '@toned/react/hosts/native'
import { isApplicationFabricHost, appReactNativeVersion } from './host-identity'
const adapter = defineReactNativeHost({
renderer: 'fabric',
version: appReactNativeVersion,
isHost: isApplicationFabricHost,
})
const primitives = { view: View, text: Text, image: Image, pressable: Pressable }
export const host: ReactHost = {
...native,
nativeHost: {
...adapter,
getViewportWidth: () => Dimensions.get('window').width,
subscribeViewport: notify => {
const subscription = Dimensions.addEventListener('change', () => notify())
return () => subscription.remove()
},
},
resolveElement: kind => primitives[kind ?? 'view'],
}The host identity module in this example belongs to your integration: verify actual forwarded hosts from the selected renderer, not merely the presence of setNativeProps. The helper declares merge patches and null resets; a version string does not prove that the renderer implements them correctly. Validate View, Text and input targets, style removal, caller baselines, ref replacement and interrupted renders in a real native application.
3. Install a renderer and render the parts
import { createNativeRenderer } from '@toned/core/server'
import { createElements, TonedProvider } from '@toned/react'
import { host } from './host'
import { cardStyles } from './styles'
import { ui } from './system'
const renderer = createNativeRenderer(ui, { tokens: {} })
const Card = createElements(cardStyles)
export default function App() {
return (
<TonedProvider renderer={renderer} host={host}>
<Card>
<Card.Root>
<Card.Title>Hello from Toned</Card.Title>
</Card.Root>
</Card>
</TonedProvider>
)
}The provider scopes renderer inputs to this tree. The element family keeps component identities stable; its provider shares variant inputs and cross-part ownership without adding a native layout wrapper. Independent parts can also render standalone with their base/default declarations. Bound refs must reach the real native hosts.
4. Measurements, states and capability limits
Viewport queries require the adapter's getViewportWidth and subscribeViewport capabilities. The example supplies them using Dimensions; Toned does not install a Dimensions subscription or browser matchMedia fallback automatically. Runtime container queries use the native binding's onLayout measurement props, including host-local measurements within one family.
Hover, active and focus facts come from primitive events. Additional semantic states need declared readers and subscriptions. Cross-part relationships also need committed parent topology; native parent traversal is not assumed. Native props include refs, event handlers and configured bridge props as well as style fields.
Grid remains a web capability. Named-area ownership alone cannot implement intrinsic native track sizing or span placement. A native grid needs an integrated layout engine and its own acceptance tests. The Expo example is an integration sketch: it does not certify a concrete Fabric renderer. The separate Fabric acceptance app verifies one pinned Android profile; see the native hosts reference.
Opaque styles from other engines must use an explicit primitive adapter and a separate prop rather than Toned's plain style merger. Ordered style arrays do not coordinate two engines' imperative writes to the same field; overlapping ownership needs an integration-aware writer.