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

Bulma Laravel Package

laravel-frontend-presets/bulma

A Laravel frontend preset that replaces the default scaffolding with Bulma, providing ready-made auth views, layouts, and styling so you can quickly build responsive Laravel applications using the Bulma CSS framework.

View on GitHub
Deep Wiki
Context7

Getting Started

Treat this as a starter kit you copy once, not a long-lived dependency — with one important update. v3.0.4 ("Fixed Preset Command dependency") addresses the single biggest problem in earlier releases: the package's PresetCommand previously leaned on framework wiring that disappeared when php artisan preset was removed in Laravel 7. The package now ships the command dependency itself, so php artisan preset bulma is expected to work on modern Laravel again.

Verify before trusting it — this is a one-line release note, not a changelog:

composer require laravel-frontend-presets/bulma:^3.0 --dev
php artisan list | grep -i preset   # should now show `preset`

Install (Laravel 5.5–6.x):

composer require laravel-frontend-presets/bulma --dev
php artisan preset bulma
npm install && npm run dev

Install (Laravel 7+, v3.0.4+):

composer require laravel-frontend-presets/bulma --dev
php artisan preset bulma
npm install && npm run dev

If the command still doesn't register (stale composer.lock, package discovery cache, or an older tag resolved), fall back to copying stubs:

php artisan vendor:publish --provider="LaravelFrontendPresets\BulmaPreset\BulmaPresetServiceProvider" 2>/dev/null
# or hand-copy from the repo's resources/ tree
npm install -D bulma sass

Then in resources/sass/app.scss (or resources/css/app.css on Vite-based apps):

@import 'bulma/bulma';

Where to look first after running the preset:

File What changed
webpack.mix.js Sass entry point, removed Bootstrap bootstrap.js bits
package.json bulma, sass, laravel-mix deps
resources/sass/app.scss @import '~bulma/bulma.sass' replaces Bootstrap
resources/views/layouts/app.blade.php Navbar + container markup
resources/views/auth/*.blade.php Login/register/passwords with field, control, input, button is-primary

First use case: scaffold auth, then restyle one CRUD screen. The preset no longer generates the make:auth wiring, so install laravel/ui first (php artisan ui:auth --views) or use Breeze, then let the preset replace the views. Convert your own index.blade.php to a table is-fullwidth is-striped with a Bulma pagination view. That single pass exercises every part of the preset you'll actually reuse.

Implementation Patterns

Theme via SCSS variables, not overrides

Bulma variables use !default, so override them before the import — the one-liner @import 'bulma/bulma' makes that impossible, so switch to the split import:

// resources/sass/app.scss
@import '~bulma/sass/utilities/_all';

$primary: #3d5afe;
$family-sans-serif: 'Inter', system-ui, sans-serif;
$navbar-item-hover-background-color: transparent;

@import '~bulma/bulma';

This is the single highest-value reason to keep the preset's Sass wiring.

Layout partials

Keep the generated layouts/app.blade.php but break out the chunks you'll edit constantly:

{{-- resources/views/layouts/app.blade.php --}}
<body>
  @include('layouts.partials.nav')
  <section class="section">
    <div class="container">
      @include('layouts.partials.flash')
      @yield('content')
    </div>
  </section>
</body>
{{-- resources/views/layouts/partials/flash.blade.php --}}
@foreach (['success' => 'is-success', 'error' => 'is-danger', 'warning' => 'is-warning'] as $key => $class)
  @if (session($key))
    <div class="notification {{ $class }}">
      <button class="delete" data-dismiss="notification"></button>
      {{ session($key) }}
    </div>
  @endif
@endforeach

Form fields as a Blade component

The preset gives you markup, not encapsulation. Wrap it once so validation styling is automatic:

{{-- resources/views/components/field.blade.php --}}
@props(['name', 'label' => null, 'type' => 'text'])

<div class="field">
  <label class="label" for="{{ $name }}">{{ $label ?? Str::headline($name) }}</label>
  <div class="control">
    <input
      id="{{ $name }}"
      name="{{ $name }}"
      type="{{ $type }}"
      class="input @error($name) is-danger @enderror"
      {{ $attributes->merge(['value' => old($name)]) }}>
  </div>
  @error($name)
    <p class="help is-danger">{{ $message }}</p>
  @enderror
</div>

Usage: <x-field name="email" type="email" />. This is the pattern that survives when the preset itself doesn't.

Pagination

Laravel's default paginator view is Tailwind (8+) or Bootstrap-flavoured. Point it at a Bulma view once in a service provider:

// app/Providers/AppServiceProvider.php
use Illuminate\Pagination\Paginator;

public function boot(): void
{
    Paginator::defaultView('vendor.pagination.bulma');
    Paginator::defaultSimpleView('vendor.pagination.bulma-simple');
}
{{-- resources/views/vendor/pagination/bulma.blade.php --}}
@if ($paginator->hasPages())
  <nav class="pagination is-small" role="navigation">
    {{-- Previous --}}
    @if ($paginator->onFirstPage())
      <a class="pagination-previous" disabled>Previous</a>
    @else
      <a class="pagination-previous" href="{{ $paginator->previousPageUrl() }}">Previous</a>
    @endif
    {{-- Next --}}
    @if ($paginator->hasMorePages())
      <a class="pagination-next" href="{{ $paginator->nextPageUrl() }}">Next</a>
    @else
      <a class="pagination-next" disabled>Next</a>
    @endif

    <ul class="pagination-list">
      @foreach ($elements as $element)
        @if (is_string($element))
          <li><span class="pagination-ellipsis">&hellip;</span></li>
        @endif
        @if (is_array($element))
          @foreach ($element as $page => $url)
            <li>
              <a class="pagination-link @if ($page == $paginator->currentPage()) is-current @endif"
                 href="{{ $url }}">{{ $page }}</a>
            </li>
          @endforeach
        @endif
      @endforeach
    </ul>
  </nav>
@endif

Bulma is CSS-only — add the JS you need

Nothing in the preset toggles the navbar burger, modals, dropdowns, or tabs. Small vanilla script in resources/js/app.js:

document.querySelectorAll('[data-bulma-toggle]').forEach((el) => {
  el.addEventListener('click', () => {
    const target = document.getElementById(el.dataset.bulmaToggle);
    target?.classList.toggle('is-active');
    el.classList.toggle('is-active');
  });
});

with <button class="navbar-burger" data-bulma-toggle="nav-menu">. Same hook pattern works for .modal (toggle is-active) and .dropdown.

Integrating with Livewire / Alpine

Bulma and Alpine compose cleanly — Alpine just flips the is-active classes:

<div class="dropdown" x-data="{ open: false }" :class="{ 'is-active': open }">
  <div class="dropdown-trigger">
    <button class="button" @click="open = !open" @click.outside="open = false">Actions</button>
  </div>
  <div class="dropdown-menu"><!-- ... --></div>
</div>

For Livewire, keep wire:model on the raw input and put Bulma classes on the same element; Livewire doesn't care about surrounding markup.

Trim the shipped CSS in production

Bulma unminified is ~200–300 KB. Gate PurgeCSS behind production in Mix:

mix.sass('resources/sass/app.scss', 'public/css')
   .options({ purgeCss: mix.inProduction() ? { enabled: true, content: ['resources/views/**/*.blade.php', 'resources/js/**/*.js'] } : false });

Note PurgeCSS must be told about dynamically composed classes (is-$variant, is-$size); add a safelist if you build classes at runtime.

Gotchas and Tips

  • v3.0.4 only fixes command registration — nothing else moved. The stubs, package.json, and webpack.mix.js are still the 2020 originals. Confirm the command shows up with php artisan list | grep preset; if it doesn't, check you resolved ^3.0 and not a cached older tag (composer show laravel-frontend-presets/bulma).
  • Package discovery can mask the fix. If preset is still missing after upgrading, run composer dump-autoload and php artisan package:discover. The fix is a dependency on the command class, so a stale provider manifest is the usual culprit.
  • Presets overwrite files without asking. webpack.mix.js, package.json, app.js, app.scss, and auth views get clobbered. Commit or branch before running it. php artisan preset none no longer exists on modern Laravel, so git checkout is your undo.
  • Path drift between Laravel versions. Laravel ≤5.6 used resources/assets/sass; 5.7+ uses resources/sass; 9+ uses resources/css + resources/js with Vite. Stubs written for the older layout will compile into the wrong place or not at all. On Vite apps expect to hand-rewrite webpack.mix.js as vite.config.js input.
  • ~ tilde resolution is Mix-only. @import '~bulma/bulma' works in webpack/Mix; with Vite use @import 'bulma/bulma' and let the resolver handle node_modules, or add resolve.alias.
  • node-sass vs sass. The package's package.json may still pin node-sass, which won't build on modern Node. Swap to sass (Dart Sass) and expect deprecation warnings for @import — Bulma 1.0 moved to @use, so pin bulma@^0.9 if you're following the preset's stubs.
  • Overrides silently no-op. Setting $primary after @import 'bulma/bulma' does nothing because every variable has !default. Always split the utilities import.
  • No icon font ships with Bulma. <span class="icon"><i class="fas fa-user"></i></span> renders an empty box until you add @fortawesome/fontawesome-free (or inline SVG). This is the most common "the preset is broken" report.
  • No JavaScript ships with Bulma either. Navbar burger, modal, tabs, and dropdown are all class-toggling on you. Budget for it.
  • Auth scaffolding moved out of the framework (Laravel 6+/8+). The preset's auth/*.blade.php stubs assume make:auth routes. Generate with laravel/ui (php artisan ui:auth --views) or Breeze first, then port the Bulma class names onto the generated views; the route/controller wiring comes from the scaffolding, not from this package.
  • Extension point if you genuinely want to keep it installed: the PresetCommand resolves preset classes under the LaravelFrontendPresets\ namespace. Subclass the shipped preset and register your own to add files to the copy set — useful for org-wide defaults (logo, favicon, base layout, flash partial) applied across projects. Now that the command registers reliably on 7+, this is a much more viable pattern than it was.
  • Debugging Sass failures: run npm run dev and read the first error; Mix reports the offending @import path, which is almost always a stale resources/assets/... path or a missing ~. rm -rf node_modules package-lock.json && npm install fixes most version-pin drift from the 2020 manifest.
  • Overall judgement: v3.0.4 removes the biggest blocker (the dead preset command), which makes the install path honest again for Laravel 7–10 — but one commit doesn't change the fundamentals: 2020 stubs, empty devDependencies era pins, no JS, no icons, ~170 stars. Use it as a one-shot preset or a reference implementation; don't expect Bulma 1.0/Vite-native stubs to arrive.
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.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
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
cgv/localized-resource