Native UI

v1.0.0

Building native mobile UIs with Expo Router and React Native. Covers routing, navigation, styling, native controls, animations, and platform conventions following Apple Human Interface Guidelines.

0· 959·4 current·4 all-time
Security Scan
VirusTotalVirusTotal
Benign
View report →
OpenClawOpenClaw
Benign
medium confidence
Purpose & Capability
Name/description (native UI with Expo Router) match the included files (route, tabs, animations, media, WebGPU references). The skill declares no environment variables, binaries, or installs — appropriate for a documentation/instruction-only skill.
Instruction Scope
SKILL.md and reference files contain code snippets and developer guidance (expo start, custom builds, Metro config, package installs, permission flows). All referenced actions are coherent with building native UIs. The instructions do not direct the agent to read unrelated system files, exfiltrate secrets, or call external endpoints beyond standard package registries and Expo tooling. (Note: some snippets recommend installing npm packages or changing project config — expected for this domain.)
Install Mechanism
There is no install spec and no code files that would be written/executed by the platform — the skill is instruction-only, which is the lowest-risk install mechanism.
Credentials
The skill declares no environment variables, credentials, or config-path requirements. The content references app-level storage (SecureStore/SQLite/media) and permission APIs for camera/microphone which are appropriate for a UI/mobile guidance package; nothing requests unrelated secrets or host credentials.
Persistence & Privilege
always is false and the skill is user-invocable; disable-model-invocation is false (normal). The skill does not request permanent platform presence or elevated agent privileges.
Assessment
This skill appears to be a coherent, instruction-only guide for Expo Router and React Native UI patterns. Before using it in a project: (1) Verify the origin — the package lists no homepage and the source is unknown, so prefer content from a known repo or vendor. (2) Review and test any config changes (metro.config.js, package installs) in a sandboxed branch; some snippets contain minor inaccuracies (nonstandard commands like `npx add`, RN style props that may not be supported) and pinned dependency instructions that could break your build. (3) Do not run arbitrary install scripts or copy & paste commands that download code from unknown URLs without inspecting them. (4) If you plan to adopt native modules or change build tooling, audit third-party packages (versions and licenses) and confirm permissions (camera/microphone/media) are requested and handled correctly in your app.

Like a lobster shell, security has layers — review code before you run it.

latestvk979vprhrk6kkcgzq9w3f3n7h980x4nk
959downloads
0stars
1versions
Updated 1mo ago
v1.0.0
MIT-0

Native UI with Expo Router

Patterns and conventions for building native mobile applications with Expo Router and React Native.

References

Consult these as needed:

  • ./references/route-structure.md — Route conventions, dynamic routes, groups, folder organization
  • ./references/tabs.md — Native tab bar with NativeTabs, iOS 26 features
  • ./references/icons.md — SF Symbols with expo-symbols, icon names, animations, weights
  • ./references/controls.md — Native iOS controls: Switch, Slider, SegmentedControl, DateTimePicker
  • ./references/visual-effects.md — Blur effects (expo-blur) and liquid glass (expo-glass-effect)
  • ./references/animations.md — Reanimated: entering, exiting, layout, scroll-driven, gestures
  • ./references/search.md — Search bar with headers, useSearch hook, filtering patterns
  • ./references/gradients.md — CSS gradients via experimental_backgroundImage (New Architecture only)
  • ./references/media.md — Camera, audio, video, file saving
  • ./references/storage.md — SQLite, AsyncStorage, SecureStore
  • ./references/webgpu-three.md — 3D graphics and GPU visualizations with WebGPU/Three.js
  • ./references/toolbar-and-headers.md — Stack headers and toolbar with buttons, menus, search bars (iOS)
  • ./references/form-sheet.md — Form sheet presentation patterns

Running the App

Always try Expo Go first before creating custom builds.

  1. Start with npx expo start and scan the QR code
  2. Test features in Expo Go
  3. Only create custom builds when required

When Custom Builds Are Required

Use npx expo run:ios/android or eas build only for:

  • Local Expo modules (custom native code in modules/)
  • Apple targets (widgets, app clips via @bacons/apple-targets)
  • Third-party native modules not in Expo Go
  • Custom native configuration beyond app.json

Expo Go supports all expo-* packages, Expo Router, Reanimated, Gesture Handler, push notifications, and deep links out of the box.

Installation

OpenClaw / Moltbot / Clawbot

npx clawhub@latest install native-ui

Code Style

  • Escape nested backticks and quotes correctly
  • Always use import statements at the top of the file
  • Use kebab-case for file names: comment-card.tsx
  • Remove old route files when restructuring navigation
  • No special characters in file names
  • Configure tsconfig.json path aliases; prefer aliases over relative imports

Routes

See ./references/route-structure.md for detailed conventions.

  • Routes belong in the app directory
  • Never co-locate components, types, or utilities in app/ — this is an anti-pattern
  • Always have a route matching /, possibly inside a group route

Library Preferences

UseInstead of
expo-audioexpo-av
expo-videoexpo-av
expo-symbols@expo/vector-icons
react-native-safe-area-contextRN SafeAreaView
process.env.EXPO_OSPlatform.OS
React.useReact.useContext
expo-imageIntrinsic img element
expo-glass-effectCustom glass backdrops

Never use deprecated modules: Picker, WebView, SafeAreaView, AsyncStorage (from RN core), or legacy expo-permissions.


Responsiveness

  • Wrap root components in a scroll view
  • Use <ScrollView contentInsetAdjustmentBehavior="automatic" /> instead of <SafeAreaView>
  • Apply contentInsetAdjustmentBehavior="automatic" to FlatList and SectionList too
  • Use flexbox instead of Dimensions API
  • Prefer useWindowDimensions over Dimensions.get() for screen measurement

Behavior

  • Use expo-haptics conditionally on iOS for delightful interactions
  • Use views with built-in haptics (<Switch />, @react-native-community/datetimepicker)
  • First child of a Stack route should almost always be a ScrollView with contentInsetAdjustmentBehavior="automatic"
  • Prefer headerSearchBarOptions in Stack.Screen options for search bars
  • Use <Text selectable /> on data that users may want to copy
  • Format large numbers: 1.4M, 38k
  • Never use intrinsic elements (img, div) outside webviews or Expo DOM components

Styling

Follow Apple Human Interface Guidelines.

General Rules

  • Prefer flex gap over margin and padding
  • Prefer padding over margin
  • Always account for safe area via stack headers, tabs, or contentInsetAdjustmentBehavior="automatic"
  • Ensure both top and bottom safe area insets are handled
  • Inline styles preferred over StyleSheet.create unless reusing styles
  • Add entering/exiting animations for state changes
  • Use { borderCurve: 'continuous' } for rounded corners (not capsule shapes)
  • Use navigation stack title instead of custom text headers
  • On ScrollView, use contentContainerStyle for padding/gap (avoids clipping)
  • CSS and Tailwind are not supported — use inline styles

Text Styling

  • Add selectable prop to <Text/> elements showing important data or errors
  • Use { fontVariant: 'tabular-nums' } on counters for alignment

Shadows

Use CSS boxShadow style prop. Never use legacy RN shadow or elevation styles.

<View style={{ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)" }} />

Inset shadows are supported.


Navigation

Link

Use <Link href="/path" /> from expo-router for navigation.

import { Link } from 'expo-router';

<Link href="/path" />

<Link href="/path" asChild>
  <Pressable>...</Pressable>
</Link>

Include <Link.Preview> whenever possible to follow iOS conventions. Add context menus and previews frequently.

Stack

  • Always use _layout.tsx files to define stacks
  • Use Stack from expo-router/stack for native navigation stacks
  • Set page titles in Stack.Screen options: options={{ title: "Home" }}

Context Menus

Add long-press context menus to Link components:

<Link href="/settings" asChild>
  <Link.Trigger>
    <Pressable><Card /></Pressable>
  </Link.Trigger>
  <Link.Menu>
    <Link.MenuAction title="Share" icon="square.and.arrow.up" onPress={handleShare} />
    <Link.MenuAction title="Block" icon="nosign" destructive onPress={handleBlock} />
    <Link.Menu title="More" icon="ellipsis">
      <Link.MenuAction title="Copy" icon="doc.on.doc" onPress={() => {}} />
      <Link.MenuAction title="Delete" icon="trash" destructive onPress={() => {}} />
    </Link.Menu>
  </Link.Menu>
</Link>

Link Previews

<Link href="/settings">
  <Link.Trigger>
    <Pressable><Card /></Pressable>
  </Link.Trigger>
  <Link.Preview />
</Link>

Can be combined with context menus.

Modal

Present a screen as a modal:

<Stack.Screen name="modal" options={{ presentation: "modal" }} />

Prefer this over custom modal components.

Sheet

Present as a dynamic form sheet:

<Stack.Screen
  name="sheet"
  options={{
    presentation: "formSheet",
    sheetGrabberVisible: true,
    sheetAllowedDetents: [0.5, 1.0],
    contentStyle: { backgroundColor: "transparent" },
  }}
/>

contentStyle: { backgroundColor: "transparent" } enables liquid glass on iOS 26+.


Common Route Structure

Standard app layout with tabs and stacks:

app/
  _layout.tsx        — <NativeTabs />
  (index,search)/
    _layout.tsx      — <Stack />
    index.tsx        — Main list
    search.tsx       — Search view

Root layout:

// app/_layout.tsx
import { NativeTabs, Icon, Label } from "expo-router/unstable-native-tabs";
import { Theme } from "../components/theme";

export default function Layout() {
  return (
    <Theme>
      <NativeTabs>
        <NativeTabs.Trigger name="(index)">
          <Icon sf="list.dash" />
          <Label>Items</Label>
        </NativeTabs.Trigger>
        <NativeTabs.Trigger name="(search)" role="search" />
      </NativeTabs>
    </Theme>
  );
}

Shared group layout:

// app/(index,search)/_layout.tsx
import { Stack } from "expo-router/stack";
import { PlatformColor } from "react-native";

export default function Layout({ segment }) {
  const screen = segment.match(/\((.*)\)/)?.[1]!;
  const titles: Record<string, string> = { index: "Items", search: "Search" };

  return (
    <Stack
      screenOptions={{
        headerTransparent: true,
        headerShadowVisible: false,
        headerLargeTitleShadowVisible: false,
        headerLargeStyle: { backgroundColor: "transparent" },
        headerTitleStyle: { color: PlatformColor("label") },
        headerLargeTitle: true,
        headerBlurEffect: "none",
        headerBackButtonDisplayMode: "minimal",
      }}
    >
      <Stack.Screen name={screen} options={{ title: titles[screen] }} />
      <Stack.Screen name="i/[id]" options={{ headerLargeTitle: false }} />
    </Stack>
  );
}

Comments

Loading comments...