diff --git a/CHANGELOG.md b/CHANGELOG.md
index b352718ccdb..d1ca4c54673 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,7 @@
## [`master`](https://github.com/elastic/eui/tree/master)
-No public interface changes since `13.3.0`.
+- Fixed `EuiSwitch` semantics to align with aria roles ([#2193](https://github.com/elastic/eui/pull/2193))
+- Removed Firefox's focus ring to match other browsers ([#2193](https://github.com/elastic/eui/pull/2193))
## [`13.3.0`](https://github.com/elastic/eui/tree/v13.3.0)
diff --git a/src-docs/src/views/form_controls/switch.js b/src-docs/src/views/form_controls/switch.js
index 2d8f061679c..f465980af56 100644
--- a/src-docs/src/views/form_controls/switch.js
+++ b/src-docs/src/views/form_controls/switch.js
@@ -11,9 +11,9 @@ export default class extends Component {
};
}
- onChange = e => {
+ onChange = () => {
this.setState({
- checked: e.target.checked,
+ checked: !this.state.checked,
});
};
diff --git a/src/components/form/_variables.scss b/src/components/form/_variables.scss
index eae29dabd11..e8bc6ece33a 100644
--- a/src/components/form/_variables.scss
+++ b/src/components/form/_variables.scss
@@ -21,4 +21,5 @@ $euiFormBorderDisabledColor: transparentize($euiColorFullShade, .92) !default;
$euiFormCustomControlDisabledIconColor: shadeOrTint($euiColorMediumShade, 38%, 48.5%) !default; // exact 508c foreground for $euiColorLightShade
$euiFormControlDisabledColor: $euiColorMediumShade !default;
$euiFormControlBoxShadow: 0 1px 1px -1px transparentize($euiShadowColor, .8), 0 3px 2px -2px transparentize($euiShadowColor, .8);
-$euiFormInputGroupLabelBackground: shadeOrTint($euiFormBackgroundDisabledColor, 0, 3%);
\ No newline at end of file
+$euiFormInputGroupLabelBackground: shadeOrTint($euiFormBackgroundDisabledColor, 0, 3%);
+$euiSwitchOffColor: lightOrDarkTheme(transparentize($euiColorMediumShade, .8), transparentize($euiColorMediumShade, .3));
diff --git a/src/components/form/switch/__snapshots__/switch.test.js.snap b/src/components/form/switch/__snapshots__/switch.test.js.snap
index 7d5d582e468..642f2dce792 100644
--- a/src/components/form/switch/__snapshots__/switch.test.js.snap
+++ b/src/components/form/switch/__snapshots__/switch.test.js.snap
@@ -4,38 +4,43 @@ exports[`EuiSwitch assigns automatically generated ID to label 1`] = `
-
-
-
-
-
+
+
+
+
-
+
+
`;
@@ -43,39 +48,44 @@ exports[`EuiSwitch is rendered 1`] = `
-
-
-
-
-
+
+
+
+
-
+
+
`;
diff --git a/src/components/form/switch/_switch.scss b/src/components/form/switch/_switch.scss
index cea8270aa94..a143b66ffee 100644
--- a/src/components/form/switch/_switch.scss
+++ b/src/components/form/switch/_switch.scss
@@ -4,30 +4,63 @@
min-height: $euiSwitchHeight;
.euiSwitch__label {
+ cursor: pointer;
padding-left: $euiSizeS;
line-height: $euiSwitchHeight;
font-size: $euiFontSizeS;
vertical-align: middle;
}
- /**
- * 1. The input is "hidden" but still focusable.
- * 2. Make sure it's still hidden when [disabled].
- */
- .euiSwitch__input,
- .euiSwitch__input[disabled] /* 2 */ {
- position: absolute;
- opacity: 0; /* 1 */
- width: 100%;
- height: 100%;
- cursor: pointer;
- }
-
- .euiSwitch__input:focus + .euiSwitch__body {
+ .euiSwitch__button {
+ line-height: 0; // ensures button takes height of switch inside
- .euiSwitch__thumb {
+ &:focus .euiSwitch__thumb {
@include euiCustomControlFocused;
}
+
+ &:disabled {
+ &:hover,
+ ~ .euiSwitch__label:hover {
+ cursor: not-allowed;
+ }
+
+ .euiSwitch__body {
+ background-color: $euiSwitchOffColor;
+ }
+
+ .euiSwitch__thumb {
+ @include euiCustomControlDisabled;
+ background-color: $euiSwitchOffColor;
+ }
+
+ .euiSwitch__icon {
+ fill: $euiFormCustomControlDisabledIconColor;
+ }
+
+ + .euiSwitch__label {
+ color: $euiFormControlDisabledColor;
+ }
+ }
+
+ &[aria-checked='false'] {
+ .euiSwitch__body {
+ background-color: $euiSwitchOffColor;
+ }
+
+ // When input is not checked, we shift around the positioning of the thumb and the icon
+ .euiSwitch__thumb { // move the thumb left
+ left: 0;
+ }
+
+ .euiSwitch__icon { // move the icon right
+ right: -$euiSizeS;
+
+ &.euiSwitch__icon--checked {
+ right: auto;
+ left: -($euiSwitchWidth - ($euiSwitchThumbSize / 2));
+ }
+ }
+ }
}
.euiSwitch__body {
@@ -77,64 +110,13 @@
fill: $euiColorEmptyShade;
}
- /**
- * The thumb is slightly scaled when in use, unless it's disabled.
- */
- &:hover {
- .euiSwitch__input:not(:disabled) ~ .euiSwitch__body {
- .euiSwitch__thumb {
- transform: scale(1.05);
- }
+ &:hover .euiSwitch__button {
+ &:not(:disabled) .euiSwitch__thumb {
+ transform: scale(1.05);
}
- }
- &:active {
- .euiSwitch__thumb {
+ &:active .euiSwitch__thumb {
transform: scale(.95);
}
}
-
- .euiSwitch__input:disabled:hover {
- cursor: not-allowed;
- }
-
- .euiSwitch__input:disabled ~ .euiSwitch__body,
- .euiSwitch__input:checked:disabled ~ .euiSwitch__body {
- background-color: lightOrDarkTheme(transparentize($euiColorMediumShade, .8), transparentize($euiColorMediumShade, .3));
-
- .euiSwitch__thumb {
- @include euiCustomControlDisabled;
- background-color: lightOrDarkTheme(transparentize($euiColorMediumShade, .8), transparentize($euiColorMediumShade, .3));
- }
-
- .euiSwitch__icon {
- fill: $euiFormCustomControlDisabledIconColor;
- }
-
- + label {
- color: $euiFormControlDisabledColor;
- }
- }
-
- .euiSwitch__input:not(:checked):not(:disabled) ~ .euiSwitch__body {
- background-color: lightOrDarkTheme(transparentize($euiColorMediumShade, .8), transparentize($euiColorMediumShade, .3));
- }
-
- /**
- * When input is not checked, we shift around the positioning of sibling/child selectors.
- */
- .euiSwitch__input:not(:checked) ~ .euiSwitch__body {
- .euiSwitch__thumb {
- left: 0;
- }
-
- .euiSwitch__icon {
- right: -$euiSizeS;
-
- &.euiSwitch__icon--checked {
- right: auto;
- left: -($euiSwitchWidth - ($euiSwitchThumbSize / 2));
- }
- }
- }
}
diff --git a/src/components/form/switch/index.d.ts b/src/components/form/switch/index.d.ts
index caaea6c1bdc..8bd9f11e8c4 100644
--- a/src/components/form/switch/index.d.ts
+++ b/src/components/form/switch/index.d.ts
@@ -1,14 +1,20 @@
import { CommonProps } from '../../common';
-import { FunctionComponent, InputHTMLAttributes, ReactNode } from 'react';
+import { FunctionComponent, ButtonHTMLAttributes, ReactNode } from 'react';
declare module '@elastic/eui' {
/**
* @see './switch.js'
*/
export type EuiSwitchProps = CommonProps &
- InputHTMLAttributes & {
- label?: ReactNode;
+ ButtonHTMLAttributes & {
+ label: ReactNode;
+ checked: boolean;
+ onChange: (
+ event: React.FormEvent
+ ) => void;
+ disabled?: boolean;
+ compressed?: boolean;
};
export const EuiSwitch: FunctionComponent;
diff --git a/src/components/form/switch/switch.js b/src/components/form/switch/switch.js
index ab16f30bcaa..3395b8a97be 100644
--- a/src/components/form/switch/switch.js
+++ b/src/components/form/switch/switch.js
@@ -15,6 +15,11 @@ export class EuiSwitch extends Component {
};
}
+ onClick = e => {
+ e.target.checked = !this.props.checked;
+ this.props.onChange(e);
+ };
+
render() {
const {
label,
@@ -40,35 +45,31 @@ export class EuiSwitch extends Component {
return (
-
-
-
-
-
-
+ onClick={this.onClick}
+ {...rest}>
+
+
+
+
-
+
+
-
+
- {label && (
-
- )}
+
);
}
diff --git a/src/global_styling/reset/_reset.scss b/src/global_styling/reset/_reset.scss
index 0824f6a834e..26d7b809ea5 100644
--- a/src/global_styling/reset/_reset.scss
+++ b/src/global_styling/reset/_reset.scss
@@ -71,6 +71,11 @@ body {
*:focus {
outline: none;
+
+ // sass-lint:disable no-vendor-prefixes
+ &::-moz-focus-inner {
+ border: none;
+ }
}
a {
@@ -136,4 +141,4 @@ hr {
fieldset {
min-inline-size: auto;
-}
\ No newline at end of file
+}