maryUI v1 is deprecated! Upgrade to v2 →

Choices

This component is intended to be used to build complex selection interfaces for single and multiple values. It also supports search on frontend or server, when dealing with large lists.

Most of time you just need a simple Select component, which renders nice natively on every device.

Selection

By default, it will look up for:

  • $object->id for option value.
  • $object->name for option display label.
  • $object->avatar for avatar picture.

Single
 
No results found.
Mason

Brooklyn

Gracie

Madilyn

Elena

Enrico

Lew

Oswald

Multiple
 
No results found.
Mason

Brooklyn

Gracie

Madilyn

Elena

Enrico

Lew

Oswald

Custom options
 
No results found.
gsawayn
Konopelskiport

pharvey
North Verlie

owolf
Port Leliaberg

iraynor
North Sandra

spencer.issac
Heidenreichmouth

dtremblay
North Kaitlyn

ansley82
Lake Kattieview

nikki.murphy
Herzogberg

It has custom options
@php
$users = $this->users;
@endphp
{{-- Notice `single` --}}
<x-choices label="Single" wire:model="user_id" :options="$users" single />
 
{{-- public array $users_multi_ids = []; --}}
<x-choices label="Multiple" wire:model="users_multi_ids" :options="$users" />
 
{{-- Custom options --}}
<x-choices
label="Custom options"
wire:model="user_custom_id"
:options="$users"
option-label="username"
option-sub-label="city.name"
option-avatar="other_avatar"
icon="o-users"
height="max-h-96" {{-- Default is `max-h-64` --}}
hint="It has custom options"
single />

Select All

This option only works for multiple and non-searchable exclusively.


Multiple
 
Select all
Remove all
No results found.
Mason

Brooklyn

Gracie

Madilyn

Elena

Enrico

Lew

Oswald

Multiple
 
Select all stuff
Delete all things
No results found.
Mason

Brooklyn

Gracie

Madilyn

Elena

Enrico

Lew

Oswald

@php
$users = $this->users;
@endphp
{{-- Notice `allow-all` --}}
<x-choices label="Multiple" wire:model="users_all_ids" :options="$users" allow-all />
 
<x-choices
label="Multiple"
wire:model="users_all2_ids"
:options="$users"
allow-all
allow-all-text="Select all stuff"
remove-all-text="Delete all things" />

Compact mode

This option only works for multiple and non-searchable exclusively.


Compact
selected
 
No results found.
Mason

Brooklyn

Gracie

Madilyn

Elena

Enrico

Lew

Oswald

Compact label
stuff chosen
 
No results found.
Mason

Brooklyn

Gracie

Madilyn

Elena

Enrico

Lew

Oswald

@php
$users = $this->users;
@endphp
{{-- Notice `compact` --}}
<x-choices label="Compact" wire:model="users_compact_ids" :options="$users" compact />
 
<x-choices
label="Compact label"
wire:model="users_compact2_ids"
:options="$users"
compact
compact-text="stuff chosen" />

You can combine allow-all and compact

Select All + Compact
selected
 
Select all
Remove all
No results found.
Mason

Brooklyn

Gracie

Madilyn

Elena

Enrico

Lew

Oswald

@php
$users = $this->users;
@endphp
<x-choices
label="Select All + Compact"
wire:model="users_all_compact_ids"
:options="$users"
compact
allow-all />

Searchable (frontend)

If you judge you don't have a huge list of items, you can make it searchable offline on "frontend side". But, if you have a huge list it is a better idea to make it searchable on "server side", otherwise you can face some slow down on frontend. See on next section.


  Search ...
No results found.
Mason

Brooklyn

Gracie

Madilyn

Elena

Enrico

Lew

Oswald

  Search ...
No results found.
Mason

Brooklyn

Gracie

Madilyn

Elena

Enrico

Lew

Oswald

@php
$users = $this->users;
@endphp
{{-- Notice `searchable` --}}
{{-- Notice this is a different component, but with same API --}}
<x-choices-offline
label="Single (frontend)"
wire:model="user_searchable_offline_id"
:options="$users"
placeholder="Search ..."
single
searchable />
 
<x-choices-offline
label="Multiple (frontend)"
wire:model="users_multi_searchable_offline_ids"
:options="$users"
placeholder="Search ..."
searchable />

Searchable (server)

When dealing with large options list use searchable parameter. By default, it calls search() method to get fresh options from "server side" while typing. You can change the method's name by using search-function parameter.


Searchable + Single
  Search ...
No results found.
Ahmed

Alayna

Alberto

Alexandra

Ally

Searchable + Multiple
  Search ...
Ops! Nothing here ...
Ahmed

Alayna

Alberto

Alexandra

Ally

@php
$usersSearchable = $this->usersSearchable;
$usersMultiSearchable = $this->usersMultiSearchable;
@endphp
{{-- Notice `searchable` + `single` --}}
<x-choices
label="Searchable + Single"
wire:model="user_searchable_id"
:options="$usersSearchable"
placeholder="Search ..."
single
searchable />
 
{{-- Notice custom `search-function` --}}
<x-choices
label="Searchable + Multiple"
wire:model="users_multi_searchable_ids"
:options="$usersMultiSearchable"
placeholder="Search ..."
search-function="searchMulti"
no-result-text="Ops! Nothing here ..."
searchable />

You must also consider displaying pre-selected items on list, when it first renders and while searching. There are many approaches to make it work, but here is an example for single search using Volt.

new class extends Component {
 
// Selected option
public ?int $user_searchable_id = null;
 
// Options list
public Collection $usersSearchable;
 
public function mount()
{
// Fill options when component first renders
$this->search();
}
 
// Also called as you type
public function search(string $value = '')
{
// Besides the search results, you must include on demand selected option
$selectedOption = User::where('id', $this->user_searchable_id)->get();
 
$this->usersSearchable = User::query()
->where('name', 'like', "%$value%")
->take(5)
->orderBy('name')
->get()
->merge($selectedOption); // <-- Adds selected option
}
}

Sometimes you don't want to hit a datasource on every keystroke. So, you can make use of debounce to control over how often a network request is sent.

Another approach is to use min-chars attribute to avoid hit search method itself until you have typed such amount of chars.

Searchable + Single + Debounce + Min chars
 
No results found.
@php
$usersSearchableMinChars = $this->usersSearchableMinChars;
@endphp
{{-- Notice `min-chars` and `debounce` --}}
<x-choices
label="Searchable + Single + Debounce + Min chars"
wire:model="user_searchable_min_chars_id"
:options="$usersSearchableMinChars"
search-function="searchMinChars"
debounce="300ms" {{-- Default is `250ms`--}}
min-chars="2" {{-- Default is `0`--}}
single
searchable />

You can pass any extra arbitrary search parameters like this.

{{-- Notice `search-function` with extra arbitrary parameters --}}
<x-choices
label="Extra parameters"
wire:model="user_id"
:options="$users"
search-function="searchExtra(123, 'thing')"
searchable />
public function search(string $value = '', int $extra1 = 0, string $extra2 = '')
{
// The first parameter is the default and comes from the search input.
}

Slots

You have full control on rendering items by using the @scope('item', $object) special blade directive. It injects the current $object from the loop's context and achieves the same behavior that you would expect from the Vue/React scoped slots.

You can customize the list item and selected item slot. Searchable (online) works with blade syntax.

Slots (online)
 
No results found.
Mason
Eligendi sunt expedita a non ipsam. Animi tempora vel quis et voluptate quia quo tenetur. Id et repellendus hic blanditiis. Qui rerum et delectus sit rerum illo ut. Blanditiis odio ut unde iure vel culpa.
gsawayn

Brooklyn
Porro iusto dolorem quod exercitationem et. Quos beatae vero molestiae possimus unde quibusdam. Quam laborum velit molestias et quos officia accusamus.
pharvey

Gracie
Sint dicta sint nesciunt non vero. Et accusantium molestiae quas voluptas. Non sed doloribus praesentium qui illum quia. Quisquam labore et et ut inventore.
owolf

Madilyn
Voluptatum facere pariatur praesentium omnis eligendi veritatis officia. Voluptatum non velit magni asperiores et. Sunt non nihil et nesciunt nihil non.
iraynor

Elena
Optio quidem ea aut. Adipisci voluptatem qui non sit. Rem sint molestiae nesciunt consequatur enim ipsum. At ea cumque velit velit ut occaecati doloremque. Neque aut tempore at molestias.
spencer.issac

Enrico
Omnis blanditiis explicabo sequi ut laborum. Explicabo suscipit blanditiis ad ut quae consequatur maiores. Hic hic suscipit ea accusantium id. In omnis excepturi porro odit eligendi veritatis ut enim.
dtremblay

Lew
Et quia ut impedit id assumenda. Dignissimos delectus et eos aut aut maiores magnam. Est natus magni possimus beatae illo eius.
ansley82

Oswald
Sed nesciunt architecto officia ipsum error aut minus. Sint eaque totam assumenda possimus dolor et similique. Delectus et consequatur sit illo. Iste animi eius officiis dolorum sapiente perspiciatis saepe aut.
nikki.murphy

<div>
@php $users = $this->users; @endphp
</div>
<x-choices label="Slots (online)" wire:model="user_custom_slot_id" :options="$users" single>
{{-- Item slot--}}
@scope('item', $user)
<x-list-item :item="$user" sub-value="bio">
<x-slot:avatar>
<x-icon name="o-user" class="bg-orange-100 p-2 w-8 h8 rounded-full" />
</x-slot:avatar>
<x-slot:actions>
<x-badge :value="$user->username" />
</x-slot:actions>
</x-list-item>
@endscope
 
{{-- Selection slot--}}
@scope('selection', $user)
{{ $user->name }} ({{ $user->username }})
@endscope
</x-choices>

You can append or prepend anything like this. Make sure to use appropriated css round class on left or right.

Slots
 
No results found.
Mason

Brooklyn

Gracie

Madilyn

Elena

Enrico

Lew

Oswald

<div>
@php $users = $this->users @endphp
</div>
<x-choices label="Slots" wire:model="user_custom_slot_id" :options="$users" single>
<x-slot:prepend>
{{-- Add `rounded-e-none` (RTL support) --}}
<x-button icon="o-trash" class="rounded-e-none" />
</x-slot:prepend>
<x-slot:append>
{{-- Add `rounded-e-none` (RTL support) --}}
<x-button label="Create" icon="o-plus" class="rounded-s-none btn-primary" />
</x-slot:append>
</x-choices>

Note about large numbers

This components uses the options id values to handle selection. It tries to determine if these values are a int or string.

But, due to Javascript limitation with large numbers like these bellow, it will break.

public array $options = [
[
'id' => 264454000038134081, # <-- Javascript won't handle this number
'name' => 'Test 1',
],
[
'id' => '264454000038134082', # <-- It is good!
'name' => 'Test 2',
],
];

As workaround, define the id as a string and use values-as-string attribute instead.

<x-choices ... values-as-string />
<x-choices-offline ... values-as-string />

Events

You can catch component events just like described on Livewire docs. In this case the component will trigger the @change-selection and it will contain the selected items keys.

The payload contains a single key or an array of keys, depending on how you set the component. Because it is a custom event, you must access the key(s) via the detail.value property on the event.

<x-choices ... @change-selection="console.log($event.detail.value)" />
<x-choices-offline ... @change-selection="console.log($event.detail.value)" />

maryUI v1
Sponsor