symfinity/ux-blocks-marketing
A Laravel package offering reusable marketing UI blocks—hero sections, CTAs, feature grids, testimonials, pricing, and newsletter signups—with responsive Blade components and simple customization for quickly building polished landing pages.
Install and verify discovery. This is a standard Laravel package with a service provider, so:
composer require symfinity/ux-blocks-marketing
php artisan vendor:publish --provider="Symfinity\UxBlocksMarketing\UxBlocksMarketingServiceProvider"
Confirm auto-discovery worked with php artisan about (look for the package under "Packages"). If it's missing, check bootstrap/providers.php / config/app.php and run php artisan package:discover.
Publish, then read what you published. The publish step is the real documentation for a package this young. After publishing, inspect:
config/ux-blocks-marketing.php — block registration, view paths, asset toggles.resources/views/vendor/ux-blocks-marketing/ — the actual Blade markup for each block. This tells you the prop names and the data shape each block expects far faster than guessing.vendor/symfinity/ux-blocks-marketing/src/ — the block classes/components and any registry.Because the package is at 0.1.2 with a single-line changelog, reading the source isn't optional — assume the README (if any) lags the code.
First use case: one block, one page. Don't scaffold a full landing page first. Drop a single hero or CTA block into an existing view and render it with minimal data:
<x-ux-blocks-marketing::hero
title="Ship faster"
subtitle="Marketing blocks for Laravel"
:cta="['label' => 'Get started', 'url' => '/signup']"
/>
That one render validates three things at once: install/discovery, view namespace resolution, and whether your asset pipeline is picking up the block styles. If the markup appears but is unstyled, jump straight to the Tailwind/purge section below — it's the single most common first-run failure.
Then wire the package's CSS/JS into your build once (Vite import in resources/css/app.css, or an @push/@stack in your layout). Keep this on a dedicated marketing layout so block resets don't bleed into your admin/app UI.
Compose pages by stacking blocks, not by hardcoding marketing markup. The value of the package is that each section is a self-contained component. Treat them like Lego:
<x-ux-blocks-marketing::hero :data="$hero" />
<x-ux-blocks-marketing::feature-grid :items="$features" />
<x-ux-blocks-marketing::testimonial :items="$testimonials" />
<x-ux-blocks-marketing::pricing :plans="$plans" />
<x-ux-blocks-marketing::cta :data="$cta" />
Persist page structure as ordered block data, then resolve dynamically. This is the pattern that scales from one landing page to a campaign site. Store a blocks JSON column of {type, data} objects and render in a loop:
@foreach ($page->blocks as $block)
<x-dynamic-component
:component="'ux-blocks-marketing::'.$block['type']"
:data="$block['data']"
/>
@endforeach
Guard the type against an allowlist of registered blocks so a bad CMS entry can't attempt to resolve an arbitrary component.
Normalize data at the boundary, keep blocks dumb. Build one DTO or validated array per block type (a BlockData cast on the model, or a FormRequest for editor submissions). The block components should never be responsible for defaulting, trimming, or validating — that makes them trivially testable and keeps the vendor views replaceable.
Configure via the published config, never vendor edits. If the package exposes block registration or an override map, register custom blocks / reorder / disable there. Anything you touch in vendor/ evaporates on composer update.
Feature-test each block in isolation. Even a light Pest suite pays for itself at 0.x:
it('renders the pricing block', function () {
$this->blade('<x-ux-blocks-marketing::pricing :plans="$plans" />', ['plans' => [...]])
->assertSee('Pro');
});
Run these after every package bump — the API is not stable and the changelog won't tell you what broke.
Override one block, not the package. If a block's markup doesn't fit, publish or shadow just that single view (or re-register a custom component under the same key). Forking or editing many vendor views is the path to permanent merge pain on a 0.x package that patches frequently.
0.x means breaking changes are normal. Pin to "^0.1.2" at minimum; for anything customer-facing, pin the exact version and snapshot rendered output. Read CHANGELOG.md in the repo on every bump — the release notes here only link to it, so subscribe to GitHub releases rather than relying on Packagist updates.
Stale published views are the classic failure mode. After a composer update, diff vendor/symfinity/ux-blocks-marketing/resources/views against your published copies. Published stubs don't auto-update, so you can end up with new component props hitting old markup.
Bust caches after anything structural. A newly registered block or a renamed view won't appear until caches clear:
php artisan optimize:clear
Component and view registration are cached; view:cache is also your fastest way to surface a missing/renamed view.
Tailwind purge will bite you in production only. If the blocks ship utility-class markup, your content globs must include the vendor views path:
content: [
'./resources/**/*.blade.php',
'./vendor/symfinity/ux-blocks-marketing/resources/views/**/*.blade.php',
],
Run npm run build early — dev server works, production build strips every class the blocks rely on. This is the number-one "it looked fine locally" report for packages like this.
Namespace discipline. Always reference blocks with the explicit package namespace (ux-blocks-marketing::). If you publish views under a name that collides with your own components, fallback resolution order decides what renders — and it may differ between environments.
When a block renders empty, check in this order: (1) prop key names vs. what the published view actually reads, (2) the view exists under the namespace (run view:cache), (3) whether the component constructor is swallowing an exception — enable APP_DEBUG and temporarily dd() the resolved data. Silent empties are almost always a data-shape mismatch, not a package bug.
Treat this as a composition kit, not a design system. The blocks are lightweight and dependency-free by design, so styling depth is on you. Budget time for theming/responsive polish beyond what ships, and don't assume consistent design tokens across block types until you've read each view.
Production posture. At 0.1.x with a zero-star, single-maintainer footprint, avoid this on revenue-critical funnels unless you've pinned the version, vendored/snapshotted the rendered HTML, and can absorb an upstream abandonment. Re-evaluate once the changelog shows a stable API surface or a 1.0 tag.
How can I help you explore Laravel packages today?