Skip to content

Commit e92232b

Browse files
sai6855siriwatknp
andauthored
[material-ui][Chip] Add slots and slotProps (#46098)
Signed-off-by: sai chand <[email protected]> Co-authored-by: Siriwat K <[email protected]>
1 parent a619144 commit e92232b

File tree

5 files changed

+139
-35
lines changed

5 files changed

+139
-35
lines changed

docs/pages/material-ui/api/chip.json

Lines changed: 25 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,17 @@
2525
"default": "'medium'"
2626
},
2727
"skipFocusWhenDisabled": { "type": { "name": "bool" }, "default": "false" },
28+
"slotProps": {
29+
"type": {
30+
"name": "shape",
31+
"description": "{ label?: func<br>&#124;&nbsp;object, root?: func<br>&#124;&nbsp;object }"
32+
},
33+
"default": "{}"
34+
},
35+
"slots": {
36+
"type": { "name": "shape", "description": "{ label?: elementType, root?: elementType }" },
37+
"default": "{}"
38+
},
2839
"sx": {
2940
"type": {
3041
"name": "union",
@@ -42,6 +53,20 @@
4253
},
4354
"name": "Chip",
4455
"imports": ["import Chip from '@mui/material/Chip';", "import { Chip } from '@mui/material';"],
56+
"slots": [
57+
{
58+
"name": "root",
59+
"description": "The component that renders the root.",
60+
"default": "div",
61+
"class": "MuiChip-root"
62+
},
63+
{
64+
"name": "label",
65+
"description": "The component that renders the label.",
66+
"default": "span",
67+
"class": "MuiChip-label"
68+
}
69+
],
4570
"classes": [
4671
{
4772
"key": "avatar",
@@ -287,12 +312,6 @@
287312
"isGlobal": false,
288313
"isDeprecated": true
289314
},
290-
{
291-
"key": "label",
292-
"className": "MuiChip-label",
293-
"description": "Styles applied to the label `span` element.",
294-
"isGlobal": false
295-
},
296315
{
297316
"key": "labelMedium",
298317
"className": "MuiChip-labelMedium",
@@ -327,12 +346,6 @@
327346
"isGlobal": false,
328347
"isDeprecated": true
329348
},
330-
{
331-
"key": "root",
332-
"className": "MuiChip-root",
333-
"description": "Styles applied to the root element.",
334-
"isGlobal": false
335-
},
336349
{
337350
"key": "sizeMedium",
338351
"className": "MuiChip-sizeMedium",

docs/translations/api-docs/chip/chip.json

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
"skipFocusWhenDisabled": {
2929
"description": "If <code>true</code>, allows the disabled chip to escape focus. If <code>false</code>, allows the disabled chip to receive focus."
3030
},
31+
"slotProps": { "description": "The props used for each slot inside." },
32+
"slots": { "description": "The components used for each slot inside." },
3133
"sx": {
3234
"description": "The system prop that allows defining system overrides as well as additional CSS styles."
3335
},
@@ -235,10 +237,6 @@
235237
"conditions": "<code>size=\"small\"</code>",
236238
"deprecationInfo": "Combine the <a href=\"/material-ui/api/chip/#chip-classes-icon\">.MuiChip-icon</a> and <a href=\"/material-ui/api/chip/#chip-classes-sizeSmall\">.MuiChip-sizeSmall</a> classes instead. See <a href=\"/material-ui/migration/migrating-from-deprecated-apis/\">Migrating from deprecated APIs</a> for more details."
237239
},
238-
"label": {
239-
"description": "Styles applied to {{nodeName}}.",
240-
"nodeName": "the label <code>span</code> element"
241-
},
242240
"labelMedium": {
243241
"description": "Styles applied to {{nodeName}} if {{conditions}}.",
244242
"nodeName": "the label <code>span</code> element",
@@ -268,7 +266,6 @@
268266
"conditions": "<code>variant=\"outlined\"</code> and <code>color=\"secondary\"</code>",
269267
"deprecationInfo": "Combine the <a href=\"/material-ui/api/chip/#chip-classes-outlined\">.MuiChip-outlined</a> and <a href=\"/material-ui/api/chip/#chip-classes-colorSecondary\">.MuiChip-colorSecondary</a> classes instead. See <a href=\"/material-ui/migration/migrating-from-deprecated-apis/\">Migrating from deprecated APIs</a> for more details."
270268
},
271-
"root": { "description": "Styles applied to the root element." },
272269
"sizeMedium": {
273270
"description": "Styles applied to {{nodeName}} if {{conditions}}.",
274271
"nodeName": "the root element",
@@ -279,5 +276,9 @@
279276
"nodeName": "the root element",
280277
"conditions": "<code>size=\"small\"</code>"
281278
}
279+
},
280+
"slotDescriptions": {
281+
"label": "The component that renders the label.",
282+
"root": "The component that renders the root."
282283
}
283284
}

packages/mui-material/src/Chip/Chip.d.ts

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,42 @@
11
import * as React from 'react';
22
import { OverridableStringUnion } from '@mui/types';
33
import { SxProps } from '@mui/system';
4+
import { CreateSlotsAndSlotProps, SlotProps } from '..';
45
import { Theme } from '../styles';
56
import { OverridableComponent, OverrideProps } from '../OverridableComponent';
67
import { ChipClasses } from './chipClasses';
78

9+
export interface ChipSlots {
10+
/**
11+
* The component that renders the root.
12+
* @default div
13+
*/
14+
root: React.ElementType;
15+
/**
16+
* The component that renders the label.
17+
* @default span
18+
*/
19+
label: React.ElementType;
20+
}
21+
22+
export type ChipSlotsAndSlotProps = CreateSlotsAndSlotProps<
23+
ChipSlots,
24+
{
25+
/**
26+
* Props forwarded to the root slot.
27+
* By default, the avaible props are based on the div element.
28+
*/
29+
root: SlotProps<'div', {}, ChipOwnerState>;
30+
/**
31+
* Props forwarded to the label slot.
32+
* By default, the avaible props are based on the span element.
33+
*/
34+
label: SlotProps<'span', {}, ChipOwnerState>;
35+
}
36+
>;
37+
38+
export interface ChipOwnerState extends Omit<ChipProps, 'slots' | 'slotProps'> {}
39+
840
export interface ChipPropsVariantOverrides {}
941

1042
export interface ChipPropsSizeOverrides {}
@@ -96,7 +128,7 @@ export interface ChipTypeMap<
96128
AdditionalProps = {},
97129
RootComponent extends React.ElementType = 'div',
98130
> {
99-
props: AdditionalProps & ChipOwnProps;
131+
props: AdditionalProps & ChipOwnProps & ChipSlotsAndSlotProps;
100132
defaultComponent: RootComponent;
101133
}
102134

packages/mui-material/src/Chip/Chip.js

Lines changed: 67 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import memoTheme from '../utils/memoTheme';
1414
import createSimplePaletteValueFilter from '../utils/createSimplePaletteValueFilter';
1515
import { useDefaultProps } from '../DefaultPropsProvider';
1616
import chipClasses, { getChipUtilityClass } from './chipClasses';
17+
import useSlot from '../utils/useSlot';
1718

1819
const useUtilityClasses = (ownerState) => {
1920
const { classes, disabled, size, color, iconColor, onDelete, clickable, variant } = ownerState;
@@ -400,6 +401,8 @@ const Chip = React.forwardRef(function Chip(inProps, ref) {
400401
variant = 'filled',
401402
tabIndex,
402403
skipFocusWhenDisabled = false, // TODO v6: Rename to `focusableWhenDisabled`.
404+
slots = {},
405+
slotProps = {},
403406
...other
404407
} = props;
405408

@@ -503,26 +506,57 @@ const Chip = React.forwardRef(function Chip(inProps, ref) {
503506
}
504507
}
505508

509+
const externalForwardedProps = {
510+
slots,
511+
slotProps,
512+
};
513+
514+
const [RootSlot, rootProps] = useSlot('root', {
515+
elementType: ChipRoot,
516+
externalForwardedProps: {
517+
...externalForwardedProps,
518+
...other,
519+
},
520+
ownerState,
521+
// The `component` prop is preserved because `Chip` relies on it for internal logic. If `shouldForwardComponentProp` were `false`, `useSlot` would remove the `component` prop, potentially breaking the component's behavior.
522+
shouldForwardComponentProp: true,
523+
ref: handleRef,
524+
className: clsx(classes.root, className),
525+
additionalProps: {
526+
disabled: clickable && disabled ? true : undefined,
527+
tabIndex: skipFocusWhenDisabled && disabled ? -1 : tabIndex,
528+
...moreProps,
529+
},
530+
getSlotProps: (handlers) => ({
531+
...handlers,
532+
onClick: (event) => {
533+
handlers.onClick?.(event);
534+
onClick(event);
535+
},
536+
onKeyDown: (event) => {
537+
handlers.onKeyDown?.(event);
538+
handleKeyDown(event);
539+
},
540+
onKeyUp: (event) => {
541+
handlers.onKeyUp?.(event);
542+
handleKeyUp(event);
543+
},
544+
}),
545+
});
546+
547+
const [LabelSlot, labelProps] = useSlot('label', {
548+
elementType: ChipLabel,
549+
externalForwardedProps,
550+
ownerState,
551+
className: classes.label,
552+
});
553+
506554
return (
507-
<ChipRoot
508-
as={component}
509-
className={clsx(classes.root, className)}
510-
disabled={clickable && disabled ? true : undefined}
511-
onClick={onClick}
512-
onKeyDown={handleKeyDown}
513-
onKeyUp={handleKeyUp}
514-
ref={handleRef}
515-
tabIndex={skipFocusWhenDisabled && disabled ? -1 : tabIndex}
516-
ownerState={ownerState}
517-
{...moreProps}
518-
{...other}
519-
>
555+
<RootSlot as={component} {...rootProps}>
520556
{avatar || icon}
521-
<ChipLabel className={classes.label} ownerState={ownerState}>
522-
{label}
523-
</ChipLabel>
557+
<LabelSlot {...labelProps}>{label}</LabelSlot>
524558
{deleteIcon}
525-
</ChipRoot>
559+
</RootSlot>
526560
);
527561
});
528562

@@ -620,6 +654,22 @@ Chip.propTypes /* remove-proptypes */ = {
620654
* @default false
621655
*/
622656
skipFocusWhenDisabled: PropTypes.bool,
657+
/**
658+
* The props used for each slot inside.
659+
* @default {}
660+
*/
661+
slotProps: PropTypes.shape({
662+
label: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
663+
root: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
664+
}),
665+
/**
666+
* The components used for each slot inside.
667+
* @default {}
668+
*/
669+
slots: PropTypes.shape({
670+
label: PropTypes.elementType,
671+
root: PropTypes.elementType,
672+
}),
623673
/**
624674
* The system prop that allows defining system overrides as well as additional CSS styles.
625675
*/

packages/mui-material/src/Chip/Chip.test.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ describe('<Chip />', () => {
3030
refInstanceof: window.HTMLDivElement,
3131
testComponentPropWith: 'span',
3232
skip: ['componentsProp'],
33+
slots: {
34+
root: {
35+
expectedClassName: classes.root,
36+
},
37+
label: {
38+
expectedClassName: classes.label,
39+
},
40+
},
3341
}));
3442

3543
describe('text only', () => {

0 commit comments

Comments
 (0)