From 652969392e79f16bf36d4a82302be3b5e1046137 Mon Sep 17 00:00:00 2001 From: Sarvar Kumar Date: Fri, 8 Aug 2025 12:24:58 +0530 Subject: [PATCH 1/4] add accessibility props to the icon interface --- index.d.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/index.d.ts b/index.d.ts index 5ac0d4a..cdab9af 100644 --- a/index.d.ts +++ b/index.d.ts @@ -1,4 +1,4 @@ -import { StyleProp, ViewStyle } from "react-native"; +import { StyleProp, ViewStyle, AccessibilityRole } from "react-native"; import { Transform, IconProp } from "@fortawesome/fontawesome-svg-core"; export type FontAwesomeIconStyle = StyleProp & { @@ -24,6 +24,9 @@ export interface Props { transform?: string | Transform; style?: FontAwesomeIconStyle; testID?: string; + accessible?: boolean; + accessibilityRole?: AccessibilityRole; + accessibilityLabel?: string; } export function FontAwesomeIcon(props: Props): JSX.Element; From 94fa5dc85fe1c11b052f5fa515ad9ac6818a3280 Mon Sep 17 00:00:00 2001 From: Sarvar Kumar Date: Fri, 8 Aug 2025 13:01:28 +0530 Subject: [PATCH 2/4] update icon to add accessibility props --- src/components/FontAwesomeIcon.js | 23 ++++++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/components/FontAwesomeIcon.js b/src/components/FontAwesomeIcon.js index 876839e..05d9c32 100644 --- a/src/components/FontAwesomeIcon.js +++ b/src/components/FontAwesomeIcon.js @@ -107,6 +107,21 @@ export default function FontAwesomeIcon (props) { rootAttributes.width = resolvedWidth rootAttributes.style = modifiedStyle + // Add accessibility properties to the root SVG element + // atleast accessibilityLabel prop should be passed to make the icon accessible + if (_props.accessibilityLabel && _props.accessible !== false) { + rootAttributes.accessible = true + rootAttributes.accessibilityLabel = _props.accessibilityLabel + + if (_props.accessibilityRole) { + rootAttributes.accessibilityRole = _props.accessibilityRole + } else { + // If accessibilityLabel is set, we default to 'image' role if not already set + // This is to ensure that screen readers can announce the icon correctly + rootAttributes.accessibilityRole = 'image' + } + } + replaceCurrentColor(abstract[0], color, secondaryColor, secondaryOpacity) return convertCurry(abstract[0]) @@ -147,7 +162,13 @@ FontAwesomeIcon.propTypes = { maskId: PropTypes.string, - transform: PropTypes.oneOfType([PropTypes.string, PropTypes.object]) + transform: PropTypes.oneOfType([PropTypes.string, PropTypes.object]), + + accessible: PropTypes.bool, + + accessibilityRole: PropTypes.string, + + accessibilityLabel: PropTypes.string } const convertCurry = convert.bind(null, React.createElement) From 7658949f2e1683219dca531b1dbd97363df2c81b Mon Sep 17 00:00:00 2001 From: Sarvar Kumar Date: Fri, 8 Aug 2025 13:01:44 +0530 Subject: [PATCH 3/4] add tests --- .../__tests__/FontAwesomeIcon.test.js | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/components/__tests__/FontAwesomeIcon.test.js b/src/components/__tests__/FontAwesomeIcon.test.js index 6482d5e..4ffd23f 100644 --- a/src/components/__tests__/FontAwesomeIcon.test.js +++ b/src/components/__tests__/FontAwesomeIcon.test.js @@ -279,6 +279,64 @@ describe('when extra props are given', () => { }) }) +describe('when accessibility props are given', () => { + test('accessibility is automatically enabled when accessibilityLabel is provided', () => { + const tree = renderer.create().toJSON() + + expect(tree.props).toHaveProperty('accessible', true) + expect(tree.props).toHaveProperty('accessibilityLabel', 'Coffee icon') + expect(tree.props).toHaveProperty('accessibilityRole', 'image') // defaults to 'image' + }) + + test('custom accessibilityRole is applied when provided with accessibilityLabel', () => { + const tree = renderer.create().toJSON() + + expect(tree.props).toHaveProperty('accessible', true) + expect(tree.props).toHaveProperty('accessibilityLabel', 'Coffee icon') + expect(tree.props).toHaveProperty('accessibilityRole', 'button') + }) + + test('no accessibility props when accessibilityLabel is not provided', () => { + const tree = renderer.create().toJSON() + + expect(tree.props).not.toHaveProperty('accessible') + expect(tree.props).not.toHaveProperty('accessibilityLabel') + expect(tree.props).not.toHaveProperty('accessibilityRole') + }) + + test('accessibility is disabled when accessible is explicitly set to false', () => { + const tree = renderer.create().toJSON() + + expect(tree.props).not.toHaveProperty('accessible') + expect(tree.props).not.toHaveProperty('accessibilityLabel') + expect(tree.props).not.toHaveProperty('accessibilityRole') + }) + + test('accessibility works when explicitly enabled with accessible=true', () => { + const tree = renderer.create().toJSON() + + expect(tree.props).toHaveProperty('accessible', true) + expect(tree.props).toHaveProperty('accessibilityLabel', 'Coffee icon') + expect(tree.props).toHaveProperty('accessibilityRole', 'image') + }) + + test('accessibilityRole only applied when accessibilityLabel is provided', () => { + const tree = renderer.create().toJSON() + + expect(tree.props).not.toHaveProperty('accessible') + expect(tree.props).not.toHaveProperty('accessibilityLabel') + expect(tree.props).not.toHaveProperty('accessibilityRole') + }) + + test('accessibility defaults to image role when only accessibilityLabel is provided', () => { + const tree = renderer.create().toJSON() + + expect(tree.props).toHaveProperty('accessible', true) + expect(tree.props).toHaveProperty('accessibilityLabel', 'Coffee icon') + expect(tree.props).toHaveProperty('accessibilityRole', 'image') + }) +}) + describe('focusable attribute', () => { test('is never used to render elements', () => { renderer.create().toJSON() From b388367585e407258dd9036026eaa5d15604b91e Mon Sep 17 00:00:00 2001 From: Sarvar Kumar Date: Fri, 8 Aug 2025 13:47:56 +0530 Subject: [PATCH 4/4] pass accessibility props to svg root element --- src/converter.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/converter.js b/src/converter.js index bc24866..40a628b 100644 --- a/src/converter.js +++ b/src/converter.js @@ -27,13 +27,18 @@ function convert (createElement, element) { const val = element.attributes[key] switch (key) { case 'class': - case 'role': case 'xmlns': delete element.attributes[key] break case 'focusable': acc.attrs[key] = val === 'true' break + case 'role': + case 'accessible': + case 'accessibilityRole': + case 'accessibilityLabel': + acc.attrs[key] = val + break default: if (key.indexOf('aria-') === 0 || key.indexOf('data-') === 0 || (key === 'fill' && val === 'currentColor')) { delete element.attributes[key]