logo light

adding search bar for navigation groups and items

Image Description
By: Lara Zeus
  • Published: 24 Mar 2025 Updated: 26 Mar 2025

when you have a lot of resources, let your users search for what they looking for int he sidebar.

adding search bar for navigation groups and items

First: add the render hook in the panel provider:

1->renderHook(PanelsRenderHook::SIDEBAR_NAV_START, fn () => view('filament.components.navigation-filter'));

Next: create the view `navigation-filter.blade.php`:

1<div
2 @if (filament()->isSidebarCollapsibleOnDesktop())
3 x-bind:class="$store.sidebar.isOpen ? 'block' : 'hidden'"
4 @endif
5>
6 <x-filament::input.wrapper
7 class="relative"
8 :inline-prefix="true"
9 prefix-icon="tabler-brand-finder"
10 >
11 <x-filament::input
12 type="text"
13 placeholder="search ..."
14 x-data="sidebarSearch()"
15 x-ref="search"
16 x-on:input.debounce.300ms="filterItems($event.target.value)"
17 x-on:keydown.escape="clearSearch"
18 x-on:keydown.meta.j.prevent.document="$refs.search.focus()"
19 />
20
21 <kbd class="absolute right-2 top-1/2 transform -translate-y-1/2 bg-gray-100 border border-gray-300 text-gray-400 dark:bg-gray-800 dark:border-gray-600 dark:text-gray-50 text-xs px-1.5 flex items-center justify-center gap-1 py-1 rounded-md">
22 @svg('tabler-command', 'h-4 w-4 text-gray-400')
23 <kd>J</kd>
24 </kbd>
25 </x-filament::input.wrapper>
26
27 <script>
28 document.addEventListener('alpine:init', () => {
29 Alpine.data('sidebarSearch', () => ({
30 init() {
31 this.$refs.search.value = ''
32 },
33
34 filterItems(searchTerm) {
35 const groups = document.querySelectorAll('.fi-sidebar-nav-groups .fi-sidebar-group')
36 searchTerm = searchTerm.toLowerCase()
37
38 groups.forEach(group => {
39 const groupButton = group.querySelector('.fi-sidebar-group-button')
40 const groupText = groupButton?.textContent.toLowerCase() || ''
41 const items = group.querySelectorAll('.fi-sidebar-item')
42 let hasVisibleItems = false
43
44 const groupMatches = groupText.includes(searchTerm)
45
46 items.forEach(item => {
47 const itemText = item.textContent.toLowerCase()
48 const isVisible = itemText.includes(searchTerm) || groupMatches
49
50 item.style.display = isVisible ? '' : 'none'
51 if (isVisible) hasVisibleItems = true
52 })
53
54 group.style.display = (hasVisibleItems || groupMatches) ? '' : 'none'
55 })
56 },
57
58 clearSearch() {
59 this.$refs.search.value = ''
60 this.filterItems('')
61 }
62 }))
63 })
64 </script>
65</div>

take a look at the result in our demo app.

thanks to Azad Furkan ŞAKAR for the gist

Back to Tricks