diff --git a/apps/v4/content/docs/components/sonner.mdx b/apps/v4/content/docs/components/sonner.mdx
index d7a761dbb..3c73bc756 100644
--- a/apps/v4/content/docs/components/sonner.mdx
+++ b/apps/v4/content/docs/components/sonner.mdx
@@ -68,7 +68,7 @@ npm install sonner next-themes
Add the Toaster component
-```tsx title="app/layout.tsx" {1,9}
+```tsx showLineNumbers title="app/layout.tsx" {1,8}
import { Toaster } from "@/components/ui/sonner"
export default function RootLayout({ children }) {
@@ -76,8 +76,8 @@ export default function RootLayout({ children }) {
- {children}
+ {children}
)
@@ -99,3 +99,56 @@ import { toast } from "sonner"
```tsx
toast("Event has been created.")
```
+
+## Examples
+
+
+
+## Changelog
+
+### 2025-10-13 Icons
+
+We've updated the Sonner component to use icons from `lucide`. Update your `sonner.tsx` file to use the new icons.
+
+```tsx showLineNumbers title="components/ui/sonner.tsx" {3-9,20-26}
+"use client"
+
+import {
+ CircleCheckIcon,
+ InfoIcon,
+ Loader2Icon,
+ OctagonXIcon,
+ TriangleAlertIcon,
+} from "lucide-react"
+import { useTheme } from "next-themes"
+import { Toaster as Sonner, ToasterProps } from "sonner"
+
+const Toaster = ({ ...props }: ToasterProps) => {
+ const { theme = "system" } = useTheme()
+
+ return (
+ ,
+ info: ,
+ warning: ,
+ error: ,
+ loading: ,
+ }}
+ style={
+ {
+ "--normal-bg": "var(--popover)",
+ "--normal-text": "var(--popover-foreground)",
+ "--normal-border": "var(--border)",
+ "--border-radius": "var(--radius)",
+ } as React.CSSProperties
+ }
+ {...props}
+ />
+ )
+}
+
+export { Toaster }
+```
diff --git a/apps/v4/public/r/styles/default/sonner.json b/apps/v4/public/r/styles/default/sonner.json
index 88ac39ce6..80bf2c577 100644
--- a/apps/v4/public/r/styles/default/sonner.json
+++ b/apps/v4/public/r/styles/default/sonner.json
@@ -10,7 +10,7 @@
"files": [
{
"path": "ui/sonner.tsx",
- "content": "\"use client\"\n\nimport { useTheme } from \"next-themes\"\nimport { Toaster as Sonner } from \"sonner\"\n\ntype ToasterProps = React.ComponentProps\n\nconst Toaster = ({ ...props }: ToasterProps) => {\n const { theme = \"system\" } = useTheme()\n\n return (\n \n )\n}\n\nexport { Toaster }\n",
+ "content": "\"use client\"\n\nimport {\n CircleCheck,\n Info,\n LoaderCircle,\n OctagonX,\n TriangleAlert,\n} from \"lucide-react\"\nimport { useTheme } from \"next-themes\"\nimport { Toaster as Sonner } from \"sonner\"\n\ntype ToasterProps = React.ComponentProps\n\nconst Toaster = ({ ...props }: ToasterProps) => {\n const { theme = \"system\" } = useTheme()\n\n return (\n ,\n info: ,\n warning: ,\n error: ,\n loading: ,\n }}\n toastOptions={{\n classNames: {\n toast:\n \"group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg\",\n description: \"group-[.toast]:text-muted-foreground\",\n actionButton:\n \"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground\",\n cancelButton:\n \"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground\",\n },\n }}\n {...props}\n />\n )\n}\n\nexport { Toaster }\n",
"type": "registry:ui",
"target": ""
}
diff --git a/apps/v4/public/r/styles/new-york-v4/registry.json b/apps/v4/public/r/styles/new-york-v4/registry.json
index 4d17f6587..2d729b812 100644
--- a/apps/v4/public/r/styles/new-york-v4/registry.json
+++ b/apps/v4/public/r/styles/new-york-v4/registry.json
@@ -6863,6 +6863,19 @@
}
]
},
+ {
+ "name": "sonner-types",
+ "type": "registry:example",
+ "registryDependencies": [
+ "sonner"
+ ],
+ "files": [
+ {
+ "path": "registry/new-york-v4/examples/sonner-types.tsx",
+ "type": "registry:example"
+ }
+ ]
+ },
{
"name": "spinner-demo",
"type": "registry:example",
diff --git a/apps/v4/public/r/styles/new-york-v4/sonner-types.json b/apps/v4/public/r/styles/new-york-v4/sonner-types.json
new file mode 100644
index 000000000..05941a138
--- /dev/null
+++ b/apps/v4/public/r/styles/new-york-v4/sonner-types.json
@@ -0,0 +1,15 @@
+{
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "sonner-types",
+ "type": "registry:example",
+ "registryDependencies": [
+ "sonner"
+ ],
+ "files": [
+ {
+ "path": "registry/new-york-v4/examples/sonner-types.tsx",
+ "content": "\"use client\"\n\nimport { toast } from \"sonner\"\n\nimport { Button } from \"@/registry/new-york-v4/ui/button\"\n\nexport default function SonnerTypes() {\n return (\n \n \n \n \n \n \n \n
\n )\n}\n",
+ "type": "registry:example"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/apps/v4/public/r/styles/new-york-v4/sonner.json b/apps/v4/public/r/styles/new-york-v4/sonner.json
index 6e63f434c..d22159c96 100644
--- a/apps/v4/public/r/styles/new-york-v4/sonner.json
+++ b/apps/v4/public/r/styles/new-york-v4/sonner.json
@@ -9,7 +9,7 @@
"files": [
{
"path": "registry/new-york-v4/ui/sonner.tsx",
- "content": "\"use client\"\n\nimport { useTheme } from \"next-themes\"\nimport { Toaster as Sonner, ToasterProps } from \"sonner\"\n\nconst Toaster = ({ ...props }: ToasterProps) => {\n const { theme = \"system\" } = useTheme()\n\n return (\n \n )\n}\n\nexport { Toaster }\n",
+ "content": "\"use client\"\n\nimport {\n CircleCheckIcon,\n InfoIcon,\n Loader2Icon,\n OctagonXIcon,\n TriangleAlertIcon,\n} from \"lucide-react\"\nimport { useTheme } from \"next-themes\"\nimport { Toaster as Sonner, ToasterProps } from \"sonner\"\n\nconst Toaster = ({ ...props }: ToasterProps) => {\n const { theme = \"system\" } = useTheme()\n\n return (\n ,\n info: ,\n warning: ,\n error: ,\n loading: ,\n }}\n style={\n {\n \"--normal-bg\": \"var(--popover)\",\n \"--normal-text\": \"var(--popover-foreground)\",\n \"--normal-border\": \"var(--border)\",\n \"--border-radius\": \"var(--radius)\",\n } as React.CSSProperties\n }\n {...props}\n />\n )\n}\n\nexport { Toaster }\n",
"type": "registry:ui"
}
]
diff --git a/apps/v4/registry.json b/apps/v4/registry.json
index 4d17f6587..2d729b812 100644
--- a/apps/v4/registry.json
+++ b/apps/v4/registry.json
@@ -6863,6 +6863,19 @@
}
]
},
+ {
+ "name": "sonner-types",
+ "type": "registry:example",
+ "registryDependencies": [
+ "sonner"
+ ],
+ "files": [
+ {
+ "path": "registry/new-york-v4/examples/sonner-types.tsx",
+ "type": "registry:example"
+ }
+ ]
+ },
{
"name": "spinner-demo",
"type": "registry:example",
diff --git a/apps/v4/registry/__index__.tsx b/apps/v4/registry/__index__.tsx
index 3fadf601d..34d41e72b 100644
--- a/apps/v4/registry/__index__.tsx
+++ b/apps/v4/registry/__index__.tsx
@@ -6956,6 +6956,24 @@ export const Index: Record = {
categories: undefined,
meta: undefined,
},
+ "sonner-types": {
+ name: "sonner-types",
+ description: "",
+ type: "registry:example",
+ registryDependencies: ["sonner"],
+ files: [{
+ path: "registry/new-york-v4/examples/sonner-types.tsx",
+ type: "registry:example",
+ target: ""
+ }],
+ component: React.lazy(async () => {
+ const mod = await import("@/registry/new-york-v4/examples/sonner-types.tsx")
+ const exportName = Object.keys(mod).find(key => typeof mod[key] === 'function' || typeof mod[key] === 'object') || item.name
+ return { default: mod.default || mod[exportName] }
+ }),
+ categories: undefined,
+ meta: undefined,
+ },
"spinner-demo": {
name: "spinner-demo",
description: "",
diff --git a/apps/v4/registry/new-york-v4/examples/sonner-types.tsx b/apps/v4/registry/new-york-v4/examples/sonner-types.tsx
new file mode 100644
index 000000000..6934a733f
--- /dev/null
+++ b/apps/v4/registry/new-york-v4/examples/sonner-types.tsx
@@ -0,0 +1,61 @@
+"use client"
+
+import { toast } from "sonner"
+
+import { Button } from "@/registry/new-york-v4/ui/button"
+
+export default function SonnerTypes() {
+ return (
+
+
+
+
+
+
+
+
+ )
+}
diff --git a/apps/v4/registry/new-york-v4/ui/sonner.tsx b/apps/v4/registry/new-york-v4/ui/sonner.tsx
index fb3015af3..2ec7deff6 100644
--- a/apps/v4/registry/new-york-v4/ui/sonner.tsx
+++ b/apps/v4/registry/new-york-v4/ui/sonner.tsx
@@ -1,5 +1,12 @@
"use client"
+import {
+ CircleCheckIcon,
+ InfoIcon,
+ Loader2Icon,
+ OctagonXIcon,
+ TriangleAlertIcon,
+} from "lucide-react"
import { useTheme } from "next-themes"
import { Toaster as Sonner, ToasterProps } from "sonner"
@@ -10,6 +17,13 @@ const Toaster = ({ ...props }: ToasterProps) => {
,
+ info: ,
+ warning: ,
+ error: ,
+ loading: ,
+ }}
style={
{
"--normal-bg": "var(--popover)",
diff --git a/apps/v4/registry/registry-examples.ts b/apps/v4/registry/registry-examples.ts
index 246b041bb..b172d29f2 100644
--- a/apps/v4/registry/registry-examples.ts
+++ b/apps/v4/registry/registry-examples.ts
@@ -2016,6 +2016,17 @@ export const examples: Registry["items"] = [
},
],
},
+ {
+ name: "sonner-types",
+ type: "registry:example",
+ registryDependencies: ["sonner"],
+ files: [
+ {
+ path: "examples/sonner-types.tsx",
+ type: "registry:example",
+ },
+ ],
+ },
{
name: "spinner-demo",
type: "registry:example",
diff --git a/apps/www/public/r/styles/default/sonner.json b/apps/www/public/r/styles/default/sonner.json
index 88ac39ce6..80bf2c577 100644
--- a/apps/www/public/r/styles/default/sonner.json
+++ b/apps/www/public/r/styles/default/sonner.json
@@ -10,7 +10,7 @@
"files": [
{
"path": "ui/sonner.tsx",
- "content": "\"use client\"\n\nimport { useTheme } from \"next-themes\"\nimport { Toaster as Sonner } from \"sonner\"\n\ntype ToasterProps = React.ComponentProps\n\nconst Toaster = ({ ...props }: ToasterProps) => {\n const { theme = \"system\" } = useTheme()\n\n return (\n \n )\n}\n\nexport { Toaster }\n",
+ "content": "\"use client\"\n\nimport {\n CircleCheck,\n Info,\n LoaderCircle,\n OctagonX,\n TriangleAlert,\n} from \"lucide-react\"\nimport { useTheme } from \"next-themes\"\nimport { Toaster as Sonner } from \"sonner\"\n\ntype ToasterProps = React.ComponentProps\n\nconst Toaster = ({ ...props }: ToasterProps) => {\n const { theme = \"system\" } = useTheme()\n\n return (\n ,\n info: ,\n warning: ,\n error: ,\n loading: ,\n }}\n toastOptions={{\n classNames: {\n toast:\n \"group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg\",\n description: \"group-[.toast]:text-muted-foreground\",\n actionButton:\n \"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground\",\n cancelButton:\n \"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground\",\n },\n }}\n {...props}\n />\n )\n}\n\nexport { Toaster }\n",
"type": "registry:ui",
"target": ""
}
diff --git a/apps/www/public/r/styles/new-york-v4/registry.json b/apps/www/public/r/styles/new-york-v4/registry.json
index 4d17f6587..2d729b812 100644
--- a/apps/www/public/r/styles/new-york-v4/registry.json
+++ b/apps/www/public/r/styles/new-york-v4/registry.json
@@ -6863,6 +6863,19 @@
}
]
},
+ {
+ "name": "sonner-types",
+ "type": "registry:example",
+ "registryDependencies": [
+ "sonner"
+ ],
+ "files": [
+ {
+ "path": "registry/new-york-v4/examples/sonner-types.tsx",
+ "type": "registry:example"
+ }
+ ]
+ },
{
"name": "spinner-demo",
"type": "registry:example",
diff --git a/apps/www/public/r/styles/new-york-v4/sonner-types.json b/apps/www/public/r/styles/new-york-v4/sonner-types.json
new file mode 100644
index 000000000..05941a138
--- /dev/null
+++ b/apps/www/public/r/styles/new-york-v4/sonner-types.json
@@ -0,0 +1,15 @@
+{
+ "$schema": "https://ui.shadcn.com/schema/registry-item.json",
+ "name": "sonner-types",
+ "type": "registry:example",
+ "registryDependencies": [
+ "sonner"
+ ],
+ "files": [
+ {
+ "path": "registry/new-york-v4/examples/sonner-types.tsx",
+ "content": "\"use client\"\n\nimport { toast } from \"sonner\"\n\nimport { Button } from \"@/registry/new-york-v4/ui/button\"\n\nexport default function SonnerTypes() {\n return (\n \n \n \n \n \n \n \n
\n )\n}\n",
+ "type": "registry:example"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/apps/www/public/r/styles/new-york-v4/sonner.json b/apps/www/public/r/styles/new-york-v4/sonner.json
index 6e63f434c..d22159c96 100644
--- a/apps/www/public/r/styles/new-york-v4/sonner.json
+++ b/apps/www/public/r/styles/new-york-v4/sonner.json
@@ -9,7 +9,7 @@
"files": [
{
"path": "registry/new-york-v4/ui/sonner.tsx",
- "content": "\"use client\"\n\nimport { useTheme } from \"next-themes\"\nimport { Toaster as Sonner, ToasterProps } from \"sonner\"\n\nconst Toaster = ({ ...props }: ToasterProps) => {\n const { theme = \"system\" } = useTheme()\n\n return (\n \n )\n}\n\nexport { Toaster }\n",
+ "content": "\"use client\"\n\nimport {\n CircleCheckIcon,\n InfoIcon,\n Loader2Icon,\n OctagonXIcon,\n TriangleAlertIcon,\n} from \"lucide-react\"\nimport { useTheme } from \"next-themes\"\nimport { Toaster as Sonner, ToasterProps } from \"sonner\"\n\nconst Toaster = ({ ...props }: ToasterProps) => {\n const { theme = \"system\" } = useTheme()\n\n return (\n ,\n info: ,\n warning: ,\n error: ,\n loading: ,\n }}\n style={\n {\n \"--normal-bg\": \"var(--popover)\",\n \"--normal-text\": \"var(--popover-foreground)\",\n \"--normal-border\": \"var(--border)\",\n \"--border-radius\": \"var(--radius)\",\n } as React.CSSProperties\n }\n {...props}\n />\n )\n}\n\nexport { Toaster }\n",
"type": "registry:ui"
}
]
diff --git a/apps/www/registry/default/ui/form.tsx b/apps/www/registry/default/ui/form.tsx
index c7cdffff7..c8e5e898a 100644
--- a/apps/www/registry/default/ui/form.tsx
+++ b/apps/www/registry/default/ui/form.tsx
@@ -24,7 +24,7 @@ type FormFieldContextValue<
name: TName
}
-const FormFieldContext = React.createContext(null);
+const FormFieldContext = React.createContext(null)
const FormField = <
TFieldValues extends FieldValues = FieldValues,
@@ -70,7 +70,7 @@ type FormItemContextValue = {
id: string
}
-const FormItemContext = React.createContext(null)
+const FormItemContext = React.createContext(null)
const FormItem = React.forwardRef<
HTMLDivElement,
diff --git a/apps/www/registry/default/ui/sonner.tsx b/apps/www/registry/default/ui/sonner.tsx
index 452f4d9f0..6e6fd25c2 100644
--- a/apps/www/registry/default/ui/sonner.tsx
+++ b/apps/www/registry/default/ui/sonner.tsx
@@ -1,5 +1,12 @@
"use client"
+import {
+ CircleCheck,
+ Info,
+ LoaderCircle,
+ OctagonX,
+ TriangleAlert,
+} from "lucide-react"
import { useTheme } from "next-themes"
import { Toaster as Sonner } from "sonner"
@@ -12,6 +19,13 @@ const Toaster = ({ ...props }: ToasterProps) => {
,
+ info: ,
+ warning: ,
+ error: ,
+ loading: ,
+ }}
toastOptions={{
classNames: {
toast:
diff --git a/apps/www/registry/new-york/ui/form.tsx b/apps/www/registry/new-york/ui/form.tsx
index 2573cc6c5..a9d6d74ae 100644
--- a/apps/www/registry/new-york/ui/form.tsx
+++ b/apps/www/registry/new-york/ui/form.tsx
@@ -24,7 +24,7 @@ type FormFieldContextValue<
name: TName
}
-const FormFieldContext = React.createContext(null);
+const FormFieldContext = React.createContext(null)
const FormField = <
TFieldValues extends FieldValues = FieldValues,
@@ -70,7 +70,7 @@ type FormItemContextValue = {
id: string
}
-const FormItemContext = React.createContext(null)
+const FormItemContext = React.createContext(null)
const FormItem = React.forwardRef<
HTMLDivElement,