diff --git a/src/components/Switch/Switch.stories.tsx b/src/components/Switch/Switch.stories.tsx
new file mode 100644
index 00000000..422be6aa
--- /dev/null
+++ b/src/components/Switch/Switch.stories.tsx
@@ -0,0 +1,66 @@
+import React from 'react';
+import { action } from '@storybook/addon-actions';
+import Switch from './Switch';
+
+export default {
+ title: 'Switch',
+ component: Switch,
+};
+
+export const DefaultSwitch = () => (
+
+
+
+
+
+);
+
+export const DiffTypeSwitch = () => (
+
+
+
+
+
+);
+
+export const DiffSizeSwitch = () => (
+
+
+
+
+);
diff --git a/src/components/Switch/Switch.test.tsx b/src/components/Switch/Switch.test.tsx
new file mode 100644
index 00000000..dfd157b7
--- /dev/null
+++ b/src/components/Switch/Switch.test.tsx
@@ -0,0 +1,110 @@
+import React from 'react';
+
+import { render, fireEvent } from '@testing-library/react';
+import Switch, { patSwitchProps } from './Switch';
+
+describe('Switch', () => {
+ it('should match snapshot', () => {
+ const { asFragment } = render();
+ expect(asFragment()).toMatchSnapshot();
+ });
+
+ it('should render default switch', () => {
+ const switchProps = {
+ onClick: jest.fn(),
+ };
+ const wrapper = render();
+
+ // for switch-wrapper
+ const switch_wrapper = wrapper.queryByTestId(
+ 'switch-wrapper'
+ ) as HTMLElement;
+ expect(switch_wrapper).toBeInTheDocument();
+ expect(switch_wrapper.tagName).toBe('DIV');
+ expect(switch_wrapper).toHaveClass(
+ 'switch-wrapper switch-default switch-medium'
+ );
+
+ // for input checkbox
+ const input_checkbox = wrapper.queryByTestId(
+ 'switch-input'
+ ) as HTMLInputElement;
+ expect(input_checkbox).toBeInTheDocument();
+ expect(input_checkbox.tagName).toBe('INPUT');
+ expect(input_checkbox.type).toBe('checkbox');
+ expect(input_checkbox).toBeEnabled();
+ expect(input_checkbox.checked).toBe(false);
+
+ // for track
+ const track = wrapper.queryByTestId('switch-track') as HTMLElement;
+ expect(track).toBeInTheDocument();
+ expect(track.tagName).toBe('SPAN');
+ expect(track).toHaveClass('switch__slider');
+
+ // for label
+ const label = wrapper.queryByText('Default Switch') as HTMLElement;
+ expect(label).toBeInTheDocument();
+ expect(label.tagName).toBe('LABEL');
+ expect(label).toHaveClass('switch__text');
+
+ expect(switchProps.onClick).toHaveBeenCalledTimes(0);
+ fireEvent.click(label);
+ expect(switchProps.onClick).toHaveBeenCalledTimes(1);
+ expect(input_checkbox.checked).toBe(true);
+ fireEvent.click(wrapper.queryByTestId('switch') as HTMLElement);
+ expect(switchProps.onClick).toHaveBeenCalledTimes(2);
+ expect(input_checkbox.checked).toBe(false);
+ });
+
+ it('should render diff size & type switch', () => {
+ const switchProps: patSwitchProps = {
+ switchSize: 'small',
+ switchType: 'primary',
+ onClick: jest.fn(),
+ checked: true,
+ color: "#FFA500",
+ };
+ const wrapper = render();
+
+ // for switch-wrapper
+ const switch_wrapper = wrapper.queryByTestId(
+ 'switch-wrapper'
+ ) as HTMLElement;
+ expect(switch_wrapper).toBeInTheDocument();
+ expect(switch_wrapper.tagName).toBe('DIV');
+ expect(switch_wrapper).toHaveClass(
+ 'switch-wrapper switch-primary switch-small'
+ );
+
+ // for input checkbox
+ const input_checkbox = wrapper.queryByTestId(
+ 'switch-input'
+ ) as HTMLInputElement;
+ expect(input_checkbox).toBeInTheDocument();
+ expect(input_checkbox.tagName).toBe('INPUT');
+ expect(input_checkbox.type).toBe('checkbox');
+ expect(input_checkbox).toBeEnabled();
+ expect(input_checkbox.checked).toBe(true);
+
+ // for track
+ const track = wrapper.queryByTestId('switch-track') as HTMLElement;
+ expect(track).toBeInTheDocument();
+ expect(track.tagName).toBe('SPAN');
+ expect(track).toHaveClass('switch__slider');
+ expect(track).toHaveStyle('background-color: #FFA500');
+
+ // for label
+ const label = wrapper.queryByText('Default Switch') as HTMLElement;
+ expect(label).toBeInTheDocument();
+ expect(label.tagName).toBe('LABEL');
+ expect(label).toHaveClass('switch__text');
+
+ expect(switchProps.onClick).toHaveBeenCalledTimes(0);
+ fireEvent.click(label);
+ expect(switchProps.onClick).toHaveBeenCalledTimes(1);
+ expect(input_checkbox.checked).toBe(false);
+ fireEvent.click(wrapper.queryByTestId('switch') as HTMLElement);
+ expect(switchProps.onClick).toHaveBeenCalledTimes(2);
+ expect(input_checkbox.checked).toBe(true);
+ });
+});
diff --git a/src/components/Switch/Switch.tsx b/src/components/Switch/Switch.tsx
new file mode 100644
index 00000000..1f2906a1
--- /dev/null
+++ b/src/components/Switch/Switch.tsx
@@ -0,0 +1,92 @@
+import React, {
+ ButtonHTMLAttributes,
+ AnchorHTMLAttributes,
+ FC,
+ MouseEvent,
+} from 'react';
+import { classNames } from '../../utils/classNames';
+
+export interface ISwitchProps {
+ /** Indicate if the button is disabled*/
+ disabled?: boolean;
+
+ /** Inital State of the Switch */
+ checked?: boolean;
+
+ /** Text to put besides Switch */
+ label?: string;
+
+ /** Type of Switch */
+ switchType?: 'default' | 'primary' | 'secondary';
+
+ /** Size of Switch */
+ switchSize?: 'medium' | 'small';
+
+ /** set action on switch toggled */
+ onClick?: (arg0: object) => void;
+
+ /** Pass Customed Color*/
+ color?: string;
+}
+
+export type patSwitchProps = ISwitchProps;
+
+/**
+ * A Switch provides a toggle checkbox.
+ *
+ * ```js
+ * import {Switch} from 'pat-ui'
+ * ```
+ */
+export const Switch: FC = (props) => {
+ const [checked, setChecked] = React.useState(props.checked || false);
+
+ const switch_classes = classNames('switch-wrapper', {
+ [`switch-${props.switchType || 'default'}`]: true,
+ [`switch-${props.switchSize || 'medium'}`]: true,
+ [`switch-color-custum`]: props.color ? true : false,
+ disabled: props.disabled || false,
+ });
+
+ return (
+ {
+ if (props.onClick) {
+ props.onClick(event);
+ }
+
+ if (!props.disabled) {
+ setChecked((e) => !e);
+ }
+ }}
+ data-testid="switch-wrapper"
+ >
+
+ null}
+ data-testid="switch-input"
+ />
+
+
+
+
+ );
+};
+
+Switch.defaultProps = {
+ checked: false,
+ disabled: false,
+ switchType: 'default',
+ switchSize: 'medium',
+};
+
+export default Switch;
diff --git a/src/components/Switch/_Switch.scss b/src/components/Switch/_Switch.scss
new file mode 100644
index 00000000..8bed978b
--- /dev/null
+++ b/src/components/Switch/_Switch.scss
@@ -0,0 +1,296 @@
+/* Variables For Switch */
+
+//Switch
+$sw-transition-time: 0.3s;
+$sw-thumb-shadow: 0px 1px 3px 0px rgba(0, 0, 0, 0.12),
+ 0px 1px 1px 0px rgba(0, 0, 0, 0.14), 0px 2px 1px 0px rgba(0, 0, 0, 0.2);
+
+//Switch Label
+$sw-font-weight-normal: $font-weight-normal;
+$sw-font-family: $font-family-base !default;
+$sw-font-size: $font-size-base !default;
+$sw-line-height: $line-height-base !default;
+
+//Switch track
+$sw-track-width: 34px;
+$sw-track-height: 14px;
+$sw-track-padding: 12px;
+$sw-track-width-small: 26px;
+$sw-track-height-small: 10px;
+$sw-track-padding-small: 7px;
+$sw-track-color-default-off: rgba(0, 0, 0, 0.3799999952316284);
+$sw-track-color-default-on: rgba(0, 0, 0, 0.5);
+$sw-track-color-disabled: rgba(0, 0, 0, 0.12);
+$sw-track-color-primary-off: rgba(0, 0, 0, 0.3799999952316284);
+$sw-track-color-primary-on: rgba(63, 81, 181, 0.5);
+$sw-track-color-secondary-off: rgba(0, 0, 0, 0.3799999952316284);
+$sw-track-color-secondary-on: rgba(245, 0, 87, 0.5);
+
+//Switch Thumb
+$sw-thumb-diameter: 20px;
+$sw-thumb-diameter-small: 16px;
+$sw-thumb-color-default-off: #fafafa;
+$sw-thumb-color-default-on: #fafafa;
+$sw-thumb-color-disabled: #bdbdbd;
+$sw-thumb-color-primary-off: #fafafa;
+$sw-thumb-color-primary-on: #3f51b5;
+$sw-thumb-color-secondary-off: #fafafa;
+$sw-thumb-color-secondary-on: #f50057;
+
+@mixin switch-style(
+ $track-width,
+ $track-height,
+ $track-padding,
+ $thumb-diameter,
+ $transition-time,
+ $thumb-shadow,
+ $track-color-off,
+ $track-color-on,
+ $thumb-color-off,
+ $thumb-color-on
+) {
+
+ display: inline-flex;
+ align-items: center;
+ box-sizing: content-box;
+ padding: 0;
+ margin: 0;
+ cursor: pointer;
+
+ /* The Label - Text besides the Switch*/
+ .switch__text {
+ font-size: $sw-font-size;
+ font-family: $sw-font-family;
+ font-style: normal;
+ font-weight: $sw-font-weight-normal;
+ line-height: $sw-line-height;
+ margin: 0;
+ cursor: inherit;
+ }
+
+ /* The switch - the wrapper around the slider */
+ .switch {
+ width: $track-width;
+ height: $track-height;
+ padding: $track-padding;
+ position: relative;
+ display: inline-block;
+ box-sizing: content-box;
+ margin: 0;
+
+ /* Hide default HTML checkbox */
+ input {
+ opacity: 0;
+ width: 0;
+ height: 0;
+ }
+
+ /* The Track of the switch */
+ .switch__slider {
+ position: absolute;
+ top: $track-padding;
+ left: $track-padding;
+ right: $track-padding;
+ bottom: $track-padding;
+ background-color: $track-color-off;
+ border-radius: $track-height/2;
+ }
+
+ /* Thumb of the Switch */
+ .switch__slider:before {
+ position: absolute;
+ content: '';
+ height: $thumb-diameter;
+ width: $thumb-diameter;
+ left: $track-width/2 - $thumb-diameter;
+ bottom: ($track-height - $thumb-diameter)/2;
+ background-color: $thumb-color-on;
+ transition: $transition-time;
+ border-radius: $thumb-diameter/2;
+
+ /* shadow-1 */
+ box-shadow: $thumb-shadow;
+ }
+
+ input:checked + .switch__slider {
+ background-color: $track-color-on;
+ }
+
+ input:checked + .switch__slider::before {
+ transform: translateX($thumb-diameter);
+ background-color: $thumb-color-on;
+ }
+ }
+
+ .switch:hover .switch__slider::before {
+ box-shadow: $thumb-shadow,
+ 0px 0px 0px ($track-height/2 + $track-padding - $thumb-diameter/2)
+ color-mix(in srgb, currentColor 8%, transparent);
+ }
+
+ // .switch:hover {
+ // .switch__slider::before {
+ // box-shadow: $thumb-shadow,
+ // 0px 0px 0px ($track-height/2 + $track-padding - $thumb-diameter/2)
+ // color-mix(in srgb, currentColor 8%, transparent);
+ // }
+ // }
+
+}
+
+/** Syle Just for changing color */
+@mixin switch-style-color(
+ $track-color-off,
+ $track-color-on,
+ $thumb-color-off,
+ $thumb-color-on
+) {
+ /* The switch - the wrapper around the slider */
+ .switch {
+ /* The Track of the switch */
+ .switch__slider {
+ background-color: $track-color-off;
+ }
+
+ /* Thumb of the Switch */
+ .switch__slider:before {
+ background-color: $thumb-color-off;
+ }
+
+ input:checked + .switch__slider {
+ background-color: $track-color-on;
+ }
+
+ input:checked + .switch__slider::before {
+ background-color: $thumb-color-on;
+ }
+ }
+}
+
+/** Style for changing size and thumb shadow*/
+@mixin switch-style-size(
+ $track-width,
+ $track-height,
+ $track-padding,
+ $thumb-diameter,
+ $thumb-shadow
+) {
+ /* The switch - the wrapper around the slider */
+ .switch {
+ width: $track-width;
+ height: $track-height;
+ padding: $track-padding;
+
+ /* The Track of the switch */
+ .switch__slider {
+ top: $track-padding;
+ left: $track-padding;
+ right: $track-padding;
+ bottom: $track-padding;
+ border-radius: $track-height/2;
+ }
+
+ /* Thumb of the Switch */
+ .switch__slider::before {
+ height: $thumb-diameter;
+ width: $thumb-diameter;
+ left: $track-width/2 - $thumb-diameter;
+ bottom: ($track-height - $thumb-diameter)/2;
+ border-radius: $thumb-diameter/2;
+
+ /* shadow-1 */
+ box-shadow: $thumb-shadow;
+ }
+
+ input:checked + .switch__slider::before {
+ transform: translateX($thumb-diameter);
+ }
+
+ }
+
+ :hover .switch__slider::before {
+ box-shadow: $thumb-shadow,
+ 0px 0px 0px ($track-height/2 + $track-padding - $thumb-diameter/2)
+ color-mix(in srgb, currentColor 8%, transparent);
+ }
+
+}
+
+/** Default style */
+.switch-wrapper {
+ @include switch-style(
+ $sw-track-width,
+ $sw-track-height,
+ $sw-track-padding,
+ $sw-thumb-diameter,
+ $sw-transition-time,
+ $sw-thumb-shadow,
+ $sw-track-color-default-off,
+ $sw-track-color-default-on,
+ $sw-thumb-color-default-off,
+ $sw-thumb-color-default-on
+ );
+}
+
+// Diff Switch Type
+.switch-primary {
+ @include switch-style-color(
+ $sw-track-color-primary-off,
+ $sw-track-color-primary-on,
+ $sw-thumb-color-primary-off,
+ $sw-thumb-color-primary-on
+ );
+}
+
+.switch-secondary {
+ @include switch-style-color(
+ $sw-track-color-secondary-off,
+ $sw-track-color-secondary-on,
+ $sw-thumb-color-secondary-off,
+ $sw-thumb-color-secondary-on
+ );
+}
+
+// Diff Switch Size
+.switch-small {
+ @include switch-style-size(
+ $sw-track-width-small,
+ $sw-track-height-small,
+ $sw-track-padding-small,
+ $sw-thumb-diameter-small,
+ $sw-thumb-shadow
+ )
+}
+
+// If disabled
+.disabled {
+ @include switch-style-color(
+ $sw-track-color-disabled,
+ $sw-track-color-disabled,
+ $sw-thumb-color-disabled,
+ $sw-thumb-color-disabled
+ );
+
+ // Cancel Hover shadow
+ :hover .switch__slider::before {
+ box-shadow: $sw-thumb-shadow;
+ }
+
+ cursor: not-allowed;
+}
+
+// If color customed
+.switch-color-custum {
+ .switch {
+ /* Thumb of the Switch */
+ .switch__slider:before {
+ opacity: 100%;
+ background-color: inherit;
+ }
+
+ input:checked + .switch__slider::before {
+ opacity: 100%;
+ background-color: inherit;
+ }
+ }
+}
diff --git a/src/components/Switch/__snapshots__/Switch.test.tsx.snap b/src/components/Switch/__snapshots__/Switch.test.tsx.snap
new file mode 100644
index 00000000..348dbde6
--- /dev/null
+++ b/src/components/Switch/__snapshots__/Switch.test.tsx.snap
@@ -0,0 +1,28 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Switch should match snapshot 1`] = `
+
+
+
+`;
diff --git a/src/components/Switch/index.tsx b/src/components/Switch/index.tsx
new file mode 100644
index 00000000..b03db7f5
--- /dev/null
+++ b/src/components/Switch/index.tsx
@@ -0,0 +1 @@
+export {default} from './Switch';
diff --git a/src/index.tsx b/src/index.tsx
index 70aeb63c..ba5d50b6 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -5,3 +5,4 @@ export { default as Message } from './components/Message';
export { default as Card } from './components/Card';
export { default as Dropdown } from './components/Dropdown';
export { default as Progress } from './components/Progress';
+export { default as Switch } from './components/Switch';
diff --git a/src/styles/index.scss b/src/styles/index.scss
index 33fa969f..00fa3910 100644
--- a/src/styles/index.scss
+++ b/src/styles/index.scss
@@ -12,3 +12,6 @@
@import '../components/Input/Input';
@import '../components/Card/Card';
@import '../components/Progress/Progress';
+
+//Switch
+@import '../components/Switch/Switch';