Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Bootstrap Switch Laravel Package

nostalgiaz/bootstrap-switch

Bootstrap Switch turns checkboxes and radio buttons into attractive, customizable toggle switches for Bootstrap. This Composer package bundles the plugin assets for easy integration into Laravel and PHP projects, with support for sizes, colors, labels, and events.

Deep Wiki
Context7

Getting Started

nostalgiaz/bootstrap-switch is not a Composer package — there is nothing to composer require. It is a jQuery plugin that replaces the visual rendering of <input type="checkbox"> / <input type="radio"> with a Bootstrap-styled toggle. Your integration work happens in resources/js and Blade, not in app/.

1. Install the frontend assets

npm i bootstrap-switch jquery

2. Wire it up in resources/js/bootstrap.js (jQuery must be global before the plugin loads):

import $ from 'jquery';
window.$ = window.jQuery = $;

require('bootstrap-switch');
import 'bootstrap-switch/dist/css/bootstrap3/bootstrap-switch.css';

Then @vite(['resources/js/app.js']) in your layout. The CSS ships in dist/css/bootstrap3/ and dist/css/bootstrap2/ — pick the one matching your Bootstrap major, and load it after Bootstrap's own stylesheet.

First use case: a boolean column on an Eloquent model. Render a normal checkbox in Blade with the correct server-side state, then upgrade it in JS:

<input type="checkbox" name="is_active" id="is_active" value="1"
       @checked(old('is_active', $user->is_active))>
$('#is_active').bootstrapSwitch({
    size: 'small',
    onText: 'Active',
    offText: 'Inactive',
    onColor: 'success',
    offColor: 'default',
});

The original input stays in the DOM, so the form still submits is_active=1 natively and $request->boolean('is_active') behaves exactly as it did before. Nothing on the Laravel side needs to know the plugin exists.

Where to look first: the plugin's option list (state, size, onColor, offColor, onText, offText, labelText, animate, readonly, disabled, indeterminate, radioAllOff) and its event names (init, switchChange, sizeChange, animate, radioChange, all suffixed .bootstrapSwitch). The public API is a single method, $(el).bootstrapSwitch(command, ...args).

Implementation Patterns

Blade partial for a reusable switch field. Because state must be rendered server-side, keep a component instead of initialising with a JS state option (which would desync from old() on validation failure):

{{-- resources/views/components/switch.blade.php --}}
@props(['name', 'label', 'checked' => false])
<div class="form-group">
    <input type="checkbox" name="{{ $name }}" id="{{ $name }}" value="1"
           data-switch
           @checked(old($name, $checked))>
    <label for="{{ $name }}">{{ $label }}</label>
</div>

Bulk initialisation with per-element options via data attributes:

$('[data-switch]').each(function () {
    const $el = $(this);
    $el.bootstrapSwitch({
        size: $el.data('size') || 'small',
        onColor: $el.data('on-color') || 'primary',
        offColor: $el.data('off-color') || 'default',
    });
});

Syncing a switch to other UI. The switchChange.bootstrapSwitch event fires on the original input, so you can hook Alpine/Vue or enable/disable dependent fields:

$('#is_active').on('switchChange.bootstrapSwitch', function (e, state) {
    $('#expires_at').prop('disabled', !state);
});

Arguments are (event, state), where state is a real boolean — use it rather than re-reading the DOM.

Programmatic control (e.g. resetting a form after an AJAX save):

$('#is_active').bootstrapSwitch('state', true);        // fires switchChange
$('#is_active').bootstrapSwitch('state', true, true);  // silent (skipEvent)
$('#is_active').bootstrapSwitch('toggleState');
$('#is_active').bootstrapSwitch('readonly', true);

Radio groups. Give every radio the same name, initialise each, and pass radioAllOff: true if you need an "unset" state — otherwise one radio is always on and $request->input('plan') can never be null.

Livewire / Turbo / Inertia. The DOM can be morphed without a page load, leaving a switch rendered as a raw checkbox. Re-hydrate only un-initialised elements and, where the value is managed by the component, wrap the markup in wire:ignore:

document.addEventListener('livewire:init', () => {
    Livewire.hook('morph.updated', ({ el }) => {
        $(el).find('[data-switch]').each(function () {
            if (!$(this).data('bootstrapSwitch')) $(this).bootstrapSwitch();
        });
    });
});

Alpine:

<div x-data x-init="$nextTick(() => $refs.sw.bootstrapSwitch())">
    <input x-ref="sw" type="checkbox" name="notify" value="1">
</div>

Gotchas and Tips

Maintenance risk is the headline gotcha. Last release was February 2017 (v3.3.4), it pins against Bootstrap 3 markup and a global jQuery, and 5k stars don't change that. On a fresh Laravel + Bootstrap 5 app, use Bootstrap's native .form-switch markup and skip this entirely; adopt bootstrap-switch only where you already have a Bootstrap 3/4 + jQuery admin theme. Budget an exit path in your own Blade component so you can swap the renderer later.

jQuery is not defined / $(...).bootstrapSwitch is not a function. Almost always load order: the plugin's UMD build resolves jQuery at import time. Set window.$/window.jQuery in the same entry before requiring the plugin, and never let Vite code-split it ahead of jQuery.

Do not set the initial state with the state option. It silently overrides the checked attribute, which is exactly the attribute Blade's old()/@checked writes. Let the server render checked and only pass presentation options to JS. This is the single most common source of "the toggle flips back after a failed validation" bugs.

Setting state from JS before init. Initialise after the input is in the DOM and after you've set .prop('checked', ...) if you must do it client-side; the plugin reads the element at construction time.

state vs. setState. bootstrapSwitch('state', v) and ('setState', v) both fire switchChange by default. If you're listening to switchChange and calling setState in the handler, you'll build a feedback loop — pass the third skipEvent argument as true.

Browser required validation behaves badly. The real input is visually hidden, so Chrome's validation bubble anchors to a near-zero-size element and looks broken. Validate server-side with Form Requests and render errors next to the switch.

disabled means "not submitted". Same semantics as a native checkbox, but developers often reach for disabled when they mean "locked on" — use readonly (visual lock, still submits checked) instead, and add a hidden input if you need a guaranteed value.

indeterminate: true is a display-only tri-state; the underlying checkbox still submits only on/off. Don't map it to a nullable DB column without a hidden field.

Bootstrap 4/5 class drift. onColor/offColor map to Bootstrap 3's btn-primary / btn-default palette. On Bootstrap 4 default no longer exists — pass secondary or override .bootstrap-switch .bootstrap-switch-handle-off in your own CSS.

Cleanup on teardown. .bootstrapSwitch('destroy') restores the bare input but leaves any listeners you attached to the original element — remove them yourself, and re-init after destroy rather than stacking a second instance ($(el).data('bootstrapSwitch') tells you if one exists).

Debugging tip: inspect the wrapper div the plugin inserts (.bootstrap-switch) — if your form-group styling collapses, it's usually because the plugin's CSS didn't load, not because the JS failed.

Extension point: the plugin exposes global defaults you can set once in bootstrap.js and forget:

$.fn.bootstrapSwitch.defaults.size = 'small';
$.fn.bootstrapSwitch.defaults.onColor = 'success';
$.fn.bootstrapSwitch.defaults.offColor = 'secondary';
$.fn.bootstrapSwitch.defaults.animate = !window.matchMedia('(prefers-reduced-motion: reduce)').matches;
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect