Close multiselect

Currently, to close a multiselect component, the user must click outside the input field. While this interaction is manageable on desktop—where users can easily click outside the input—it becomes less intuitive on mobile devices, particularly on Android. On mobile, users often notice the dropdown arrow but tapping it does not close the multiselect. This results in confusion and a poor user experience, as there is no clear visual cue or gesture to dismiss the options list. Question: Has anyone encountered and resolved this usability issue without overriding the Blade template? I am specifically looking for a solution that enhances the mobile experience without the need to rewrite the component's view.
Solution:
I recommend using afterStateHydrated ``` use Filament\Forms\Components\Select; Select::make('tags')...
Jump to solution
2 Replies
Solution
!Sergo
!Sergo7d ago
I recommend using afterStateHydrated
use Filament\Forms\Components\Select;

Select::make('tags')
->multiple()
->afterStateHydrated(function ($component) {
$component->extraAttributes([
'x-init' => <<<JS
const arrow = $el.parentElement.querySelector('[data-select-toggle]');
if (arrow) {
arrow.addEventListener('click', (e) => {
e.stopPropagation();
$el.closest('[x-data]').__x.$data.open = !$el.closest('[x-data]').__x.$data.open;
});
}
JS,
]);
})
use Filament\Forms\Components\Select;

Select::make('tags')
->multiple()
->afterStateHydrated(function ($component) {
$component->extraAttributes([
'x-init' => <<<JS
const arrow = $el.parentElement.querySelector('[data-select-toggle]');
if (arrow) {
arrow.addEventListener('click', (e) => {
e.stopPropagation();
$el.closest('[x-data]').__x.$data.open = !$el.closest('[x-data]').__x.$data.open;
});
}
JS,
]);
})
like this
arnaudsf
arnaudsfOP6d ago
Thanks, genius! Here's my code for future reference:
->afterStateHydrated(function ($component) {
$component->extraAttributes([
'x-data' => '',
'x-init' => <<<'JS'
$nextTick(() => {
const inputWrapper = $el.querySelector('.choices__inner');
const listWrapper = $el.querySelector('.choices__list.choices__list--dropdown');

if (inputWrapper && listWrapper) {
inputWrapper.addEventListener('click', (e) => {
if(!listWrapper.classList.contains('is-active')) {
return;
}

e.stopPropagation();
document.body.click()
});
}
});
JS,
]);
}),
->afterStateHydrated(function ($component) {
$component->extraAttributes([
'x-data' => '',
'x-init' => <<<'JS'
$nextTick(() => {
const inputWrapper = $el.querySelector('.choices__inner');
const listWrapper = $el.querySelector('.choices__list.choices__list--dropdown');

if (inputWrapper && listWrapper) {
inputWrapper.addEventListener('click', (e) => {
if(!listWrapper.classList.contains('is-active')) {
return;
}

e.stopPropagation();
document.body.click()
});
}
});
JS,
]);
}),

Did you find this page helpful?