diff --git a/packages/mui-material-next/src/Button/Button.test.js b/packages/mui-material-next/src/Button/Button.test.js
index 5c6954c1fed9ef..94ea0f10e3b564 100644
--- a/packages/mui-material-next/src/Button/Button.test.js
+++ b/packages/mui-material-next/src/Button/Button.test.js
@@ -1,8 +1,11 @@
import * as React from 'react';
import { expect } from 'chai';
-import { describeConformance, createRenderer, fireEvent } from 'test/utils';
+import { spy, stub } from 'sinon';
+import { describeConformance, createRenderer, fireEvent, act } from 'test/utils';
import Button, { buttonClasses as classes } from '@mui/material-next/Button';
+import * as useTouchRipple from '@mui/material-next/Button/useTouchRipple';
import { CssVarsProvider, extendTheme } from '@mui/material-next/styles';
+import { camelCase } from 'lodash';
describe('', () => {
const { render, renderToString } = createRenderer();
@@ -179,4 +182,58 @@ describe('', () => {
expect(button).to.have.class(classes.active);
});
+
+ describe('Event handlers', () => {
+ const events = ['click', 'focus', 'mouse-down', 'mouse-up'];
+ const withFocusEvents = ['key-down', 'key-up'];
+
+ const eventHandlers = [
+ ...events.map((event) => ({
+ name: camelCase(`on-${event}`),
+ triggerFunction: fireEvent[camelCase(event)],
+ })),
+ ...withFocusEvents.map((event) => ({
+ name: camelCase(`on-${event}`),
+ triggerFunction: (target) => {
+ target.focus();
+ fireEvent[camelCase(event)](document.activeElement);
+ },
+ })),
+ ];
+
+ eventHandlers.forEach(({ name, triggerFunction }) => {
+ it(`should call ${name} handler`, () => {
+ const handleSpy = spy();
+ const handlerProp = { [name]: handleSpy };
+
+ const { container } = render();
+ const button = container.querySelector('button');
+
+ act(() => {
+ triggerFunction(button);
+ });
+
+ expect(handleSpy.callCount).to.equal(1);
+ });
+ });
+ });
+
+ describe('Ripple', () => {
+ it('should call ripple mouse down handler', () => {
+ const mouseDownSpy = spy();
+ stub(useTouchRipple, 'default').returns({
+ enableTouchRipple: true,
+ getRippleHandlers: () => ({
+ onMouseDown: mouseDownSpy,
+ }),
+ });
+ const { getByRole } = render();
+
+ expect(mouseDownSpy.callCount).to.equal(0);
+
+ fireEvent.mouseDown(getByRole('button'));
+
+ expect(mouseDownSpy.callCount).to.equal(1);
+ });
+ });
});
diff --git a/packages/mui-material-next/src/Button/Button.tsx b/packages/mui-material-next/src/Button/Button.tsx
index df462b9d2f2277..69cd22d87023a7 100644
--- a/packages/mui-material-next/src/Button/Button.tsx
+++ b/packages/mui-material-next/src/Button/Button.tsx
@@ -1,7 +1,6 @@
'use client';
import * as React from 'react';
import PropTypes from 'prop-types';
-import clsx from 'clsx';
import {
elementTypeAcceptingRef,
refType,
@@ -9,7 +8,7 @@ import {
unstable_useForkRef as useForkRef,
} from '@mui/utils';
import useButton from '@mui/base/useButton';
-import { EventHandlers } from '@mui/base/utils';
+import { EventHandlers, useSlotProps } from '@mui/base/utils';
import composeClasses from '@mui/base/composeClasses';
import { useThemeProps, alpha } from '@mui/system';
import TouchRipple from './TouchRipple';
@@ -432,13 +431,9 @@ const Button = React.forwardRef(function Button<
fullWidth = false,
LinkComponent = 'a',
onBlur,
- onClick,
onContextMenu,
onDragLeave,
- onFocus,
onFocusVisible,
- onKeyDown,
- onKeyUp,
onMouseDown,
onMouseLeave,
onMouseUp,
@@ -526,6 +521,22 @@ const Button = React.forwardRef(function Button<
const classes = useUtilityClasses(ownerState);
+ const rootProps = useSlotProps({
+ elementType: ButtonRoot,
+ getSlotProps: (otherHandlers: EventHandlers) =>
+ getRootProps({
+ ...otherHandlers,
+ ...getRippleHandlers(props),
+ }),
+ externalForwardedProps: other,
+ externalSlotProps: {},
+ additionalProps: {
+ as: ComponentProp,
+ },
+ ownerState,
+ className: [classes.root, className],
+ });
+
const startIcon = startIconProp && (
{startIconProp}
@@ -539,13 +550,7 @@ const Button = React.forwardRef(function Button<
);
return (
-
+
{startIcon}
{children}
{endIcon}
@@ -647,10 +652,6 @@ Button.propTypes /* remove-proptypes */ = {
* @ignore
*/
onBlur: PropTypes.func,
- /**
- * @ignore
- */
- onClick: PropTypes.func,
/**
* @ignore
*/
@@ -659,22 +660,10 @@ Button.propTypes /* remove-proptypes */ = {
* @ignore
*/
onDragLeave: PropTypes.func,
- /**
- * @ignore
- */
- onFocus: PropTypes.func,
/**
* @ignore
*/
onFocusVisible: PropTypes.func,
- /**
- * @ignore
- */
- onKeyDown: PropTypes.func,
- /**
- * @ignore
- */
- onKeyUp: PropTypes.func,
/**
* @ignore
*/