From 4c663b9a32491c91e2ad6da6ef0a4c35b86d9631 Mon Sep 17 00:00:00 2001 From: Sagar Gupta Date: Thu, 9 Jul 2026 17:41:20 +0530 Subject: [PATCH] fix(vue): support kebab-case icon-node prop on Icon component (#4512) * fix(vue): support kebab-case icon-node prop on Icon component The Icon component destructured `iconNode` camelCase-only while `stroke-width`/`absolute-stroke-width` accept both cases, so the idiomatic Vue usage `` left iconNode undefined and crashed with 'Cannot read properties of undefined (reading map)' (#3485). Accept the kebab-case alias and guard the render path. Closes #3485 * Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * chore(vue): apply prettier formatting to Icon.ts --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Co-authored-by: Eric Fennis --- packages/vue/src/Icon.ts | 14 +++++++++----- packages/vue/tests/Icon.spec.ts | 12 ++++++++++++ 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/packages/vue/src/Icon.ts b/packages/vue/src/Icon.ts index 75d85aee4..8d4254460 100644 --- a/packages/vue/src/Icon.ts +++ b/packages/vue/src/Icon.ts @@ -4,15 +4,16 @@ import defaultAttributes from './defaultAttributes'; import { IconNode, LucideProps } from './types'; import { useLucideProps } from './context'; -interface IconProps { - iconNode: IconNode; - name: string; -} +type IconProps = { name: string } & ( + | { iconNode: IconNode; 'icon-node'?: never } + | { 'icon-node': IconNode; iconNode?: never } +); const Icon: FunctionalComponent = ( { name, iconNode, + 'icon-node': iconNodeKebabCase, absoluteStrokeWidth, 'absolute-stroke-width': absoluteStrokeWidthKebabCase, strokeWidth, @@ -71,7 +72,10 @@ const Icon: FunctionalComponent = ( : ['lucide-icon']), ), }, - [...iconNode.map((child) => h(...child)), ...(slots.default ? [slots.default()] : [])], + [ + ...(iconNode ?? iconNodeKebabCase ?? []).map((child) => h(...child)), + ...(slots.default ? [slots.default()] : []), + ], ); }; diff --git a/packages/vue/tests/Icon.spec.ts b/packages/vue/tests/Icon.spec.ts index 968a36d05..d8ec174a8 100644 --- a/packages/vue/tests/Icon.spec.ts +++ b/packages/vue/tests/Icon.spec.ts @@ -19,6 +19,18 @@ describe('Using Icon Component', () => { expect(container.firstChild).toBeDefined(); }); + it('should render when iconNode is passed as the kebab-case icon-node prop', async () => { + const { container } = render(Icon, { + props: { + 'icon-node': airVent, + name: 'AirVent', + }, + }); + + expect(container.firstChild).toBeDefined(); + expect(container.querySelector('svg')).toBeTruthy(); + }); + it('should render icon and match snapshot', async () => { const { container } = render(Icon, { props: {