diff --git a/apps/www/config/docs.ts b/apps/www/config/docs.ts
index 19e1ea203..a91746c27 100644
--- a/apps/www/config/docs.ts
+++ b/apps/www/config/docs.ts
@@ -495,6 +495,12 @@ export const docsConfig: DocsConfig = {
items: [],
label: "",
},
+ {
+ title: "Nebula Toggle",
+ href: "/docs/components/nebula-toggle",
+ items: [],
+ label: "New",
+ },
],
},
{
diff --git a/apps/www/content/docs/components/nebula-toggle.mdx b/apps/www/content/docs/components/nebula-toggle.mdx
new file mode 100644
index 000000000..3ed9d4514
--- /dev/null
+++ b/apps/www/content/docs/components/nebula-toggle.mdx
@@ -0,0 +1,49 @@
+---
+title: Nebula Toggle
+date: 2026-07-11
+description: A cosmic, ethereal theme toggle switch with light and dark mode animations.
+author: magicui
+published: true
+---
+
+
+
+## Installation
+
+
+
+
+ CLI
+ Manual
+
+
+
+```bash
+npx shadcn@latest add @magicui/nebula-toggle
+```
+
+
+
+
+
+
+
+Copy and paste the following code into your project.
+
+
+
+Update the import paths to match your project setup.
+
+
+
+
+
+
+
+## Props
+
+| Prop | Type | Default | Description |
+| ----------- | ---------------------------- | ----------- | ------------------------------------------------------- |
+| `checked` | `boolean` | `undefined` | Controlled checked state. If omitted, uses local state. |
+| `onChange` | `(checked: boolean) => void` | `undefined` | Callback fired when the state of the toggle changes. |
+| `className` | `string` | `undefined` | Custom CSS class styles to apply to the container. |
diff --git a/apps/www/public/llms-full.txt b/apps/www/public/llms-full.txt
index c84bf080e..4759ffd36 100644
--- a/apps/www/public/llms-full.txt
+++ b/apps/www/public/llms-full.txt
@@ -13097,6 +13097,293 @@ export default function MorphingTextDemo() {
+===== COMPONENT: nebula-toggle =====
+Title: Nebula Toggle
+Description: A cosmic, ethereal theme toggle button with light and dark mode animations.
+
+--- file: magicui/nebula-toggle.tsx ---
+"use client"
+
+import React, { useEffect, useState } from "react"
+
+import { cn } from "@/lib/utils"
+
+export interface NebulaToggleProps {
+ checked?: boolean
+ onChange?: (checked: boolean) => void
+ className?: string
+}
+
+export function NebulaToggle({
+ checked: controlledChecked,
+ onChange,
+ className,
+}: NebulaToggleProps) {
+ const [isMounted, setIsMounted] = useState(false)
+ const [checked, setChecked] = useState(false)
+
+ useEffect(() => {
+ setIsMounted(true)
+ const saved = localStorage.getItem("theme-preference")
+ if (saved === "dark") {
+ setChecked(true)
+ } else if (saved === "light") {
+ setChecked(false)
+ } else {
+ const prefersDark = window.matchMedia(
+ "(prefers-color-scheme: dark)"
+ ).matches
+ setChecked(prefersDark)
+ }
+ }, [])
+
+ const isDark = controlledChecked !== undefined ? controlledChecked : checked
+
+ useEffect(() => {
+ if (isMounted) {
+ const root = window.document.documentElement
+ if (isDark) {
+ root.classList.add("dark")
+ } else {
+ root.classList.remove("dark")
+ }
+ }
+ }, [isDark, isMounted])
+
+ const handleToggle = () => {
+ const nextValue = !isDark
+ if (controlledChecked === undefined) {
+ setChecked(nextValue)
+ localStorage.setItem("theme-preference", nextValue ? "dark" : "light")
+ }
+ onChange?.(nextValue)
+ }
+
+ const handleKeyDown = (e: React.KeyboardEvent) => {
+ if (e.key === " " || e.key === "Enter") {
+ e.preventDefault()
+ handleToggle()
+ }
+ }
+
+ return (
+ <>
+
+
+ {/* Outer nebula glow ring */}
+
+
+ {/* Ambient glow around toggle */}
+
+
+
+
+ {/* Track - cosmic nebula with ethereal glow */}
+
+ {/* Swirling Nebula clouds */}
+
+
+ {/* Track inner glow line */}
+
+
+
+ {/* Thumb */}
+
+ {/* Glass reflection on thumb */}
+
+
+ {/* Cosmic glow ring around thumb */}
+
+
+ {/* Icons */}
+
+ ☀️
+
+
+ 🌙
+
+
+
+ {/* Floating cosmic dust */}
+
+
+
+
+
+ >
+ )
+}
+
+
+===== EXAMPLE: nebula-toggle-demo =====
+Title: Nebula Toggle Demo
+
+--- file: example/nebula-toggle-demo.tsx ---
+import { NebulaToggle } from "@/registry/magicui/nebula-toggle"
+
+export default function NebulaToggleDemo() {
+ return (
+
+
+
+ )
+}
+
+
+===== EXAMPLE: nebula-toggle-demo =====
+Title: Nebula Toggle Demo
+
+--- file: example/nebula-toggle-demo.tsx ---
+import { NebulaToggle } from "@/registry/magicui/nebula-toggle"
+
+export default function NebulaToggleDemo() {
+ return (
+
+
+
+ )
+}
+
+
+
===== COMPONENT: neon-gradient-card =====
Title: Neon Gradient Card
Description: A beautiful neon card effect
diff --git a/apps/www/public/llms.txt b/apps/www/public/llms.txt
index a375dac2d..2d7f0150c 100644
--- a/apps/www/public/llms.txt
+++ b/apps/www/public/llms.txt
@@ -51,6 +51,7 @@ This file provides LLM-friendly entry points to documentation and examples.
- [Marquee](https://magicui.design/docs/components/marquee): An infinite scrolling component that can be used to display text, images, or videos.
- [Meteors](https://magicui.design/docs/components/meteors): A meteor shower effect.
- [Morphing Text](https://magicui.design/docs/components/morphing-text): A dynamic text morphing component for Magic UI.
+- [Nebula Toggle](https://magicui.design/docs/components/nebula-toggle): A cosmic, ethereal theme toggle button with light and dark mode animations.
- [Neon Gradient Card](https://magicui.design/docs/components/neon-gradient-card): A beautiful neon card effect
- [Noise Texture](https://magicui.design/docs/components/noise-texture): An SVG fractal noise layer using feTurbulence, desaturation, and contrast controls for subtle texture overlays.
- [Number Ticker](https://magicui.design/docs/components/number-ticker): Animate numbers to count up or down to a target number
@@ -254,6 +255,7 @@ This file provides LLM-friendly entry points to documentation and examples.
- [kinetic-text-demo](https://github.com/magicuidesign/magicui/blob/main/example/kinetic-text-demo.tsx): Example usage
- [Text 3D Flip Demo](https://github.com/magicuidesign/magicui/blob/main/example/text-3d-flip-demo.tsx): Example usage
- [Text 3D Flip Demo 2](https://github.com/magicuidesign/magicui/blob/main/example/text-3d-flip-demo-2.tsx): Example usage
+- [Nebula Toggle Demo](https://github.com/magicuidesign/magicui/blob/main/example/nebula-toggle-demo.tsx): Example usage
## Optional
diff --git a/apps/www/public/r/nebula-toggle-demo.json b/apps/www/public/r/nebula-toggle-demo.json
new file mode 100644
index 000000000..8c4af2dfb
--- /dev/null
+++ b/apps/www/public/r/nebula-toggle-demo.json
@@ -0,0 +1,18 @@
+{
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "nebula-toggle-demo",
+ "type": "registry:example",
+ "title": "Nebula Toggle Demo",
+ "description": "Example showing a cosmic theme toggle with light/dark transition animations.",
+ "registryDependencies": [
+ "nebula-toggle",
+ "@magicui/nebula-toggle"
+ ],
+ "files": [
+ {
+ "path": "registry/example/nebula-toggle-demo.tsx",
+ "content": "import { NebulaToggle } from \"@/registry/magicui/nebula-toggle\"\n\nexport default function NebulaToggleDemo() {\n return (\n \n \n
\n )\n}\n",
+ "type": "registry:example"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/apps/www/public/r/nebula-toggle.json b/apps/www/public/r/nebula-toggle.json
new file mode 100644
index 000000000..2322414a0
--- /dev/null
+++ b/apps/www/public/r/nebula-toggle.json
@@ -0,0 +1,15 @@
+{
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "nebula-toggle",
+ "type": "registry:ui",
+ "title": "Nebula Toggle",
+ "description": "A cosmic, ethereal theme toggle button with light and dark mode animations.",
+ "dependencies": [],
+ "files": [
+ {
+ "path": "registry/magicui/nebula-toggle.tsx",
+ "content": "\"use client\"\n\nimport React, { useEffect, useState } from \"react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport interface NebulaToggleProps {\n checked?: boolean\n onChange?: (checked: boolean) => void\n className?: string\n}\n\nexport function NebulaToggle({\n checked: controlledChecked,\n onChange,\n className,\n}: NebulaToggleProps) {\n const [isMounted, setIsMounted] = useState(false)\n const [checked, setChecked] = useState(false)\n\n useEffect(() => {\n setIsMounted(true)\n const saved = localStorage.getItem(\"theme-preference\")\n if (saved === \"dark\") {\n setChecked(true)\n } else if (saved === \"light\") {\n setChecked(false)\n } else {\n const prefersDark = window.matchMedia(\n \"(prefers-color-scheme: dark)\"\n ).matches\n setChecked(prefersDark)\n }\n }, [])\n\n const isDark = controlledChecked !== undefined ? controlledChecked : checked\n\n useEffect(() => {\n if (isMounted) {\n const root = window.document.documentElement\n if (isDark) {\n root.classList.add(\"dark\")\n } else {\n root.classList.remove(\"dark\")\n }\n }\n }, [isDark, isMounted])\n\n const handleToggle = () => {\n const nextValue = !isDark\n if (controlledChecked === undefined) {\n setChecked(nextValue)\n localStorage.setItem(\"theme-preference\", nextValue ? \"dark\" : \"light\")\n }\n onChange?.(nextValue)\n }\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n if (e.key === \" \" || e.key === \"Enter\") {\n e.preventDefault()\n handleToggle()\n }\n }\n\n return (\n <>\n \n \n {/* Outer nebula glow ring */}\n
\n\n {/* Ambient glow around toggle */}\n
\n\n
\n\n {/* Track - cosmic nebula with ethereal glow */}\n
\n {/* Swirling Nebula clouds */}\n
\n\n {/* Track inner glow line */}\n
\n
\n\n {/* Thumb */}\n
\n {/* Glass reflection on thumb */}\n
\n\n {/* Cosmic glow ring around thumb */}\n
\n\n {/* Icons */}\n
\n ☀️\n \n
\n 🌙\n \n
\n\n {/* Floating cosmic dust */}\n
\n
\n
\n
\n
\n >\n )\n}\n",
+ "type": "registry:ui"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/apps/www/public/r/registry.json b/apps/www/public/r/registry.json
index b624cc4c0..21eb68643 100644
--- a/apps/www/public/r/registry.json
+++ b/apps/www/public/r/registry.json
@@ -1360,6 +1360,19 @@
}
]
},
+ {
+ "name": "nebula-toggle",
+ "type": "registry:ui",
+ "title": "Nebula Toggle",
+ "description": "A cosmic, ethereal theme toggle button with light and dark mode animations.",
+ "dependencies": [],
+ "files": [
+ {
+ "path": "registry/magicui/nebula-toggle.tsx",
+ "type": "registry:ui"
+ }
+ ]
+ },
{
"name": "magic-card-demo",
"type": "registry:example",
@@ -3950,6 +3963,22 @@
}
]
},
+ {
+ "name": "nebula-toggle-demo",
+ "type": "registry:example",
+ "title": "Nebula Toggle Demo",
+ "description": "Example showing a cosmic theme toggle with light/dark transition animations.",
+ "registryDependencies": [
+ "nebula-toggle",
+ "@magicui/nebula-toggle"
+ ],
+ "files": [
+ {
+ "path": "registry/example/nebula-toggle-demo.tsx",
+ "type": "registry:example"
+ }
+ ]
+ },
{
"name": "utils",
"type": "registry:lib",
diff --git a/apps/www/public/registry.json b/apps/www/public/registry.json
index b624cc4c0..21eb68643 100644
--- a/apps/www/public/registry.json
+++ b/apps/www/public/registry.json
@@ -1360,6 +1360,19 @@
}
]
},
+ {
+ "name": "nebula-toggle",
+ "type": "registry:ui",
+ "title": "Nebula Toggle",
+ "description": "A cosmic, ethereal theme toggle button with light and dark mode animations.",
+ "dependencies": [],
+ "files": [
+ {
+ "path": "registry/magicui/nebula-toggle.tsx",
+ "type": "registry:ui"
+ }
+ ]
+ },
{
"name": "magic-card-demo",
"type": "registry:example",
@@ -3950,6 +3963,22 @@
}
]
},
+ {
+ "name": "nebula-toggle-demo",
+ "type": "registry:example",
+ "title": "Nebula Toggle Demo",
+ "description": "Example showing a cosmic theme toggle with light/dark transition animations.",
+ "registryDependencies": [
+ "nebula-toggle",
+ "@magicui/nebula-toggle"
+ ],
+ "files": [
+ {
+ "path": "registry/example/nebula-toggle-demo.tsx",
+ "type": "registry:example"
+ }
+ ]
+ },
{
"name": "utils",
"type": "registry:lib",
diff --git a/apps/www/registry.json b/apps/www/registry.json
index b624cc4c0..21eb68643 100644
--- a/apps/www/registry.json
+++ b/apps/www/registry.json
@@ -1360,6 +1360,19 @@
}
]
},
+ {
+ "name": "nebula-toggle",
+ "type": "registry:ui",
+ "title": "Nebula Toggle",
+ "description": "A cosmic, ethereal theme toggle button with light and dark mode animations.",
+ "dependencies": [],
+ "files": [
+ {
+ "path": "registry/magicui/nebula-toggle.tsx",
+ "type": "registry:ui"
+ }
+ ]
+ },
{
"name": "magic-card-demo",
"type": "registry:example",
@@ -3950,6 +3963,22 @@
}
]
},
+ {
+ "name": "nebula-toggle-demo",
+ "type": "registry:example",
+ "title": "Nebula Toggle Demo",
+ "description": "Example showing a cosmic theme toggle with light/dark transition animations.",
+ "registryDependencies": [
+ "nebula-toggle",
+ "@magicui/nebula-toggle"
+ ],
+ "files": [
+ {
+ "path": "registry/example/nebula-toggle-demo.tsx",
+ "type": "registry:example"
+ }
+ ]
+ },
{
"name": "utils",
"type": "registry:lib",
diff --git a/apps/www/registry/__index__.tsx b/apps/www/registry/__index__.tsx
index 35aa0bc8a..1efa5597e 100644
--- a/apps/www/registry/__index__.tsx
+++ b/apps/www/registry/__index__.tsx
@@ -1324,6 +1324,23 @@ export const Index: Record = {
}),
meta: undefined,
},
+ "nebula-toggle": {
+ name: "nebula-toggle",
+ description: "A cosmic, ethereal theme toggle button with light and dark mode animations.",
+ type: "registry:ui",
+ registryDependencies: undefined,
+ files: [{
+ path: "registry/magicui/nebula-toggle.tsx",
+ type: "registry:ui",
+ target: ""
+ }],
+ component: React.lazy(async () => {
+ const mod = await import("@/registry/magicui/nebula-toggle.tsx")
+ const exportName = Object.keys(mod).find(key => typeof mod[key] === 'function' || typeof mod[key] === 'object') ?? item.name
+ return { default: mod.default ?? mod[exportName] }
+ }),
+ meta: undefined,
+ },
"magic-card-demo": {
name: "magic-card-demo",
description: "Example showing a spotlight effect that follows your mouse cursor and highlights borders on hover.",
@@ -4184,6 +4201,23 @@ export const Index: Record = {
}),
meta: undefined,
},
+ "nebula-toggle-demo": {
+ name: "nebula-toggle-demo",
+ description: "Example showing a cosmic theme toggle with light/dark transition animations.",
+ type: "registry:example",
+ registryDependencies: ["nebula-toggle","@magicui/nebula-toggle"],
+ files: [{
+ path: "registry/example/nebula-toggle-demo.tsx",
+ type: "registry:example",
+ target: ""
+ }],
+ component: React.lazy(async () => {
+ const mod = await import("@/registry/example/nebula-toggle-demo.tsx")
+ const exportName = Object.keys(mod).find(key => typeof mod[key] === 'function' || typeof mod[key] === 'object') ?? item.name
+ return { default: mod.default ?? mod[exportName] }
+ }),
+ meta: undefined,
+ },
"utils": {
name: "utils",
description: "",
diff --git a/apps/www/registry/example/nebula-toggle-demo.tsx b/apps/www/registry/example/nebula-toggle-demo.tsx
new file mode 100644
index 000000000..190651054
--- /dev/null
+++ b/apps/www/registry/example/nebula-toggle-demo.tsx
@@ -0,0 +1,9 @@
+import { NebulaToggle } from "@/registry/magicui/nebula-toggle"
+
+export default function NebulaToggleDemo() {
+ return (
+
+
+
+ )
+}
diff --git a/apps/www/registry/magicui/nebula-toggle.tsx b/apps/www/registry/magicui/nebula-toggle.tsx
new file mode 100644
index 000000000..52f16adfa
--- /dev/null
+++ b/apps/www/registry/magicui/nebula-toggle.tsx
@@ -0,0 +1,249 @@
+"use client"
+
+import React, { useEffect, useState } from "react"
+
+import { cn } from "@/lib/utils"
+
+export interface NebulaToggleProps {
+ checked?: boolean
+ onChange?: (checked: boolean) => void
+ className?: string
+}
+
+export function NebulaToggle({
+ checked: controlledChecked,
+ onChange,
+ className,
+}: NebulaToggleProps) {
+ const [isMounted, setIsMounted] = useState(false)
+ const [checked, setChecked] = useState(false)
+
+ useEffect(() => {
+ setIsMounted(true)
+ const saved = localStorage.getItem("theme-preference")
+ if (saved === "dark") {
+ setChecked(true)
+ } else if (saved === "light") {
+ setChecked(false)
+ } else {
+ const prefersDark = window.matchMedia(
+ "(prefers-color-scheme: dark)"
+ ).matches
+ setChecked(prefersDark)
+ }
+ }, [])
+
+ const isDark = controlledChecked !== undefined ? controlledChecked : checked
+
+ useEffect(() => {
+ if (isMounted) {
+ const root = window.document.documentElement
+ if (isDark) {
+ root.classList.add("dark")
+ } else {
+ root.classList.remove("dark")
+ }
+ }
+ }, [isDark, isMounted])
+
+ const handleToggle = () => {
+ const nextValue = !isDark
+ if (controlledChecked === undefined) {
+ setChecked(nextValue)
+ localStorage.setItem("theme-preference", nextValue ? "dark" : "light")
+ }
+ onChange?.(nextValue)
+ }
+
+ const handleKeyDown = (e: React.KeyboardEvent) => {
+ if (e.key === " " || e.key === "Enter") {
+ e.preventDefault()
+ handleToggle()
+ }
+ }
+
+ return (
+ <>
+
+
+ {/* Outer nebula glow ring */}
+
+
+ {/* Ambient glow around toggle */}
+
+
+
+
+ {/* Track - cosmic nebula with ethereal glow */}
+
+ {/* Swirling Nebula clouds */}
+
+
+ {/* Track inner glow line */}
+
+
+
+ {/* Thumb */}
+
+ {/* Glass reflection on thumb */}
+
+
+ {/* Cosmic glow ring around thumb */}
+
+
+ {/* Icons */}
+
+ ☀️
+
+
+ 🌙
+
+
+
+ {/* Floating cosmic dust */}
+
+
+
+
+
+ >
+ )
+}
diff --git a/apps/www/registry/registry-examples.ts b/apps/www/registry/registry-examples.ts
index eb8c8ff10..8c26c0a18 100644
--- a/apps/www/registry/registry-examples.ts
+++ b/apps/www/registry/registry-examples.ts
@@ -2245,4 +2245,18 @@ export const examples: Registry["items"] = [
},
],
},
+ {
+ name: "nebula-toggle-demo",
+ type: "registry:example",
+ title: "Nebula Toggle Demo",
+ description:
+ "Example showing a cosmic theme toggle with light/dark transition animations.",
+ registryDependencies: ["nebula-toggle", "@magicui/nebula-toggle"],
+ files: [
+ {
+ path: "example/nebula-toggle-demo.tsx",
+ type: "registry:example",
+ },
+ ],
+ },
]
diff --git a/apps/www/registry/registry-ui.ts b/apps/www/registry/registry-ui.ts
index 81f626874..cdb8c9386 100644
--- a/apps/www/registry/registry-ui.ts
+++ b/apps/www/registry/registry-ui.ts
@@ -1312,4 +1312,18 @@ export const ui: Registry["items"] = [
},
],
},
+ {
+ name: "nebula-toggle",
+ type: "registry:ui",
+ title: "Nebula Toggle",
+ description:
+ "A cosmic, ethereal theme toggle button with light and dark mode animations.",
+ dependencies: [],
+ files: [
+ {
+ path: "magicui/nebula-toggle.tsx",
+ type: "registry:ui",
+ },
+ ],
+ },
]