Native UI for Expo
kara is a design system for Expo whose components render real SwiftUI and Jetpack Compose views — a Switch is a SwiftUI Toggle on iOS and a Material Switch on Android — styled through one token-typed sx surface. Platform colours and the platform’s typeface by default; yours through the theme.
A first screen
Mount KaraProvider once at the root. A screen of native views starts with Screen; everything inside lays out natively and takes sx props resolved from the theme’s tokens.
import {Button, KaraProvider, Screen, Text, VStack} from '@hzblj/kara-ui'
export const App = () => (
<KaraProvider>
<Screen>
<VStack p="s16" spacing="s12" wide>
<Text variant="headingS">Hello</Text>
<Button label="Continue" onPress={next} wide />
</VStack>
</Screen>
</KaraProvider>
)kara needs a development build — its views are native code, so Expo Go cannot run them. iOS and Android, Expo SDK 57. There is no web target.
Two tiers
Native views live in a native host. Most of kara is that native tier; the rest is a React Native tier of plain React Native views with the same sx props, for layout, long lists and the pieces a native host does not suit.
| Tier | Renders | Where it goes | Examples |
|---|---|---|---|
| Native | SwiftUI on iOS, Jetpack Compose on Android | Inside a Screen or an Island | Button, Switch, Text, VStack, List |
| React Native | React Native views — some backed by kara’s own UIKit and Compose views | Anywhere | Box, RnText, Pressable, Sheet, ContextMenu, GlassView |
A page that is mostly React Native drops native views in where it needs them, each in an Island:
import {Box, Button, Island, RnScrollView, RnText} from '@hzblj/kara-ui'
export const Checkout = () => (
<RnScrollView content={{gap: 's24', p: 's20'}}>
<RnText variant="headingS">Checkout</RnText>
<Box bg="surface.primary" borderRadius="large" p="s16">
<RnText color="content.secondary">2 items · €129</RnText>
</Box>
<Island>
<Button label="Pay €129" onPress={pay} wide />
</Island>
</RnScrollView>
)