diff --git a/docs/src/examples/components/Checkbox/States/CheckboxExampleIndeterminate.shorthand.tsx b/docs/src/examples/components/Checkbox/States/CheckboxExampleIndeterminate.shorthand.tsx
new file mode 100644
index 0000000000..a0724a3572
--- /dev/null
+++ b/docs/src/examples/components/Checkbox/States/CheckboxExampleIndeterminate.shorthand.tsx
@@ -0,0 +1,12 @@
+import { Checkbox } from '@fluentui/react'
+import * as React from 'react'
+
+const CheckboxExampleIndeterminate = () => {
+ return (
+ <>
+
+ >
+ )
+}
+
+export default CheckboxExampleIndeterminate
diff --git a/docs/src/examples/components/Checkbox/States/index.tsx b/docs/src/examples/components/Checkbox/States/index.tsx
index bcc90bd532..239c950fd9 100644
--- a/docs/src/examples/components/Checkbox/States/index.tsx
+++ b/docs/src/examples/components/Checkbox/States/index.tsx
@@ -15,6 +15,11 @@ const States = () => (
description="A checkbox can be read-only and unable to change states."
examplePath="components/Checkbox/States/CheckboxExampleDisabled"
/>
+
)
diff --git a/packages/accessibility/src/behaviors/Checkbox/checkboxBehavior.ts b/packages/accessibility/src/behaviors/Checkbox/checkboxBehavior.ts
index c19a674928..7cc3e5f493 100644
--- a/packages/accessibility/src/behaviors/Checkbox/checkboxBehavior.ts
+++ b/packages/accessibility/src/behaviors/Checkbox/checkboxBehavior.ts
@@ -13,7 +13,7 @@ import { IS_FOCUSABLE_ATTRIBUTE } from '../../attributes'
const checkboxBehavior: Accessibility = props => ({
attributes: {
root: {
- 'aria-checked': !!props.checked,
+ 'aria-checked': props.indeterminate ? 'mixed' : props.checked ? 'true' : 'false',
'aria-disabled': props.disabled,
role: 'checkbox',
tabIndex: 0,
@@ -36,4 +36,6 @@ type CheckboxBehaviorProps = {
checked: boolean
/** If the checkbox is in disabled state. */
disabled?: boolean
+ /** If the checkbox is in indetermiante state. */
+ indeterminate?: boolean
}
diff --git a/packages/react/src/components/Checkbox/Checkbox.tsx b/packages/react/src/components/Checkbox/Checkbox.tsx
index 8ae819f263..fe52d9ba1d 100644
--- a/packages/react/src/components/Checkbox/Checkbox.tsx
+++ b/packages/react/src/components/Checkbox/Checkbox.tsx
@@ -33,6 +33,12 @@ export interface CheckboxProps extends UIComponentProps, ChildrenComponentProps
/** A checkbox's checked state can be controlled. */
checked?: SupportedIntrinsicInputProps['checked']
+ /** A checkbox can be indetermiante by default - uncontrolled state. */
+ defaultIndeterminate?: SupportedIntrinsicInputProps['defaultIndeterminate']
+
+ /** A checkbox's indeterminate state can be controlled. */
+ indeterminate?: SupportedIntrinsicInputProps['indeterminate']
+
/** A checkbox can appear disabled and be unable to change states. */
disabled?: SupportedIntrinsicInputProps['disabled']
@@ -65,6 +71,7 @@ export interface CheckboxProps extends UIComponentProps, ChildrenComponentProps
export interface CheckboxState {
checked: CheckboxProps['checked']
+ indeterminate: CheckboxProps['indeterminate']
}
class Checkbox extends AutoControlledComponent, CheckboxState> {
@@ -82,8 +89,10 @@ class Checkbox extends AutoControlledComponent, Checkb
}),
checked: PropTypes.bool,
defaultChecked: PropTypes.bool,
+ defaultIndeterminate: PropTypes.bool,
disabled: PropTypes.bool,
icon: customPropTypes.itemShorthandWithoutJSX,
+ indeterminate: PropTypes.bool,
label: customPropTypes.itemShorthand,
labelPosition: PropTypes.oneOf(['start', 'end']),
onChange: PropTypes.func,
@@ -107,30 +116,42 @@ class Checkbox extends AutoControlledComponent, Checkb
}
getInitialAutoControlledState(): CheckboxState {
- return { checked: false }
+ return { checked: false, indeterminate: false }
}
handleChange = (e: React.ChangeEvent) => {
// Checkbox component doesn't present any `input` component in markup, however all of our
// components should handle events transparently.
- const { disabled } = this.props
+ const { disabled, indeterminate } = this.props
const checked = !this.state.checked
if (!disabled) {
- this.setState({ checked })
- _.invoke(this.props, 'onChange', e, { ...this.props, checked })
+ this.setState({ checked, indeterminate })
+ _.invoke(this.props, 'onChange', e, {
+ ...this.props,
+ checked,
+ indetermiante: !this.state.indeterminate,
+ })
}
}
handleClick = (e: React.MouseEvent | React.KeyboardEvent) => {
- const { disabled } = this.props
+ const { disabled, indeterminate } = this.props
const checked = !this.state.checked
if (!disabled) {
- this.setState({ checked })
-
- _.invoke(this.props, 'onClick', e, { ...this.props, checked })
- _.invoke(this.props, 'onChange', e, { ...this.props, checked })
+ this.setState({ checked, indeterminate })
+
+ _.invoke(this.props, 'onClick', e, {
+ ...this.props,
+ checked,
+ indetermiante: !this.state.indeterminate,
+ })
+ _.invoke(this.props, 'onChange', e, {
+ ...this.props,
+ checked,
+ indetermiante: !this.state.indeterminate,
+ })
}
}
@@ -164,7 +185,11 @@ class Checkbox extends AutoControlledComponent, Checkb
outline: toggle && !this.state.checked,
size: toggle ? 'medium' : 'smaller',
className: Checkbox.slotClassNames.indicator,
- name: toggle ? 'icon-circle' : 'icon-checkmark',
+ name: toggle
+ ? 'icon-circle'
+ : this.state.indeterminate
+ ? 'icon-square'
+ : 'icon-checkmark',
styles: toggle ? styles.toggle : styles.checkbox,
}),
})}
diff --git a/packages/react/src/themes/teams/components/Checkbox/checkboxStyles.ts b/packages/react/src/themes/teams/components/Checkbox/checkboxStyles.ts
index 55249efc44..165a9ce349 100644
--- a/packages/react/src/themes/teams/components/Checkbox/checkboxStyles.ts
+++ b/packages/react/src/themes/teams/components/Checkbox/checkboxStyles.ts
@@ -84,6 +84,13 @@ const checkboxStyles: ComponentSlotStylesPrepared<
background: v.disabledBackgroundChecked,
borderColor: 'transparent',
}),
+
+ // TODO: in the case of indeterminate, set icon-square
+ // to be smaller on all sides inside the larger input box.
+ // ...(p.indeterminate && {
+ // boxSizing: 'border-box',
+ // flexShrink: 0,
+ // }),
}),
toggle: ({ props: p, variables: v }): ICSSInJSStyle => ({
diff --git a/packages/react/src/themes/teams/components/Checkbox/checkboxVariables.ts b/packages/react/src/themes/teams/components/Checkbox/checkboxVariables.ts
index d1c9342c8d..da0456b8a5 100644
--- a/packages/react/src/themes/teams/components/Checkbox/checkboxVariables.ts
+++ b/packages/react/src/themes/teams/components/Checkbox/checkboxVariables.ts
@@ -122,4 +122,5 @@ export default (siteVars: any): CheckboxVariables => ({
'colorScheme.default.foregroundDisabled',
defaultValue,
),
+ // TODO: add variables for indeterminate state.
})
diff --git a/packages/react/src/utils/htmlPropsUtils.tsx b/packages/react/src/utils/htmlPropsUtils.tsx
index 432d7d43e5..1740821320 100644
--- a/packages/react/src/utils/htmlPropsUtils.tsx
+++ b/packages/react/src/utils/htmlPropsUtils.tsx
@@ -55,9 +55,11 @@ export type HtmlInputAttrs =
| 'autoCorrect'
| 'autoFocus'
| 'checked'
+ | 'defaultIndeterminate'
| 'disabled'
| 'form'
| 'id'
+ | 'indeterminate'
| 'list'
| 'max'
| 'maxLength'
@@ -92,9 +94,11 @@ export const htmlInputAttrs: HtmlInputAttrs[] = [
'autoCorrect',
'autoFocus',
'checked',
+ 'defaultIndeterminate',
'disabled',
'form',
'id',
+ 'indeterminate',
'list',
'max',
'maxLength',