Plan your Web Applications Design – Mandatory Listing Page Features for Web Applications

Posted by

for any listing page, these should be treated as mandatory standard options.

Mandatory Options for Every Listing Page

#Mandatory OptionPurpose
1Page TitleClearly show what data is listed
2SearchSearch records quickly by keyword
3FilterNarrow records by status, category, date, type, etc.
4SortArrange records by newest, oldest, name, status, etc.
5PaginationLoad data page by page instead of all at once
6Rows Per PageAllow user to choose 10, 25, 50, 100 records
7Total Records CountShow total records and current range
8Status BadgeShow clear status like Active, Pending, Approved
9Row ActionsView, Edit, Delete, Approve, etc.
10Bulk SelectionSelect multiple records using checkboxes
11Bulk ActionsDelete, export, approve, assign multiple records
12Add/Create ButtonAdd new record from the listing page
13Refresh ButtonReload latest data
14Export OptionExport data as CSV/Excel/PDF
15Loading StateShow loader/skeleton while data is loading
16Empty StateShow proper message when no data is found
17Error StateShow retry option when API/data loading fails
18Mobile Responsive ViewListing should work properly on mobile
19Column/Header LabelsClear column names for table/list data
20Date/Time FormattingDisplay dates in readable format
21Search/Filter ResetClear all applied search and filters
22Confirmation ModalConfirm before delete or destructive action
23Permission-Based ActionsShow/hide actions based on user role
24URL Query PersistenceKeep search/filter/page/sort in URL
25Server-Side Search/Filter/Sort/PaginationRequired for large data performance

Prompt for Claude

You are working as a senior full-stack web application developer.

For every listing page, table page, admin list page, data grid page, management page, or CRUD index page in this application, you MUST follow the mandatory listing page standard below.

Do not create any listing page without these required features. If any feature is missing in the existing code, identify it and implement it. Keep the UI consistent across all modules.

Mandatory Listing Page Features:

1. Page Title
- Clearly show what data is listed.
- Example: Users, Hospitals, Doctors, Orders, Products, Tasks, Bookings.

2. Search
- Add keyword search to quickly find records.
- Search should support common fields like name, email, phone, title, ID, or relevant searchable fields.

3. Filter
- Add filters to narrow records by status, category, date, type, role, location, or module-specific fields.
- Filters should be easy to reset.

4. Sort
- Allow records to be sorted by common fields.
- Examples: newest, oldest, name A-Z, status, priority, created date, updated date.

5. Pagination
- Do not load all records at once.
- Load records page by page.

6. Rows Per Page
- Allow users to choose page size.
- Standard options: 10, 25, 50, 100.

7. Total Records Count
- Show current range and total count.
- Example: Showing 125 of 1,240 records.

8. Status Badge
- Display status using clear badges.
- Examples: Active, Inactive, Pending, Approved, Rejected, Draft, Published, Suspended.

9. Row Actions
- Each row must have relevant actions.
- Examples: View, Edit, Delete, Approve, Reject, Activate, Deactivate.

10. Bulk Selection
- Add checkbox selection for multiple records.
- Include select one, select all on current page, and clear selection.

11. Bulk Actions
- Allow actions on selected records where applicable.
- Examples: Delete, Export, Approve, Reject, Assign, Activate, Deactivate.

12. Add/Create Button
- Provide a clear button to add a new record.
- Example: Add User, Add Hospital, Create Product.

13. Refresh Button
- Add a refresh/reload button to fetch the latest data.

14. Export Option
- Add export functionality where applicable.
- Standard formats: CSV, Excel, PDF.

15. Loading State
- Show a proper loading state while records are being fetched.
- Prefer skeleton loader over only spinner.

16. Empty State
- Show a meaningful empty state when no records exist.
- Example: No records found. Try changing your search or filters.

17. Error State
- Show a proper error message when API/data loading fails.
- Include a Retry button.

18. Mobile Responsive View
- Listing page must work properly on mobile, tablet, and desktop.
- On mobile, use responsive table, card layout, or horizontal scroll where needed.

19. Column/Header Labels
- Every column must have clear and human-readable labels.
- Avoid unclear database-style names in UI.

20. Date/Time Formatting
- Display dates and times in readable format.
- Example: 08 Jun 2026, 07:30 PM.
- Do not show raw timestamps unless required.

21. Search/Filter Reset
- Provide a Clear All or Reset Filters button.
- It should reset search, filters, sort, and page when required.

22. Confirmation Modal
- Any destructive action must show confirmation.
- Examples: Delete, bulk delete, deactivate, archive.
- Do not perform destructive actions directly without confirmation.

23. Permission-Based Actions
- Show or hide actions based on user role/permission.
- Example: Admin can delete; viewer can only view.

24. URL Query Persistence
- Search, filter, sort, page, and rows-per-page state must be stored in URL query parameters.
- This allows refresh, browser back, bookmark, and sharing of filtered listing pages.

25. Server-Side Search/Filter/Sort/Pagination
- For performance, listing pages must use server-side search, filtering, sorting, and pagination.
- Do not fetch thousands of records and process everything only on the frontend.

Standard UI Layout:

Page Title + Description                       [Add/Create Button]

Search Bar     [Filter] [Sort] [Export] [Refresh]

Quick Filter Chips / Status Tabs

Showing 125 of 1,240 records        Rows per page: 25

Table/List/Card Data

Bulk Action Bar, visible only when records are selected

Pagination: Previous  1 2 3  Next

Standard API Query Pattern:

GET /api/{module}
?page=1
&per_page=25
&search=keyword
&status=active
&sort_by=created_at
&sort_order=desc

Implementation Rules:

- Keep this standard reusable across all listing pages.
- Create reusable components where possible:
  - ListingHeader
  - SearchBar
  - FilterPanel
  - SortDropdown
  - DataTable
  - StatusBadge
  - Pagination
  - BulkActionBar
  - EmptyState
  - ErrorState
  - LoadingSkeleton
  - ConfirmationModal

- Do not duplicate listing logic unnecessarily.
- Keep UI consistent across all modules.
- Make the design clean, modern, responsive, and user-friendly.
- Ensure backend/API supports the required query parameters.
- Ensure frontend state syncs with URL query parameters.
- Ensure role-based permissions are respected before showing actions.
- Ensure destructive actions require confirmation.
- Ensure large datasets are handled efficiently using server-side logic.

Before finalizing any listing page, verify this checklist:

[ ] Page Title
[ ] Search
[ ] Filter
[ ] Sort
[ ] Pagination
[ ] Rows Per Page
[ ] Total Records Count
[ ] Status Badge
[ ] Row Actions
[ ] Bulk Selection
[ ] Bulk Actions
[ ] Add/Create Button
[ ] Refresh Button
[ ] Export Option
[ ] Loading State
[ ] Empty State
[ ] Error State
[ ] Mobile Responsive View
[ ] Column/Header Labels
[ ] Date/Time Formatting
[ ] Search/Filter Reset
[ ] Confirmation Modal
[ ] Permission-Based Actions
[ ] URL Query Persistence
[ ] Server-Side Search/Filter/Sort/Pagination

Your task:
Review the current listing page implementation and update it to fully comply with this mandatory listing page standard. If this is a new page, build it using this standard from the beginning.Code language: JavaScript (javascript)

Minimum Mandatory UI Structure

Page Title                         [Add New]

Search Bar                         [Filter] [Sort] [Export] [Refresh]

Status / Quick Filters

Showing 125 of 1,240 records

Table / List / Card Data

Bulk Action Bar

Rows per page: 25     Previous  1 2 3  Next
Code language: PHP (php)

Minimum Mandatory API Parameters

?page=1
&per_page=25
&search=keyword
&filter_status=active
&sort_by=created_at
&sort_order=desc

Final Mandatory Checklist

Search
Filter
Sort
Pagination
Rows per page
Total count
Add button
Refresh
Export
Status badge
Row actions
Bulk selection
Bulk actions
Loading state
Empty state
Error state
Reset filters
Confirmation modal
Permission-based actions
Mobile responsive layout
Server-side data handling
URL query persistence
Code language: JavaScript (javascript)

This should be your fixed mandatory listing-page standard for all websites and applications.

Absolutely, Rajesh. For any listing page in a web application — users list, products list, hospitals list, doctors list, bookings list, tasks list, orders list, blogs list, etc. — you should standardize one common template.

A good name for this is:

Standard Listing Page / Data Grid Template

This template should define all common features required to display, search, filter, sort, manage, and navigate large amounts of data consistently.


1. Page Header Options

Every listing page should have a consistent top section.

Common items:

FeatureMeaning
Page TitleExample: Users, Hospitals, Doctors, Bookings
Page DescriptionSmall explanation of what this page is for
BreadcrumbDashboard > Users > All Users
Primary Action ButtonAdd User, Add Hospital, Create Booking
Secondary ActionsImport, Export, Refresh, Download
Help / Info IconOpens guide or tooltip
Last Updated TimeShows when list was refreshed

Example:

Users
Manage all registered users and their account status.

[Import] [Export] [Add User]
Code language: CSS (css)

2. Search Options

Search is one of the most important parts of listing pages.

Common search types:

Search TypeExample
Global SearchSearch across name, email, phone, ID
Field-Specific SearchSearch only by email or mobile
Keyword SearchSearch by text
Exact Match SearchSearch exact user ID or order ID
Partial SearchSearch “raj” and match “Rajesh”
Advanced SearchMultiple fields combined
Search SuggestionsAuto-suggest while typing
Recent SearchesShow previously searched terms
Search HighlightingHighlight matching words in result
Clear SearchReset search box

Recommended standard:

Search by name, email, phone, ID...

Also keep a clear button:

[X] Clear
Code language: CSS (css)

3. Filter Options

Filters help users narrow down records.

Common filter types:

Filter TypeExample
Status FilterActive, Inactive, Pending, Suspended
Category FilterPremium, Free, Verified
Date Range FilterToday, Last 7 Days, This Month
Custom Date FilterFrom Date / To Date
Location FilterCountry, State, City
Role FilterAdmin, User, Manager
Type FilterHospital, Doctor, Patient
Price / Amount FilterMin amount / Max amount
Rating Filter1 star to 5 stars
Tag FilterFeatured, Popular, New
Owner / Assigned To FilterAssigned user or manager
Boolean FilterYes / No, Verified / Not Verified
Multi-select FilterSelect multiple statuses
Dependent FilterCountry → State → City
Saved FilterSave commonly used filter combinations

Example filters:

Status: Active
Role: Admin
Country: India
Created Date: Last 30 Days
Verification: Verified
Code language: JavaScript (javascript)

4. Sorting Options

Sorting helps users organize records.

Common sorting options:

Sort OptionExample
Sort by NameA-Z / Z-A
Sort by Created DateNewest First / Oldest First
Sort by Updated DateRecently Updated
Sort by StatusActive first
Sort by PriceLow to High / High to Low
Sort by RatingHighest Rated
Sort by PopularityMost viewed / most used
Sort by PriorityHigh priority first
Sort by Custom OrderManual ordering
Multi-column SortSort by status, then date

Recommended UI:

Sort By: Newest First

For table columns, allow clicking column headers:

Name ↑
Created DateCode language: JavaScript (javascript)

5. Pagination Options

Pagination is required when data is large.

Common pagination features:

FeatureMeaning
Page Numbers1, 2, 3, 4
Previous / NextMove one page
First / Last PageJump to start or end
Rows Per Page10, 25, 50, 100
Total Records CountShowing 1–25 of 2,340
Infinite ScrollLoad more while scrolling
Load More ButtonManual next batch
Cursor PaginationBetter for very large data
Server-side PaginationBackend returns limited data
Client-side PaginationFrontend paginates loaded data

Recommended standard:

Showing 1–25 of 2,340 records
Rows per page: 25
[Previous] 1 2 3 4 [Next]
Code language: CSS (css)

For large systems, use server-side pagination.


6. Column Management

Very useful for admin panels and dashboards.

FeatureMeaning
Column VisibilityShow/hide columns
Column ReorderingDrag columns left/right
Column ResizingAdjust width
Fixed ColumnsKeep important columns sticky
Sticky HeaderHeader stays visible while scrolling
Column AlignmentText left, numbers right
Column FormattingDate, currency, status badges
Responsive ColumnsHide less important columns on mobile

Example:

Columns: Name, Email, Phone, Status, Created Date, Actions
Code language: JavaScript (javascript)

Add a button:

[Customize Columns]
Code language: JSON / JSON with Comments (json)

7. View Options

Different users prefer different viewing styles.

View TypeMeaning
Table ViewBest for admin data
Card ViewBest for mobile or visual data
Grid ViewBest for products, doctors, hospitals
List ViewCompact vertical list
Kanban ViewStatus-based workflow
Calendar ViewBookings, appointments, events
Map ViewLocation-based listings
Timeline ViewActivity/history-based data

Example:

[Table] [Grid] [Card] [Map]
Code language: JSON / JSON with Comments (json)

8. Bulk Actions

Bulk actions save time when managing many records.

Bulk ActionExample
Select OneCheckbox per row
Select All on PageSelect visible records
Select All Matching FilterSelect all 2,340 records
Bulk DeleteDelete selected records
Bulk Activate / DeactivateChange status
Bulk Approve / RejectApprove listings
Bulk AssignAssign to manager
Bulk ExportExport selected records
Bulk TagAdd tags
Bulk MoveMove to category
Bulk Email / NotifySend notification
Bulk ArchiveArchive records

Standard message:

25 records selected
[Delete] [Export] [Change Status] [Assign]
Code language: CSS (css)

9. Row-Level Actions

Each row/card usually needs actions.

Common row actions:

ActionMeaning
ViewOpen detail page
EditModify record
DeleteRemove record
DuplicateCopy record
ArchiveSoft remove
RestoreRestore deleted/archived record
ApproveApprove pending record
RejectReject request
ActivateEnable record
DeactivateDisable record
VerifyMark as verified
FeatureMark as featured
AssignAssign to team member
More ActionsDropdown menu

Recommended:

[View] [Edit] [More]
Code language: JSON / JSON with Comments (json)

Inside More:

Duplicate
Archive
Delete

10. Status Indicators

Status should be visually clear.

Common status indicators:

Status TypeExample
Active / InactiveUser status
PendingWaiting approval
ApprovedAccepted
RejectedDeclined
DraftNot published
PublishedLive
SuspendedBlocked
VerifiedConfirmed
UnverifiedNot confirmed
FeaturedHighlighted
ExpiredTime over
Failed / SuccessJob or payment status

Use badges:

Active
Pending
Verified
Premium

11. Data Display Formatting

Data should look consistent.

Common formatting standards:

Data TypeFormat
Date08 Jun 2026
Date + Time08 Jun 2026, 07:30 PM
Currency₹4,999 / $100
Percentage85%
Phone+91 98765 43210
BooleanYes / No
Empty Value
Long TextTruncate with tooltip
URLClickable link
EmailClickable mail link
ImageThumbnail/avatar
FileFile icon + download

Avoid showing raw values like:

null
undefined
0000-00-00
Code language: JavaScript (javascript)

Use:


12. Empty State

When no data exists, show a helpful message.

Types of empty states:

Empty StateExample
No Records YetNo users have been added
No Search ResultsNo result found for “Rajesh”
No Filter ResultsNo active users found
Error StateCould not load data
Permission StateYou do not have access

Good empty state:

No hospitals found.

Try changing your filters or add a new hospital.

[Add Hospital]
Code language: PHP (php)

13. Loading State

Important for good UX.

Common loading options:

Loading TypeMeaning
SpinnerBasic loading
Skeleton LoaderBetter modern loading
Shimmer EffectPremium loading UI
Button LoadingWhile submitting
Lazy LoadingLoad only visible rows
Progressive LoadingLoad important data first

Recommended for listing page:

Skeleton table rows while data loads
Code language: JavaScript (javascript)

14. Error Handling

Every listing page should handle errors cleanly.

Common error states:

ErrorMessage
API FailedUnable to load records
Network ErrorPlease check your internet connection
Permission ErrorYou do not have permission
TimeoutRequest took too long
Server ErrorSomething went wrong
Invalid FilterPlease check selected filters

Useful buttons:

[Retry]
[Refresh]
[Contact Support]
Code language: JSON / JSON with Comments (json)

15. Refresh and Sync Options

Important for real-time or admin systems.

FeatureMeaning
Manual RefreshRefresh button
Auto RefreshRefresh every X seconds
Last Synced TimeLast updated 2 mins ago
Real-time UpdatesWebSocket/live updates
Pull to RefreshMobile-friendly
Sync StatusSynced / Sync Failed

Example:

Last updated: 2 minutes ago
[Refresh]
Code language: CSS (css)

16. Export Options

Most admin listing pages need export.

Common export formats:

Export TypeUse
CSVCommon data export
ExcelBusiness users
PDFReports
JSONDevelopers/API
PrintPrintable list
Selected Rows ExportExport only selected
Filtered ExportExport current filtered result
Full ExportExport all records

Example:

[Export CSV] [Export Excel] [Export PDF]
Code language: JSON / JSON with Comments (json)

17. Import Options

Useful for bulk data entry.

Import FeatureMeaning
Upload CSVBulk upload
Upload ExcelBulk upload
Download Sample TemplateProvide correct format
Import ValidationCheck errors before saving
Import PreviewShow records before final import
Duplicate HandlingSkip/update/overwrite
Import HistoryShow past imports

Example:

[Import Users]
[Download Sample CSV]
Code language: JSON / JSON with Comments (json)

18. Saved Views

Very useful for admin dashboards.

Saved views allow users to save search, filter, sort, and column settings.

Examples:

All Users
Active Users
Pending Approval
Premium Hospitals
Recently Added
My Assigned Tasks

Features:

FeatureMeaning
Default ViewSystem default
Personal ViewUser-specific
Shared ViewShared with team
Rename ViewChange saved view name
Delete ViewRemove saved view
Pin ViewKeep favorite view first

19. Advanced Filter Panel

For complex pages, use a filter drawer/sidebar.

Common fields:

Keyword
Status
Category
Country
State
City
Created Date
Updated Date
Owner
Price Range
Verification Status
Tags
Code language: JavaScript (javascript)

Buttons:

[Apply Filters]
[Reset]
[Save View]
Code language: JSON / JSON with Comments (json)

20. Quick Filter Chips

Useful for common filters.

Example:

[All] [Active] [Pending] [Verified] [Premium] [Expired]
Code language: JSON / JSON with Comments (json)

Or:

Today
Last 7 Days
This Month
This Year

21. Record Count Summary

Always show useful counts.

Examples:

Total Users: 2,340
Active: 1,920
Pending: 120
Suspended: 35

For dashboards:

All 2,340 | Active 1,920 | Pending 120 | Blocked 35

22. Permissions and Role-Based Visibility

Not every user should see every action.

Examples:

RoleAccess
AdminView, Add, Edit, Delete, Export
ManagerView, Edit, Assign
StaffView only
ViewerRead-only

Hide actions if the user lacks permission.

Example:

Admin sees Delete
Normal user does not see Delete

23. Audit and Activity Options

For serious applications, track actions.

Useful options:

FeatureMeaning
Created ByWho created record
Created AtWhen created
Updated ByWho last edited
Updated AtLast update time
Activity LogFull change history
Version HistoryPrevious versions
Deleted ByWho deleted
Restored ByWho restored

24. Mobile Responsiveness

Listing pages must work well on mobile.

Mobile options:

FeatureMeaning
Card LayoutBetter than wide table
Horizontal Scroll TableFor admin tables
Sticky Action ButtonAdd button fixed
Collapsible FiltersFilter drawer
Bottom Sheet ActionsMobile-friendly row actions
Swipe ActionsSwipe to edit/delete
Compact PaginationPrevious / Next only
Search on TopAlways visible

For mobile, prefer:

Card View + Filter Drawer + Sort Dropdown

25. Performance Options for Large Data

Very important when records are large.

FeatureMeaning
Server-side PaginationLoad limited records
Server-side SearchSearch from backend
Server-side SortingSort in database
Server-side FilteringFilter in database
Database IndexingFast query performance
Debounced SearchWait before API call
Lazy LoadingLoad only needed data
Virtual ScrollingRender only visible rows
CachingStore repeated results
API Query ParamsConsistent backend queries
Cursor PaginationBetter for millions of records
Background ExportExport large data asynchronously
Optimized Count QueryAvoid slow total count
CDN for ImagesFaster thumbnails
Thumbnail ImagesAvoid loading full images

Example API:

GET /api/users?page=1&per_page=25&search=rajesh&status=active&sort=created_at&order=desc

26. Accessibility Options

Good listing pages should be usable by everyone.

FeatureMeaning
Keyboard NavigationTab through controls
Screen Reader LabelsProper aria labels
Proper ContrastReadable text
Focus StateVisible selected field
Sort AnnouncementsTell user sort changed
Button LabelsAvoid icon-only buttons
Table HeadersProper semantic table
Error MessagesClear and readable

27. Confirmation and Safety

For destructive actions, add confirmation.

Examples:

Are you sure you want to delete this user?
This action cannot be undone.
[Cancel] [Delete]
Code language: JavaScript (javascript)

For bulk delete:

You are about to delete 25 records.
Type DELETE to confirm.
Code language: JavaScript (javascript)

Useful safety options:

FeatureMeaning
Soft DeleteMove to trash instead of permanent delete
RestoreBring deleted data back
Confirmation ModalPrevent accidental delete
Undo ActionUndo recent action
Permission CheckOnly authorized users can delete

28. Notifications and Feedback

After every action, show feedback.

Examples:

User updated successfully.
25 records exported successfully.
Unable to delete record. Please try again.
Code language: JavaScript (javascript)

Types:

TypeExample
Success ToastSaved successfully
Error ToastFailed to save
Warning ToastSome records skipped
Info ToastExport is being prepared

29. Detail Preview Options

Instead of opening a new page every time, you can show quick preview.

FeatureMeaning
Side Drawer PreviewOpens details on right
Expand RowShow extra row details
Modal PreviewQuick popup
Hover PreviewSmall tooltip preview
Quick ViewView without leaving list

Example:

Click row → open side panel with details
Code language: JavaScript (javascript)

30. Selection and Checkbox Behavior

Important for bulk operations.

Standard options:

Checkbox per row
Select all visible records
Select all matching filter
Clear selection
Show selected count

Example:

25 selected on this page.
Select all 2,340 matching records?
Code language: JavaScript (javascript)

31. Tabs and Segmentation

Tabs are useful when data has clear groups.

Examples:

All
Active
Pending
Rejected
Archived

Or:

Hospitals
Doctors
Patients
Appointments

32. Search + Filter + Sort URL Persistence

Very important for professional apps.

When user applies filters, URL should update:

/users?search=rajesh&status=active&page=2&sort=created_at&order=desc

Benefits:

BenefitMeaning
Shareable URLUser can share filtered view
Browser Back WorksBack button behaves properly
Refresh SafeFilter does not disappear
BookmarkableUser can save view

33. Default Values

Every listing page should define defaults.

Example:

Default Sort: Created Date DESC
Default Page Size: 25
Default View: Table
Default Filter: Active Records
Default Columns: Name, Email, Status, Created Date, Actions
Code language: PHP (php)

34. Admin-Specific Listing Features

For admin panels, include:

Search
Advanced Filter
Sort
Pagination
Bulk Action
Export
Import
Status Change
Role-Based Actions
Audit Log
Trash/Restore
Column Customization
Saved Views

35. User-Friendly Microcopy

Use clear text everywhere.

Instead of:

No data

Use:

No records found. Try adjusting your search or filters.
Code language: PHP (php)

Instead of:

Submit

Use:

Apply Filters

Instead of:

Reset

Use:

Clear All Filters

Final Master Checklist for Listing Pages

Use this checklist for every website/application listing page:

1. Page title
2. Page description
3. Breadcrumb
4. Add/Create button
5. Global search
6. Advanced search
7. Filters
8. Quick filter chips
9. Sort dropdown
10. Column sorting
11. Pagination
12. Rows per page
13. Total record count
14. Table view
15. Card/grid view
16. Column show/hide
17. Column resize/reorder
18. Sticky header
19. Row actions
20. Bulk selection
21. Bulk actions
22. Status badges
23. Date/currency formatting
24. Empty state
25. Loading skeleton
26. Error state
27. Retry button
28. Refresh button
29. Last updated time
30. Export CSV/Excel/PDF
31. Import CSV/Excel
32. Saved views
33. Filter persistence in URL
34. Role-based permissions
35. Audit fields
36. Activity log
37. Detail preview drawer
38. Confirmation modal
39. Toast notifications
40. Soft delete/trash
41. Restore option
42. Mobile responsive layout
43. Accessibility support
44. Server-side pagination
45. Server-side search
46. Server-side filtering
47. Server-side sorting
48. Debounced search
49. Database indexing
50. API query standard
Code language: JavaScript (javascript)

Best Standard Template Name

You can call this internally:

Universal Listing Page Template

or

Standard Data Listing / Data Grid Framework

or

CRUD Listing Page UI Standard

My recommended name:

Universal Data Listing Page Standard

Recommended Standard Layout

------------------------------------------------
Breadcrumb
Page Title + Description              [Add New]
------------------------------------------------
Search Bar                            [Export]
Quick Filters                         [Import]
Advanced Filter Button                [Columns]
------------------------------------------------
Summary Counts
All | Active | Pending | Archived
------------------------------------------------
Table / Card / Grid Data
------------------------------------------------
Bulk Actions Bar
------------------------------------------------
Pagination + Rows Per Page + Total Count
------------------------------------------------
Code language: PHP (php)

Best Common API Pattern

Use the same backend query style everywhere:

GET /api/{module}
    ?page=1
    &per_page=25
    &search=keyword
    &status=active
    &sort_by=created_at
    &sort_order=desc
    &from_date=2026-01-01
    &to_date=2026-06-08
Code language: JavaScript (javascript)

Example:

GET /api/hospitals?page=1&per_page=25&search=apollo&status=active&sort_by=created_at&sort_order=desc

Minimum Features Every Listing Page Must Have

At minimum, every listing page should include:

Search
Filter
Sort
Pagination
Rows per page
Total count
Status badge
View/Edit/Delete actions
Bulk selection
Export
Refresh
Empty state
Loading state
Error state
Mobile responsive layout
Code language: JavaScript (javascript)

For professional admin systems, also include:

Saved views
Column customization
Advanced filters
Audit log
Role-based actions
URL persistence
Server-side performance optimization

This standard will make all your website listing pages consistent, scalable, and much easier for users to understand.

  • Standard Listing Page Requirements for Web Applications
  • Essential Features Every Listing Page Must Have
  • Universal Listing Page Standard for Web Developers
  • Mandatory Data Listing Page Checklist
  • Common Listing Page Features for Admin Panels and Web Apps
  • Standard Data Grid and Listing Page Guidelines
  • Listing Page UI/UX Standards for Web Applications
  • Essential Search, Filter, Sort, and Pagination Standards
  • Reusable Listing Page Template for Web Applications
  • Web Application Listing Page Best Practices

Rajesh, for your stack — Laravel + Node + Alpine.js + Tailwind CSS — the best implementation is:

Build One Universal Server-Side Listing Framework

Do not create search, filter, sort, pagination, export, bulk action, etc. separately for every page.

Instead, create one reusable listing system and use it everywhere.

Example:

Users Listing
Hospitals Listing
Doctors Listing
Products Listing
Blogs Listing
Tasks Listing
Orders Listing
Payments Listing

All should use the same common framework.


Best Architecture for Your Stack

Tailwind CSS
    ↓
Common UI Components

Alpine.js
    ↓
Search, filters, sort, pagination, URL query sync

Laravel
    ↓
Main listing API, database query, pagination, permissions

Node.js
    ↓
Optional: heavy exports, background jobs, realtime updates, external APIs

Database
    ↓
Indexed search/filter/sort columns

Best division:

LayerResponsibility
LaravelMain backend listing logic
Alpine.jsFrontend interactivity
Tailwind CSSCommon listing UI design
Node.jsOptional heavy processing / realtime / workers
DatabaseIndexed server-side search/filter/sort

Most Important Rule

Never do this:

Load 50,000 records in browser
Then search/filter/sort using JavaScript

Always do this:

Load only 10/25/50/100 records
Search/filter/sort/paginate on server side
Return only required records
Code language: PHP (php)

This is the main secret for performance.


Standard Query Pattern for Every Listing Page

Use the same URL/query parameters everywhere:

/users?page=1&per_page=25&search=rajesh&status=active&sort_by=created_at&sort_order=desc

Same pattern for hospitals:

/hospitals?page=1&per_page=25&search=apollo&status=verified&sort_by=name&sort_order=asc

Same pattern for blogs:

/blogs?page=1&per_page=25&search=laravel&status=published&sort_by=created_at&sort_order=desc

Recommended Folder Structure in Laravel

app/
 ├── Support/
 │    └── Listing/
 │         ├── ListingQuery.php
 │         └── ListingConfig.php
 │
 ├── Http/
 │    ├── Requests/
 │    │    └── ListingRequest.php
 │    └── Controllers/
 │         ├── UserController.php
 │         ├── HospitalController.php
 │         └── BlogController.php

resources/
 ├── views/
 │    ├── components/
 │    │    └── listing/
 │    │         ├── layout.blade.php
 │    │         ├── search.blade.php
 │    │         ├── filters.blade.php
 │    │         ├── table.blade.php
 │    │         ├── pagination.blade.php
 │    │         ├── bulk-actions.blade.php
 │    │         ├── empty-state.blade.php
 │    │         ├── error-state.blade.php
 │    │         └── loading-skeleton.blade.php
 │    │
 │    └── admin/
 │         ├── users/index.blade.php
 │         ├── hospitals/index.blade.php
 │         └── blogs/index.blade.php
Code language: PHP (php)

Step 1: Create Common Listing Request

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class ListingRequest extends FormRequest
{
    public function authorize(): bool
    {
        return true;
    }

    public function rules(): array
    {
        return [
            'search' => ['nullable', 'string', 'max:100'],
            'page' => ['nullable', 'integer', 'min:1'],
            'per_page' => ['nullable', 'integer', 'in:10,25,50,100'],
            'sort_by' => ['nullable', 'string', 'max:50'],
            'sort_order' => ['nullable', 'in:asc,desc'],

            // common optional filters
            'status' => ['nullable', 'string', 'max:50'],
            'type' => ['nullable', 'string', 'max:50'],
            'role' => ['nullable', 'string', 'max:50'],
            'from_date' => ['nullable', 'date'],
            'to_date' => ['nullable', 'date'],
        ];
    }

    public function perPage(): int
    {
        return (int) $this->input('per_page', 25);
    }

    public function sortOrder(): string
    {
        return $this->input('sort_order', 'desc') === 'asc' ? 'asc' : 'desc';
    }
}
Code language: HTML, XML (xml)

Step 2: Create Reusable Laravel Listing Query Service

<?php

namespace App\Support\Listing;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Http\Request;

class ListingQuery
{
    public static function apply(
        Builder $query,
        Request $request,
        array $config
    ) {
        $searchable = $config['searchable'] ?? [];
        $filterable = $config['filterable'] ?? [];
        $sortable = $config['sortable'] ?? [];
        $defaultSort = $config['default_sort'] ?? 'created_at';
        $defaultOrder = $config['default_order'] ?? 'desc';

        /**
         * Search
         */
        if ($request->filled('search') && count($searchable) > 0) {
            $search = trim($request->input('search'));

            $query->where(function ($q) use ($searchable, $search) {
                foreach ($searchable as $column) {
                    $q->orWhere($column, 'LIKE', $search . '%');
                }
            });
        }

        /**
         * Filters
         */
        foreach ($filterable as $filter => $column) {
            if ($request->filled($filter)) {
                $query->where($column, $request->input($filter));
            }
        }

        /**
         * Date filters
         */
        if ($request->filled('from_date')) {
            $query->whereDate('created_at', '>=', $request->input('from_date'));
        }

        if ($request->filled('to_date')) {
            $query->whereDate('created_at', '<=', $request->input('to_date'));
        }

        /**
         * Sorting with whitelist
         */
        $sortBy = $request->input('sort_by', $defaultSort);
        $sortOrder = $request->input('sort_order', $defaultOrder);

        if (! in_array($sortBy, $sortable)) {
            $sortBy = $defaultSort;
        }

        if (! in_array($sortOrder, ['asc', 'desc'])) {
            $sortOrder = $defaultOrder;
        }

        $query->orderBy($sortBy, $sortOrder);

        /**
         * Pagination
         */
        $perPage = (int) $request->input('per_page', 25);

        if (! in_array($perPage, [10, 25, 50, 100])) {
            $perPage = 25;
        }

        return $query->paginate($perPage)->withQueryString();
    }
}
Code language: HTML, XML (xml)

Step 3: Use It in Every Controller

Example: UserController.php

<?php

namespace App\Http\Controllers;

use App\Models\User;
use App\Http\Requests\ListingRequest;
use App\Support\Listing\ListingQuery;

class UserController extends Controller
{
    public function index(ListingRequest $request)
    {
        $query = User::query()
            ->select([
                'id',
                'name',
                'email',
                'phone',
                'role',
                'status',
                'created_at',
            ]);

        $users = ListingQuery::apply($query, $request, [
            'searchable' => ['name', 'email', 'phone'],
            'filterable' => [
                'status' => 'status',
                'role' => 'role',
            ],
            'sortable' => [
                'name',
                'email',
                'status',
                'role',
                'created_at',
                'updated_at',
            ],
            'default_sort' => 'created_at',
            'default_order' => 'desc',
        ]);

        return view('admin.users.index', [
            'records' => $users,
            'filters' => $request->validated(),
        ]);
    }
}
Code language: HTML, XML (xml)

Now for hospitals:

$hospitals = ListingQuery::apply($query, $request, [
    'searchable' => ['name', 'email', 'phone', 'city'],
    'filterable' => [
        'status' => 'status',
        'city' => 'city',
        'type' => 'type',
    ],
    'sortable' => ['name', 'status', 'city', 'created_at'],
    'default_sort' => 'created_at',
    'default_order' => 'desc',
]);
Code language: PHP (php)

Same framework. Only config changes. Beautiful.


Step 4: Create Common Blade Listing Layout

Example:

{{-- resources/views/components/listing/layout.blade.php --}}

<div 
    x-data="listingPage()" 
    class="space-y-4"
>
    <div class="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
        <div>
            <h1 class="text-2xl font-bold text-gray-900">
                {{ $title }}
            </h1>

            @isset($description)
                <p class="text-sm text-gray-500">
                    {{ $description }}
                </p>
            @endisset
        </div>

        <div class="flex gap-2">
            {{ $actions ?? '' }}
        </div>
    </div>

    <div class="rounded-xl border bg-white p-4 shadow-sm">
        {{ $toolbar ?? '' }}

        <div class="mt-4">
            {{ $slot }}
        </div>

        <div class="mt-4">
            {{ $pagination ?? '' }}
        </div>
    </div>
</div>
Code language: HTML, XML (xml)

Step 5: Example Users Listing Page

<x-listing.layout 
    title="Users" 
    description="Manage all registered users"
>
    <x-slot:actions>
        <a href="{{ route('users.create') }}"
           class="rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white hover:bg-blue-700">
            Add User
        </a>
    </x-slot:actions>

    <x-slot:toolbar>
        <form method="GET" class="grid grid-cols-1 gap-3 md:grid-cols-5">
            <input 
                type="text"
                name="search"
                value="{{ request('search') }}"
                placeholder="Search by name, email, phone..."
                class="rounded-lg border-gray-300 md:col-span-2"
            >

            <select name="status" class="rounded-lg border-gray-300">
                <option value="">All Status</option>
                <option value="active" @selected(request('status') === 'active')>Active</option>
                <option value="inactive" @selected(request('status') === 'inactive')>Inactive</option>
                <option value="pending" @selected(request('status') === 'pending')>Pending</option>
            </select>

            <select name="sort_by" class="rounded-lg border-gray-300">
                <option value="created_at" @selected(request('sort_by') === 'created_at')>Created Date</option>
                <option value="name" @selected(request('sort_by') === 'name')>Name</option>
                <option value="status" @selected(request('sort_by') === 'status')>Status</option>
            </select>

            <div class="flex gap-2">
                <button class="rounded-lg bg-gray-900 px-4 py-2 text-white">
                    Apply
                </button>

                <a href="{{ route('users.index') }}"
                   class="rounded-lg border px-4 py-2">
                    Reset
                </a>
            </div>
        </form>
    </x-slot:toolbar>

    <div class="mb-3 flex items-center justify-between text-sm text-gray-600">
        <div>
            Showing {{ $records->firstItem() }} to {{ $records->lastItem() }}
            of {{ $records->total() }} records
        </div>

        <form method="GET">
            @foreach(request()->except('per_page', 'page') as $key => $value)
                <input type="hidden" name="{{ $key }}" value="{{ $value }}">
            @endforeach

            <select name="per_page" onchange="this.form.submit()" class="rounded-lg border-gray-300">
                <option value="10" @selected(request('per_page', 25) == 10)>10</option>
                <option value="25" @selected(request('per_page', 25) == 25)>25</option>
                <option value="50" @selected(request('per_page', 25) == 50)>50</option>
                <option value="100" @selected(request('per_page', 25) == 100)>100</option>
            </select>
        </form>
    </div>

    <div class="overflow-x-auto">
        <table class="min-w-full divide-y divide-gray-200 text-sm">
            <thead class="bg-gray-50">
                <tr>
                    <th class="px-4 py-3 text-left">
                        <input type="checkbox">
                    </th>
                    <th class="px-4 py-3 text-left">Name</th>
                    <th class="px-4 py-3 text-left">Email</th>
                    <th class="px-4 py-3 text-left">Role</th>
                    <th class="px-4 py-3 text-left">Status</th>
                    <th class="px-4 py-3 text-left">Created At</th>
                    <th class="px-4 py-3 text-right">Actions</th>
                </tr>
            </thead>

            <tbody class="divide-y divide-gray-100 bg-white">
                @forelse($records as $user)
                    <tr>
                        <td class="px-4 py-3">
                            <input type="checkbox" value="{{ $user->id }}">
                        </td>

                        <td class="px-4 py-3 font-medium">
                            {{ $user->name }}
                        </td>

                        <td class="px-4 py-3">
                            {{ $user->email }}
                        </td>

                        <td class="px-4 py-3">
                            {{ ucfirst($user->role) }}
                        </td>

                        <td class="px-4 py-3">
                            <span class="rounded-full px-2 py-1 text-xs font-medium
                                {{ $user->status === 'active' ? 'bg-green-100 text-green-700' : 'bg-gray-100 text-gray-700' }}">
                                {{ ucfirst($user->status) }}
                            </span>
                        </td>

                        <td class="px-4 py-3">
                            {{ $user->created_at->format('d M Y, h:i A') }}
                        </td>

                        <td class="px-4 py-3 text-right">
                            <a href="{{ route('users.show', $user) }}" class="text-blue-600">
                                View
                            </a>

                            <a href="{{ route('users.edit', $user) }}" class="ml-3 text-indigo-600">
                                Edit
                            </a>

                            @can('delete', $user)
                                <button 
                                    type="button"
                                    class="ml-3 text-red-600"
                                    onclick="confirm('Are you sure?')">
                                    Delete
                                </button>
                            @endcan
                        </td>
                    </tr>
                @empty
                    <tr>
                        <td colspan="7" class="px-4 py-10 text-center text-gray-500">
                            No records found. Try changing your search or filters.
                        </td>
                    </tr>
                @endforelse
            </tbody>
        </table>
    </div>

    <x-slot:pagination>
        {{ $records->links() }}
    </x-slot:pagination>
</x-listing.layout>
Code language: HTML, XML (xml)

Step 6: Add Alpine.js for Better Search UX

Use Alpine.js for debounce search and URL sync.

<script>
function listingPage() {
    return {
        search: new URLSearchParams(window.location.search).get('search') || '',
        timeout: null,

        updateSearch() {
            clearTimeout(this.timeout);

            this.timeout = setTimeout(() => {
                const params = new URLSearchParams(window.location.search);

                if (this.search.length >= 2) {
                    params.set('search', this.search);
                } else {
                    params.delete('search');
                }

                params.set('page', 1);

                window.location.search = params.toString();
            }, 400);
        }
    }
}
</script>
Code language: HTML, XML (xml)

Use it:

<input
    type="text"
    x-model="search"
    x-on:input="updateSearch"
    placeholder="Search..."
    class="rounded-lg border-gray-300"
/>
Code language: JavaScript (javascript)

This prevents API/database hits on every keypress.


Step 7: Database Indexes Are Mandatory

For performance, add indexes on columns used in search, filter, and sort.

Example for users:

Schema::table('users', function (Blueprint $table) {
    $table->index('status');
    $table->index('role');
    $table->index('created_at');
    $table->index(['status', 'created_at']);
    $table->index('email');
});
Code language: PHP (php)

For hospitals:

Schema::table('hospitals', function (Blueprint $table) {
    $table->index('status');
    $table->index('city');
    $table->index('country');
    $table->index('created_at');
    $table->index(['status', 'city']);
});
Code language: PHP (php)

Without indexes, server-side filtering can still become slow.


Step 8: Do Not Use SELECT *

Bad:

User::query()->paginate(25);
Code language: PHP (php)

Better:

User::query()
    ->select(['id', 'name', 'email', 'status', 'created_at'])
    ->paginate(25);
Code language: PHP (php)

Only return the fields required for the listing page.


Step 9: Export Should Not Load Huge Data in Browser

For small export:

Export current filtered result directly from Laravel
Code language: JavaScript (javascript)

For large export:

Create background export job
Generate CSV/Excel
Store file
Show download link
Code language: JavaScript (javascript)

Good pattern:

User clicks Export
    ↓
Laravel creates export job
    ↓
Queue worker generates file
    ↓
User downloads file
Code language: JavaScript (javascript)

Node.js can also handle heavy export jobs, but Laravel queues are enough for most applications.


Step 10: Bulk Action Best Practice

Do not send full records.

Bad:

{
  "records": [
    {"id": 1, "name": "Rajesh"},
    {"id": 2, "name": "Amit"}
  ]
}
Code language: JSON / JSON with Comments (json)

Good:

{
  "ids": [1, 2, 3],
  "action": "activate"
}
Code language: JSON / JSON with Comments (json)

For “select all matching filters”:

{
  "select_all_matching": true,
  "filters": {
    "status": "pending",
    "search": "doctor"
  },
  "action": "approve"
}
Code language: JSON / JSON with Comments (json)

Where Node.js Fits

Since you are also using Node.js, use it only where it adds value.

Use Node.js for:

Realtime notifications
WebSocket updates
Heavy export workers
External API sync
Background processing
Activity stream
Search microservice
Code language: JavaScript (javascript)

Do not use Node.js just to duplicate Laravel listing APIs. That creates unnecessary complexity.

Best approach:

Laravel = primary listing backend
Node.js = optional async/realtime services
Alpine.js = frontend interaction
Tailwind CSS = UI design
Code language: JavaScript (javascript)

Best Implementation Strategy for Entire Application

Phase 1: Create Common Foundation

Build these once:

ListingRequest
ListingQuery service
Listing Blade components
StatusBadge component
Pagination component
Search/filter toolbar
Bulk action component
Empty/loading/error states
Confirmation modal
Code language: PHP (php)

Phase 2: Define Standard Per Module

For every module, define only this:

[
    'title' => 'Users',
    'searchable' => ['name', 'email', 'phone'],
    'filterable' => [
        'status' => 'status',
        'role' => 'role',
    ],
    'sortable' => ['name', 'status', 'created_at'],
    'columns' => ['name', 'email', 'status', 'created_at'],
    'actions' => ['view', 'edit', 'delete'],
]
Code language: PHP (php)

Phase 3: Apply to Every Listing Page

Convert pages one by one:

Users
Hospitals
Doctors
Products
Orders
Bookings
Blogs
Tasks
Payments
Reports

Phase 4: Optimize Database

For every listing table, add indexes for:

Search fields
Filter fields
Sort fields
Foreign keys
Created date
Status

Final Mandatory Performance Rules

Use this as your internal rule:

1. All listing pages must use server-side pagination.
2. All search must be handled by backend/database.
3. All filters must be handled by backend/database.
4. All sorting must be handled by backend/database.
5. Frontend should never load all records.
6. Search input must be debounced by 300–500ms.
7. Only whitelisted fields can be sorted or filtered.
8. Only required columns should be selected.
9. Database indexes must exist for common filters/sorts.
10. Large exports must run in background jobs.
11. Permission checks must exist on frontend and backend.
12. URL query parameters must store search/filter/sort/page state.
Code language: PHP (php)

Best Final Recommendation

For your application, implement this:

Universal Laravel Listing Framework with Alpine.js and Tailwind CSS

Use:

Laravel ListingQuery service
Laravel FormRequest validation
Reusable Blade listing components
Alpine.js URL/search/filter interactivity
Tailwind CSS responsive UI
Laravel queues or Node workers for heavy exports
Database indexes for all listing fields

This gives you:

Consistent UI
Fast performance
Reusable code
Easy maintenance
Mobile-friendly pages
Secure permissions
Scalable listing pages

This is the best and safest way to apply the same mandatory listing standard across your entire web application.

Leave a Reply