From 320f82283633d57ce0bc6c8d2a8e68c3b82a5a4e Mon Sep 17 00:00:00 2001 From: Carla Goncalves Date: Tue, 24 Feb 2026 12:45:55 +0000 Subject: [PATCH 1/2] Add switch component --- .../content/design-system/atoms/meta.json | 1 + .../content/design-system/atoms/switch.mdx | 528 +++ apps/eclipse/src/app/layout.tsx | 6 +- packages/eclipse/package.json | 39 +- packages/eclipse/src/components/index.ts | 2 + packages/eclipse/src/components/switch.tsx | 33 + pnpm-lock.yaml | 3389 +++++++++-------- 7 files changed, 2362 insertions(+), 1636 deletions(-) create mode 100644 apps/eclipse/content/design-system/atoms/switch.mdx create mode 100644 packages/eclipse/src/components/switch.tsx diff --git a/apps/eclipse/content/design-system/atoms/meta.json b/apps/eclipse/content/design-system/atoms/meta.json index 5e19985389..1a85984cb3 100644 --- a/apps/eclipse/content/design-system/atoms/meta.json +++ b/apps/eclipse/content/design-system/atoms/meta.json @@ -15,6 +15,7 @@ "separator", "slider", "spinner", + "switch", "tooltip" ] } diff --git a/apps/eclipse/content/design-system/atoms/switch.mdx b/apps/eclipse/content/design-system/atoms/switch.mdx new file mode 100644 index 0000000000..7f696f588b --- /dev/null +++ b/apps/eclipse/content/design-system/atoms/switch.mdx @@ -0,0 +1,528 @@ +--- +title: Switch +description: A toggle switch component built on Radix UI for binary on/off states with accessible keyboard support. +--- + +import { Switch, Field, FieldLabel, FieldDescription } from "@prisma-docs/eclipse"; + +### Usage + +**Basic Switch** + +```tsx +import { Switch } from "@prisma-docs/eclipse"; + +export function BasicSwitch() { + return ; +} +``` + +**Live Example:** + +
+ +
+ +**With Label** + +Use labels to make switches more accessible and user-friendly: + +```tsx +import { Switch } from "@prisma-docs/eclipse"; + +export function SwitchWithLabel() { + return ( +
+ + +
+ ); +} +``` + +**Live Example:** + +
+ + +
+ +**With Field Component** + +Use the Field component for proper form structure with labels and descriptions: + +```tsx +import { Switch, Field, FieldLabel, FieldDescription } from "@prisma-docs/eclipse"; + +export function SwitchWithField() { + return ( + +
+ Push Notifications + Receive push notifications on your device. +
+ +
+ ); +} +``` + +**Live Example:** + +
+ +
+ Push Notifications + Receive push notifications on your device. +
+ +
+
+ +**Controlled Switch** + +Control the switch state with React state: + +```tsx +import { Switch } from "@prisma-docs/eclipse"; +import { useState } from "react"; + +export function ControlledSwitch() { + const [enabled, setEnabled] = useState(false); + + return ( +
+
+ + +
+

+ Status: {enabled ? "On" : "Off"} +

+
+ ); +} +``` + +**Live Example:** + +
+
+ + +
+
+ +**Switch Sizes** + +The Switch component supports two sizes: `sm` (small) and `default`: + +```tsx +import { Switch } from "@prisma-docs/eclipse"; + +export function SwitchSizes() { + return ( +
+
+ + +
+
+ + +
+
+ ); +} +``` + +**Live Example:** + +
+
+ + +
+
+ + +
+
+ +**Disabled State** + +```tsx +import { Switch } from "@prisma-docs/eclipse"; + +export function DisabledSwitch() { + return ( +
+
+ + +
+
+ + +
+
+ ); +} +``` + +**Live Example:** + +
+
+ + +
+
+ + +
+
+ +**Settings Panel Example** + +Create a settings panel with multiple switches: + +```tsx +import { Switch, Field, FieldLabel, FieldDescription } from "@prisma-docs/eclipse"; + +export function SettingsPanel() { + return ( +
+

Notification Settings

+ + +
+ Email Notifications + Receive notifications via email. +
+ +
+ + +
+ Push Notifications + Receive push notifications on your devices. +
+ +
+ + +
+ SMS Notifications + Receive notifications via text message. +
+ +
+
+ ); +} +``` + +**Live Example:** + +
+

Notification Settings

+ + +
+ Email Notifications + Receive notifications via email. +
+ +
+ + +
+ Push Notifications + Receive push notifications on your devices. +
+ +
+ + +
+ SMS Notifications + Receive notifications via text message. +
+ +
+
+ +**Form Integration** + +```tsx +import { Switch } from "@prisma-docs/eclipse"; +import { useState } from "react"; + +export function SwitchForm() { + const [settings, setSettings] = useState({ + darkMode: false, + notifications: true, + analytics: false, + }); + + const handleSubmit = (e: React.FormEvent) => { + e.preventDefault(); + console.log("Settings:", settings); + }; + + return ( +
+

App Settings

+ +
+ + + setSettings({ ...settings, darkMode: checked }) + } + /> +
+ +
+ + + setSettings({ ...settings, notifications: checked }) + } + /> +
+ +
+ + + setSettings({ ...settings, analytics: checked }) + } + /> +
+ + +
+ ); +} +``` + +### Component Props + +**Switch** + +The Switch component extends all Radix UI Switch props: + +- `checked` - Controlled checked state (boolean, optional) +- `defaultChecked` - Default checked state for uncontrolled usage (boolean, optional) +- `onCheckedChange` - Callback when checked state changes ((checked: boolean) => void, optional) +- `disabled` - Whether the switch is disabled (boolean, default: false) +- `required` - Whether the switch is required (boolean, default: false) +- `name` - Name for form submission (string, optional) +- `value` - Value for form submission (string, default: "on") +- `id` - HTML id attribute (string, optional) +- `size` - Size variant: `"sm"` or `"default"` (default: "default") +- `className` - Additional CSS classes (string, optional) +- All standard Radix UI Switch Root props + +### Features + +- ✅ Built on Radix UI for robust accessibility +- ✅ Keyboard navigation support (Space/Enter to toggle) +- ✅ Controlled and uncontrolled modes +- ✅ Two size variants (sm, default) +- ✅ Disabled state +- ✅ Smooth animations and transitions +- ✅ Focus visible indicators with ring +- ✅ Works with forms +- ✅ Screen reader support +- ✅ Customizable with className +- ✅ Fully typed with TypeScript +- ✅ Dark mode support + +### Best Practices + +- Always pair switches with labels for better UX and accessibility +- Use `htmlFor` on labels to match switch `id` for clickable labels +- Use switches for immediate state changes (like enabling/disabling features) +- Use checkboxes for form submissions that require confirmation +- Position labels to the left of switches in settings panels +- Use Field components for forms with descriptions +- Provide clear, concise label text that describes the "on" state +- Use disabled state sparingly and only when necessary +- Consider showing immediate feedback when state changes +- Use the small size (`sm`) for compact UIs or inline controls +- Test keyboard navigation (Tab, Space, Enter) +- Ensure labels clearly communicate what the switch controls + +### Common Use Cases + +The Switch component is perfect for: + +- **Settings toggles** - Enable/disable application features +- **Feature flags** - Turn features on or off +- **Notification preferences** - Control notification channels +- **Privacy settings** - Manage privacy and data sharing +- **Theme switching** - Toggle dark/light mode +- **Accessibility options** - Enable assistive features +- **Permission controls** - Grant or revoke permissions +- **Status toggles** - Active/inactive states +- **Display options** - Show/hide UI elements +- **Auto-save** - Enable automatic saving + +### Switch vs Checkbox + +Use **Switch** when: +- The change takes effect immediately +- Toggling a feature on/off +- Representing a binary state (enabled/disabled) +- In settings or preferences panels + +Use **Checkbox** when: +- Part of a form that requires submission +- Selecting multiple items from a list +- Accepting terms or agreements +- The change requires confirmation + +### Accessibility + +The Switch component follows accessibility best practices: + +- Uses Radix UI's accessible switch primitive +- Proper ARIA attributes (`role="switch"`, `aria-checked`) +- Keyboard accessible (Space/Enter to toggle, Tab to navigate) +- Focus visible indicators with ring +- Screen reader support with proper labels +- Disabled state prevents interaction +- Works with form validation +- Supports required attribute +- Proper focus management +- High contrast in both checked and unchecked states +- Smooth animations respect `prefers-reduced-motion` + +### Keyboard Shortcuts + +- **Space** or **Enter** - Toggle switch on/off +- **Tab** - Move focus to next element +- **Shift + Tab** - Move focus to previous element + +### Styling + +The Switch component uses Eclipse design tokens: + +- **Unchecked background**: `bg-input` +- **Checked background**: `bg-primary` +- **Thumb**: `bg-background` (unchecked), `bg-primary-foreground` (checked in dark mode) +- **Focus ring**: `ring-ring/50` with 3px width +- **Border**: Transparent with shadow +- **Sizes**: + - Small (`sm`): 14px height × 24px width, 12px thumb + - Default: ~18px height × 32px width, 16px thumb +- **Border radius**: Fully rounded (`rounded-full`) +- **Shadow**: `shadow-xs` + +Customize by passing `className`: + +```tsx + +``` + +### Integration with Other Components + +Switch works well with: + +- **Field** - Form structure with labels and descriptions +- **FieldLabel** - Accessible labels +- **FieldDescription** - Helper text +- **Forms** - Settings and preferences +- **Cards** - Feature toggles within cards +- **Lists** - Settings lists +- **Dialogs** - Preference dialogs + +### Form Integration + +The Switch component works seamlessly with forms: + +```tsx +
+ + + +``` + +When checked, the form data will include: `notifications=enabled` + +### Animation + +The Switch component includes smooth animations: + +- Thumb slides horizontally when toggled +- Background color transitions smoothly +- Focus ring fades in/out +- All animations use CSS transitions +- Respects user's motion preferences + +### Dark Mode + +The Switch component automatically adapts to dark mode: + +- Unchecked state uses `bg-input/80` in dark mode +- Thumb uses `bg-foreground` when unchecked in dark mode +- Checked state remains consistent across themes +- All colors use design tokens for automatic theme adaptation \ No newline at end of file diff --git a/apps/eclipse/src/app/layout.tsx b/apps/eclipse/src/app/layout.tsx index 1fb716e0e7..f6c60ecbc1 100644 --- a/apps/eclipse/src/app/layout.tsx +++ b/apps/eclipse/src/app/layout.tsx @@ -16,7 +16,11 @@ const barlow = Barlow({ export default function Layout({ children }: LayoutProps<"/">) { return ( - +