diff --git a/docs/app/components/content/examples/icon/IconSvgExample.vue b/docs/app/components/content/examples/icon/IconSvgExample.vue
new file mode 100644
index 0000000000..64820133ca
--- /dev/null
+++ b/docs/app/components/content/examples/icon/IconSvgExample.vue
@@ -0,0 +1,25 @@
+
+
+
+
+
diff --git a/docs/content/docs/2.components/icon.md b/docs/content/docs/2.components/icon.md
index a3b174febd..1c6923b602 100644
--- a/docs/content/docs/2.components/icon.md
+++ b/docs/content/docs/2.components/icon.md
@@ -1,5 +1,5 @@
---
-description: A component to display any icon from Iconify.
+description: A component to display any icon from Iconify or another component.
category: element
links:
- label: IcĂ´nes
@@ -27,6 +27,30 @@ It's highly recommended to install the icons collections you need, read more abo
:::
::
+## Examples
+
+### SVG
+
+You can also pass a Vue component into the `name` prop:
+
+::component-example
+---
+name: 'icon-svg-example'
+---
+::
+
+You can define your icon components yourself, or use [`unplugin-icons`](https://github.com/unplugin/unplugin-icons) to import them directly from SVG files:
+
+```vue
+
+
+
+
+
+```
+
## API
### Props
diff --git a/src/runtime/components/Accordion.vue b/src/runtime/components/Accordion.vue
index 52af6f112b..da99b2271d 100644
--- a/src/runtime/components/Accordion.vue
+++ b/src/runtime/components/Accordion.vue
@@ -3,6 +3,7 @@
import type { AccordionRootProps, AccordionRootEmits } from 'reka-ui'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/ui/accordion'
+import type { IconProps } from '../types'
import type { DynamicSlots } from '../types/utils'
import type { ComponentConfig } from '../types/tv'
@@ -13,11 +14,11 @@ export interface AccordionItem {
/**
* @IconifyIcon
*/
- icon?: string
+ icon?: IconProps['name']
/**
* @IconifyIcon
*/
- trailingIcon?: string
+ trailingIcon?: IconProps['name']
slot?: string
content?: string
/** A unique value for the accordion item. Defaults to the index. */
@@ -40,7 +41,7 @@ export interface AccordionProps extends
* @defaultValue appConfig.ui.icons.chevronDown
* @IconifyIcon
*/
- trailingIcon?: string
+ trailingIcon?: IconProps['name']
/**
* The key used to get the label from the item.
* @defaultValue 'label'
diff --git a/src/runtime/components/Alert.vue b/src/runtime/components/Alert.vue
index d2366dafad..1d9ab5c5c1 100644
--- a/src/runtime/components/Alert.vue
+++ b/src/runtime/components/Alert.vue
@@ -1,7 +1,7 @@
-
+
+
diff --git a/src/runtime/components/InputMenu.vue b/src/runtime/components/InputMenu.vue
index 18b93353e2..1a1128a8b6 100644
--- a/src/runtime/components/InputMenu.vue
+++ b/src/runtime/components/InputMenu.vue
@@ -4,7 +4,7 @@ import type { ComboboxRootProps, ComboboxRootEmits, ComboboxContentProps, Combob
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/ui/input-menu'
import type { UseComponentIconsProps } from '../composables/useComponentIcons'
-import type { AvatarProps, ChipProps, InputProps } from '../types'
+import type { AvatarProps, ChipProps, IconProps, InputProps } from '../types'
import type { AcceptableValue, ArrayOrNested, GetItemKeys, GetItemValue, GetModelValue, GetModelValueEmits, NestedItem, EmitsToProps } from '../types/utils'
import type { ComponentConfig } from '../types/tv'
@@ -15,7 +15,7 @@ interface _InputMenuItem {
/**
* @IconifyIcon
*/
- icon?: string
+ icon?: IconProps['name']
avatar?: AvatarProps
chip?: ChipProps
/**
@@ -61,20 +61,20 @@ export interface InputMenuProps = ArrayOr
* @defaultValue appConfig.ui.icons.chevronDown
* @IconifyIcon
*/
- trailingIcon?: string
+ trailingIcon?: IconProps['name']
/**
* The icon displayed when an item is selected.
* @defaultValue appConfig.ui.icons.check
* @IconifyIcon
*/
- selectedIcon?: string
+ selectedIcon?: IconProps['name']
/**
* The icon displayed to delete a tag.
* Works only when `multiple` is `true`.
* @defaultValue appConfig.ui.icons.close
* @IconifyIcon
*/
- deleteIcon?: string
+ deleteIcon?: IconProps['name']
/**
* The content of the menu.
* @defaultValue { side: 'bottom', sideOffset: 8, collisionPadding: 8, position: 'popper' }
diff --git a/src/runtime/components/InputNumber.vue b/src/runtime/components/InputNumber.vue
index 4400c4c108..a387d0fa08 100644
--- a/src/runtime/components/InputNumber.vue
+++ b/src/runtime/components/InputNumber.vue
@@ -2,7 +2,7 @@
import type { NumberFieldRootProps } from 'reka-ui'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/ui/input-number'
-import type { ButtonProps } from '../types'
+import type { ButtonProps, IconProps } from '../types'
import type { ComponentConfig } from '../types/tv'
type InputNumber = ComponentConfig
@@ -35,7 +35,7 @@ export interface InputNumberProps extends Pick
@@ -39,7 +39,7 @@ export interface InputTagsProps extends P
* @defaultValue appConfig.ui.icons.close
* @IconifyIcon
*/
- deleteIcon?: string
+ deleteIcon?: IconProps['name']
/** Highlight the ring color like a focus state. */
highlight?: boolean
class?: any
diff --git a/src/runtime/components/Modal.vue b/src/runtime/components/Modal.vue
index 7e1c11de18..0bc75a7010 100644
--- a/src/runtime/components/Modal.vue
+++ b/src/runtime/components/Modal.vue
@@ -2,7 +2,7 @@
import type { DialogRootProps, DialogRootEmits, DialogContentProps, DialogContentEmits } from 'reka-ui'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/ui/modal'
-import type { ButtonProps } from '../types'
+import type { ButtonProps, IconProps } from '../types'
import type { EmitsToProps } from '../types/utils'
import type { ComponentConfig } from '../types/tv'
@@ -44,7 +44,7 @@ export interface ModalProps extends DialogRootProps {
* @defaultValue appConfig.ui.icons.close
* @IconifyIcon
*/
- closeIcon?: string
+ closeIcon?: IconProps['name']
/**
* When `false`, the modal will not close when clicking outside or pressing escape.
* @defaultValue true
diff --git a/src/runtime/components/NavigationMenu.vue b/src/runtime/components/NavigationMenu.vue
index 68af27ba04..bd4e47aff0 100644
--- a/src/runtime/components/NavigationMenu.vue
+++ b/src/runtime/components/NavigationMenu.vue
@@ -3,7 +3,7 @@
import type { NavigationMenuRootProps, NavigationMenuRootEmits, NavigationMenuContentProps, NavigationMenuContentEmits, AccordionRootProps } from 'reka-ui'
import type { AppConfig } from '@nuxt/schema'
import theme from '#build/ui/navigation-menu'
-import type { AvatarProps, BadgeProps, LinkProps, PopoverProps, TooltipProps } from '../types'
+import type { AvatarProps, BadgeProps, IconProps, LinkProps, PopoverProps, TooltipProps } from '../types'
import type { ArrayOrNested, DynamicSlots, MergeTypes, NestedItem, EmitsToProps } from '../types/utils'
import type { ComponentConfig } from '../types/tv'
@@ -20,7 +20,7 @@ export interface NavigationMenuItem extends Omit
* @defaultValue appConfig.ui.icons.chevronDown
* @IconifyIcon
*/
- trailingIcon?: string
+ trailingIcon?: IconProps['name']
/**
* The icon displayed when the item is an external link.
* Set to `false` to hide the external icon.
* @defaultValue appConfig.ui.icons.external
* @IconifyIcon
*/
- externalIcon?: boolean | string
+ externalIcon?: boolean | IconProps['name']
items?: T
/**
* @defaultValue 'primary'
diff --git a/src/runtime/components/PageAnchors.vue b/src/runtime/components/PageAnchors.vue
index 7f0aecc9e0..719d431089 100644
--- a/src/runtime/components/PageAnchors.vue
+++ b/src/runtime/components/PageAnchors.vue
@@ -1,7 +1,7 @@
diff --git a/src/runtime/components/prose/Collapsible.vue b/src/runtime/components/prose/Collapsible.vue
index f14c0f2526..df87bc4ef6 100644
--- a/src/runtime/components/prose/Collapsible.vue
+++ b/src/runtime/components/prose/Collapsible.vue
@@ -1,6 +1,7 @@
@@ -11,5 +13,6 @@ defineProps()
-
+
+