A list of cases, tasks or properties is not a table, as each record reads as a card, and forcing it into columns leaves gaps and odd widths.
Wirelist draws those lists. Records as divided rows, separate cards or a grid, each one opening its record, with a row actions menu, load more and the 11 themes of the wire* family. It is built on Wiretables, so tables and lists share their look and sit together on one screen.
Install
It requires Wiretables, which Composer installs with it. Publish both CSS:
composer require edulazaro/wirelist
php artisan vendor:publish --tag=wiretables-assets
php artisan vendor:publish --tag=wirelist-assets
Load the cores and, if you want one, the theme of the same name from each package. With Vite:
@import "../../vendor/edulazaro/wiretables/resources/css/wiretables-core.css";
@import "../../vendor/edulazaro/wiretables/resources/css/themes/studio.css";
@import "../../vendor/edulazaro/wirelist/resources/css/wirelist-core.css";
@import "../../vendor/edulazaro/wirelist/resources/css/themes/studio.css";
Wiretables' theme file brings the colours both share; Wirelist's adds what only a list needs.
A list
Each record is an item with a title, a muted line and slots around them:
<x-wirelist items="separated">
@forelse ($cases as $case)
<x-wirelist.item wire:key="case-{{ $case->id }}" :title="$case->title" :subtitle="$case->company" :href="route('cases.show', $case)">
<x-slot:badges>
@foreach ($case->tags as $tag)
<span class="badge">{{ $tag->name }}</span>
@endforeach
</x-slot:badges>
<x-slot:aside>
<span>{{ $case->members_count }} members</span>
<span class="status">{{ $case->status }}</span>
</x-slot:aside>
<x-slot:actions>
<x-wiretable.menu :label="'Actions of '.$case->title">
<x-wiretable.menu-item wire:click="archive({{ $case->id }})" danger>Archive…</x-wiretable.menu-item>
</x-wiretable.menu>
</x-slot:actions>
</x-wirelist.item>
@empty
<x-wirelist.empty>No cases yet.</x-wirelist.empty>
@endforelse
</x-wirelist>
The slots cover what these lists usually carry:
| Slot | |
|---|---|
leading |
An avatar or an icon; in a grid, the cover image |
badges |
Beside the title: tags, a draft mark, a category |
aside |
On the right: counts, a status, a date |
actions |
The "⋯" menu or a button |
header |
A strip above the record |
| default | More lines under the subtitle |
Three shapes, one markup
The same items draw three different lists:
-
items="divided", the default, puts every record in one frame with a line between them: a queue or a short dashboard list. -
items="separated"draws each record as a card of its own. -
layout="grid"puts the cards side by side, as many as fit. Theleadingslot becomes a cover running edge to edge on top, and the aside lines up at the foot of every card in the row.
Since the markup does not change, a list/grid switch is one Livewire property:
<x-wirelist :layout="$view">…</x-wirelist>
A card that opens without nesting buttons
The usual way to make a whole card clickable is to wrap it in an <a>, and then a delete button ends up inside a link. HTML does not allow it, keyboards and screen readers trip on it, and the click goes to whichever element the browser picks.
With href, Wirelist stretches the title's link over the item instead:
.wtl-item-link::after {
content: "";
position: absolute;
inset: 0;
}
A click anywhere on the card opens the record, while the badges, the aside, the actions and any link or button in the content sit above the stretched link and keep their own clicks. The markup stays valid: the menu is a sibling of the link, never inside it.
On a phone
Lists adapt without configuration: the actions stay beside the title and the aside goes under both. The grid drops to as many columns as fit, down to one.
Load more and sorting
Wiretables' traits work the same with a list:
use EduLazaro\Wiretables\Concerns\WithLoadMore;
$cases = $this->loadMoreFrom(LegalCase::query()->latest());
<x-wirelist>…</x-wirelist>
<x-wiretable.load-more :show="$hasMore" />
The list re-reads from the start on each load, so nothing is repeated or lost when records change meanwhile, and the client cannot ask for more pages than it loaded.
Themes
The theme is the same attribute as the rest of the family:
<html data-wire-theme="minimal">
Colours, lines and radius come from Wiretables' --wtb-* variables, so one setting reaches tables and lists alike. The list's own shape lives in --wtl-*:
:root {
--wtl-item-padding: 14px 20px;
--wtl-grid-min: 18rem;
--wtl-cover-ratio: 4 / 3;
}
Links
👉 Source: Wirelist on GitHub
👉 Packagist: Wirelist on Packagist
👉 Documentation: Wirelist Documentation
Top comments (0)