All skills
expo avatar

/expo-native-ui

@4503deb official
by expoexpo/skills2.6k stars
156

Framework (OSS). Build beautiful, native-feeling Expo screens. Covers Apple HIG styling, semantic colors, native controls, SF Symbols, media, visual effects, gradients, storage, and responsive layout. For routing and navigation, use the expo-router skill; for motion and animation, use the expo-animation skill.

Use this Skill: https://skilld.dev/gh/expo/skills/expo-native-ui

This session only. Nothing lands on disk.

referencescontrols.md

≈1.3k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Native Controls

Native iOS controls provide built-in haptics, accessibility, and platform-appropriate styling.

Prefer @expo/ui for these controls. Its Slider, Switch, DateTimePicker, Menu, and segmented pickers render as real SwiftUI / Jetpack Compose and follow platform design conventions automatically — recommended over the React Native controls below. See the expo-ui skill; use the React Native controls below as a fallback when you're not using @expo/ui.

Switch

Use for binary on/off settings. Has built-in haptics.

import { Switch } from "react-native";
import { useState } from "react";

const [enabled, setEnabled] = useState(false);

<Switch value={enabled} onValueChange={setEnabled} />;

Don't recolor the Switch — native styling adapts to dark mode automatically.

Segmented Control

Use for non-navigational tabs or mode selection. Avoid changing default colors.

import SegmentedControl from "@react-native-segmented-control/segmented-control";
import { useState } from "react";

const [index, setIndex] = useState(0);

<SegmentedControl
  values={["All", "Active", "Done"]}
  selectedIndex={index}
  onChange={({ nativeEvent }) => setIndex(nativeEvent.selectedSegmentIndex)}
/>;

Rules

  • Maximum 4 options — use a picker for more
  • Keep labels short (1-2 words)
  • Avoid custom colors — native styling adapts to dark mode

With Icons (iOS 14+)

<SegmentedControl
  values={[
    { label: "List", icon: "list.bullet" },
    { label: "Grid", icon: "square.grid.2x2" },
  ]}
  selectedIndex={index}
  onChange={({ nativeEvent }) => setIndex(nativeEvent.selectedSegmentIndex)}
/>

Slider

Continuous value selection.

import Slider from "@react-native-community/slider";
import { useState } from "react";

const [value, setValue] = useState(0.5);

<Slider
  value={value}
  onValueChange={setValue}
  minimumValue={0}
  maximumValue={1}
/>;

Discrete Steps

<Slider
  value={value}
  onValueChange={setValue}
  minimumValue={0}
  maximumValue={10}
  step={1}
/>

Date/Time Picker

Compact pickers with popovers. Has built-in haptics.

import DateTimePicker from "@react-native-community/datetimepicker";
import { useState } from "react";

const [date, setDate] = useState(new Date());

<DateTimePicker
  value={date}
  onChange={(event, selectedDate) => {
    if (selectedDate) setDate(selectedDate);
  }}
  mode="datetime"
/>;

Modes

  • date — Date only
  • time — Time only
  • datetime — Date and time

Display Styles

// Compact inline (default)
<DateTimePicker value={date} mode="date" />

// Spinner wheel
<DateTimePicker
  value={date}
  mode="date"
  display="spinner"
  style={{ width: 200, height: 150 }}
/>

// Full calendar
<DateTimePicker value={date} mode="date" display="inline" />

Time Intervals

<DateTimePicker
  value={date}
  mode="time"
  minuteInterval={15}
/>

Min/Max Dates

<DateTimePicker
  value={date}
  mode="date"
  minimumDate={new Date(2020, 0, 1)}
  maximumDate={new Date(2030, 11, 31)}
/>

TextInput

Native text input with various keyboard types.

import { TextInput } from "react-native";
import { colors } from "@/theme/colors";

<TextInput
  placeholder="Enter text..."
  placeholderTextColor={colors.secondaryLabel as string}
  style={{
    padding: 12,
    fontSize: 16,
    borderRadius: 8,
    backgroundColor: colors.secondarySystemBackground,
  }}
/>

Keyboard Types

// Email
<TextInput keyboardType="email-address" autoCapitalize="none" />

// Phone
<TextInput keyboardType="phone-pad" />

// Number
<TextInput keyboardType="numeric" />

// Password
<TextInput secureTextEntry />

// Search
<TextInput
  returnKeyType="search"
  enablesReturnKeyAutomatically
/>

Multiline

<TextInput
  multiline
  numberOfLines={4}
  textAlignVertical="top"
  style={{ minHeight: 100 }}
/>

Picker (Wheel)

For selection from many options (5+ items).

import { Picker } from "@react-native-picker/picker";
import { useState } from "react";

const [selected, setSelected] = useState("js");

<Picker selectedValue={selected} onValueChange={setSelected}>
  <Picker.Item label="JavaScript" value="js" />
  <Picker.Item label="TypeScript" value="ts" />
  <Picker.Item label="Python" value="py" />
  <Picker.Item label="Go" value="go" />
</Picker>;

Best Practices

  • Haptics: Switch and DateTimePicker have built-in haptics — don't add extra
  • No native Stepper: React Native has no Stepper component — compose increment/decrement from two Buttons or a numeric TextInput
  • Accessibility: Native controls have proper accessibility labels by default
  • Dark Mode: Avoid custom colors — native styling adapts automatically
  • Spacing: Use consistent padding around controls (12-16pt)
  • Labels: Place labels above or to the left of controls
  • Grouping: Group related controls in sections with headers

Source: SKILL.md on GitHub

No alerts22d3 checks · Risk SAFE
  • Gen Agent Trust Hub22d

    The skill provides comprehensive guidelines and code samples for developing native-feeling Expo applications. It includes standard package installation instructions and a feedback submission command using a vendor-aligned utility tool.

  • Socket22d

    No alerts

  • Snyk22d

    Risk: LOW · No issues

Signed by skilld at 4503deb. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub 3 days ago.

Activeupdated 3 weeks ago
version
1.1.1

README badge

README badge for expo/skills/expo-native-ui