- +
- ```
-
- or 2. you can follow one of the overrides approach described on the ([Style Library Interoperability](/guides/interoperability/)) page. The class names for the Slider component can be find on the [API page](/api/slider/#css).
-
### Snackbar
- The notification now displays at the bottom left on large screens.
diff --git a/packages/material-ui-unstyled/src/SliderUnstyled/SliderUnstyled.d.ts b/packages/material-ui-unstyled/src/SliderUnstyled/SliderUnstyled.d.ts
index 22c536085850dc..95c123362ae5d3 100644
--- a/packages/material-ui-unstyled/src/SliderUnstyled/SliderUnstyled.d.ts
+++ b/packages/material-ui-unstyled/src/SliderUnstyled/SliderUnstyled.d.ts
@@ -1,4 +1,4 @@
-import { OverridableComponent, OverridableTypeMap } from '../OverridableComponent';
+import { OverridableComponent, OverridableTypeMap, OverrideProps } from '../OverridableComponent';
export interface Mark {
value: number;
@@ -26,6 +26,51 @@ export interface SliderUnstyledTypeMap;
as: React.ElementType;
+ styleProps?: Omit['props'], 'components' | 'componentsProps'>;
};
track?: {
as?: React.ElementType;
+ styleProps?: Omit['props'], 'components' | 'componentsProps'>;
};
rail?: {
as?: React.ElementType;
+ styleProps?: Omit['props'], 'components' | 'componentsProps'>;
};
thumb?: {
as?: React.ElementType;
+ styleProps?: Omit['props'], 'components' | 'componentsProps'>;
};
mark?: {
as?: React.ElementType;
+ styleProps?: Omit['props'], 'components' | 'componentsProps'>;
};
markLabel?: {
as?: React.ElementType;
+ styleProps?: Omit['props'], 'components' | 'componentsProps'>;
};
valueLabel?: {
as?: React.ElementType;
+ styleProps?: Omit['props'], 'components' | 'componentsProps'>;
};
};
/**
@@ -219,4 +270,11 @@ export type ExtendSliderUnstyled = OverridableComp
*/
declare const SliderUnstyled: OverridableComponent;
+export type SliderUnstyledProps<
+ D extends React.ElementType = SliderUnstyledTypeMap['defaultComponent'],
+ P = {}
+> = OverrideProps, D>;
+
+export type SliderUnstyledClassKey = keyof NonNullable;
+
export default SliderUnstyled;
diff --git a/packages/material-ui-unstyled/src/SliderUnstyled/SliderUnstyled.js b/packages/material-ui-unstyled/src/SliderUnstyled/SliderUnstyled.js
index 3c84b47eacd6e3..17d204b9bb73eb 100644
--- a/packages/material-ui-unstyled/src/SliderUnstyled/SliderUnstyled.js
+++ b/packages/material-ui-unstyled/src/SliderUnstyled/SliderUnstyled.js
@@ -149,24 +149,41 @@ const getUtilityClass = (name) => {
};
const useSliderClasses = (props) => {
- const { color, disabled, marked, orientation, track } = props;
+ const { color, disabled, marked, orientation, track, classes = {} } = props;
const utilityClasses = {
- root: clsx(getUtilityClass('root'), getUtilityClass(`color${capitalize(color)}`), {
- 'Mui-disabled': disabled,
- [getUtilityClass('marked')]: marked,
- [getUtilityClass('vertical')]: orientation === 'vertical',
- [getUtilityClass('trackInverted')]: track === 'inverted',
- [getUtilityClass('trackFalse')]: track === false,
- }),
- rail: getUtilityClass('rail'),
- track: getUtilityClass('track'),
- mark: getUtilityClass('mark'),
- markLabel: getUtilityClass('markLabel'),
- valueLabel: getUtilityClass('valueLabel'),
- thumb: clsx(getUtilityClass('thumb'), getUtilityClass(`thumbColor${capitalize(color)}`), {
- 'Mui-disabled': disabled,
- }),
+ root: clsx(
+ getUtilityClass('root'),
+ classes['root'],
+ getUtilityClass(`color${capitalize(color)}`),
+ classes[`color${capitalize(color)}`],
+ {
+ 'Mui-disabled': disabled,
+ [getUtilityClass('marked')]: marked,
+ [classes['marked']]: marked,
+ [getUtilityClass('vertical')]: orientation === 'vertical',
+ [classes['vertical']]: orientation === 'vertical',
+ [getUtilityClass('trackInverted')]: track === 'inverted',
+ [classes['trackInverted']]: track === 'inverted',
+ [getUtilityClass('trackFalse')]: track === false,
+ [classes['trackFalse']]: track === false,
+ },
+ ),
+ rail: clsx(getUtilityClass('rail'), classes['rail']),
+ track: clsx(getUtilityClass('track'), classes['track']),
+ mark: clsx(getUtilityClass('mark'), classes['mark']),
+ markLabel: clsx(getUtilityClass('markLabel'), classes['markLabel']),
+ valueLabel: clsx(getUtilityClass('valueLabel'), classes['valueLabel']),
+ thumb: clsx(
+ getUtilityClass('thumb'),
+ classes['thumb'],
+ getUtilityClass(`thumbColor${capitalize(color)}`),
+ classes[`thumbColor${capitalize(color)}`],
+ {
+ 'Mui-disabled': disabled,
+ [getUtilityClass('vertical')]: orientation === 'vertical',
+ },
+ ),
};
return utilityClasses;
@@ -599,6 +616,7 @@ const SliderUnstyled = React.forwardRef(function SliderUnstyled(props, ref) {
// consider extracting to hook an reusing the lint rule for the varints
const stateAndProps = {
...props,
+ classes: {},
color,
disabled,
max,
@@ -627,9 +645,20 @@ const SliderUnstyled = React.forwardRef(function SliderUnstyled(props, ref) {
{...other}
className={clsx(utilityClasses.root, rootProps.className, className)}
>
-
+
@@ -658,6 +687,10 @@ const SliderUnstyled = React.forwardRef(function SliderUnstyled(props, ref) {
= ExtendSliderUnstyledTypeMap<{
props: P & {
+ /**
+ * Override or extend the styles applied to the component.
+ */
+ classes?: {
+ /** Class name applied to the root element. */
+ root?: string;
+ /** Class name applied to the root element if `color="primary"`. */
+ colorPrimary?: string;
+ /** Class name applied to the root element if `color="secondary"`. */
+ colorSecondary?: string;
+ /** Class name applied to the root element if `marks` is provided with at least one label. */
+ marked?: string;
+ /** Class name applied to the root element if `orientation="vertical"`. */
+ vertical?: string;
+ /** Pseudo-class applied to the root and thumb element if `disabled={true}`. */
+ disabled?: string;
+ /** Class name applied to the rail element. */
+ rail?: string;
+ /** Class name applied to the track element. */
+ track?: string;
+ /** Class name applied to the track element if `track={false}`. */
+ trackFalse?: string;
+ /** Class name applied to the track element if `track="inverted"`. */
+ trackInverted?: string;
+ /** Class name applied to the thumb element. */
+ thumb?: string;
+ /** Class name applied to the thumb element if `color="primary"`. */
+ thumbColorPrimary?: string;
+ /** Class name applied to the thumb element if `color="secondary"`. */
+ thumbColorSecondary?: string;
+ /** Pseudo-class applied to the thumb element if it's active. */
+ active?: string;
+ /** Pseudo-class applied to the thumb element if keyboard focused. */
+ focusVisible?: string;
+ /** Class name applied to the thumb label element. */
+ valueLabel?: string;
+ /** Class name applied to the mark element. */
+ mark?: string;
+ /** Class name applied to the mark element if active (depending on the value). */
+ markActive?: string;
+ /** Class name applied to the mark label element. */
+ markLabel?: string;
+ /** Class name applied to the mark label element if active (depending on the value). */
+ markLabelActive?: string;
+ };
/**
* The system prop that allows defining system overrides as well as additional CSS styles.
*/
@@ -17,7 +62,20 @@ export type SliderTypeMap<
}>;
type SliderRootProps = NonNullable['root'];
+type SliderMarkProps = NonNullable['mark'];
+type SliderMarkLabelProps = NonNullable['markLabel'];
+type SliderRailProps = NonNullable['rail'];
+type SliderTrackProps = NonNullable['track'];
+type SliderThumbProps = NonNullable['thumb'];
+type SliderValueLabel = NonNullable['valueLabel'];
+
export const SliderRoot: React.FC;
+export const SliderMark: React.FC;
+export const SliderMarkLabel: React.FC;
+export const SliderRail: React.FC;
+export const SliderTrack: React.FC;
+export const SliderThumb: React.FC;
+export const SliderValueLabel: React.FC;
/**
*
diff --git a/packages/material-ui/src/Slider/Slider.js b/packages/material-ui/src/Slider/Slider.js
index 1c9ecba32bfe1f..1333b6825ef62f 100644
--- a/packages/material-ui/src/Slider/Slider.js
+++ b/packages/material-ui/src/Slider/Slider.js
@@ -1,9 +1,15 @@
import * as React from 'react';
import PropTypes from 'prop-types';
import { chainPropTypes } from '@material-ui/utils';
+import {
+ useThemeProps,
+ experimentalStyled,
+ alpha,
+ lighten,
+ darken,
+} from '@material-ui/core/styles';
+import { capitalize } from '@material-ui/core/utils';
import SliderUnstyled, { SliderValueLabelUnstyled } from '@material-ui/unstyled/SliderUnstyled';
-import { useThemeProps, experimentalStyled, alpha, lighten, darken } from '../styles';
-import capitalize from '../utils/capitalize';
const overridesResolver = (props, styles, name) => {
const {
@@ -48,7 +54,7 @@ const overridesResolver = (props, styles, name) => {
return styleOverrides;
};
-const SliderRoot = experimentalStyled(
+export const SliderRoot = experimentalStyled(
'span',
{},
{ muiName: 'MuiSlider', overridesResolver },
@@ -94,125 +100,138 @@ const SliderRoot = experimentalStyled(
marginRight: 20,
}),
}),
- '& .MuiSlider-rail': {
- display: 'block',
+}));
+
+export const SliderRail = experimentalStyled(
+ 'span',
+ {},
+ { muiName: 'MuiSlider-rail' },
+)((props) => ({
+ display: 'block',
+ position: 'absolute',
+ width: '100%',
+ height: 2,
+ borderRadius: 1,
+ backgroundColor: 'currentColor',
+ opacity: 0.38,
+ ...(props.styleProps.orientation === 'vertical' && {
+ height: '100%',
+ width: 2,
+ }),
+ ...(props.styleProps.track === 'inverted' && {
+ opacity: 1,
+ }),
+}));
+
+export const SliderTrack = experimentalStyled(
+ 'span',
+ {},
+ { muiName: 'MuiSlider-track' },
+)((props) => ({
+ display: 'block',
+ position: 'absolute',
+ height: 2,
+ borderRadius: 1,
+ backgroundColor: 'currentColor',
+ ...(props.styleProps.orientation === 'vertical' && {
+ width: 2,
+ }),
+ ...(props.styleProps.track === false && {
+ display: 'none',
+ }),
+ ...(props.styleProps.track === 'inverted' && {
+ backgroundColor:
+ // Same logic as the LinearProgress track color
+ props.theme.palette.mode === 'light'
+ ? lighten(props.theme.palette.primary.main, 0.62)
+ : darken(props.theme.palette.primary.main, 0.5),
+ }),
+}));
+
+export const SliderThumb = experimentalStyled(
+ 'span',
+ {},
+ { muiName: 'MuiSlider-thumb' },
+)((props) => ({
+ position: 'absolute',
+ width: 12,
+ height: 12,
+ marginLeft: -6,
+ marginTop: -5,
+ boxSizing: 'border-box',
+ borderRadius: '50%',
+ outline: 0,
+ backgroundColor: 'currentColor',
+ display: 'flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ transition: props.theme.transitions.create(['box-shadow'], {
+ duration: props.theme.transitions.duration.shortest,
+ }),
+ '&::after': {
position: 'absolute',
- width: '100%',
- height: 2,
- borderRadius: 1,
- backgroundColor: 'currentColor',
- opacity: 0.38,
- ...(props.styleProps.orientation === 'vertical' && {
- height: '100%',
- width: 2,
- }),
- ...(props.styleProps.track === 'inverted' && {
- opacity: 1,
- }),
+ content: '""',
+ borderRadius: '50%',
+ // reach 42px hit target (2 * 15 + thumb diameter)
+ left: -15,
+ top: -15,
+ right: -15,
+ bottom: -15,
},
- '& .MuiSlider-track': {
- display: 'block',
- position: 'absolute',
- height: 2,
- borderRadius: 1,
- backgroundColor: 'currentColor',
- ...(props.styleProps.orientation === 'vertical' && {
- width: 2,
- }),
- ...(props.styleProps.track === false && {
- display: 'none',
- }),
- ...(props.styleProps.track === 'inverted' && {
- backgroundColor:
- // Same logic as the LinearProgress track color
- props.theme.palette.mode === 'light'
- ? lighten(props.theme.palette.primary.main, 0.62)
- : darken(props.theme.palette.primary.main, 0.5),
- }),
+ '&:hover, &.Mui-focusVisible': {
+ boxShadow: `0px 0px 0px 8px ${alpha(props.theme.palette.primary.main, 0.16)}`,
+ '@media (hover: none)': {
+ boxShadow: 'none',
+ },
},
- '& .MuiSlider-thumb': {
- position: 'absolute',
- width: 12,
- height: 12,
- marginLeft: -6,
- marginTop: -5,
- boxSizing: 'border-box',
- borderRadius: '50%',
- outline: 0,
- backgroundColor: 'currentColor',
- display: 'flex',
- alignItems: 'center',
- justifyContent: 'center',
- transition: props.theme.transitions.create(['box-shadow'], {
- duration: props.theme.transitions.duration.shortest,
- }),
- '::after': {
- position: 'absolute',
- content: '""',
- borderRadius: '50%',
- // reach 42px hit target (2 * 15 + thumb diameter)
- left: -15,
- top: -15,
- right: -15,
- bottom: -15,
+ '&.Mui-active': {
+ boxShadow: `0px 0px 0px 14px ${alpha(props.theme.palette.primary.main, 0.16)}`,
+ },
+ '&.Mui-disabled': {
+ width: 8,
+ height: 8,
+ marginLeft: -4,
+ marginTop: -3,
+ '&:hover': {
+ boxShadow: 'none',
},
- ':hover, &.Mui-focusVisible': {
- boxShadow: `0px 0px 0px 8px ${alpha(props.theme.palette.primary.main, 0.16)}`,
- '@media (hover: none)': {
- boxShadow: 'none',
- },
+ },
+ '&.MuiSlider-vertical': {
+ marginLeft: -5,
+ marginBottom: -6,
+ },
+ '&.MuiSlider-vertical&.Mui-disabled': {
+ marginLeft: -3,
+ marginBottom: -4,
+ },
+ ...(props.styleProps.color === 'secondary' && {
+ '&:hover, &.Mui-focusVisible': {
+ boxShadow: `0px 0px 0px 8px ${alpha(props.theme.palette.secondary.main, 0.16)}`,
},
'&.Mui-active': {
- boxShadow: `0px 0px 0px 14px ${alpha(props.theme.palette.primary.main, 0.16)}`,
+ boxShadow: `0px 0px 0px 14px ${alpha(props.theme.palette.secondary.main, 0.16)}`,
},
- '&.Mui-disabled': {
- width: 8,
- height: 8,
- marginLeft: -4,
- marginTop: -3,
- ':hover': {
- boxShadow: 'none',
- },
- ...(props.styleProps.orientation === 'vertical' && {
- marginLeft: -3,
- marginBottom: -4,
- }),
+ }),
+}));
+
+export const SliderValueLabel = experimentalStyled(SliderValueLabelUnstyled)((props) => ({
+ // IE 11 centering bug, to remove from the customization demos once no longer supported
+ left: 'calc(-50% - 4px)',
+ '&.MuiSlider-valueLabelOffset': {
+ '&.MuiSlider-valueLabelOpen': {
+ transform: 'scale(1) translateY(-10px)',
},
- ...(props.styleProps.orientation === 'vertical' && {
- marginLeft: -5,
- marginBottom: -6,
- }),
- ...(props.styleProps.color === 'secondary' && {
- ':hover': {
- boxShadow: `0px 0px 0px 8px ${alpha(props.theme.palette.secondary.main, 0.16)}`,
- },
- '&.Mui-focusVisible': {
- boxShadow: `0px 0px 0px 8px ${alpha(props.theme.palette.secondary.main, 0.16)}`,
- },
- '&.Mui-active': {
- boxShadow: `0px 0px 0px 14px ${alpha(props.theme.palette.secondary.main, 0.16)}`,
- },
+ zIndex: 1,
+ ...props.theme.typography.body2,
+ fontSize: props.theme.typography.pxToRem(12),
+ lineHeight: 1.2,
+ transition: props.theme.transitions.create(['transform'], {
+ duration: props.theme.transitions.duration.shortest,
}),
- },
- '& .MuiSlider-valueLabel': {
- // IE11 centering bug, to remove from the customization demos once no longer supported
- left: 'calc(-50% - 4px)',
- '&.MuiSlider-valueLabelOffset': {
- '&.MuiSlider-valueLabelOpen': {
- transform: 'scale(1) translateY(-10px)',
- },
- zIndex: 1,
- ...props.theme.typography.body2,
- fontSize: props.theme.typography.pxToRem(12),
- lineHeight: 1.2,
- transition: props.theme.transitions.create(['transform'], {
- duration: props.theme.transitions.duration.shortest,
- }),
- top: -34,
- transformOrigin: 'bottom center',
- transform: 'scale(0)',
- position: 'absolute',
- },
+ top: -34,
+ transformOrigin: 'bottom center',
+ transform: 'scale(0)',
+ position: 'absolute',
},
'& .MuiSlider-valueLabelCircle': {
display: 'flex',
@@ -229,42 +248,98 @@ const SliderRoot = experimentalStyled(
transform: 'rotate(45deg)',
textAlign: 'center',
},
- '& .MuiSlider-mark': {
- position: 'absolute',
- width: 2,
- height: 2,
- borderRadius: 1,
- backgroundColor: 'currentColor',
- '&.MuiSlider-markActive': {
- backgroundColor: props.theme.palette.background.paper,
- opacity: 0.8,
- },
+}));
+
+export const SliderMark = experimentalStyled(
+ 'span',
+ {},
+ { muiName: 'MuiSlider-mark' },
+)((props) => ({
+ position: 'absolute',
+ width: 2,
+ height: 2,
+ borderRadius: 1,
+ backgroundColor: 'currentColor',
+ '&.MuiSlider-markActive': {
+ backgroundColor: props.theme.palette.background.paper,
+ opacity: 0.8,
},
- '& .MuiSlider-markLabel': {
- ...props.theme.typography.body2,
- color: props.theme.palette.text.secondary,
- position: 'absolute',
- top: 26,
- transform: 'translateX(-50%)',
- whiteSpace: 'nowrap',
+}));
+
+export const SliderMarkLabel = experimentalStyled(
+ 'span',
+ {},
+ { muiName: 'MuiSlider-markLabel' },
+)((props) => ({
+ ...props.theme.typography.body2,
+ color: props.theme.palette.text.secondary,
+ position: 'absolute',
+ top: 26,
+ transform: 'translateX(-50%)',
+ whiteSpace: 'nowrap',
+ ...(props.styleProps.orientation === 'vertical' && {
+ top: 'auto',
+ left: 26,
+ transform: 'translateY(50%)',
+ }),
+ '@media (pointer: coarse)': {
+ top: 40,
...(props.styleProps.orientation === 'vertical' && {
- top: 'auto',
- left: 26,
- transform: 'translateY(50%)',
+ left: 31,
}),
- '@media (pointer: coarse)': {
- top: 40,
- ...(props.styleProps.orientation === 'vertical' && {
- top: 'auto',
- left: 31,
- }),
- },
- '&.MuiSlider-markLabelActive': {
- color: props.theme.palette.text.primary,
- },
+ },
+ '&.MuiSlider-markLabelActive': {
+ color: props.theme.palette.text.primary,
},
}));
+SliderRoot.propTypes = {
+ // ----------------------------- Warning --------------------------------
+ // | These PropTypes are generated from the TypeScript type definitions |
+ // | To update them edit the d.ts file and run "yarn proptypes" |
+ // ----------------------------------------------------------------------
+ /**
+ * @ignore
+ */
+ children: PropTypes.node,
+ /**
+ * @ignore
+ */
+ styleProps: PropTypes.shape({
+ 'aria-label': PropTypes.string,
+ 'aria-labelledby': PropTypes.string,
+ 'aria-valuetext': PropTypes.string,
+ classes: PropTypes.object,
+ color: PropTypes.oneOf(['primary', 'secondary']),
+ defaultValue: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.number), PropTypes.number]),
+ disabled: PropTypes.bool,
+ getAriaLabel: PropTypes.func,
+ getAriaValueText: PropTypes.func,
+ isRtl: PropTypes.bool,
+ marks: PropTypes.oneOfType([
+ PropTypes.arrayOf(
+ PropTypes.shape({
+ label: PropTypes.node,
+ value: PropTypes.number.isRequired,
+ }),
+ ),
+ PropTypes.bool,
+ ]),
+ max: PropTypes.number,
+ min: PropTypes.number,
+ name: PropTypes.string,
+ onChange: PropTypes.func,
+ onChangeCommitted: PropTypes.func,
+ orientation: PropTypes.oneOf(['horizontal', 'vertical']),
+ scale: PropTypes.func,
+ step: PropTypes.number,
+ track: PropTypes.oneOf(['inverted', 'normal', false]),
+ value: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.number), PropTypes.number]),
+ valueLabelDisplay: PropTypes.oneOf(['auto', 'off', 'on']),
+ valueLabelFormat: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
+ }),
+};
+
const Slider = React.forwardRef(function Slider(inputProps, ref) {
const props = useThemeProps({ props: inputProps, name: 'MuiSlider' });
const { components = {}, ...other } = props;
@@ -273,7 +348,12 @@ const Slider = React.forwardRef(function Slider(inputProps, ref) {
{...other}
components={{
Root: SliderRoot,
- ValueLabel: SliderValueLabelUnstyled,
+ Rail: SliderRail,
+ Track: SliderTrack,
+ Thumb: SliderThumb,
+ ValueLabel: SliderValueLabel,
+ Mark: SliderMark,
+ MarkLabel: SliderMarkLabel,
...components,
}}
ref={ref}
@@ -322,6 +402,10 @@ Slider.propTypes = {
* @ignore
*/
children: PropTypes.node,
+ /**
+ * Override or extend the styles applied to the component.
+ */
+ classes: PropTypes.object,
/**
* The color of the component. It supports those theme colors that make sense for this component.
* @default 'primary'
diff --git a/packages/material-ui/src/Slider/index.js b/packages/material-ui/src/Slider/index.js
index 9898d6a85d1d01..006f966fe2404f 100644
--- a/packages/material-ui/src/Slider/index.js
+++ b/packages/material-ui/src/Slider/index.js
@@ -1 +1,2 @@
export { default } from './Slider';
+export * from './Slider';