diff --git a/docs/data/material/customization/focus-visible/demos/full/FullFocusVisibleDemo.tsx b/docs/data/material/customization/focus-visible/demos/full/FullFocusVisibleDemo.tsx
index f7103078aa0607..272830eb828cc9 100644
--- a/docs/data/material/customization/focus-visible/demos/full/FullFocusVisibleDemo.tsx
+++ b/docs/data/material/customization/focus-visible/demos/full/FullFocusVisibleDemo.tsx
@@ -33,6 +33,7 @@ import TableBody from '@mui/material/TableBody';
import TableRow from '@mui/material/TableRow';
import TableCell from '@mui/material/TableCell';
import TableSortLabel from '@mui/material/TableSortLabel';
+import TablePagination from '@mui/material/TablePagination';
import Slider from '@mui/material/Slider';
import Link from '@mui/material/Link';
import Breadcrumbs from '@mui/material/Breadcrumbs';
@@ -429,6 +430,18 @@ export default function FullFocusVisibleDemo() {
)}
/>
+
+
+
diff --git a/packages/mui-material/src/TablePagination/TablePagination.js b/packages/mui-material/src/TablePagination/TablePagination.js
index 69c5797a865b51..a00e57f1154e25 100644
--- a/packages/mui-material/src/TablePagination/TablePagination.js
+++ b/packages/mui-material/src/TablePagination/TablePagination.js
@@ -8,6 +8,8 @@ import composeClasses from '@mui/utils/composeClasses';
import { styled } from '../zero-styled';
import memoTheme from '../utils/memoTheme';
import { useDefaultProps } from '../DefaultPropsProvider';
+import { applyInsetFocusVisible } from '../styles/focusVisible';
+import { buttonBaseClasses } from '../ButtonBase';
import InputBase from '../InputBase';
import MenuItem from '../MenuItem';
import Select from '../Select';
@@ -57,6 +59,9 @@ const TablePaginationToolbar = styled(Toolbar, {
[`& .${tablePaginationClasses.actions}`]: {
flexShrink: 0,
marginLeft: 20,
+ ...(theme.focusVisible && {
+ [`& .${buttonBaseClasses.root}`]: applyInsetFocusVisible(1),
+ }),
},
})),
);
@@ -104,11 +109,17 @@ const TablePaginationSelect = styled(Select, {
});
const TablePaginationInputBase = styled(InputBase)(
- memoTheme(({ theme }) => ({
- [`& .${tablePaginationClasses.select}:focus`]: {
- backgroundColor: (theme.vars || theme).palette.action.focus,
- },
- })),
+ memoTheme(({ theme }) =>
+ theme.focusVisible
+ ? {
+ [`& .${tablePaginationClasses.select}:focus-visible`]: theme.focusVisible,
+ }
+ : {
+ [`& .${tablePaginationClasses.select}:focus`]: {
+ backgroundColor: (theme.vars || theme).palette.action.focus,
+ },
+ },
+ ),
);
const TablePaginationMenuItem = styled(MenuItem, {
@@ -276,7 +287,9 @@ const TablePagination = React.forwardRef(function TablePagination(inProps, ref)
{rowsPerPageOptions.length > 1 && (
})}
+ {...(!selectProps.variant && {
+ input: ,
+ })}
value={rowsPerPage}
onChange={onRowsPerPageChange}
id={selectId}
diff --git a/packages/mui-material/src/TablePagination/TablePagination.test.js b/packages/mui-material/src/TablePagination/TablePagination.test.js
index 7572f41258bdc6..4cc42d040d94f5 100644
--- a/packages/mui-material/src/TablePagination/TablePagination.test.js
+++ b/packages/mui-material/src/TablePagination/TablePagination.test.js
@@ -2,7 +2,15 @@ import { describe, it, expect, beforeEach } from 'vitest';
import * as React from 'react';
import { spy } from 'sinon';
import PropTypes from 'prop-types';
-import { fireEvent, createRenderer, isJsdom, screen } from '@mui/internal-test-utils';
+import {
+ act,
+ fireEvent,
+ createRenderer,
+ focusVisible,
+ isJsdom,
+ screen,
+ simulatePointerDevice,
+} from '@mui/internal-test-utils';
import TableFooter from '@mui/material/TableFooter';
import TableCell from '@mui/material/TableCell';
import TableRow from '@mui/material/TableRow';
@@ -11,6 +19,7 @@ import { inputClasses } from '@mui/material/Input';
import { outlinedInputClasses } from '@mui/material/OutlinedInput';
import { filledInputClasses } from '@mui/material/FilledInput';
import { createTheme, ThemeProvider } from '@mui/material/styles';
+import { inputBaseClasses } from '@mui/material/InputBase';
import IconButton, { iconButtonClasses } from '@mui/material/IconButton';
import { svgIconClasses } from '@mui/material/SvgIcon';
import { createSvgIcon } from '@mui/material/utils';
@@ -566,6 +575,88 @@ describe('', () => {
});
});
+ describe('theme: focusVisible', () => {
+ function setup(theme) {
+ render(
+
+
+ ,
+ );
+
+ return screen.getByRole('combobox');
+ }
+
+ it.skipIf(isJsdom())('keeps the focus tint on the select without the theme ring', () => {
+ const combobox = setup(createTheme());
+
+ act(() => combobox.focus());
+
+ expect(combobox).toHaveComputedStyle({ backgroundColor: 'rgba(0, 0, 0, 0.12)' });
+ });
+
+ it.skipIf(isJsdom())('drops the focus tint on the select with the theme ring', () => {
+ const combobox = setup(createTheme({ focusVisible: true }));
+
+ act(() => combobox.focus());
+
+ expect(combobox).toHaveComputedStyle({ backgroundColor: 'rgba(0, 0, 0, 0)' });
+ });
+
+ it.skipIf(isJsdom())('rings the select on keyboard focus instead of the InputBase root', () => {
+ const combobox = setup(createTheme({ focusVisible: true }));
+
+ focusVisible(combobox);
+
+ expect(combobox).toHaveComputedStyle({ outlineStyle: 'solid', outlineWidth: '2px' });
+ expect(combobox.closest(`.${inputBaseClasses.root}`)).toHaveComputedStyle({
+ outlineStyle: 'none',
+ });
+ });
+
+ it.skipIf(isJsdom())('insets the action button ring so the root cannot clip it', () => {
+ render(
+
+
+ ,
+ );
+ const nextButton = screen.getByRole('button', { name: 'Go to next page' });
+
+ simulatePointerDevice();
+ focusVisible(nextButton);
+
+ expect(nextButton).toHaveComputedStyle({ outlineStyle: 'solid', outlineOffset: '-2px' });
+ });
+ });
+
describe('prop: rowsPerPage', () => {
it('should display max number of rows text when prop is -1', () => {
const { container } = render(