Switch primitive wrapper
import { Switch } from '@/components/ui/switch'
...import { Switch } from '@/components/ui/switch'
export default function SwitchDemoExample() {
return (
<label class="flex items-center gap-2">
<Switch id="airplane-mode" /> Airplane Mode
</label>
)
}
Installation
npx @fictjs/shadcn@latest add switchInstall the runtime dependencies:
npm install @fictjs/radix-uiCopy the Fict shadcn component into your project.
Source
components/ui/switch.tsx
src/components/ui/switch.tsx
import { Switch as SwitchPrimitive } from '@fictjs/radix-ui'
import { cn } from '@/lib/cn'
type SwitchProps = {
class?: string
thumbClass?: string
size?: 'default' | 'sm'
[key: string]: unknown
}
export function Switch(props: SwitchProps) {
const { class: className, thumbClass, size = 'default', ...rest } = props
return (
<SwitchPrimitive.Root
data-size={size}
class={cn(
'peer inline-flex shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent bg-input transition-colors data-[state=checked]:bg-primary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
size === 'sm' ? 'h-4 w-7' : 'h-5 w-9',
className,
)}
{...rest}
>
<SwitchPrimitive.Thumb
class={cn(
'pointer-events-none block rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=unchecked]:translate-x-0',
size === 'sm'
? 'h-3 w-3 data-[state=checked]:translate-x-3'
: 'h-4 w-4 data-[state=checked]:translate-x-4',
thumbClass,
)}
/>
</SwitchPrimitive.Root>
)
}
Usage
Examples
Description
Focus is shared across devices, and turns off when you leave the app.
import { Switch } from '@/components/ui/switch'
...import { Switch } from '@/components/ui/switch'
export default function SwitchDescriptionExample() {
return (
<div class="flex w-full max-w-sm items-center justify-between gap-4">
<div>
<label for="switch-focus-mode" class="font-medium">
Share across devices
</label>
<p class="text-sm text-muted-foreground">
Focus is shared across devices, and turns off when you leave the app.
</p>
</div>
<Switch id="switch-focus-mode" />
</div>
)
}
Choice Card
Focus is shared across devices, and turns off when you leave the app.
Receive notifications when focus mode is enabled or disabled.
import { Switch } from '@/components/ui/switch'
...import { Switch } from '@/components/ui/switch'
export default function SwitchChoiceCardExample() {
return (
<div class="grid w-full max-w-sm gap-4">
<label
for="switch-share"
class="flex items-center justify-between gap-4 rounded-lg border p-4"
>
<span>
<strong class="block">Share across devices</strong>
<small class="text-muted-foreground">
Focus is shared across devices, and turns off when you leave the app.
</small>
</span>
<Switch id="switch-share" />
</label>
<label
for="switch-notifications"
class="flex items-center justify-between gap-4 rounded-lg border p-4"
>
<span>
<strong class="block">Enable notifications</strong>
<small class="text-muted-foreground">
Receive notifications when focus mode is enabled or disabled.
</small>
</span>
<Switch id="switch-notifications" defaultChecked />
</label>
</div>
)
}
Disabled
import { Switch } from '@/components/ui/switch'
...import { Switch } from '@/components/ui/switch'
export default function SwitchDisabledExample() {
return (
<label class="flex items-center gap-2 opacity-50">
<Switch id="switch-disabled-unchecked" disabled /> Disabled
</label>
)
}
Invalid
You must accept the terms and conditions to continue.
import { Switch } from '@/components/ui/switch'
...import { Switch } from '@/components/ui/switch'
export default function SwitchInvalidExample() {
return (
<div class="flex w-full max-w-sm items-center justify-between gap-4">
<div>
<label for="switch-terms" class="font-medium">
Accept terms and conditions
</label>
<p class="text-sm text-destructive">
You must accept the terms and conditions to continue.
</p>
</div>
<Switch id="switch-terms" aria-invalid="true" />
</div>
)
}
Sizes
import { Switch } from '@/components/ui/switch'
...import { Switch } from '@/components/ui/switch'
export default function SwitchSizesExample() {
return (
<div class="grid gap-4">
<label class="flex items-center gap-2">
<Switch id="switch-size-sm" size="sm" /> Small
</label>
<label class="flex items-center gap-2">
<Switch id="switch-size-default" /> Default
</label>
</div>
)
}
Rtl
يتم مشاركة التركيز عبر الأجهزة، ويتم إيقاف تشغيله عند مغادرة التطبيق.
import { Switch } from '@/components/ui/switch'
...import { Switch } from '@/components/ui/switch'
const translations = {
ar: {
dir: 'rtl',
label: 'المشاركة عبر الأجهزة',
description: 'يتم مشاركة التركيز عبر الأجهزة، ويتم إيقاف تشغيله عند مغادرة التطبيق.',
},
he: {
dir: 'rtl',
label: 'שיתוף בין מכשירים',
description: 'המיקוד משותף בין מכשירים, וכבה כשאתה עוזב את האפליקציה.',
},
en: {
dir: 'ltr',
label: 'Share across devices',
description: 'Focus is shared across devices, and turns off when you leave the app.',
},
} as const
export default function SwitchRtlExample() {
let language = $state<keyof typeof translations>('ar')
const text = () => translations[language]
return (
<div class="grid gap-4">
<select
value={language}
onChange={event => {
language = event.currentTarget.value as keyof typeof translations
}}
>
<option value="ar">Arabic (العربية)</option>
<option value="he">Hebrew (עברית)</option>
<option value="en">English</option>
</select>
<div class="flex w-full max-w-sm items-center justify-between gap-4" dir={text().dir}>
<div>
<label for="switch-focus-mode-rtl" class="font-medium">
{text().label}
</label>
<p class="text-sm text-muted-foreground">{text().description}</p>
</div>
<Switch id="switch-focus-mode-rtl" dir={text().dir} />
</div>
</div>
)
}