diff --git a/src/icons/AccessTime/AccessTimeIcon.tsx b/src/icons/AccessTime/AccessTimeIcon.tsx
index 82ce8860f..bbceb3a7d 100644
--- a/src/icons/AccessTime/AccessTimeIcon.tsx
+++ b/src/icons/AccessTime/AccessTimeIcon.tsx
@@ -1,26 +1,8 @@
-import { DEFAULT_FILL_NONE, DEFAULT_HEIGHT, DEFAULT_WIDTH } from '../../constants/constants';
-import { IconProps } from '../types';
+import { createIcon } from '../createIcon';
-export const AccessTimeIcon = ({
- width = DEFAULT_WIDTH,
- height = DEFAULT_HEIGHT,
- fill = DEFAULT_FILL_NONE,
- ...props
-}: IconProps): JSX.Element => {
- return (
-
- );
-};
+export const AccessTimeIcon = createIcon({
+ displayName: 'AccessTimeIcon',
+ d: 'M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2M12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8m.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z'
+});
export default AccessTimeIcon;
diff --git a/src/icons/Add/AddIcon.tsx b/src/icons/Add/AddIcon.tsx
index 563551257..de85f276b 100644
--- a/src/icons/Add/AddIcon.tsx
+++ b/src/icons/Add/AddIcon.tsx
@@ -1,24 +1,11 @@
-import { DEFAULT_FILL_NONE, DEFAULT_HEIGHT, DEFAULT_WIDTH } from '../../constants/constants';
-import { IconProps } from '../types';
+import { createIcon } from '../createIcon';
-export const AddIcon = ({
- width = DEFAULT_WIDTH,
- height = DEFAULT_HEIGHT,
- fill = DEFAULT_FILL_NONE,
- ...props
-}: IconProps): JSX.Element => {
- return (
-
- );
-};
+export const AddIcon = createIcon({
+ displayName: 'AddIcon',
+ d: 'M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z',
+ defaultProps: {
+ 'data-testid': 'add-icon-svg'
+ }
+});
export default AddIcon;
diff --git a/src/icons/createIcon/createIcon.tsx b/src/icons/createIcon/createIcon.tsx
new file mode 100644
index 000000000..65cb7e4a6
--- /dev/null
+++ b/src/icons/createIcon/createIcon.tsx
@@ -0,0 +1,95 @@
+import React from 'react';
+import { DEFAULT_FILL_NONE, DEFAULT_HEIGHT, DEFAULT_WIDTH } from '../../constants/constants';
+import { IconProps } from '../types';
+
+/**
+ * Configuration options for creating an SVG icon component with `createIcon`.
+ */
+export interface CreateIconOptions {
+ /**
+ * The icon SVG viewBox.
+ * @default '0 0 24 24'
+ */
+ viewBox?: string;
+
+ /**
+ * The SVG path or elements to render inside the SVG.
+ */
+ path?: React.ReactNode | ((props: IconProps) => React.ReactNode);
+
+ /**
+ * Shorthand SVG path `d` attribute when providing a single path string.
+ */
+ d?: string;
+
+ /**
+ * The display name of the icon component (for React DevTools and testing).
+ */
+ displayName?: string;
+
+ /**
+ * Default props to override standard defaults (e.g. custom default fill or dimensions).
+ */
+ defaultProps?: Partial & Record;
+}
+
+/**
+ * Factory function to create reusable, consistent SVG icon components.
+ * Standardizes prop handling (width, height, fill, viewBox, title), default values,
+ * and ref forwarding across icons.
+ *
+ * @param options - Configuration options for the icon (viewBox, path, d, displayName, defaultProps).
+ * @returns A React forwardRef component rendering the SVG icon.
+ */
+export function createIcon(options: CreateIconOptions): React.ForwardRefExoticComponent<
+ IconProps & React.RefAttributes
+> {
+ const {
+ viewBox = '0 0 24 24',
+ d: pathDefinition,
+ path: pathElement,
+ displayName,
+ defaultProps = {}
+ } = options;
+
+ const Comp = React.forwardRef((props, ref) => {
+ const mergedProps = { ...defaultProps, ...props };
+ const {
+ width = DEFAULT_WIDTH,
+ height = DEFAULT_HEIGHT,
+ fill = DEFAULT_FILL_NONE,
+ title,
+ ...rest
+ } = mergedProps;
+
+ let content: React.ReactNode = null;
+ if (typeof pathElement === 'function') {
+ content = pathElement(mergedProps);
+ } else if (pathElement) {
+ content = pathElement;
+ } else if (pathDefinition) {
+ content = ;
+ }
+
+ return (
+
+ );
+ });
+
+ Comp.displayName = displayName || 'Icon';
+
+ return Comp;
+}
+
+export default createIcon;
diff --git a/src/icons/createIcon/index.ts b/src/icons/createIcon/index.ts
new file mode 100644
index 000000000..cdb278409
--- /dev/null
+++ b/src/icons/createIcon/index.ts
@@ -0,0 +1 @@
+export { createIcon, default, type CreateIconOptions } from './createIcon';
diff --git a/src/icons/index.ts b/src/icons/index.ts
index 8299cb93e..ee59fd13c 100644
--- a/src/icons/index.ts
+++ b/src/icons/index.ts
@@ -51,6 +51,7 @@ export * from './ContentClassIcons';
export * from './ContentFilter';
export * from './Copy';
export * from './CreateNew';
+export * from './createIcon';
export * from './Credential';
export * from './CrossCircle';
export * from './Dashboard';
diff --git a/src/index.tsx b/src/index.tsx
index 33a25a51f..22b5132df 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -164,3 +164,9 @@ export {
type Team as TeamPickerRecord,
type TeamSearchFieldProps
} from './custom/DashboardWidgets/GettingStartedWidget/TeamSearchField';
+
+export {
+ createIcon,
+ type CreateIconOptions
+} from './icons/createIcon';
+