From d278d4be7461fea9f2f08b8a24f47902133c5531 Mon Sep 17 00:00:00 2001 From: Kai Gritun Date: Wed, 11 Feb 2026 14:52:32 -0500 Subject: [PATCH 1/6] fix(mui): prevent nested interactive elements in navigation buttons Use Button's component prop to render as LinkComponent directly instead of nesting Button inside LinkComponent. This fixes an accessibility issue where button elements were incorrectly nested inside anchor elements. Affects: CreateButton, EditButton, ShowButton, ListButton, CloneButton Fixes #7085 --- .../src/components/buttons/clone/index.tsx | 34 +++++++-------- .../src/components/buttons/create/index.tsx | 36 +++++++--------- .../mui/src/components/buttons/edit/index.tsx | 42 +++++++++---------- .../mui/src/components/buttons/list/index.tsx | 34 +++++++-------- .../mui/src/components/buttons/show/index.tsx | 34 +++++++-------- 5 files changed, 80 insertions(+), 100 deletions(-) diff --git a/packages/mui/src/components/buttons/clone/index.tsx b/packages/mui/src/components/buttons/clone/index.tsx index 7b013011a768d..9771d673109fd 100644 --- a/packages/mui/src/components/buttons/clone/index.tsx +++ b/packages/mui/src/components/buttons/clone/index.tsx @@ -44,9 +44,10 @@ export const CloneButton: React.FC = ({ const { sx, ...restProps } = rest; return ( - ) => { if (isDisabled) { e.preventDefault(); @@ -57,23 +58,18 @@ export const CloneButton: React.FC = ({ onClick(e); } }} - style={{ textDecoration: "none" }} + startIcon={!hideText && } + title={title} + sx={{ minWidth: 0, textDecoration: "none", ...sx }} + data-testid={RefineButtonTestIds.CloneButton} + className={RefineButtonClassNames.CloneButton} + {...restProps} > - - + {hideText ? ( + + ) : ( + children ?? label + )} + ); }; diff --git a/packages/mui/src/components/buttons/create/index.tsx b/packages/mui/src/components/buttons/create/index.tsx index 65b72471067e0..1549105a1f64f 100644 --- a/packages/mui/src/components/buttons/create/index.tsx +++ b/packages/mui/src/components/buttons/create/index.tsx @@ -42,9 +42,10 @@ export const CreateButton: React.FC = ({ const { sx, ...restProps } = props; return ( - ) => { if (isDisabled) { e.preventDefault(); @@ -55,24 +56,19 @@ export const CreateButton: React.FC = ({ onClick(e); } }} - style={{ textDecoration: "none" }} + startIcon={!hideText && } + title={title} + variant="contained" + sx={{ minWidth: 0, textDecoration: "none", ...sx }} + data-testid={RefineButtonTestIds.CreateButton} + className={RefineButtonClassNames.CreateButton} + {...restProps} > - - + {hideText ? ( + + ) : ( + children ?? label + )} + ); }; diff --git a/packages/mui/src/components/buttons/edit/index.tsx b/packages/mui/src/components/buttons/edit/index.tsx index a188eb3c04a18..5b525ff3ed79a 100644 --- a/packages/mui/src/components/buttons/edit/index.tsx +++ b/packages/mui/src/components/buttons/edit/index.tsx @@ -43,9 +43,10 @@ export const EditButton: React.FC = ({ const { sx, ...restProps } = rest; return ( - ) => { if (isDisabled) { e.preventDefault(); @@ -56,27 +57,22 @@ export const EditButton: React.FC = ({ onClick(e); } }} - style={{ textDecoration: "none" }} + startIcon={ + !hideText && ( + + ) + } + title={title} + sx={{ minWidth: 0, textDecoration: "none", ...sx }} + data-testid={RefineButtonTestIds.EditButton} + className={RefineButtonClassNames.EditButton} + {...restProps} > - - + {hideText ? ( + + ) : ( + children ?? label + )} + ); }; diff --git a/packages/mui/src/components/buttons/list/index.tsx b/packages/mui/src/components/buttons/list/index.tsx index f350193ae4660..3f7be4fba9575 100644 --- a/packages/mui/src/components/buttons/list/index.tsx +++ b/packages/mui/src/components/buttons/list/index.tsx @@ -41,9 +41,10 @@ export const ListButton: React.FC = ({ const { sx, ...restProps } = rest; return ( - ) => { if (isDisabled) { e.preventDefault(); @@ -54,23 +55,18 @@ export const ListButton: React.FC = ({ onClick(e); } }} - style={{ textDecoration: "none" }} + startIcon={!hideText && } + title={title} + sx={{ minWidth: 0, textDecoration: "none", ...sx }} + data-testid={RefineButtonTestIds.ListButton} + className={RefineButtonClassNames.ListButton} + {...restProps} > - - + {hideText ? ( + + ) : ( + children ?? label + )} + ); }; diff --git a/packages/mui/src/components/buttons/show/index.tsx b/packages/mui/src/components/buttons/show/index.tsx index ebc80cfe4a202..d36dd217408d8 100644 --- a/packages/mui/src/components/buttons/show/index.tsx +++ b/packages/mui/src/components/buttons/show/index.tsx @@ -43,9 +43,10 @@ export const ShowButton: React.FC = ({ const { sx, ...restProps } = rest; return ( - ) => { if (isDisabled) { e.preventDefault(); @@ -56,23 +57,18 @@ export const ShowButton: React.FC = ({ onClick(e); } }} - style={{ textDecoration: "none" }} + startIcon={!hideText && } + title={title} + sx={{ minWidth: 0, textDecoration: "none", ...sx }} + data-testid={RefineButtonTestIds.ShowButton} + className={RefineButtonClassNames.ShowButton} + {...restProps} > - - + {hideText ? ( + + ) : ( + children ?? label + )} + ); }; From b38da2f5459370dac144658995ed033442866932 Mon Sep 17 00:00:00 2001 From: Kai Gritun Date: Wed, 11 Feb 2026 14:53:58 -0500 Subject: [PATCH 2/6] chore: add changeset --- .changeset/fix-mui-nested-buttons.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/fix-mui-nested-buttons.md diff --git a/.changeset/fix-mui-nested-buttons.md b/.changeset/fix-mui-nested-buttons.md new file mode 100644 index 0000000000000..19247a2171954 --- /dev/null +++ b/.changeset/fix-mui-nested-buttons.md @@ -0,0 +1,5 @@ +--- +"@refinedev/mui": patch +--- + +fix(mui): prevent nested interactive elements in navigation buttons From 7237c5c107cd8c94726b843f9f4530fff8f37b1b Mon Sep 17 00:00:00 2001 From: kaigritun Date: Thu, 12 Feb 2026 07:55:56 -0500 Subject: [PATCH 3/6] fix: restore replace prop and original prop order in clone/edit buttons --- packages/mui/src/components/buttons/clone/index.tsx | 3 ++- packages/mui/src/components/buttons/edit/index.tsx | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/mui/src/components/buttons/clone/index.tsx b/packages/mui/src/components/buttons/clone/index.tsx index 9771d673109fd..d595a79cc0578 100644 --- a/packages/mui/src/components/buttons/clone/index.tsx +++ b/packages/mui/src/components/buttons/clone/index.tsx @@ -45,9 +45,10 @@ export const CloneButton: React.FC = ({ return ( + + - + +
+ + - + +
+ + + + Posts + + + + Create
@@ -1718,50 +1713,40 @@ exports[`MuiListInferencer > should match the snapshot 1`] = ` tabindex="-1" > - + + - + + @@ -1997,50 +1982,40 @@ exports[`MuiListInferencer > should match the snapshot 1`] = ` tabindex="-1" > - + + - + + diff --git a/packages/inferencer/src/inferencers/mui/__tests__/__snapshots__/show.test.tsx.snap b/packages/inferencer/src/inferencers/mui/__tests__/__snapshots__/show.test.tsx.snap index 43a3d93517e95..9eac00eb44fce 100644 --- a/packages/inferencer/src/inferencers/mui/__tests__/__snapshots__/show.test.tsx.snap +++ b/packages/inferencer/src/inferencers/mui/__tests__/__snapshots__/show.test.tsx.snap @@ -95,32 +95,27 @@ exports[`MuiShowInferencer > should match the snapshot 1`] = ` class="MuiBox-root css-10egq61" > - + + + + Posts