Settings screen
ProReact Native · ExpoA complete settings screen in inset grouped sections: account, notification switches that flip optimistically, a light, dark and system appearance switch, privacy, storage with a cache size that rolls down to zero when cleared, about, and a destructive sign out confirmed in an alert that runs it.
Installation
$ npx shadcn@latest add @goodui-native-pro/settings-screenThen run npx expo install --fix so react-native-svg match your Expo SDK. Files land in components/goodui-native/settings-screen.
Pro screens install from the license-gated @goodui-native-pro registry. Setup: Pro access.
- Wrap the app in GestureHandlerRootView and ThemeProvider (the alert renders in its overlay layer).
Usage
// app/(tabs)/settings.tsx
import { Stack, router } from "expo-router";
import { SettingsScreen } from "@/components/goodui-native/settings-screen/settings-screen";
import { api, useAccount } from "@/lib/account";
import { useColorSchemeSetting } from "@/lib/theme"; // your store behind ThemeProvider colorScheme
export default function SettingsRoute() {
const account = useAccount();
const [appearance, setAppearance] = useColorSchemeSetting();
return (
<>
<Stack.Screen options={{ headerShown: false }} />
<SettingsScreen
account={{ name: account.name, email: account.email, avatar: account.photoUrl, plan: account.plan }}
appearance={appearance}
onAppearanceChange={setAppearance}
notifications={account.notifications}
onNotificationChange={(key, value) => api.updateNotifications({ [key]: value })}
privateAccount={account.isPrivate}
onPrivateAccountChange={(value) => api.updatePrivacy({ isPrivate: value })}
cacheSize={account.cacheMegabytes}
onClearCache={() => api.clearCache()}
onNavigate={(route) => router.push(`/settings/${route}`)}
onSignOut={async () => {
await api.signOut();
router.replace("/sign-in");
}}
/>
</>
);
}When to use
- The settings tab or screen of a consumer app with an account, notifications and appearance.
- A starting point you trim: every navigation row only shows a chevron when you pass onNavigate.
- Editing profile fields (name, username, bio): use edit-profile-screen and link to it from the Edit profile row.
- Settings with dozens of rows or search: compose ListSection and ListRow in a sticky-header-list or your own sections.
Examples
On its own, with a sample account
<SettingsScreen />Drive the app theme from the appearance switch
const [scheme, setScheme] = useState<"light" | "dark" | "system">("system");
<ThemeProvider colorScheme={scheme}>
<SettingsScreen appearance={scheme} onAppearanceChange={setScheme} />
</ThemeProvider>API reference
| Prop | Type | Default |
|---|---|---|
| account | SettingsAccount | sampleAccount |
| appearance Appearance (controlled). Pair it with `onAppearanceChange`. | "light" | "dark" | "system" | — |
| defaultAppearance Starting appearance when uncontrolled. Default "system". | "light" | "dark" | "system" | "system" |
| onAppearanceChange Called with light, dark or system. Wire it to ThemeProvider's colorScheme. | (appearance: SettingsAppearance) => void | — |
| notifications Starting notification switches. | SettingsNotifications | { push: true, email: false, sounds: true } |
| onNotificationChange A notification switch changed. Return a promise: the switch flips at once and flips back if it rejects. | (key: keyof SettingsNotifications, value: boolean) => unknown | — |
| privateAccount Starting state of the private account switch. | boolean | false |
| onPrivateAccountChange The private account switch changed. Return a promise for an optimistic switch with rollback. | (value: boolean) => unknown | — |
| quietHours Quiet hours as 24 h "HH:mm" start and end, shown with the device's time format. | { start: string; end: string } | null | { start: "22:00", end: "07:00" } |
| blockedCount Number of blocked accounts shown in its row. | number | 3 |
| twoFactor Shows two-factor authentication as on or off. | boolean | true |
| cacheSize Cache size in megabytes. | number | 248.6 |
| onClearCache Clear cache was tapped. Return a promise: the row spins, then the size rolls down to zero. | () => unknown | — |
| version Version shown in About, for example "2.4.1 (318)". | string | "2.4.1 (318)" |
| onNavigate A navigation row was tapped. | (route: SettingsRoute) => void | — |
| onSignOut Sign out was confirmed in the alert. Return a promise and the alert keeps a spinner on Sign out until it settles; it closes on success and shakes with an error on failure. | () => unknown | — |
| title Large title. Default "Settings". | string | "Settings" |
| onBack Shows a back button in the bar. | () => void | — |
| locale BCP 47 locale for numbers and times. Defaults to the device locale. | string | — |
| testID Identifier for end-to-end tests. | string | — |
Motion and haptics
- Clearing the cache: the row spins, then the size rolls down digit by digit to zero.
- The large title collapses into the bar as you scroll; the appearance highlight stretches between segments and can be dragged.
- Switches squash and stretch as they flip and flip back with a shake if their promise rejects.
- Sign out: the alert springs in, keeps a spinner on Sign out while it runs and shakes on failure.
- Reduced motion: the size changes in place, the title cross-fades without moving, the highlight moves without stretching and the alert fades.
- Haptic: toggle-on or toggle-off on a switch flip, select on an appearance change, error when a switch's promise rejects
- Haptic: error when Clear cache rejects
- Haptic: success or error when the sign out promise settles (AlertDialog)
- Switches, the segment highlight, the digit roll and the title collapse run on the UI thread.
- Rows are plain views; the whole screen renders once and only rows whose state changes update.
Accessibility
- Section headers are headers; navigation rows are buttons named by their title and value; switch rows hand the title to the switch.
- Appearance is a tab list named 'Appearance' with the selected option marked.
- The cache row reads 'Cache, 248.6 MB' on native; on the web its visible text names it. 'Cache cleared' is announced when the size reaches zero.
- Clear cache reports busy while it runs and is disabled at zero.
- Sign out opens an alert dialog that needs an answer: Cancel or Sign out, with the error announced if signing out fails.
Notes for AI
- Pass appearance and onAppearanceChange and feed the value to ThemeProvider colorScheme; 'system' follows the device.
- Switch values are starting states; the switches keep their own state and call onNotificationChange(key, value) or onPrivateAccountChange(value). Return a promise for a server setting and a rejection flips the switch back.
- onClearCache and onSignOut may return promises; the screen shows pending and error states itself. Navigate after sign out inside your onSignOut.
- Navigation rows only become pressable when onNavigate is passed; route keys are edit-profile, subscription, password, quiet-hours, blocked, two-factor, help, terms and privacy-policy.
- quietHours takes 24 h 'HH:mm' strings and shows them in the device's time format; pass null for Off.
- Render it full-bleed with the navigator header hidden (headerShown: false).
Related
Settings and navigation cells with a token-colored icon tile, title, subtitle and a trailing value, switch, badge, check or chevron, grouped in inset sections with headers and footers. On touch down the highlight floods in, the tile sinks and the chevron leans forward; on release the highlight lingers and fades.
An iOS-style switch with squash and stretch: the thumb stretches toward where it is going on touch down, then travels on a spring while the track color follows. Settings-row layout, tones, sizes and optimistic async changes.
Two to five views of the same thing with an elastic highlight that stretches toward the new segment, can be dragged, and ticks at every boundary. Includes a billing toggle.
A centered alert that springs in from slightly larger; touch an action and slide across the others with a tick per action, tap outside and it nudges, and async actions keep it open with a spinner until they settle.
A number whose digits roll in the direction of change, with digits that open and close in place and currency signs that glide instead of jumping.
Edit your own profile: change the photo from an action sheet (take, choose, remove) and watch the new one spring in, fields that validate as you leave them, Save with its own pending, saved and error states riding on the keyboard, and an alert that guards unsaved changes on back.
An iOS large title that collapses into a compact bar as the content scrolls: the titles cross-fade, the bar fades in, the title stretches when pulled past the top and a half-finished collapse settles on either state.