yekta-kalantary / ui-livewire
Reusable Livewire components built on top of yekta-kalantary/ui.
Requires
- php: ^8.3
- illuminate/support: ^13.0
- illuminate/view: ^13.0
- livewire/livewire: ^4.3
- yekta-kalantary/ui: dev-main
Requires (Dev)
- orchestra/testbench: ^11.1
- phpunit/phpunit: ^12.5
This package is auto-updated.
Last update: 2026-08-10 08:22:24 UTC
README
Reusable Livewire components built on top of yekta-kalantary/ui.
yekta-kalantary/ui-livewire owns reusable interactive UI state. It does not own application models, database schema, business queries, permissions or domain workflows.
- Packagist: https://packagist.org/packages/yekta-kalantary/ui-livewire
- Base UI package: https://packagist.org/packages/yekta-kalantary/ui
- Source: https://github.com/yekta-kalantary/ui-livewire
- Issues: https://github.com/yekta-kalantary/ui-livewire/issues
Requirements
- PHP 8.3+
- Laravel 13
- Livewire 4.3+
yekta-kalantary/ui- Tailwind CSS 4 when using the bundled UI styling
Installation
Both packages are available on Packagist. No custom Composer repository is required.
Before the first stable release
Both packages currently use their main development line. In a normal Laravel application whose minimum-stability is stable, require both development packages explicitly at the root:
composer require \
yekta-kalantary/ui:dev-main \
yekta-kalantary/ui-livewire:dev-main
Both main branches are aliased to 1.0.x-dev for Composer version resolution.
After stable 1.x tags exist
Installation will become:
composer require yekta-kalantary/ui-livewire
Composer will then resolve a compatible stable yekta-kalantary/ui automatically.
Laravel package discovery registers Yekta\UiLivewire\UiLivewireServiceProvider automatically.
Tailwind CSS 4 setup
The interactive components render Blade from both packages. Scan both vendor view directories and import the base UI stylesheet:
@import 'tailwindcss'; @import '../../vendor/yekta-kalantary/ui/resources/css/ui.css'; @source '../../vendor/yekta-kalantary/ui/resources/views/**/*.blade.php'; @source '../../vendor/yekta-kalantary/ui-livewire/resources/views/**/*.blade.php';
Without both @source entries, Tailwind may omit package utility classes from the final application CSS.
SearchSelect
The first interactive component is a generic server-backed search select.
It separates reusable interaction behavior from application-owned search logic:
SearchSelect
↓
SearchProvider contract
↓
Application query / service
The package owns:
- debounced Livewire search state;
- minimum-character behavior;
- dropdown visibility;
- loading and no-result states;
- selected-value synchronization;
- clearing;
- disabled state;
- result limits;
- selected-value validation through the provider.
The consuming application owns:
- which model or service is searched;
- which database columns are searched;
- authorization and tenant scope;
- result labels and descriptions;
- indexes and query performance.
Quick start
Create a provider:
<?php declare(strict_types=1); namespace App\Ui; use App\Models\Contact; use Yekta\UiLivewire\Contracts\SearchProvider; use Yekta\UiLivewire\Support\SearchOption; final class ContactSearchProvider implements SearchProvider { public function search(string $query, int $limit): array { return Contact::query() ->where(function ($builder) use ($query) { $builder ->where('first_name', 'like', "%{$query}%") ->orWhere('last_name', 'like', "%{$query}%") ->orWhere('mobile', 'like', "%{$query}%") ->orWhere('email', 'like', "%{$query}%"); }) ->limit($limit) ->get() ->map(fn (Contact $contact) => new SearchOption( value: $contact->getKey(), label: trim($contact->first_name.' '.$contact->last_name), description: $contact->mobile ?: $contact->email, )) ->all(); } public function find(string|int $value): ?SearchOption { $contact = Contact::query()->find($value); if (! $contact) { return null; } return new SearchOption( value: $contact->getKey(), label: trim($contact->first_name.' '.$contact->last_name), description: $contact->mobile ?: $contact->email, ); } }
Use it from a parent Livewire view:
<livewire:ui-livewire::search-select wire:model="contactId" :provider="\App\Ui\ContactSearchProvider::class" label="مخاطب" placeholder="نام، موبایل یا ایمیل..." />
Parent component property:
public int|string|null $contactId = null;
For the full lifecycle, props, edge cases and examples, see SearchSelect reference.
SearchProvider
Every search implementation must implement:
use Yekta\UiLivewire\Contracts\SearchProvider; use Yekta\UiLivewire\Support\SearchOption; interface SearchProvider { /** @return list<SearchOption> */ public function search(string $query, int $limit): array; public function find(string|int $value): ?SearchOption; }
Providers are resolved through Laravel's service container, so application services can be injected into their constructors.
find() is not optional. It is the trust boundary used to validate and hydrate selected values.
See Provider design for query, authorization, tenancy and performance guidance.
SearchOption
A result is represented by an immutable value object:
use Yekta\UiLivewire\Support\SearchOption; $option = new SearchOption( value: 15, label: 'Yekta Kalantary', description: '09121234567', );
| Property | Type | Required |
|---|---|---|
value |
`string | int` |
label |
string |
yes |
description |
?string |
no |
Localization
English and Persian translations are included for built-in component states:
- placeholder
- clear action
- searching state
- minimum-character feedback
- no-results state
The active Laravel locale is used automatically.
Publish overrides with:
php artisan vendor:publish --tag=ui-livewire-translations
Destination:
lang/vendor/ui-livewire
Publishing views
Publishing is optional:
php artisan vendor:publish --tag=ui-livewire-views
Destination:
resources/views/vendor/ui-livewire
Prefer the vendor view unless an application intentionally needs a markup override.
Architecture
Dependency direction is one-way:
ui-livewire
↓
ui
ui-livewire may depend on ui. The base package must never depend on Livewire or ui-livewire.
Business-specific components stay in the application unless their behavior can be expressed through a generic contract.
Examples that should stay application-owned:
ContactSearchProviderTicketAssigneeSearchProvider- permission checks
- tenant scoping
- Eloquent query details
The reusable SearchSelect interaction belongs here.
Development
git clone https://github.com/yekta-kalantary/ui-livewire.git cd ui-livewire composer update composer test
Validate Composer metadata:
composer validate --strict
CI covers:
- PHP 8.3 and 8.4;
- lowest supported dependency versions;
- highest matching dependency versions;
- package registration and localization;
- SearchSelect state transitions and provider validation.
See Architecture, testing and development.
Documentation
- SearchSelect reference
- Provider design and database search
- Styling and localization
- Architecture, testing and development
License
MIT