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

Components Laravel Package

marshmallow/components

Marshmallow Components is a Laravel package offering a collection of reusable, ready-to-use Blade UI components. It helps you build consistent interfaces faster with minimal markup and sensible defaults, keeping your views clean and maintainable.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package alongside Marshmallow itself — it is a UI layer, not a standalone framework, so it is only useful once the parent admin package is running.

composer require marshmallow/components
php artisan vendor:publish --tag=marshmallow-components-config
php artisan vendor:publish --tag=marshmallow-components-views   # only if you plan to override

Version note. As of v1.5.0 the package supports Laravel 13. If your app is on Laravel 13, require ^1.5 explicitly — earlier tags cap the framework constraint and Composer will either refuse the install or resolve you onto an older Laravel. On Laravel 10–12 the earlier tags remain fine.

Where to look first. Before writing any markup, spend ten minutes in three places in the repo:

  1. src/View/Components/ — the class components and their constructor signatures. This is the real API; the README will lag behind it.
  2. resources/views/components/ — the anonymous Blade components and their @props defaults. This tells you which attributes are forwarded to the root element and which are consumed internally.
  3. config/marshmallow-components.php — the prefix, view namespace, and any default styling hooks.

First use case. The fastest win is replacing hand-rolled form markup inside a Marshmallow screen with the package's input/field components, so validation state, error display, and label association are handled for you:

<x-marshmallow::field name="email" label="Email address">
    <x-marshmallow::input type="email" name="email" wire:model.defer="email" />
</x-marshmallow::field>

If that renders and validation errors appear without extra wiring, the package integrates cleanly with your Marshmallow version. If not, check the component namespace against config('marshmallow-components.prefix') before debugging anything else.

Implementation Patterns

Treat the components as layout primitives, not as a design system. The value is in the attribute forwarding and slot structure, so compose them inside your own domain components rather than scattering them across views:

{{-- resources/views/components/admin/stat-card.blade.php --}}
@props(['label', 'value', 'trend' => null])

<x-marshmallow::card {{ $attributes->class(['admin-stat']) }}>
    <x-slot:header>{{ $label }}</x-slot:header>
    <p class="text-2xl font-semibold">{{ $value }}</p>
    @if ($trend)
        <x-marshmallow::badge :variant="$trend > 0 ? 'success' : 'danger'">
            {{ $trend > 0 ? '+' : '' }}{{ $trend }}%
        </x-marshmallow::badge>
    @endif
</x-marshmallow::card>

Wrap, don't fork. For any component whose markup you dislike, create a project-local component that renders the package component in its slot and applies your own classes via $attributes->class([...]). You keep upstream fixes and still get your look. Only publish views for components where the structure is wrong, and publish individual files rather than the whole directory — a full publish freezes you out of upstream template changes.

Extend the class components when you need new behavior. If src/View/Components/ contains class-based components (inputs, tables, modals), subclassing is cheaper than reimplementing:

namespace App\View\Components;

use Marshmallow\Components\View\Components\Input;

class MoneyInput extends Input
{
    public function render()
    {
        return view('components.money-input');
    }
}

Confirm the parent's properties are protected/public and not private, otherwise subclassing buys you nothing.

Livewire-aware usage. Marshmallow screens are typically Livewire-driven, so keep bindings on the component's forwarded attributes and avoid wrapping them in extra DOM that breaks morphing:

<x-marshmallow::select name="status" wire:model.live="status" :options="$statuses" />

Composition over configuration. Reach for the config file only for cross-cutting things (namespace prefix, default icon set, theme class). Per-instance styling belongs in attributes at the call site, where a reviewer can see it.

Testing pattern. Blade components are trivially snapshot-testable; assert rendered output rather than mocking:

$this->blade('<x-marshmallow::badge variant="success">OK</x-marshmallow::badge>')
     ->assertSee('OK')
     ->assertSee('badge--success', false);

That gives you a cheap upgrade-safety net, which matters more than usual here. Run it after every composer update, since the release cadence is driven by framework-compatibility bumps rather than a documented changelog of behavior.

Gotchas and Tips

  • Laravel-version coupling is the top upgrade risk. Recent releases are almost entirely framework-support bumps (v1.5.0 is "Laravel 13 support" and nothing else). That means a minor version can change your framework constraint, not just the components. Read the diff of composer.json in every tag before bumping, and run the full suite on the framework version you actually deploy — CI on the newest Laravel proves nothing about your Laravel 12 app.
  • Attribute merge order is the #1 source of surprise. $attributes->merge(['class' => 'default']) places defaults after caller classes in the resulting string, so your defaults can win in specificity-sensitive utilities. Prefer $attributes->class(['default' => $condition]) or $attributes->twMerge(...) if tailwind-merge is available in the parent stack.
  • @props defaults silently swallow attributes. If a prop isn't declared and isn't forwarded, the attribute disappears with no error. When an attribute "doesn't work," check the component's @props list before assuming a bug.
  • View namespace collisions. The package registers a namespace via loadViewsFrom. If your app also publishes to resources/views/vendor/..., a stale published copy shadows upstream updates forever. Keep a note of every published file; git diff against the vendor path after each upgrade.
  • View cache masks everything. After changing config or publishing views, run php artisan view:clear && php artisan config:clear. A missing-component InvalidArgumentException after a deploy is almost always a stale compiled view rather than a broken install.
  • Blade class components resolve by name, not class. If you override a view, the class component keeps instantiating the original; changing the view is not the same as changing the component. Pick one extension strategy per component and stick to it.
  • Livewire + Alpine hydration. Components that render conditional wrappers (modals, dropdowns) can lose Alpine state on re-render. Add wire:ignore or move the state out of the server component rather than patching the package views.
  • Small-package risk is real. Zero stars and zero dependents means no community bug reports, and a single maintainer. Pin the version ("marshmallow/components": "^1.5"), commit your lockfile, and read the diff on every upgrade — there is no ecosystem to catch a regression for you. Vendor the two or three components you actually use if the API surface you depend on is small; the package is young enough that a breaking change is plausible.
  • Debugging order of operations. 1) php artisan about to confirm the provider is booted and which Laravel/PHP versions resolved, 2) Blade::componentNamespace()/prefix in the config, 3) view:clear, 4) read the component source. Skipping straight to step 4 with a cached view wastes the most time — and a version-constraint conflict masquerades as a "component not found" more often than you'd expect.
  • Useful extension points: the config prefix (lets you avoid clashing with app components like <x-card>), Blade::componentNamespace() for aliasing, and published views for structural overrides. Avoid editing anything under vendor/ — the next composer update erases it silently.
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.
coleus/frame
thtg88/journalism
filagora/filagora-ai-forums
rlacerda83/query-parser
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings