HTML checkbox switches

I’ve been using Switchery in various sites to make nice looking checkboxes, however whilst browsing the projects GitHub issues I spotted one post that said it was possible to replicate it’s functionality using pure CSS (though possibly at the cost of browser compatibility).

This seems to work pretty nicely and I’ve added in some CSS for disabled checkboxes.

CSS

/* Switch */
.ios-switch-cb {
    display: none;
}

.switchery {
    background-color: #fff;
    border: 1px solid rgb(223, 223, 223);
    border-radius: 20px;
    cursor: pointer;
    display: inline-block;
    height: 30px;
    position: relative;
    vertical-align: middle;
    width: 50px;
    -moz-user-select: none;
    -khtml-user-select: none;
    -webkit-user-select: none;
    -ms-user-select: none;
    user-select: none;
    box-sizing: content-box;
    background-clip: content-box;
    box-shadow: rgb(223, 223, 223) 0px 0px 0px 0px inset;
    transition: border 0.4s, box-shadow 0.4s;
}

.switchery:before {
    content: '';
    background: #fff;
    border-radius: 50%;
    box-shadow: 0 1px 3px rgba(0,0,0,0.4);
    position: absolute;
    top: 0;
    left: 0;
    height: 30px;
    width: 30px;
    transition: background-color 0.4s, left 0.2s;
}

.ios-switch-cb:checked + .switchery {
    background-color: rgb(100, 189, 99);
    box-shadow: rgb(100, 189, 99) 0px 0px 0px 16px inset;
    transition: border 0.4s, box-shadow 0.4s, background-color 1.2s;
    border-color: rgb(100, 189, 99);
}

.ios-switch-cb:checked + input + .switchery {
    background-color: rgb(100, 189, 99);
    box-shadow: rgb(100, 189, 99) 0px 0px 0px 16px inset;
    transition: border 0.4s, box-shadow 0.4s, background-color 1.2s;
    border-color: rgb(100, 189, 99);
}

.ios-switch-cb:checked:disabled + .switchery {
    opacity: 0.75
}

.ios-switch-cb:checked:disabled + input + .switchery {
    opacity: 0.75
}

.ios-switch-cb:disabled:hover + .switchery {
    cursor: not-allowed;
}

.ios-switch-cb:disabled:hover + input + .switchery {
    cursor: not-allowed;
}

.ios-switch-cb:checked + .switchery:before {
    left: 20px;
}

.ios-switch-cb:checked + input + .switchery:before {
    left: 20px;
}

I’m using this in an ASP.NET Core web application in which a lot of the work for the form is done by tag helpers but this will work in plain HTML as well. I wanted these switches to be readonly as they’re just used for displaying data rather than editing it, though as some values are editable I wanted everything to be passed back in the POST on submit and as disabled fields aren’t returned on submit I’ve added some hidden fields to store the values.

The tag helper that inserts the checkbox HTML into your webpage also inserts a hidden input which is used for holding false values as otherwise these wouldn’t be passed through to the controller when the form is submitted. Unfortunately this is inserted between the ios-switch-cb input and the switchery span thus causing the checked CSS selector to fail to match, as a solution to this I’ve just specified that the CSS should also apply if there’s an input element in between the input and the span.

View


<form asp-controller="Treatment" asp-action="ControlPanel" method="post" class="form-label-left" data-toggle="validator" role="form">
	<fieldset>
		<div class="item form-group field">
			<div class="row">
				<div class="col-sm-2">
					<label asp-for="@Model.TreatmentId" class="control-label text-left"></label>
				</div>
				<div class="col-sm-10">
					<input asp-for="@Model.TreatmentId" class="form-control" readonly="readonly" />
				</div>
			</div>
		</div>
		<div class="item form-group field">
			<div class="row">
				<div class="col-sm-2">
					<label asp-for="@Model.IsActive" class="control-label text-left"></label>
				</div>
				<div class="col-sm-10">
					<label>
						<input asp-for="@Model.IsActive" class="ios-switch-cb" disabled="disabled" />
						<span class="switchery"></span>
					</label>
					<input asp-for="@Model.IsActive" type="hidden" />
				</div>
			</div>
		</div>
		<div class="form-group">
			<div class="col-xs-12">
				<div class="col-sm-offset-2">
					<button type="submit"class="btn btn-info">Update</button>
					<a asp-area="" asp-controller="Treatment" asp-action="ControlPanel" asp-route-id="@Model.TreatmentId" class="btn btn-warning" role="button">Cancel</a>
				</div>
			</div>
		</div>
	</fieldset>
</form>

3 Comments

Julio · 26th February 2019 at 4:32 pm

your code does not work.

Code in .NET

Code Render in HTML

the problem is the input between ios-switch-cb and the span. If I delete x html the hidden, if it works.

    Shinigami · 26th February 2019 at 4:58 pm

    Strange, it definitely worked for me when I originally used it, possibly it’s a version issue with Bootstrap or .NET. Next time I use this in a project I’ll update the post if I encounter any issues.

Leave a Reply

Your email address will not be published. Required fields are marked *


Fatal error: Uncaught GuzzleHttp\Exception\ClientException: Client error: `POST https://dc.services.visualstudio.com/v2/track` resulted in a `400 Invalid instrumentation key` response: {"itemsReceived":1,"itemsAccepted":0,"errors":[{"index":0,"statusCode":400,"message":"Invalid instrumentation key"}]} in D:\home\site\wwwroot\wp-content\plugins\application-insights\vendor\guzzlehttp\guzzle\src\Exception\RequestException.php:113 Stack trace: #0 D:\home\site\wwwroot\wp-content\plugins\application-insights\vendor\guzzlehttp\guzzle\src\Middleware.php(66): GuzzleHttp\Exception\RequestException::create(Object(GuzzleHttp\Psr7\Request), Object(GuzzleHttp\Psr7\Response)) #1 D:\home\site\wwwroot\wp-content\plugins\application-insights\vendor\guzzlehttp\promises\src\Promise.php(203): GuzzleHttp\Middleware::GuzzleHttp\{closure}(Object(GuzzleHttp\Psr7\Response)) #2 D:\home\site\wwwroot\wp-content\plugins\application-insights\vendor\guzzlehttp\promises\src\Promise.php(156): GuzzleHttp\Promise\Promise::callHandler(1, Object(GuzzleHttp\P in D:\home\site\wwwroot\wp-content\plugins\application-insights\vendor\guzzlehttp\guzzle\src\Exception\RequestException.php on line 113