diff --git a/.gitignore b/.gitignore
index 41a9f0839..a4016ec89 100644
--- a/.gitignore
+++ b/.gitignore
@@ -20,6 +20,8 @@ packages/**/src/icons/*.tsx
packages/**/src/aliases/*.ts
packages/**/src/aliases.ts
!packages/**/src/aliases/index.ts
+packages/**/src/utils/*.ts
+!packages/shared/src/utils/*.ts
packages/**/src/dynamicIconImports.ts
packages/**/DynamicIcon.d.ts
packages/**/dynamicIconImports.js
diff --git a/docs/guide/advanced/accessibility.md b/docs/guide/advanced/accessibility.md
index 131928c2a..b868a9d63 100644
--- a/docs/guide/advanced/accessibility.md
+++ b/docs/guide/advanced/accessibility.md
@@ -10,6 +10,11 @@ because they can quickly give information.
However, not everyone can understand them easily. When using icons it is very important to consider
the following aspects of accessibility.
+::: info
+By default, we hide icons from screen readers using `aria-hidden="true"`.
+You can make them accessible yourself by following the guidelines below.
+:::
+
## Provide visible labels
Icons are a helpful tool to improve perception, but they aren't a replacement for text.
diff --git a/docs/guide/packages/lucide-angular.md b/docs/guide/packages/lucide-angular.md
index 737ccc01f..240f75472 100644
--- a/docs/guide/packages/lucide-angular.md
+++ b/docs/guide/packages/lucide-angular.md
@@ -167,3 +167,15 @@ import { coconut } from '@lucide/lab';
})
export class AppModule { }
```
+
+## Accessibility
+
+By default, we hide icons from screen readers using `aria-hidden="true"`.
+
+You can add accessibility attributes using aria-labels.
+
+```html
+
+```
+
+For best practices on accessibility, please see our [accessibility guide](../advanced/accessibility.md).
diff --git a/docs/guide/packages/lucide-astro.md b/docs/guide/packages/lucide-astro.md
index 0ae1525d4..937da2918 100644
--- a/docs/guide/packages/lucide-astro.md
+++ b/docs/guide/packages/lucide-astro.md
@@ -192,3 +192,19 @@ import LucideIcon from './LucideIcon.astro';
```
+
+## Accessibility
+
+By default, we hide icons from screen readers using `aria-hidden="true"`.
+
+You can add accessibility attributes using aria-labels.
+
+```jsx
+---
+import { Check } from '@lucide/astro';
+---
+
+
+```
+
+For best practices on accessibility, please see our [accessibility guide](../advanced/accessibility.md).
diff --git a/docs/guide/packages/lucide-preact.md b/docs/guide/packages/lucide-preact.md
index 817acbdf1..4585af11f 100644
--- a/docs/guide/packages/lucide-preact.md
+++ b/docs/guide/packages/lucide-preact.md
@@ -131,3 +131,19 @@ const App = () => {
export default App;
```
+
+## Accessibility
+
+By default, we hide icons from screen readers using `aria-hidden="true"`.
+
+You can add accessibility attributes using aria-labels.
+
+```jsx
+import { Check } from 'lucide-preact';
+
+const App = () => {
+ return ;
+};
+```
+
+For best practices on accessibility, please see our [accessibility guide](../advanced/accessibility.md).
diff --git a/docs/guide/packages/lucide-react.md b/docs/guide/packages/lucide-react.md
index ac34ba186..79e9dcb4c 100644
--- a/docs/guide/packages/lucide-react.md
+++ b/docs/guide/packages/lucide-react.md
@@ -109,3 +109,19 @@ const App = () => (
);
```
+
+## Accessibility
+
+By default, we hide icons from screen readers using `aria-hidden="true"`.
+
+You can add accessibility attributes using aria-labels.
+
+```jsx
+import { Check } from 'lucide-react';
+
+const App = () => {
+ return ;
+};
+```
+
+For best practices on accessibility, please see our [accessibility guide](../advanced/accessibility.md).
diff --git a/docs/guide/packages/lucide-solid.md b/docs/guide/packages/lucide-solid.md
index 5f76d4fc3..57641c287 100644
--- a/docs/guide/packages/lucide-solid.md
+++ b/docs/guide/packages/lucide-solid.md
@@ -144,3 +144,19 @@ const App = () => {
export default App;
```
+
+## Accessibility
+
+By default, we hide icons from screen readers using `aria-hidden="true"`.
+
+You can add accessibility attributes using aria-labels.
+
+```jsx
+import { Check } from 'lucide-solid';
+
+const App = () => {
+ return ;
+};
+```
+
+For best practices on accessibility, please see our [accessibility guide](../advanced/accessibility.md).
diff --git a/docs/guide/packages/lucide-svelte.md b/docs/guide/packages/lucide-svelte.md
index eebe1ebac..e3ba6d25d 100644
--- a/docs/guide/packages/lucide-svelte.md
+++ b/docs/guide/packages/lucide-svelte.md
@@ -331,3 +331,19 @@ The example below imports all ES Modules, so exercise caution when using it. Imp
```
+
+## Accessibility
+
+By default, we hide icons from screen readers using `aria-hidden="true"`.
+
+You can add accessibility attributes using aria-labels.
+
+```svelte
+
+
+
+```
+
+For best practices on accessibility, please see our [accessibility guide](../advanced/accessibility.md).
diff --git a/docs/guide/packages/lucide-vue-next.md b/docs/guide/packages/lucide-vue-next.md
index 3c4c09ae2..fffd005f9 100644
--- a/docs/guide/packages/lucide-vue-next.md
+++ b/docs/guide/packages/lucide-vue-next.md
@@ -146,3 +146,25 @@ All other props listed above also work on the `Icon` Component.
```
+
+## Accessibility
+
+By default, we hide icons from screen readers using `aria-hidden="true"`.
+
+You can add accessibility attributes using aria-labels.
+
+```vue
+
+
+
+
+
+```
+
+For best practices on accessibility, please see our [accessibility guide](../advanced/accessibility.md).
diff --git a/docs/guide/packages/lucide.md b/docs/guide/packages/lucide.md
index 5125865e2..6b1a62b62 100644
--- a/docs/guide/packages/lucide.md
+++ b/docs/guide/packages/lucide.md
@@ -203,3 +203,23 @@ createIcons({
}
});
```
+
+## Accessibility
+
+By default, we hide icons from screen readers using `aria-hidden="true"`.
+
+You can add accessibility attributes using aria-labels.
+
+```html
+
+
+
+
+
+
+
+```
+
+For best practices on accessibility, please see our [accessibility guide](../advanced/accessibility.md).
diff --git a/packages/astro/package.json b/packages/astro/package.json
index b5f1e36cb..4bb49e7c8 100644
--- a/packages/astro/package.json
+++ b/packages/astro/package.json
@@ -39,18 +39,20 @@
}
},
"scripts": {
- "build": "pnpm clean && pnpm copy:license && pnpm build:icons",
+ "build": "pnpm clean && pnpm copy:license && pnpm copy:utils && pnpm build:icons",
"build:icons": "build-icons --output=./src --templateSrc=./scripts/exportTemplate.mts --renderUniqueKey --withAliases --aliasesFileExtension=.ts --iconFileExtension=.ts --exportFileName=index.ts --pretty=false",
"clean": "rm -rf dist && rm -rf stats && rm -rf ./src/icons/*.ts",
"copy:license": "cp ../../LICENSE ./LICENSE",
- "test": "pnpm build:icons && vitest run",
+ "copy:utils": "mkdir -p ./src/utils && for f in hasA11yProp toKebabCase mergeClasses; do cp -f ../../packages/shared/src/utils/$f.ts ./src/utils/; done",
+ "test": "pnpm copy:utils && pnpm build:icons && vitest run",
+ "test:watch": "pnpm build:icons && vitest run --watch",
"version": "pnpm version --git-tag-version=false"
},
"devDependencies": {
"@astrojs/ts-plugin": "^1.10.4",
"@lucide/build-icons": "workspace:*",
"@testing-library/dom": "^10.4.0",
- "@testing-library/jest-dom": "^6.6.3",
+ "@testing-library/jest-dom": "^6.8.0",
"jest-serializer-html": "^7.1.0",
"linkedom": "^0.18.5",
"prettier": "^3.4.2",
diff --git a/packages/astro/src/Icon.astro b/packages/astro/src/Icon.astro
index 415395730..eb504dbad 100644
--- a/packages/astro/src/Icon.astro
+++ b/packages/astro/src/Icon.astro
@@ -1,6 +1,8 @@
---
import defaultAttributes from './defaultAttributes';
import type { IconProps as Props } from './types';
+import { hasA11yProp } from './utils/hasA11yProp';
+
const {
color = 'currentColor',
@@ -20,6 +22,7 @@ const {
height: size,
stroke: color,
'stroke-width': absoluteStrokeWidth ? (Number(strokeWidth) * 24) / Number(size) : strokeWidth,
+ ...(!hasA11yProp(rest) && { 'aria-hidden': 'true' }),
...rest,
}}
class:list={['lucide', className]}
diff --git a/packages/astro/src/createLucideIcon.ts b/packages/astro/src/createLucideIcon.ts
index ab6b0fd50..7ff99d5ec 100644
--- a/packages/astro/src/createLucideIcon.ts
+++ b/packages/astro/src/createLucideIcon.ts
@@ -1,8 +1,9 @@
-import { mergeClasses, toKebabCase } from './utils';
import type { AstroComponentFactory } from 'astro/runtime/server/render/astro/factory.js';
import type { IconNode } from './types';
import { render, renderSlot, createComponent, renderComponent } from 'astro/compiler-runtime';
import Icon from './Icon.astro';
+import { mergeClasses } from './utils/mergeClasses';
+import { toKebabCase } from './utils/toKebabCase';
export default (iconName: string, iconNode: IconNode): AstroComponentFactory => {
const Component = createComponent(
diff --git a/packages/astro/src/types.ts b/packages/astro/src/types.ts
index 805ababc7..71f1d527f 100644
--- a/packages/astro/src/types.ts
+++ b/packages/astro/src/types.ts
@@ -10,6 +10,7 @@ export interface IconProps extends SVGAttributes {
absoluteStrokeWidth?: boolean;
class?: string;
iconNode?: IconNode;
+ title?: string;
}
export type SVGAttributes = HTMLAttributes<'svg'>;
diff --git a/packages/astro/tests/Icon.spec.ts b/packages/astro/tests/Icon.spec.ts
index e1d125a08..af2ce9ebb 100644
--- a/packages/astro/tests/Icon.spec.ts
+++ b/packages/astro/tests/Icon.spec.ts
@@ -1,7 +1,7 @@
import { describe, it, expect } from 'vitest';
import { airVent } from './testIconNodes';
-import { render } from './utils';
-import { Icon } from '../src/lucide-astro';
+import { createAstroHTMLString, render } from './utils';
+import { Icon, Rocket } from '../src/lucide-astro';
describe('Using Icon Component', async () => {
const { container } = await render(Icon, {
@@ -16,3 +16,44 @@ describe('Using Icon Component', async () => {
expect(container.innerHTML).toBeDefined();
});
});
+
+describe('Icon Component Accessibility', () => {
+ it('should have aria-hidden prop when no aria prop is present', async () => {
+ const { container } = await render(Icon, {
+ props: {
+ iconNode: airVent,
+ size: 48,
+ stroke: 'red',
+ absoluteStrokeWidth: true,
+ },
+ });
+
+ expect(container.firstChild).toHaveAttribute('aria-hidden', 'true');
+ });
+
+ it('should not have aria-hidden prop when aria prop is present', async () => {
+ const { container } = await render(Rocket, {
+ props: {
+ size: 48,
+ stroke: 'red',
+ absoluteStrokeWidth: true,
+ 'aria-label': 'Release icon',
+ },
+ });
+
+ expect(container.firstChild).not.toHaveAttribute('aria-hidden');
+ });
+
+ it('should not have aria-hidden prop when title prop is present', async () => {
+ const { container } = await render(Rocket, {
+ props: {
+ size: 48,
+ stroke: 'red',
+ absoluteStrokeWidth: true,
+ title: 'Release icon',
+ },
+ });
+
+ expect(container.firstChild).not.toHaveAttribute('aria-hidden');
+ });
+});
diff --git a/packages/astro/tests/__snapshots__/Icon.spec.ts.snap b/packages/astro/tests/__snapshots__/Icon.spec.ts.snap
index f96b087eb..a550ccb86 100644
--- a/packages/astro/tests/__snapshots__/Icon.spec.ts.snap
+++ b/packages/astro/tests/__snapshots__/Icon.spec.ts.snap
@@ -10,6 +10,7 @@ exports[`Using Icon Component > should render icon and match snapshot 1`] = `
stroke-width="1"
stroke-linecap="round"
stroke-linejoin="round"
+ aria-hidden="true"
class="lucide"
>
diff --git a/packages/astro/tests/__snapshots__/createLucideIcon.spec.ts.snap b/packages/astro/tests/__snapshots__/createLucideIcon.spec.ts.snap
index 7c01619e8..13a285420 100644
--- a/packages/astro/tests/__snapshots__/createLucideIcon.spec.ts.snap
+++ b/packages/astro/tests/__snapshots__/createLucideIcon.spec.ts.snap
@@ -10,6 +10,7 @@ exports[`Using createLucideIcon > should create a component from an iconNode 1`]
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
+ aria-hidden="true"
class="lucide lucide-air-vent"
>
diff --git a/packages/astro/tests/__snapshots__/lucide-astro.spec.ts.snap b/packages/astro/tests/__snapshots__/lucide-astro.spec.ts.snap
index fcf978635..a6ff7f2e4 100644
--- a/packages/astro/tests/__snapshots__/lucide-astro.spec.ts.snap
+++ b/packages/astro/tests/__snapshots__/lucide-astro.spec.ts.snap
@@ -10,6 +10,7 @@ exports[`Using lucide icon components > should add a non-default attribute to th
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
+ aria-hidden="true"
style="position: absolute"
class="lucide lucide-smile"
>
@@ -45,6 +46,7 @@ exports[`Using lucide icon components > should adjust the size, stroke color and
stroke-width="4"
stroke-linecap="round"
stroke-linejoin="round"
+ aria-hidden="true"
class="lucide lucide-grid-3x3"
>
should apply all classes to the element
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
+ aria-hidden="true"
class="lucide lucide-droplet my-icon"
>
@@ -92,6 +95,7 @@ exports[`Using lucide icon components > should not scale the strokeWidth when ab
stroke-width="1"
stroke-linecap="round"
stroke-linejoin="round"
+ aria-hidden="true"
class="lucide lucide-grid-3x3"
>
should pass children to the icon slot 1`
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
+ aria-hidden="true"
class="lucide lucide-smile"
>
should render a component 1`] = `
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
+ aria-hidden="true"
class="lucide lucide-grid-3x3"
>
should render the icon with default attr
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
+ aria-hidden="true"
class="lucide lucide-grid-3x3"
>
{
let testHostComponent: TestHostComponent;
let testHostFixture: ComponentFixture;
- const getSvgAttribute = (attr: string) =>
+ const getAttribute = (attr: string) =>
testHostFixture.nativeElement.querySelector('svg').getAttribute(attr);
+ const getRootAttribute = (attr: string) =>
+ testHostFixture.nativeElement.querySelector('i-lucide').getAttribute(attr);
const testIcons: LucideIcons = {
Demo: [['polyline', { points: '1 1 22 22' }]],
};
@@ -31,28 +33,28 @@ describe('LucideAngularComponent', () => {
it('should add all classes', () => {
testHostFixture.detectChanges();
- expect(getSvgAttribute('class')).toBe('lucide lucide-demo my-icon');
+ expect(getAttribute('class')).toBe('lucide lucide-demo my-icon');
});
it('should set color', () => {
const color = 'red';
testHostComponent.setColor(color);
testHostFixture.detectChanges();
- expect(getSvgAttribute('stroke')).toBe(color);
+ expect(getAttribute('stroke')).toBe(color);
});
it('should set size', () => {
const size = 12;
testHostComponent.setSize(size);
testHostFixture.detectChanges();
- expect(getSvgAttribute('width')).toBe(size.toString(10));
+ expect(getAttribute('width')).toBe(size.toString(10));
});
it('should set stroke width', () => {
const strokeWidth = 1.41;
testHostComponent.setStrokeWidth(strokeWidth);
testHostFixture.detectChanges();
- expect(getSvgAttribute('stroke-width')).toBe(strokeWidth.toString(10));
+ expect(getAttribute('stroke-width')).toBe(strokeWidth.toString(10));
});
it('should adjust stroke width', () => {
@@ -62,27 +64,61 @@ describe('LucideAngularComponent', () => {
testHostComponent.setSize(12);
testHostComponent.setAbsoluteStrokeWidth(true);
testHostFixture.detectChanges();
- expect(getSvgAttribute('stroke-width')).toBe(
+ expect(getAttribute('stroke-width')).toBe(
formatFixed(strokeWidth / (size / defaultAttributes.height)),
);
});
+ it('should have aria-hidden prop when no aria prop is present', async () => {
+ testHostFixture.detectChanges();
+ expect(getRootAttribute('aria-hidden')).toBe('true');
+ });
+
+ it('should not have aria-hidden prop when aria prop is present', async () => {
+ const ariaLabel = 'Demo icon';
+ testHostComponent.setAriaLabel(ariaLabel);
+ testHostFixture.detectChanges();
+ expect(getRootAttribute('aria-label')).toBe(ariaLabel);
+ expect(getRootAttribute('aria-hidden')).toBeNull();
+ });
+
+ it('should not have aria-hidden prop when title prop is present', async () => {
+ const ariaLabel = 'Demo icon';
+ testHostComponent.setTitle(ariaLabel);
+ testHostFixture.detectChanges();
+ expect(getRootAttribute('title')).toBe(ariaLabel);
+ expect(getRootAttribute('aria-hidden')).toBeNull();
+ });
+
+ it('should never override aria-hidden prop', async () => {
+ testHostComponent.setAriaHidden(true);
+ testHostFixture.detectChanges();
+ expect(getRootAttribute('aria-hidden')).toBe('true');
+ });
+
@Component({
selector: 'lucide-spec-host-component',
- template: ` `,
+ [attr.aria-label]="ariaLabel"
+ [attr.title]="title"
+ [attr.aria-hidden]="ariaHidden"
+ >
+ `,
})
class TestHostComponent {
color?: string;
size?: number;
strokeWidth?: number;
absoluteStrokeWidth = true;
+ ariaLabel?: string = undefined;
+ title?: string = undefined;
+ ariaHidden?: boolean = undefined;
setColor(color: string): void {
this.color = color;
@@ -99,5 +135,17 @@ describe('LucideAngularComponent', () => {
setAbsoluteStrokeWidth(absoluteStrokeWidth: boolean): void {
this.absoluteStrokeWidth = absoluteStrokeWidth;
}
+
+ setAriaLabel(label: string): void {
+ this.ariaLabel = label;
+ }
+
+ setTitle(title: string): void {
+ this.title = title;
+ }
+
+ setAriaHidden(ariaHidden: boolean): void {
+ this.ariaHidden = ariaHidden;
+ }
}
});
diff --git a/packages/lucide-angular/src/lib/lucide-angular.component.ts b/packages/lucide-angular/src/lib/lucide-angular.component.ts
index 931239cba..42952cea0 100644
--- a/packages/lucide-angular/src/lib/lucide-angular.component.ts
+++ b/packages/lucide-angular/src/lib/lucide-angular.component.ts
@@ -12,6 +12,7 @@ import { LucideIconData } from '../icons/types';
import defaultAttributes from '../icons/constants/default-attributes';
import { LUCIDE_ICONS, LucideIconProviderInterface } from './lucide-icon.provider';
import { LucideIconConfig } from './lucide-icon.config';
+import { hasA11yProp } from '../utils/hasA11yProp';
interface TypedChange extends SimpleChange {
previousValue: T;
@@ -99,6 +100,12 @@ export class LucideAngularComponent implements OnChanges {
this.strokeWidth = this.parseNumber(this.strokeWidth ?? this.iconConfig.strokeWidth);
this.absoluteStrokeWidth = this.absoluteStrokeWidth ?? this.iconConfig.absoluteStrokeWidth;
const nameOrIcon = this.img ?? this.name;
+ const restAttributes = this.getRestAttributes();
+
+ if (!hasA11yProp(restAttributes)) {
+ this.renderer.setAttribute(this.elem.nativeElement, 'aria-hidden', 'true');
+ }
+
if (typeof nameOrIcon === 'string') {
const icoOfName = this.getIcon(this.toPascalCase(nameOrIcon));
if (icoOfName) {
@@ -119,6 +126,8 @@ export class LucideAngularComponent implements OnChanges {
}
replaceElement(img: LucideIconData): void {
+ const childElements = this.elem.nativeElement.childNodes;
+
const attributes = {
...defaultAttributes,
width: this.size,
@@ -133,6 +142,7 @@ export class LucideAngularComponent implements OnChanges {
if (typeof this.name === 'string') {
icoElement.classList.add(`lucide-${this.name.replace('_', '-')}`);
}
+
if (this.class) {
icoElement.classList.add(
...this.class
@@ -141,13 +151,21 @@ export class LucideAngularComponent implements OnChanges {
.filter((a) => a.length > 0),
);
}
- const childElements = this.elem.nativeElement.childNodes;
+
for (const child of childElements) {
this.renderer.removeChild(this.elem.nativeElement, child);
}
this.renderer.appendChild(this.elem.nativeElement, icoElement);
}
+ getRestAttributes(): Record {
+ const restAttributeMap: NamedNodeMap = this.elem.nativeElement.attributes;
+ const restAttributes = Object.fromEntries(
+ Array.from(restAttributeMap).map((item) => [item.name, item.value]),
+ );
+ return restAttributes;
+ }
+
toPascalCase(str: string): string {
return str.replace(
/(\w)([a-z0-9]*)(_|-|\s*)/g,
diff --git a/packages/lucide-preact/package.json b/packages/lucide-preact/package.json
index b73f6d6d3..c6ddb6ae4 100644
--- a/packages/lucide-preact/package.json
+++ b/packages/lucide-preact/package.json
@@ -46,7 +46,7 @@
"@lucide/rollup-plugins": "workspace:*",
"@lucide/shared": "workspace:*",
"@preact/preset-vite": "^2.10.2",
- "@testing-library/jest-dom": "^6.1.4",
+ "@testing-library/jest-dom": "^6.8.0",
"@testing-library/preact": "^3.2.3",
"jest-serializer-html": "^7.1.0",
"preact": "^10.27.3",
diff --git a/packages/lucide-preact/src/Icon.ts b/packages/lucide-preact/src/Icon.ts
index bfbda2297..ee654721c 100644
--- a/packages/lucide-preact/src/Icon.ts
+++ b/packages/lucide-preact/src/Icon.ts
@@ -1,6 +1,7 @@
import { h, toChildArray } from 'preact';
import defaultAttributes from './defaultAttributes';
import type { IconNode, LucideProps } from './types';
+import { hasA11yProp } from '@lucide/shared';
interface IconComponentProps extends LucideProps {
iconNode: IconNode;
@@ -42,6 +43,7 @@ const Icon = ({
? (Number(strokeWidth) * 24) / Number(size)
: strokeWidth,
class: ['lucide', classes].join(' '),
+ ...(!children && !hasA11yProp(rest) && { 'aria-hidden': 'true' }),
...rest,
},
[...iconNode.map(([tag, attrs]) => h(tag, attrs)), ...toChildArray(children)],
diff --git a/packages/lucide-preact/tests/Icon.spec.tsx b/packages/lucide-preact/tests/Icon.spec.tsx
index d43760ba9..a78874888 100644
--- a/packages/lucide-preact/tests/Icon.spec.tsx
+++ b/packages/lucide-preact/tests/Icon.spec.tsx
@@ -31,3 +31,62 @@ describe('Using Icon Component', () => {
expect(container.firstChild).toMatchSnapshot();
});
});
+
+describe('Icon Component Accessibility', () => {
+ it('should not have aria-hidden prop when aria prop is present', async () => {
+ const { container } = render(
+ ,
+ );
+
+ expect(container.firstChild).not.toHaveAttribute('aria-hidden');
+ });
+
+ it('should not have aria-hidden prop when title prop is present', async () => {
+ const { container } = render(
+ ,
+ );
+
+ expect(container.firstChild).not.toHaveAttribute('aria-hidden');
+ });
+
+ it('should not have aria-hidden prop when there are children that could be a element', async () => {
+ const { container } = render(
+
+ Some title
+ ,
+ );
+
+ expect(container.firstChild).not.toHaveAttribute('aria-hidden');
+ });
+
+ it('should never override aria-hidden prop', async () => {
+ const { container } = render(
+ ,
+ );
+
+ expect(container.firstChild).toHaveAttribute('aria-hidden', 'false');
+ });
+});
diff --git a/packages/lucide-preact/tests/__snapshots__/Icon.spec.tsx.snap b/packages/lucide-preact/tests/__snapshots__/Icon.spec.tsx.snap
index 2e30bf9a6..0908247fd 100644
--- a/packages/lucide-preact/tests/__snapshots__/Icon.spec.tsx.snap
+++ b/packages/lucide-preact/tests/__snapshots__/Icon.spec.tsx.snap
@@ -2,6 +2,7 @@
exports[`Using Icon Component > should render icon and match snapshot 1`] = `