import { useState } from "react";
import { View } from "react-native";
import { useKitTheme } from "@/component-lib/shared/native";
import { Switch } from "@/component-lib/switch";
import { Section } from "./layout"; // Section and Row: page layout for the demo
const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));
export function SwitchDemo() {
const { tokens } = useKitTheme();
const [wifi, setWifi] = useState(true);
const [failNext, setFailNext] = useState(true);
return (
<>
<Section title="Switch · sizes">
<Switch size="sm" label="Small" defaultChecked />
<Switch size="md" label="Medium" />
<Switch size="lg" label="Large" defaultChecked />
</Section>
<Section title="Switch · states">
<Switch label="Controlled Wi-Fi" checked={wifi} onCheckedChange={setWifi} description={wifi ? "Connected" : "Off"} />
<Switch label="Disabled" disabled defaultChecked />
<Switch label="Read only" readOnly defaultChecked />
<Switch label="Accept terms" required error="You need to accept the terms to continue." />
<Switch label="Loading from outside" loading defaultChecked />
</Section>
<Section title="Switch · async save">
<Switch
label="Email me receipts"
description="Saves for 1.2 s, then succeeds."
onCheckedChange={() => wait(1200)}
/>
<Switch
label="Flaky setting"
description={failNext ? "Next save fails and the switch goes back." : "Next save succeeds."}
onCheckedChange={async () => {
await wait(1200);
const fail = failNext;
setFailNext((f) => !f);
if (fail) throw new Error("Network error");
}}
/>
</Section>
<Section title="Switch · settings row (label at start)">
<View style={{ borderWidth: 1, borderColor: tokens.border, borderRadius: tokens.radius, paddingHorizontal: 12 }}>
<Switch labelPosition="start" label="Notifications" description="Push alerts for new payments" defaultChecked />
<Switch labelPosition="start" label="Dark statements" />
</View>
</Section>
</>
);
}Install
npx @grampro/kit@native add SwitchUsage
import { Switch } from "@/component-lib/switch";
<Switch label="Email me receipts" onCheckedChange={(on) => saveSetting(on)} />Props
SwitchProps
| Prop | Type | Description |
|---|---|---|
checked | boolean | On or off (controlled). |
defaultChecked | boolean | The starting state when you are not controlling checked. |
onCheckedChange | (checked: boolean) => void | Promise<unknown> | Fires with the new state. Return a promise and the switch stays on the new setting with a busy indicator until it resolves, then puts itself back if it rejects. |
label | ReactNode | The text beside the track. Tapping it flips the switch. |
description | ReactNode | A hint under the label, read as the switch's hint. |
error | ReactNode | The validation message. Setting it is enough: it is shown and announced. |
size | SwitchSize | Default md. |
labelPosition | SwitchLabelPosition | Default end: the label after the track. start puts the track on the right, for settings rows. |
loading | boolean | Show the busy state and block presses from outside, e.g. while a form saves. |
disabled | boolean | |
readOnly | boolean | |
required | boolean | |
style | StyleProp<ViewStyle> | ((state: SwitchStyleState) => StyleProp<ViewStyle>) | |
styles | Partial<{ root: StyleProp<ViewStyle>; control: StyleProp<ViewStyle>; track: StyleProp<V… | |
localeText | Partial<SwitchLocaleText> |
Also accepts the props of Omit<PressableProps, "children" | "style" | "onPress" | "disabled" | "role">.
Native and web
- Sizes are larger for touch than on the web.
labelPosition="start"makes a settings row. - Web version: Switch on the web.