Skip to content

Instantly share code, notes, and snippets.

@Temzasse
Last active March 13, 2017 12:27
Show Gist options
  • Save Temzasse/f01d268c75b81ffcd31b8bc182ce9751 to your computer and use it in GitHub Desktop.
Save Temzasse/f01d268c75b81ffcd31b8bc182ce9751 to your computer and use it in GitHub Desktop.
iOS styled toggle switch UI component with labels
import React, { PropTypes, Component } from 'react';
import styled from 'styled-components';
// Styled components
const ToggleSwitchWrapper = styled.div`
display: flex;
flex-direction: column;
position: relative;
`;
const Toggle = styled.div`
display: flex;
align-items: center;
overflow: hidden;
position: relative;
transform: translate3d(0, 0, 0);
background-color: ${props => props.bgClear};
height: ${props => (props.width / 2)}px;
width: ${props => props.width}px;
border-radius: ${props => props.width / 4}px;
padding: ${props => props.padding}px;
border: 1px solid ${props => props.toggled ?
props.bgToggled :
props.borderColor
};
`;
const ToggleBall = styled.div`
z-index: 2;
border-radius: 50%;
box-shadow: 0px 0px 3px rgba(0,0,0,0.2);
transition: transform 0.3s cubic-bezier(1,.19,.15,.7);
transition-delay: 0.1s;
will-change: transform;
background-color: ${props => props.ballColor};
border: 1px solid ${props => props.borderColor};
height: ${props => (props.width / 2) - (props.padding * 2)}px;
width: ${props => (props.width / 2) - (props.padding * 2)}px;
transform: ${props => props.toggled ?
`translateX(${props.width - (props.width / 2)}px)` :
'translateX(0px)'
};
&:active {
background-color: ${props => props.ballColorActive};
}
`;
const RippleBg = styled.div`
width: 100%;
height: 100%;
top: 0;
left: 0;
background-image: radial-gradient(
circle, ${props => props.bgToggled} 10%, transparent 10.01%
);
background-repeat: no-repeat;
background-position: 50%;
pointer-events: none;
transition: transform 0.5s, opacity 0.3s ease;
transform: ${props => props.visible ? 'scale(10, 10)' : 'scale(0, 0)'};
opacity: ${props => props.visible ? 1 : 0};
position: absolute;
z-index: 1;
`;
const InnerLabel = styled.span`
font-size: ${props => props.size}px;
color: ${props => props.color};
position: absolute;
z-index: 2;
${props => props.left && 'left: 10px;'};
${props => props.right && 'right: 10px;'};
`;
const OuterLabel = styled.span`
font-size: ${props => props.size}px;
color: ${props => props.color};
position: absolute;
top: 0px;
transform: translateY(-110%);
width: 100%;
text-align: center;
`;
const propTypes = {
innerLabelLeft: PropTypes.string,
innerLabelRight: PropTypes.string,
innerLabelColor: PropTypes.string,
innerLabelSize: PropTypes.string,
outerLabel: PropTypes.string,
outerLabelColor: PropTypes.string,
outerLabelSize: PropTypes.string,
initial: PropTypes.bool,
onToggle: PropTypes.func.isRequired,
width: PropTypes.number.isRequired,
padding: PropTypes.number.isRequired,
ballColor: PropTypes.string.isRequired,
ballColorActive: PropTypes.string.isRequired,
bgToggled: PropTypes.string.isRequired,
bgClear: PropTypes.string.isRequired,
borderColor: PropTypes.string.isRequired,
};
class ToggleSwitch extends Component {
constructor(props) {
super(props);
this.toggle = this.toggle.bind(this);
this.state = {
toggled: props.initial || false,
};
}
toggle() {
// Update local state first and then call toggle handler
this.setState(state => ({ toggled: !state.toggled }),
() => this.props.onToggle(this.state.toggled)
);
}
render() {
return (
<ToggleSwitchWrapper>
{this.props.outerLabel &&
<OuterLabel
size={this.props.outerLabelSize}
color={this.props.outerLabelColor}
>
{this.props.outerLabel}
</OuterLabel>
}
<Toggle
onClick={this.toggle}
toggled={this.state.toggled}
{...this.props}
>
<ToggleBall
toggled={this.state.toggled}
{...this.props}
/>
<RippleBg
visible={this.state.toggled}
{...this.props}
/>
{this.props.innerLabelLeft &&
<InnerLabel
left
size={this.props.innerLabelSize}
color={this.props.innerLabelColor}
>
{this.props.innerLabelLeft}
</InnerLabel>
}
{this.props.innerLabelRight &&
<InnerLabel
right
size={this.props.innerLabelSize}
color={this.props.innerLabelColor}
>
{this.props.innerLabelRight}
</InnerLabel>
}
</Toggle>
</ToggleSwitchWrapper>
);
}
}
ToggleSwitch.propTypes = propTypes;
const green = '#22e222';
const lightGrey = '#f5f5f5';
const grey = '#ddd';
const white = '#fff';
const black = '#222';
oggleSwitch.defaultProps = {
initial: false,
width: 80,
padding: 3,
ballColor: white,
ballColorActive: lightGrey,
bgToggled: green,
bgClear: white,
borderColor: grey,
innerLabelSize: 12,
innerLabelColor: black,
outerLabelSize: 16,
outerLabelColor: black,
};
export default ToggleSwitch;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment