Repository: mui/material-ui (TypeScript)
Date: 2020-06-07 19:12:48+00:00
Task type: Bug Fix

Issue:
[Checkbox][Radio] Icon font size override
<!-- Provide a general summary of the issue in the Title above -->
When using the `icon` and `checkedIcon` props for the `Checkbox` component, passing a custom `fontSize` doesn't change size of the icons.

This issue is also present in the Checkbox demos, where the Custom Size example is the same size as all the other examples.

<!--
  Thank you very much for contributing to Material-UI by creating an issue! ❤️
  To avoid duplicate issues we ask you to check off the following list.
-->

<!-- Checked checkbox should look like this: [x] -->

- [x] The issue is present in the latest release.
- [x] I have searched the [issues](https://github.com/mui-org/material-ui/issues) of this repository and believe that this is not a duplicate.

## Current Behavior 😯

<!-- Describe what happens instead of the expected behavior. -->
Passing a `fontSize` prop to the `icon` or `customIcon`  component does nothing.

```javascript
<Checkbox
  icon={<CheckBoxOutlineBlankIcon fontSize="small" />} // this doesn't do anything
  checkedIcon={<CheckBoxIcon fontSize="large" />} // neither does this
/>

// other props like color work as expected
<Checkbox
  icon={<CheckBoxOutlineBlankIcon color="secondary" />}
/>
```

## Expected Behavior 🤔

<!-- Describe what should happen. -->
Passing a valid `fontSize` prop to `icon` or `customIcon` should increase the size of the ` Icon`.

## Steps to Reproduce 🕹

<!--
  Provide a link to a live example (you can use codesandbox.io) and an unambiguous set of steps to reproduce this bug.
  Include code to reproduce, if relevant (which it most likely is).

  You should use the official codesandbox template as a starting point: https://material-ui.com/r/issue-template

  If you have an issue concerning TypeScript please start from this TypeScript playground: https://material-ui.com/r/ts-issue-template

  Issues without some form of live example have a longer response time.
-->
Steps:

1. Create a `Checkbox` component
2. Pass a custom component to `icon` or `checkedIcon` props
3. Add a custom `fontSize`
4. See nothing happen

### Links
Sandbox with error reproduced: https://codesandbox.io/s/checkbox-issue-demo-ksr7k

Documentation section with the same error: https://material-ui.com/components/checkboxes/#checkbox-with-formcontrollabel



## Context 🔦

<!--
  What are you trying to accomplish? How has this issue affected you?
  Providing context helps us come up with a solution that is most useful in the real world.
-->
I want to be able to customize the size of my Checkboxes. Note that other props like `color` are not overridden in the same manner.

A somewhat similar issue is currently open regarding `Input` size props:
https://github.com/mui-org/material-ui/issues/19796

## Your Environment 🌎

<!--
  Include as many relevant details about the environment with which you experienced the bug.
  If you encounter issues with typescript please include version and tsconfig.
-->

| Tech        | Version |
| ----------- | ------- |
| Material-UI | v4.10.1 |
| React       | 16.13.1 |
| Browser     | Chrome version 83.0.4103.61 (64 bit) |



Issue discussion:
@samuelcolburn Thanks for reporting the issue. It comes from the usage of cloneElement that forces a value. It affects the Radio component too. What do you think of this fix?

```diff
diff --git a/packages/material-ui/src/Checkbox/Checkbox.js b/packages/material-ui/src/Checkbox/Checkbox.js
index 7916091ab..6d28ca15c 100644
--- a/packages/material-ui/src/Checkbox/Checkbox.js
+++ b/packages/material-ui/src/Checkbox/Checkbox.js
@@ -64,14 +64,17 @@ const Checkbox = React.forwardRef(function Checkbox(props, ref) {
     checkedIcon = defaultCheckedIcon,
     classes,
     color = 'secondary',
-    icon = defaultIcon,
+    icon: iconProp = defaultIcon,
     indeterminate = false,
-    indeterminateIcon = defaultIndeterminateIcon,
+    indeterminateIcon: indeterminateIconProp = defaultIndeterminateIcon,
     inputProps,
     size = 'medium',
     ...other
   } = props;

+  const icon = indeterminate ? indeterminateIconProp : iconProp;
+  const indeterminateIcon = indeterminate ? indeterminateIconProp : checkedIcon;
+
   return (
     <SwitchBase
       type="checkbox"
@@ -87,11 +90,11 @@ const Checkbox = React.forwardRef(function Checkbox(props, ref) {
         'data-indeterminate': indeterminate,
         ...inputProps,
       }}
-      icon={React.cloneElement(indeterminate ? indeterminateIcon : icon, {
-        fontSize: size === 'small' ? 'small' : 'default',
+      icon={React.cloneElement(icon, {
+        fontSize: icon.props.fontSize === undefined && size !== 'medium' ? size : icon.props.fontSize,
       })}
-      checkedIcon={React.cloneElement(indeterminate ? indeterminateIcon : checkedIcon, {
-        fontSize: size === 'small' ? 'small' : 'default',
+      checkedIcon={React.cloneElement(indeterminateIcon, {
+        fontSize: indeterminateIcon.props.fontSize === undefined && size !== 'medium' ? size : indeterminateIcon.props.fontSize
       })}
       ref={ref}
       {...other}
@@ -171,7 +174,7 @@ Checkbox.propTypes = {
    * The size of the checkbox.
    * `small` is equivalent to the dense checkbox styling.
    */
-  size: PropTypes.oneOf(['medium', 'small']),
+  size: PropTypes.oneOf(['large', 'medium', 'small']),
   /**
    * The value of the component. The DOM API casts this to a string.
    * The browser uses "on" as the default value.
```

It's a start. Do you want to work on a pull request? :)
@oliviertassinari I wish to work on this as my first issue if it is not taken by someone else already, thanks.
@kn1ves Awesome, it's all yours. Note that the above fix isn't meant to be the final solution, but a proof of concept, they will be a couple of rough edges to polish :).

Solution patch:
diff --git a/packages/material-ui/src/Checkbox/Checkbox.js b/packages/material-ui/src/Checkbox/Checkbox.js
--- a/packages/material-ui/src/Checkbox/Checkbox.js
+++ b/packages/material-ui/src/Checkbox/Checkbox.js
@@ -64,14 +64,17 @@ const Checkbox = React.forwardRef(function Checkbox(props, ref) {
     checkedIcon = defaultCheckedIcon,
     classes,
     color = 'secondary',
-    icon = defaultIcon,
+    icon: iconProp = defaultIcon,
     indeterminate = false,
-    indeterminateIcon = defaultIndeterminateIcon,
+    indeterminateIcon: indeterminateIconProp = defaultIndeterminateIcon,
     inputProps,
     size = 'medium',
     ...other
   } = props;
 
+  const icon = indeterminate ? indeterminateIconProp : iconProp;
+  const indeterminateIcon = indeterminate ? indeterminateIconProp : checkedIcon;
+
   return (
     <SwitchBase
       type="checkbox"
@@ -87,11 +90,15 @@ const Checkbox = React.forwardRef(function Checkbox(props, ref) {
         'data-indeterminate': indeterminate,
         ...inputProps,
       }}
-      icon={React.cloneElement(indeterminate ? indeterminateIcon : icon, {
-        fontSize: size === 'small' ? 'small' : 'default',
+      icon={React.cloneElement(icon, {
+        fontSize:
+          icon.props.fontSize === undefined && size !== 'medium' ? size : icon.props.fontSize,
       })}
-      checkedIcon={React.cloneElement(indeterminate ? indeterminateIcon : checkedIcon, {
-        fontSize: size === 'small' ? 'small' : 'default',
+      checkedIcon={React.cloneElement(indeterminateIcon, {
+        fontSize:
+          indeterminateIcon.props.fontSize === undefined && size !== 'medium'
+            ? size
+            : indeterminateIcon.props.fontSize,
       })}
       ref={ref}
       {...other}


Test patch:
diff --git a/packages/material-ui/src/Checkbox/Checkbox.test.js b/packages/material-ui/src/Checkbox/Checkbox.test.js
--- a/packages/material-ui/src/Checkbox/Checkbox.test.js
+++ b/packages/material-ui/src/Checkbox/Checkbox.test.js
@@ -115,4 +115,20 @@ describe('<Checkbox />', () => {
       });
     });
   });
+
+  it('should allow custom icon font sizes', () => {
+    const fontSizeSpy = spy();
+    const MyIcon = (props) => {
+      const { fontSize, ...other } = props;
+
+      React.useEffect(() => {
+        fontSizeSpy(fontSize);
+      });
+
+      return <div {...other} />;
+    };
+    render(<Checkbox icon={<MyIcon fontSize="foo" />} />);
+
+    expect(fontSizeSpy.args[0][0]).to.equal('foo');
+  });
 });