<body>
<link href="https://fonts.googleapis.com/css?family=Antic+Slab" rel="stylesheet">
<style>
*,
*:before,
*:after {
box-sizing: inherit;
}
body {
font-family: 'Antic Slab', serif;
}
hr {
width: 100%;
}
/*
toggle styles copied and modified from
https://codepen.io/mallendeo/pen/eLIiG
by Mauricio Allende (https://mallendeo.com/)
*/
.toggle-btn {
display: inline-block;
outline: 0;
width: 4em;
height: 2em;
position: relative;
cursor: pointer;
user-select: none;
background: #fbfbfb;
border-radius: 2em;
padding: 2px;
transition: all 0.4s ease;
border: 1px solid #e8eae9;
}
.toggle-btn:focus::after,
.toggle-btn:active::after {
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1),
0 4px 0 rgba(0, 0, 0, 0.08),
inset 0px 0px 0px 1.5px #9c9c9c;
}
.toggle-btn::after {
left: 0;
position: relative;
display: block;
content: '';
width: 50%;
height: 100%;
border-radius: 2em;
background: #fbfbfb;
transition: all 0.3s
cubic-bezier(0.175, 0.885, 0.32, 1.275),
padding 0.3s ease, margin 0.3s ease;
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.1),
0 4px 0 rgba(0, 0, 0, 0.08);
}
.toggle-btn.toggle-btn-on::after {
left: 50%;
}
.toggle-btn.toggle-btn-on {
background: #86d993;
}
.toggle-btn.toggle-btn-on:active {
box-shadow: none;
}
.toggle-btn.toggle-btn-on:active::after {
margin-left: -0.8em;
}
.toggle-btn:active::after {
padding-right: 0.8em;
}
.toggle-input {
display: none;
}
</style>
<script src="https://unpkg.com/react@16.0.0/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16.0.0/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/babel-standalone@6.26.0/babel.js"></script>
<div id="⚛️"></div>
<script type="text/babel">
function ToggleOn({on, children}) {
return on ? children : null
}
function ToggleOff({on, children}) {
return on ? null : children
}
function ToggleButton({on, toggle, ...props}) {
return (
<Switch on={on} onClick={toggle} {...props} />
)
}
class Toggle extends React.Component {
static On = ToggleOn
static Off = ToggleOff
static Button = ToggleButton
static defaultProps = {onToggle: () => {}}
state = {on: false}
toggle = () =>
this.setState(
({on}) => ({on: !on}),
() => this.props.onToggle(this.state.on),
)
render() {
const children = React.Children.map(
this.props.children,
child =>
React.cloneElement(child, {
on: this.state.on,
toggle: this.toggle,
}),
)
return <div>{children}</div>
}
}
function App() {
return (
<Toggle
onToggle={on => console.log('toggle', on)}
>
<Toggle.On>The button is on</Toggle.On>
<Toggle.Off>The button is off</Toggle.Off>
<Toggle.Button />
</Toggle>
)
}
/*
*
*
* Below here are irrelevant
* implementation details...
*
*
*/
function Switch({on, className = '', ...props}) {
return (
<div className="toggle">
<input
className="toggle-input"
type="checkbox"
/>
<button
className={`${className} toggle-btn ${on
? 'toggle-btn-on'
: 'toggle-btn-off'}`}
aria-expanded={on}
{...props}
/>
</div>
)
}
ReactDOM.render(
<div
style={{
marginTop: 40,
display: 'flex',
justifyContent: 'center',
flexDirection: 'column',
textAlign: 'center',
}}
>
<App />
</div>,
document.getElementById('⚛️'),
)
</script>
</body>