<div class="flex items-center space-x-3">
<label for="switch-preview" class="relative inline-flex items-center cursor-pointer">
<input type="checkbox" id="switch-preview" class="sr-only peer" checked />
<div class="w-11 h-6 bg-muted peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-primary/40 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-border after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-primary"></div>
</label>
<span class="text-sm font-medium text-foreground select-none">Enable notifications</span>
</div>
import React from "react";
export function Switch({ checked = false, onChange, label, disabled = false }: { checked?: boolean; onChange?: (checked: boolean) => void; label?: string; disabled?: boolean }) {
return (
<label className={`flex items-center space-x-3 cursor-pointer select-none ${disabled ? "opacity-50 pointer-events-none" : ""}`}>
<div className="relative inline-flex items-center">
<input
type="checkbox"
checked={checked}
onChange={(e) => onChange?.(e.target.checked)}
disabled={disabled}
className="sr-only peer"
/>
<div className="w-11 h-6 bg-muted peer-focus:outline-none peer-focus:ring-2 peer-focus:ring-primary/40 rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-border after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-primary"></div>
</div>
{label && <span className="text-sm font-medium text-foreground">{label}</span>}
</label>
);
}
"use client";
import React, { useState } from "react";
export interface SwitchProps {
label?: string;
description?: string;
defaultChecked?: boolean;
disabled?: boolean;
onChange?: (checked: boolean) => void;
}
export default function Switch({
label = "Push Notifications",
description = "Receive instant push alerts for new activities",
defaultChecked = false,
disabled = false,
onChange,
}: SwitchProps) {
const [enabled, setEnabled] = useState(defaultChecked);
const toggle = () => {
if (disabled) return;
const next = !enabled;
setEnabled(next);
onChange?.(next);
};
return (
<div className="flex items-center justify-between gap-4 w-full max-w-sm p-3.5 rounded-xl border border-border bg-card shadow-2xs">
<div className="space-y-0.5">
<label
onClick={toggle}
className="text-xs sm:text-sm font-semibold text-foreground cursor-pointer select-none"
>
{label}
</label>
{description && (
<p className="text-[11px] sm:text-xs text-muted-foreground leading-relaxed">
{description}
</p>
)}
</div>
<button
type="button"
role="switch"
aria-checked={enabled}
disabled={disabled}
onClick={toggle}
onKeyDown={(e) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
toggle();
}
}}
className={`relative inline-flex h-6 w-11 shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 ${
enabled ? "bg-primary" : "bg-muted"
}`}
>
<span
className={`pointer-events-none inline-block h-5 w-5 transform rounded-full bg-white shadow-lg ring-0 transition duration-200 ease-in-out ${
enabled ? "translate-x-5" : "translate-x-0"
}`}
/>
</button>
</div>
);
}
"use client";
import React, { useState } from "react";
import { motion } from "framer-motion";
import { Check, X } from "lucide-react";
export interface AnimatedSwitchProps {
label?: string;
defaultChecked?: boolean;
onChange?: (checked: boolean) => void;
}
export default function AnimatedSwitch({
label = "Airplane Mode",
defaultChecked = true,
onChange,
}: AnimatedSwitchProps) {
const [isOn, setIsOn] = useState(defaultChecked);
const toggle = () => {
const next = !isOn;
setIsOn(next);
onChange?.(next);
};
return (
<div className="flex items-center justify-between gap-4 w-full max-w-sm p-4 rounded-2xl border border-border bg-card/60 backdrop-blur-sm shadow-sm">
<span className="text-sm font-semibold text-foreground select-none">{label}</span>
<motion.button
type="button"
role="switch"
aria-checked={isOn}
onClick={toggle}
whileTap={{ scale: 0.94 }}
className={`relative inline-flex h-7 w-13 shrink-0 cursor-pointer rounded-full p-1 transition-colors duration-300 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary focus-visible:ring-offset-2 ${
isOn ? "bg-primary" : "bg-muted"
}`}
>
<motion.span
layout
transition={{ type: "spring", stiffness: 600, damping: 30 }}
className={`flex h-5 w-5 items-center justify-center rounded-full bg-white shadow-md text-zinc-900 ${
isOn ? "ml-auto" : "mr-auto"
}`}
>
{isOn ? (
<Check className="h-3 w-3 text-primary stroke-[3]" />
) : (
<X className="h-3 w-3 text-zinc-400 stroke-[2.5]" />
)}
</motion.span>
</motion.button>
</div>
);
}