To offer a simple toggle switch, mirroring the same attributes as other form controls. Using attributes such as value, disabled to offer a drop in control for configuring something off or on. Bootstraped from a bootstrap file, by importing into a bigger application or direct as html script (ensure you build fallback for IE support).
<my-switch></my-switch>
<!-- Polyfill -->
<script src="/node_modules/promise-polyfill/dist/polyfill.min.js"></script>
<script src="/node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js"></script>
<!-- Bootstrap component only, ensure you have built fallback for IE support too (.js)! -->
<script type="module" src="./your/path/my-switch.mjs"></script>
<script nomodule src="./your/path/my-switch.js"></script>
<!-- Or add your switch import to a bootstrap js file/app using ES6 import and use that instead of the component directly... -->
<script type="module" src="./your/path/index.mjs"></script>
<script nomodule src="./your/path/index.js"></script>
<!-- example basic fouc resolution -->
<style>
[fouc] { opacity: 0; transition: opacity 200ms ease-in-out; }
[fouc="loaded"] { opacity: 1; }
</style>
...
<div class="info">
<div class="class">
<div class="row" fouc>
<div class="col-sm-4">
<my-switch></my-switch>
</div>
<div class="col-sm-4">
<my-switch value="1"></my-switch>
</div>
<div class="col-sm-4">
<my-switch value="1" disabled></my-switch>
</div>
</div>
</div>
</div>
...
<!-- fouc for individual components -->
<script> setTimeout(() => document.querySelector('[fouc]').setAttribute('fouc', 'loaded'), 1000); </script>
import { CustomHTMLElement, html } from '../../../node_modules/custom-web-component/index.js';
/**
* @public @name MySwitch
* @extends CustomHTMLElement
* @description Library web component putting a sliding switch on teh screen
*/
class MySwitch extends CustomHTMLElement {
/**
* @public @constructor @name constructor
* @description Triggered when component is instantiated (but not ready or in DOM, must call super() first)
*/
constructor() {
super();
this.value;
}
/**
* @public @static @name template
* @description Template function to return web component UI
* @return {TemplateResult} HTML template result
*/
static template() {
return html`
<style>
:host {
display: inline-block;
width: 100%;
height: 62px;
box-sizing: border-box;
}
.control-switch {
display: block;
width: inherit;
height: inherit;
text-align: var(--my-switch--text-align, left);
}
.control-switch [invisible] {
opacity: 0;
}
.control-switch label {
display: block;
height: 20px;
font-size: 14px;
flex: 1 1;
text-align: var(--my-switch--label--text-align, left);
color: var(--my-switch--label--color, #111);
font-weight: var(--my-switch--label--font-weight, normal);
}
.control-switch .switch-box {
display: inline-block;
position: relative;
margin: 1px;
width: 80px;
height: 30px;
border-radius: var(--my-switch--border-radius, 0px);
border: var(--my-switch--border, 1px solid black);
box-sizing: border-box;
}
.control-switch .switch-box .switch-blob {
display: block;
position: absolute;
left: 1px;
top: 1px;
height: 26px;
width: 36px;
color: var(--my-switch--color, white);
background: var(--my-switch--background, #222);
border-radius: var(--my-switch--border-radius, 0px);
text-align: center;
font-size: 12px;
line-height: 26px;
cursor: default;
transition: left 0.1s ease-in-out;
}
.control-switch .switch-box .switch-blob[on] {
left: 41px;
}
:host(:hover) .control-switch .switch-box .switch-blob {
background: var(--my-switch--background--hover, black);
}
:host([justify="center"]) .control-switch {
text-align: center;
}
:host([justify="right"]) .control-switch {
text-align: right;
}
:host([disabled]) .control-switch .switch-box {
pointer-events: none;
cursor: not-allowed;
opacity: var(--my-switch--disabled--opacity, 0.6);
}
</style>
<div class="control-switch">
<label ?invisible="${!this.hasAttribute('label')}">${this.getAttribute('label')}</label>
<div class="switch-box" @click="${this._changeEvent.bind(this)}">
<div class="switch-blob" ?on="${this.value}">${this.value ? 'ON' : 'OFF'}</div>
</div>
</div>
`;
}
/**
* @public @static @get @name observedProperties
* @description Provide properties to watch for changes
* @return {Array} Array of property names as strings
*/
static get observedProperties() { return ['value'] }
/**
* @public @name propertyChanged
* @description Callback run when a custom elements properties change
* @param {String} property The property name
* @param {Mixed} oldValue The old value
* @param {Mixed} newValue The new value
*/
propertyChanged(property, oldValue, newValue) { this.updateTemplate() }
/**
* @public @static @get @name observedAttributes
* @description Provide attributes to watch for changes
* @return {Array} Array of attribute names as strings
*/
static get observedAttributes() { return ['disabled', 'label'] }
/**
* @public @name attributeChanged
* @description Callback run when a custom elements attributes change
* @param {String} attribute The attribute name
* @param {Mixed} oldValue The old value
* @param {Mixed} newValue The new value
*/
attributeChanged(attribute, oldValue, newValue) { this.updateTemplate() }
/**
* @public @name constructed
* @description Lifecycle hook that gets called when the element is finished contructing, perfect for setting up
properties
*/
constructed() { this.value = this.hasAttribute('value') ? true : this.value }
/**
* @private @name _event
* @description Detect an event, update a property and dispatch an event
* @param {Event} ev Any event that kicks the function
*/
_changeEvent(ev) {
if (this.hasAttribute('disabled')) return;
this.value = !this.value;
this.dispatchEvent(new CustomEvent('change', { detail: this.value }));
}
}
// bootstrap the class as a new web component
customElements.define('my-switch', MySwitch);