From 94458d7b2a8259fc0edfed111cc4f85f357d693c Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Mon, 9 Feb 2026 17:40:12 +0100 Subject: [PATCH 1/6] Document slot props for cell slots --- resources/js/stories/docs/Listing.mdx | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/resources/js/stories/docs/Listing.mdx b/resources/js/stories/docs/Listing.mdx index dd2fe0d3c1..eae1178236 100644 --- a/resources/js/stories/docs/Listing.mdx +++ b/resources/js/stories/docs/Listing.mdx @@ -9,8 +9,14 @@ A full-featured data listing component with sorting, searching, pagination, colu ## Customizing the cells Customize how individual cells are rendered using cell slots. Use the pattern `#cell-{fieldName}` to target specific columns. + +Inside the slot, you have access to a few slot props: +- `row` is the current row's data +- `value` is the current column's value +- `isColumnVisible` is a method which allows you to determine if a specific column is visible + ## With Actions You can add your own dropdown items via the `prepended-row-actions` slot. From 56f2543b73754df4b766b61c75dcb33f9a1308d9 Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Mon, 9 Feb 2026 17:10:29 +0000 Subject: [PATCH 2/6] improve json endpoint docs --- resources/js/stories/docs/Listing.mdx | 115 +++++++++++++++++++++++++- 1 file changed, 114 insertions(+), 1 deletion(-) diff --git a/resources/js/stories/docs/Listing.mdx b/resources/js/stories/docs/Listing.mdx index eae1178236..c2f8b32510 100644 --- a/resources/js/stories/docs/Listing.mdx +++ b/resources/js/stories/docs/Listing.mdx @@ -22,7 +22,120 @@ You can add your own dropdown items via the `prepended-row-actions` slot. ## Using a JSON endpoint -The `Listing` component can pull data from a JSON endpoint. Simply specify a `url` and return an [API Resource](https://laravel.com/docs/12.x/eloquent-resources#main-content) from your controller. +The `Listing` component can pull data from a JSON endpoint. It's a little more involved though... + +1. You'll need to make a controller to query your data. The Listing component will provide `page`, `perPage`, `sort`, `order`, `search`, `columns` and `filters` as query parameters. + + You may also want to make a [JSON resource](https://laravel.com/docs/master/eloquent-resources#main-content) to have more control over the response. + + ```php + use Illuminate\Http\Request; + + public function json(Request $request) + { + $query = TeamMember::query(); + + if ($search $request->input('search')) { + $query->where('name', 'like', "%{$search}%"); + } + + $query->orderBy( + $request->input('sort', 'name'), // column + $request->input('order', 'asc') // direction + ); + + return TeamMemberResource::collection($query->paginate($request->input('perPage'))); + } + ``` + +2. Create a route and provide the `url` prop instead of `items`: + + ```php + Route::get('team-members/json', [TeamMemberController::class, 'json']); + ``` + + ```vue + + ``` + +3. Refresh your listing and hope for the best! 🎉 + +### Actions +To enable [actions](https://statamic.dev/backend-apis/actions), you'll need to make another controller. It should extend Statamic's `ActionController`. + +The `$key` should match what's returned by [action's `visibleTo` method](https://statamic.dev/backend-apis/actions#filtering-actions). Inside `getSelectedItems`, you should lookup items via their IDs: + +```php +map(function ($item) { + return TeamMember::find($item); + }); + } +} +``` + +Next, add two routes pointing to the controller: + +```php +Route::get('team-members/actions', [TeamMemberActionController::class, 'run']); +Route::get('team-members/actions/list', [TeamMemberActionController::class, 'bulkActions']); +``` + +Finally, pass the URL for the first route to the `actionUrl` prop: + +```vue ++``` + +### Filtering +To enable filters on your listing, you'll need to call `Scope::filters()` in your controller and pass it to the `Listing` component on your page. + +The `Scope::filters()` method expects a key (which should match what's returned by the [filter's `visibleTo` method](https://statamic.dev/backend-apis/query-scopes-and-filters#filters) along with any additional context you wish to provide. + +```php +return Interia::render('team-members/Index', [ + 'filters' => Scope::filters('team-members', [ + 'company' => 'Statamic', + ]), + // ... +]); +``` + +```vue + + + +``` ## Arguments From e0d9ad6bd95dcd956c2697a6e0218a702bf3ec7c Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Mon, 9 Feb 2026 17:11:02 +0000 Subject: [PATCH 3/6] ensure lists are styled correctly --- .storybook/storybook.css | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.storybook/storybook.css b/.storybook/storybook.css index ef88592e72..6cdf7c8c4c 100644 --- a/.storybook/storybook.css +++ b/.storybook/storybook.css @@ -85,6 +85,14 @@ p:not(.sb-anchor, .sb-unstyled, .sb-unstyled p) { font-weight: 300; } + + ul { + list-style: circle; + } + + ol { + list-style: decimal; + } } } From 910d67801e6b7dd9a96e2cab118710567b11198e Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Mon, 9 Feb 2026 17:11:27 +0000 Subject: [PATCH 4/6] wrap listing in a div so classes work --- .../js/components/ui/Listing/Listing.vue | 90 ++++++++++--------- 1 file changed, 48 insertions(+), 42 deletions(-) diff --git a/resources/js/components/ui/Listing/Listing.vue b/resources/js/components/ui/Listing/Listing.vue index 798c517433..2b7218abe3 100644 --- a/resources/js/components/ui/Listing/Listing.vue +++ b/resources/js/components/ui/Listing/Listing.vue @@ -5,7 +5,11 @@ export const [injectListingContext, provideListingContext] = createContext('List From 36b4354f12b7de3eebd322d694e3b6180dcc4db0 Mon Sep 17 00:00:00 2001 From: Duncan McClean Date: Tue, 10 Feb 2026 13:16:47 +0000 Subject: [PATCH 5/6] document the listing's default slot --- resources/js/stories/Listing.stories.ts | 65 ++++++++++++++++++++++++- resources/js/stories/docs/Listing.mdx | 34 +++++++++++-- 2 files changed, 94 insertions(+), 5 deletions(-) diff --git a/resources/js/stories/Listing.stories.ts b/resources/js/stories/Listing.stories.ts index 81cec4d013..5bb3c9f0bd 100644 --- a/resources/js/stories/Listing.stories.ts +++ b/resources/js/stories/Listing.stories.ts @@ -14,7 +14,9 @@ import { ListingTable, ListingTableBody, ListingTableHead, - ListingToggleAll + ListingToggleAll, + Panel, + PanelFooter, } from '@ui'; const meta = { @@ -208,4 +210,65 @@ export const _WithActions: Story = { components: { Listing, Badge, DropdownItem }, template: actionsCode, }), +}; + +const customLayoutCode = ` ++
+ + + +
+ + + + + + + + +
+`; + +export const _CustomLayout: Story = { + tags: ['!dev'], + parameters: { + docs: { + source: { code: customLayoutCode } + } + }, + render: () => ({ + components: { + Listing, + ListingPresets, + ListingSearch, + ListingFilters, + ListingCustomizeColumns, + ListingTable, + ListingPagination, + Panel, + PanelFooter, + Badge, + DropdownItem, + }, + template: customLayoutCode, + }), }; \ No newline at end of file diff --git a/resources/js/stories/docs/Listing.mdx b/resources/js/stories/docs/Listing.mdx index c2f8b32510..46755a4088 100644 --- a/resources/js/stories/docs/Listing.mdx +++ b/resources/js/stories/docs/Listing.mdx @@ -12,15 +12,41 @@ Customize how individual cells are rendered using cell slots. Use the pattern `# -Inside the slot, you have access to a few slot props: -- `row` is the current row's data -- `value` is the current column's value -- `isColumnVisible` is a method which allows you to determine if a specific column is visible +The cell slots expose a few props: +- `row` - the current row's data +- `value` - the current column's value +- `isColumnVisible(column)` - determine whether a column is currently visible ## With Actions You can add your own dropdown items via the `prepended-row-actions` slot. +## Customizing the layout +The `Listing` component includes a sensible default layout, but you can fully control the structure by providing your own markup in the default slot. + +Inside the slot, you can compose your layout using the provided `Listing` sub-components, which automatically connect to the parent `Listing` via shared context. + +If you need to customize table columns or row actions, you can do so inside the `ListingTable` component's slots. + + + +### Available components +You can use the following components to build your own layout: + +- `ListingCustomizeColumns` +- `ListingFilters` +- `ListingPagination` +- `ListingPresets` +- `ListingSearch` +- `ListingTable` + +### Slot props +The default slot exposes a few props: + +- `items` - the items for the current page +- `isColumnVisible(column)` - determine whether a column is currently visible +- `loading` - whether results are being fetched from the server + ## Using a JSON endpoint The `Listing` component can pull data from a JSON endpoint. It's a little more involved though... From ea27cdc057c3d7ef7aeeed57785c608caab0423b Mon Sep 17 00:00:00 2001 From: Jason Varga Date: Wed, 11 Feb 2026 12:27:52 -0500 Subject: [PATCH 6/6] they've got this. --- resources/js/stories/docs/Listing.mdx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/resources/js/stories/docs/Listing.mdx b/resources/js/stories/docs/Listing.mdx index 46755a4088..d044fd9c3a 100644 --- a/resources/js/stories/docs/Listing.mdx +++ b/resources/js/stories/docs/Listing.mdx @@ -48,7 +48,7 @@ The default slot exposes a few props: - `loading` - whether results are being fetched from the server ## Using a JSON endpoint -The `Listing` component can pull data from a JSON endpoint. It's a little more involved though... +The `Listing` component can pull data from a JSON endpoint. 1. You'll need to make a controller to query your data. The Listing component will provide `page`, `perPage`, `sort`, `order`, `search`, `columns` and `filters` as query parameters. @@ -87,8 +87,6 @@ The `Listing` component can pull data from a JSON endpoint. It's a little more i /> ``` -3. Refresh your listing and hope for the best! 🎉 - ### Actions To enable [actions](https://statamic.dev/backend-apis/actions), you'll need to make another controller. It should extend Statamic's `ActionController`.