diff --git a/docs/pages/base-ui/api/use-slider.json b/docs/pages/base-ui/api/use-slider.json
index 9978166f327161..620535067170fd 100644
--- a/docs/pages/base-ui/api/use-slider.json
+++ b/docs/pages/base-ui/api/use-slider.json
@@ -62,22 +62,22 @@
},
"getHiddenInputProps": {
"type": {
- "name": "<TOther extends EventHandlers = {}>(otherHandlers?: TOther) => UseSliderHiddenInputProps<TOther>",
- "description": "<TOther extends EventHandlers = {}>(otherHandlers?: TOther) => UseSliderHiddenInputProps<TOther>"
+ "name": "<ExternalProps extends Record<string, unknown> = {}>(externalProps?: ExternalProps) => UseSliderHiddenInputProps<ExternalProps>",
+ "description": "<ExternalProps extends Record<string, unknown> = {}>(externalProps?: ExternalProps) => UseSliderHiddenInputProps<ExternalProps>"
},
"required": true
},
"getRootProps": {
"type": {
- "name": "<TOther extends EventHandlers = {}>(otherHandlers?: TOther) => UseSliderRootSlotProps<TOther>",
- "description": "<TOther extends EventHandlers = {}>(otherHandlers?: TOther) => UseSliderRootSlotProps<TOther>"
+ "name": "<ExternalProps extends Record<string, unknown> = {}>(externalProps?: ExternalProps) => UseSliderRootSlotProps<ExternalProps>",
+ "description": "<ExternalProps extends Record<string, unknown> = {}>(externalProps?: ExternalProps) => UseSliderRootSlotProps<ExternalProps>"
},
"required": true
},
"getThumbProps": {
"type": {
- "name": "<TOther extends EventHandlers = {}>(otherHandlers?: TOther) => UseSliderThumbSlotProps<TOther>",
- "description": "<TOther extends EventHandlers = {}>(otherHandlers?: TOther) => UseSliderThumbSlotProps<TOther>"
+ "name": "<ExternalProps extends Record<string, unknown> = {}>(externalProps?: ExternalProps) => UseSliderThumbSlotProps<ExternalProps>",
+ "description": "<ExternalProps extends Record<string, unknown> = {}>(externalProps?: ExternalProps) => UseSliderThumbSlotProps<ExternalProps>"
},
"required": true
},
diff --git a/packages/mui-base/src/useSlider/useSlider.test.js b/packages/mui-base/src/useSlider/useSlider.test.js
new file mode 100644
index 00000000000000..b717f0e934b57e
--- /dev/null
+++ b/packages/mui-base/src/useSlider/useSlider.test.js
@@ -0,0 +1,90 @@
+import * as React from 'react';
+import { expect } from 'chai';
+import { spy } from 'sinon';
+import { createRenderer, screen, fireEvent } from '@mui-internal/test-utils';
+import { useSlider } from './useSlider';
+
+describe('useSlider', () => {
+ const { render } = createRenderer();
+ describe('getRootProps', () => {
+ it('forwards external props including event handlers', () => {
+ const rootRef = React.createRef();
+
+ const handleClick = spy();
+
+ function Test() {
+ const { getRootProps } = useSlider({
+ rootRef,
+ marks: [
+ {
+ label: 'One',
+ value: 1,
+ },
+ ],
+ });
+
+ return (
+
+ );
+ }
+
+ render();
+
+ const slider = screen.getByTestId('test-slider-root');
+ expect(slider).not.to.equal(null);
+ expect(rootRef.current).to.deep.equal(slider);
+
+ fireEvent.click(slider);
+ expect(handleClick.callCount).to.equal(1);
+ });
+ });
+
+ describe('getHiddenInputProps', () => {
+ function Test(
+ props = {
+ slotProps: {
+ input: {},
+ },
+ },
+ ) {
+ const { getRootProps, getThumbProps, getHiddenInputProps } = useSlider({
+ marks: [
+ {
+ label: 'One',
+ value: 1,
+ },
+ ],
+ });
+
+ return (
+
+ );
+ }
+
+ it('forwards external props including event handlers', () => {
+ const handleClick = spy();
+ render(
+ ,
+ );
+
+ const input = screen.getByTestId('test-input');
+ expect(input).not.to.equal(null);
+
+ fireEvent.click(input);
+ expect(handleClick.callCount).to.equal(1);
+ });
+ });
+});
diff --git a/packages/mui-base/src/useSlider/useSlider.ts b/packages/mui-base/src/useSlider/useSlider.ts
index 1a382af52cc029..219d18666c51df 100644
--- a/packages/mui-base/src/useSlider/useSlider.ts
+++ b/packages/mui-base/src/useSlider/useSlider.ts
@@ -17,7 +17,7 @@ import {
UseSliderRootSlotProps,
UseSliderThumbSlotProps,
} from './useSlider.types';
-import { areArraysEqual, EventHandlers } from '../utils';
+import { areArraysEqual, EventHandlers, extractEventHandlers } from '../utils';
const INTENTIONAL_DRAG_COUNT_THRESHOLD = 2;
@@ -282,7 +282,7 @@ export function useSlider(parameters: UseSliderParameters): UseSliderReturnValue
const handleRef = useForkRef(ref, handleFocusRef);
const createHandleHiddenInputFocus =
- (otherHandlers: Record>) => (event: React.FocusEvent) => {
+ (otherHandlers: EventHandlers) => (event: React.FocusEvent) => {
const index = Number(event.currentTarget.getAttribute('data-index'));
handleFocusVisible(event);
if (isFocusVisibleRef.current === true) {
@@ -292,7 +292,7 @@ export function useSlider(parameters: UseSliderParameters): UseSliderReturnValue
otherHandlers?.onFocus?.(event);
};
const createHandleHiddenInputBlur =
- (otherHandlers: Record>) => (event: React.FocusEvent) => {
+ (otherHandlers: EventHandlers) => (event: React.FocusEvent) => {
handleBlurVisible(event);
if (isFocusVisibleRef.current === false) {
setFocusedThumbIndex(-1);
@@ -319,7 +319,7 @@ export function useSlider(parameters: UseSliderParameters): UseSliderReturnValue
}
const createHandleHiddenInputChange =
- (otherHandlers: Record>) => (event: React.ChangeEvent) => {
+ (otherHandlers: EventHandlers) => (event: React.ChangeEvent) => {
otherHandlers.onChange?.(event);
const index = Number(event.currentTarget.getAttribute('data-index'));
@@ -571,8 +571,7 @@ export function useSlider(parameters: UseSliderParameters): UseSliderReturnValue
}, [disabled, stopListening]);
const createHandleMouseDown =
- (otherHandlers: Record>) =>
- (event: React.MouseEvent) => {
+ (otherHandlers: EventHandlers) => (event: React.MouseEvent) => {
otherHandlers.onMouseDown?.(event);
if (disabled) {
return;
@@ -610,26 +609,29 @@ export function useSlider(parameters: UseSliderParameters): UseSliderReturnValue
const trackOffset = valueToPercent(range ? values[0] : min, min, max);
const trackLeap = valueToPercent(values[values.length - 1], min, max) - trackOffset;
- const getRootProps = (
- otherHandlers: TOther = {} as TOther,
- ): UseSliderRootSlotProps => {
+ const getRootProps = = {}>(
+ externalProps: ExternalProps = {} as ExternalProps,
+ ): UseSliderRootSlotProps => {
+ const externalHandlers = extractEventHandlers(externalProps);
+
const ownEventHandlers = {
- onMouseDown: createHandleMouseDown(otherHandlers || {}),
+ onMouseDown: createHandleMouseDown(externalHandlers || {}),
};
const mergedEventHandlers = {
- ...otherHandlers,
+ ...externalHandlers,
...ownEventHandlers,
};
+
return {
+ ...externalProps,
ref: handleRef,
...mergedEventHandlers,
};
};
const createHandleMouseOver =
- (otherHandlers: Record>) =>
- (event: React.MouseEvent) => {
+ (otherHandlers: EventHandlers) => (event: React.MouseEvent) => {
otherHandlers.onMouseOver?.(event);
const index = Number(event.currentTarget.getAttribute('data-index'));
@@ -637,23 +639,25 @@ export function useSlider(parameters: UseSliderParameters): UseSliderReturnValue
};
const createHandleMouseLeave =
- (otherHandlers: Record>) =>
- (event: React.MouseEvent) => {
+ (otherHandlers: EventHandlers) => (event: React.MouseEvent) => {
otherHandlers.onMouseLeave?.(event);
setOpen(-1);
};
- const getThumbProps = (
- otherHandlers: TOther = {} as TOther,
- ): UseSliderThumbSlotProps => {
+ const getThumbProps = = {}>(
+ externalProps: ExternalProps = {} as ExternalProps,
+ ): UseSliderThumbSlotProps => {
+ const externalHandlers = extractEventHandlers(externalProps);
+
const ownEventHandlers = {
- onMouseOver: createHandleMouseOver(otherHandlers || {}),
- onMouseLeave: createHandleMouseLeave(otherHandlers || {}),
+ onMouseOver: createHandleMouseOver(externalHandlers || {}),
+ onMouseLeave: createHandleMouseLeave(externalHandlers || {}),
};
return {
- ...otherHandlers,
+ ...externalProps,
+ ...externalHandlers,
...ownEventHandlers,
};
};
@@ -665,17 +669,19 @@ export function useSlider(parameters: UseSliderParameters): UseSliderReturnValue
};
};
- const getHiddenInputProps = (
- otherHandlers: TOther = {} as TOther,
- ): UseSliderHiddenInputProps => {
+ const getHiddenInputProps = = {}>(
+ externalProps: ExternalProps = {} as ExternalProps,
+ ): UseSliderHiddenInputProps => {
+ const externalHandlers = extractEventHandlers(externalProps);
+
const ownEventHandlers = {
- onChange: createHandleHiddenInputChange(otherHandlers || {}),
- onFocus: createHandleHiddenInputFocus(otherHandlers || {}),
- onBlur: createHandleHiddenInputBlur(otherHandlers || {}),
+ onChange: createHandleHiddenInputChange(externalHandlers || {}),
+ onFocus: createHandleHiddenInputFocus(externalHandlers || {}),
+ onBlur: createHandleHiddenInputBlur(externalHandlers || {}),
};
const mergedEventHandlers = {
- ...otherHandlers,
+ ...externalHandlers,
...ownEventHandlers,
};
@@ -691,6 +697,7 @@ export function useSlider(parameters: UseSliderParameters): UseSliderReturnValue
max: parameters.max,
step: parameters.step === null && parameters.marks ? 'any' : parameters.step ?? undefined,
disabled,
+ ...externalProps,
...mergedEventHandlers,
style: {
...visuallyHidden,
diff --git a/packages/mui-base/src/useSlider/useSlider.types.ts b/packages/mui-base/src/useSlider/useSlider.types.ts
index 95eaa44b22d11f..0319f6384b9c8a 100644
--- a/packages/mui-base/src/useSlider/useSlider.types.ts
+++ b/packages/mui-base/src/useSlider/useSlider.types.ts
@@ -1,5 +1,4 @@
import * as React from 'react';
-import { EventHandlers } from '../utils';
export interface UseSliderParameters {
/**
@@ -113,7 +112,10 @@ export type UseSliderRootSlotOwnProps = {
ref: React.RefCallback | null;
};
-export type UseSliderRootSlotProps = Omit &
+export type UseSliderRootSlotProps = Omit<
+ ExternalProps,
+ keyof UseSliderRootSlotOwnProps
+> &
UseSliderRootSlotOwnProps;
export type UseSliderThumbSlotOwnProps = {
@@ -121,7 +123,10 @@ export type UseSliderThumbSlotOwnProps = {
onMouseOver: React.MouseEventHandler;
};
-export type UseSliderThumbSlotProps = Omit &
+export type UseSliderThumbSlotProps = Omit<
+ ExternalProps,
+ keyof UseSliderThumbSlotOwnProps
+> &
UseSliderThumbSlotOwnProps;
export type UseSliderHiddenInputOwnProps = {
@@ -140,8 +145,8 @@ export type UseSliderHiddenInputOwnProps = {
type?: React.InputHTMLAttributes['type'];
};
-export type UseSliderHiddenInputProps = Omit<
- TOther,
+export type UseSliderHiddenInputProps = Omit<
+ ExternalProps,
keyof UseSliderHiddenInputOwnProps
> &
UseSliderHiddenInputOwnProps;
@@ -190,28 +195,28 @@ export interface UseSliderReturnValue {
focusedThumbIndex: number;
/**
* Resolver for the hidden input slot's props.
- * @param otherHandlers props for the hidden input slot
+ * @param externalProps props for the hidden input slot
* @returns props that should be spread on the hidden input slot
*/
- getHiddenInputProps: (
- otherHandlers?: TOther,
- ) => UseSliderHiddenInputProps;
+ getHiddenInputProps: = {}>(
+ externalProps?: ExternalProps,
+ ) => UseSliderHiddenInputProps;
/**
* Resolver for the root slot's props.
- * @param otherHandlers props for the root slot
+ * @param externalProps props for the root slot
* @returns props that should be spread on the root slot
*/
- getRootProps: (
- otherHandlers?: TOther,
- ) => UseSliderRootSlotProps;
+ getRootProps: = {}>(
+ externalProps?: ExternalProps,
+ ) => UseSliderRootSlotProps;
/**
* Resolver for the thumb slot's props.
- * @param otherHandlers props for the thumb slot
+ * @param externalProps props for the thumb slot
* @returns props that should be spread on the thumb slot
*/
- getThumbProps: (
- otherHandlers?: TOther,
- ) => UseSliderThumbSlotProps;
+ getThumbProps: = {}>(
+ externalProps?: ExternalProps,
+ ) => UseSliderThumbSlotProps;
/**
* Resolver for the thumb slot's style prop.
* @param index of the currently moved thumb