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

April Ui Laravel Package

yungifez/april-ui

April UI is a Laravel/PHP UI toolkit for building modern, responsive interfaces with reusable components and minimal setup. It helps teams ship clean, maintainable dashboards and admin panels faster.

View on GitHub
Deep Wiki
Context7

Getting Started

April UI is a Blade component library with a shadcn-style vocabulary, so the mental model transfers almost directly if you've used shadcn/ui before: you compose components with Tailwind classes and let Alpine own the interactive behavior. The difference is that everything is server-rendered Blade rather than React.

Install is the usual two steps: pull it in with Composer, then make its views and compiled assets available to your app.

composer require yungifez/april-ui
php artisan vendor:publish --tag=april-ui-assets   # confirm tag names in the README

Then do three things in this order:

  1. Register the component namespace. The package should auto-register its april prefix via its service provider, so <april:button> works out of the box. Verify with a single component before going further.
  2. Wire Tailwind to scan the vendor views. This is the step people skip and then spend an hour debugging "why are all the styles missing." Add the package's view path to your Tailwind content globs (v3) or an @source directive (v4). Without this, the classes in the component markup are never generated.
  3. Include Alpine exactly once. If you're on Livewire, Alpine is already bundled — don't add a second copy.

First use case: pick one screen with a form and a confirmation flow — a settings page or a "create record" modal. Rebuild it with <april:card>, <april:button>, <april:dialog> and the input components. That exercises the three things you need to learn: slot composition, class merging, and Alpine scope. Where to look first: the published preview/docs site for the component list, then vendor/yungifez/april-ui/resources/views/components/ for the actual markup — the source is the real documentation for anything the docs site skips.

Implementation Patterns

Compose with slots, not with named-slot soup. The package's own convention is worth adopting in your wrappers: default slot for the primary content (<april:button>Save</april:button>), a named slot for one auxiliary region (title, footer), and dedicated child components for collections. Anything repeated — sidebar menu items, list rows — should be child components composed through the parent's default slot, not a named slot holding a blob of markup. This keeps your own abstractions aligned with the library's.

Never edit vendor views; override via classes. Attribute forwarding plus twMerge means <april:button class="w-full bg-emerald-600"> should win over the component's defaults. Prefer this over publishing views, because published views become your maintenance burden on every upgrade. If you find yourself wanting to publish three or four views to change paddings, you probably want a thin wrapper component in resources/views/components/ instead.

Treat public Alpine methods as the API, and events as the safer API. The components expose Alpine data factories with init and public methods. You can call them from your own x-data, but Alpine resolves bare method names to the nearest enclosing scope, which makes cross-component calls fragile in nested layouts. For anything programmatic — open a dialog after a fetch, close a sheet on save — prefer $dispatch from your code and let the component listen, or use component-specific method names rather than generic ones.

Livewire works, with the usual caveats. These are Blade + Alpine components, so wire:model, wire:click, and wire:loading all compose fine. Use wire:key on any component rendered inside a loop, otherwise Alpine state gets reused across rows and you'll see dropdowns opening on the wrong item. For dialogs driven by Livewire validation, keep the dialog's open state in Alpine and let the server response drive it via a dispatched event rather than re-rendering the whole modal.

Tables own the query, but you own the defaults. The table component layers user-chosen sorting on top of an Eloquent/query builder you hand it. As of v1.3.6 the user's chosen sort is applied before the builder's own orderBy, so a ->orderBy('name') you set up as a sensible default no longer silently defeats a column click. Keep writing that default order — it's the fallback for the initial page load — but stop reaching for reorder()/removing orderBy as a workaround on v1.3.5 and below.

Theming happens at the token layer. shadcn-inspired libraries typically define semantic CSS variables (--background, --foreground, --primary) and reference them from Tailwind. Set those in your app stylesheet rather than overriding individual components. Same for dark mode: configure the strategy once, in one place, and confirm it matches what the package expects.

Layout components (sidebar) are the exception to local scoping. The docs call this out explicitly: the sidebar reader can place its trigger, rail, and menu buttons anywhere on the page, so everything goes through a shared receiver. Practically, that means your trigger can live in a topbar far from the sidebar markup. Don't assume proximity.

Gotchas and Tips

Tailwind not scanning vendor views is the #1 failure mode. Symptoms: layout is right but colors/spacing are flat. Fix the content/@source config, not the component.

Asset tags used to be baked in at view compile time — fixed in v1.3.6. If you're pinned at v1.3.5 or below, the <script>/<link> tags emitted by the package were captured when the compiled view was generated, so republishing assets, bumping the package, or changing asset config could leave you serving stale bundles until you ran php artisan view:clear. That was a genuinely confusing failure mode: correct files on disk, correct config, browser still loading the old hash. v1.3.6 builds the tags per request, so upgrading makes that class of bug go away — but clearing compiled views after any asset change is still a cheap habit to keep.

Class overrides may land on the wrapper, not the control. If class="h-9" on an input does nothing, inspect the DOM — attribute forwarding sometimes targets the outer element. Reach for class on the inner element via a published view only as a last resort.

twMerge doesn't resolve everything. Conflicting utilities merge; arbitrary values, prose classes, and custom plugin utilities often don't. When an override silently loses, stop guessing and check the rendered class list.

Nested interactive components are the sharpest edge. Dropdown inside dialog inside sidebar means many Alpine scopes resolving the same short names. The library names its own methods specifically to avoid this (closeDropdownMenu vs closeSub), and you should do the same in your wrappers. If the wrong thing closes, you've hit scope resolution, not a bug in the package.

Optional dependencies load per page. The rich-text editor (TipTap) is the example: it's loaded only on pages that use it. If the component renders but the toolbar is dead, check the network tab for the missing bundle before reading component source.

Pin the version and re-check after upgrades. Release Please + conventional commits means fix:/feat: land in patch/minor releases frequently — v1.3.6 is a two-line patch that nevertheless changes the precedence of your table's orderBy and the timing of asset tag generation. Pin to a tag, read the changelog on bump, and re-run your visual smoke test — class names and Alpine method names are the things most likely to shift, and sort/ordering semantics are the thing most likely to change quietly.

Budget for reading source. At ~365 stars and an active release cadence, this is a young library: the docs site lags the code, and component APIs will move. vendor/yungifez/april-ui/resources/views/ and the matching JS files under the package's resources/js/ are the ground truth. Ten minutes there beats an hour of guessing.

Debugging tip: install the Alpine DevTools extension and inspect the component root's data. You'll immediately see which scope owns the method being called and what state is actually set — that resolves most "the dropdown won't open" reports faster than any amount of Blade spelunking.

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.
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
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo