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

Ux Blocks Interactive Laravel Package

symfinity/ux-blocks-interactive

A Laravel package for building interactive UI blocks, letting you compose dynamic, reusable front-end components with PHP. It pairs clean server-side block definitions with client-side interactivity for faster, more maintainable interfaces.

View on GitHub
Deep Wiki
Context7

Getting Started

What you're actually adopting. symfinity/ux-blocks-interactive is a Laravel package that ships Stimulus-backed interactive widgets as Blade components. The description and the package name pull in two directions — the name echoes Symfony UX "Blocks", the description promises "reusable interactive UI blocks" — so before you build a feature on it, spend ten minutes confirming what's actually in the box. At v0.1.x with a single star and a bugfix-only release history, you are early. Treat it as a small dependency you might fork, not infrastructure you inherit.

Where to look first, in order:

  1. vendor/symfinity/ux-blocks-interactive/composer.json — read extra.laravel.providers and extra.laravel.aliases. This tells you what registers itself and whether the Blade namespace is auto-loaded.
  2. The service provider (src/*ServiceProvider.php) — this is the real documentation. Look for loadViewsFrom, loadViewsFrom with a namespace, publish(), Blade::componentNamespace(), and any Route:: calls. Those five calls describe 90% of how you'll interact with the package.
  3. config/ux-blocks-interactive.php after publishing — the widget/block registry, asset paths, and any Stimulus controller prefix live here.
  4. resources/views/ in the vendor directory — enumerate the components. ls vendor/symfinity/ux-blocks-interactive/resources/views/components is faster than any README for discovering what you can actually render.
  5. CHANGELOG.md — the v0.1.3 release body just links to it, so the changelog is the only real record of what changed and what broke.

Minimal install:

composer require symfinity/ux-blocks-interactive

php artisan vendor:publish --tag=ux-blocks-interactive-config
php artisan vendor:publish --tag=ux-blocks-interactive-assets

Publish tags are guesses until you run php artisan vendor:publish interactively once and read the menu — that menu is authoritative. Then register the controllers in your Vite entrypoint:

// resources/js/app.js
import { Application } from '@hotwired/stimulus'
import { registerControllers } from 'stimulus-vite-helpers'

const app = Application.start()
const controllers = import.meta.glob(
  './../../vendor/symfinity/ux-blocks-interactive/resources/js/controllers/**/*_controller.js',
  { eager: true }
)
registerControllers(app, Object.values(controllers))

First use case. Don't adopt the whole package for a content editor on day one. Pick the single widget that maps to a UI problem you already have — a toggle, a reorderable list, an inline-edit field — render it inside one existing Blade form, and confirm it (a) hydrates, (b) submits a value your controller already validates, and (c) survives npm run build. If those three hold, you have a viable dependency; if the Stimulus controller never connects, you've lost an afternoon instead of a sprint.

Implementation Patterns

Render-through-Blade, persist-through-Eloquent. The package owns the client behaviour; your app owns state. Keep the component's contract narrow — it should emit a form field or dispatch a custom event, and nothing more. The moment you start reaching into the package's controllers from application code, upgrades get expensive.

<form method="POST" action="{{ route('pages.update', $page) }}">
    @csrf @method('PUT')

    <x-ux-blocks-interactive::some-widget
        name="settings[notifications]"
        :value="old('settings.notifications', $page->settings['notifications'] ?? true)"
    />

    <button type="submit">Save</button>
</form>

Bridge Stimulus events into Alpine or Livewire rather than duplicating state. If your app is already Alpine-based, use x-on: listeners on the wrapping element to catch whatever custom event the widget dispatches. This keeps the package's controllers untouched:

<div x-data="{ open: false }" @ux-blocks:changed.window="open = $event.detail.value">

If you're on Livewire, the same pattern works with wire:model bound to a hidden input the widget writes to — but verify the widget dispatches a native input/change event before assuming wire:model picks it up. Many small packages only dispatch custom events.

Wrap each widget in your own Blade component. Create resources/views/components/ui/toggle.blade.php that calls the vendor component with your project's defaults (sizes, variants, aria attributes). One indirection layer means a future v0.2 rename touches one file instead of forty:

{{-- resources/views/components/ui/toggle.blade.php --}}
@props(['name', 'value' => false])
<x-ux-blocks-interactive::toggle :name="$name" :checked="$value" {{ $attributes->merge(['class' => 'toggle toggle--sm']) }} />

Asset loading under Vite is a build concern, not a runtime one. If the package ships pre-built assets, importing them through Vite gives you hashing and cache busting for free; if it ships raw controllers, the glob import above handles it. Either way, add a smoke check to CI: a Dusk/Pest browser test that asserts the widget's root element gains the expected class or attribute after JS runs. That single test catches the "works in dev, silent in prod" failure that dominates packages of this maturity.

Config-driven widget allow-listing. If the config exposes a registry, keep it explicit rather than auto-discovering. Enumerating the widgets you use means a new release can't silently introduce a controller into your bundle:

// config/ux-blocks-interactive.php
'widgets' => [
    'toggle'   => true,
    'reorder'  => true,
    'inline-edit' => false,
],

Feature tests around the contract, not the DOM. Write one test per widget asserting the rendered HTML contains the expected data-controller attribute and form field name. Don't assert on internal class names or controller identifiers — those are the first thing to change in a patch release:

it('renders a toggle wired to the controller', function () {
    $this->blade('<x-ui.toggle name="foo" />')
        ->assertSee('data-controller', false)
        ->assertSee('name="foo"', false);
});

Gotchas and Tips

  • v0.1.x has no BC promise. Pin ^0.1.3 — never *, never dev-main in a project you care about. The v0.1.3 release is a bugfix drop, which is exactly the kind of release that quietly changes a data-* attribute name and breaks a custom listener you wrote six weeks ago.

  • The release notes are a redirect. v0.1.3's GitHub body is a single link to CHANGELOG.md. Read the changelog, and after upgrading diff the vendor directory (git diff on a committed vendor in a throwaway branch, or just diff -r against a composer.lock-pinned copy) to see which controllers and views moved. For a package this small, reading the diff is faster than debugging the symptom.

  • Asset publishing is a one-way door for customisations. Edit the vendor/package JS only in your own controllers. If you re-publish assets on upgrade, anything you changed in the published copies is gone. Keep overrides in resources/js/ and register your version of a controller under a different identifier if you need to replace behaviour.

  • Stimulus identifier collisions are the most likely integration failure. The package registers controllers under identifiers derived from filenames. If you already run Stimulus, check for clashes (application.getControllerForElementAndIdentifier is your debugging friend, or just log Object.keys(app.router.modules) after Application.start()). A collision manifests as "the wrong widget's behaviour runs on the wrong element", which is confusing enough to waste a day.

  • Debug hydration in the DOM before touching PHP. When a widget doesn't respond, open devtools, inspect the rendered root element, and verify the expected data-controller and data-*-value attributes are present and correct. If they're missing, it's a Blade/component-attribute problem (often @props swallowing an attribute you meant to pass through). If they're present but nothing happens, it's a JS registration or import path problem. This split saves you from opening the service provider when the real issue is a typo in import.meta.glob.

  • Watch for Stimulus value and class API drift. Small packages built against early Stimulus 3.x can use deprecated patterns (this.data.get(...) instead of this.fooValue). If you're on Stimulus 3.2+, check the controller source for deprecation warnings in the console and be prepared to fork a controller — at 1 star, upstream fixes may be slow.

  • Config cache surprises. Anything the config file exposes — asset paths, controller prefix, enabled widgets — must be re-cached after edits: php artisan config:cache in deploy pipelines, php artisan config:clear locally. If a widget works locally but 404s in staging, this is the first thing to check.

  • Extension points, ranked by safety. Override through (1) your own wrapper Blade components, (2) the published config, (3) the published views if the package allows vendor:publish --tag=...-views. Extending vendor PHP classes or overriding Stimulus controllers is last resort — those internals are the most likely to shift before 1.0. Prefer composition over inheritance for exactly this reason.

  • Budget an exit. At this maturity, keep the wrapper components thin enough that swapping in hand-written Alpine/Stimulus in six months is an afternoon's work, not a rewrite. The wrapper pattern above exists precisely so you can delete the vendor dependency without touching the views that consume it.

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.
shitoudev/permissionmanager
johannesclimacus/laravel-tui
hocvt/seotools
vitalybaev/sypexgeo
amphibee/themosis-ignition
gito-me/fast-excel
frankyso/laravel-ipaymu
geolize-studio/laravel-chile
boomerangui/chat
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