How to Use the SearchDialog Component for Global Search in Celeris Web
The SearchDialog component provides a reusable modal interface that aggregates searchable items from the Vue Router menu and custom groups, enabling global search functionality that can be triggered from anywhere in the Celeris Web admin application.
The SearchDialog component in the kirklin/celeris-web repository delivers a unified "search-anywhere" experience for Vue.js admin interfaces. By combining the reactive state management of the useSearchDialog composable with automatically generated search groups derived from the application router, developers can implement a centralized global search system that filters navigable pages and executes custom actions when users select results.
Understanding the SearchDialog Architecture
Core Component Structure
The SearchDialog.vue component located at apps/admin/src/component/SearchDialog/src/SearchDialog.vue serves as the visual container for the global search experience. It renders a modal overlay containing a search input field, grouped result lists, and keyboard navigation handlers. Internally, the component constructs its default dataset from shallowMenus, which represents the flattened navigation tree of the Vue Router configuration, ensuring every registered admin route appears in the search index without manual configuration.
The useSearchDialog Composable
Located at apps/admin/src/composables/useSearchDialog.ts, this composable exports a reactive state object containing:
open: A boolean ref controlling the dialog's visibility statetrigger(open): A method to programmatically display the dialog by passing the open stateclose: A method to dismiss the dialog and reset focussearchGroups: A reactive array ofSearchResultItemgroups that powers the filterable result list
Each item in searchGroups must conform to the interface defined in apps/admin/src/component/SearchDialog/src/types.ts, requiring a unique key, display title, filterable label, and an action callback function that executes when the user selects the item.
Triggering the Search Dialog
Header Button Integration
The SearchAnyWhere.vue component at apps/admin/src/layouts/header/components/SearchAnyWhere.vue demonstrates the standard implementation pattern. Import the composable, destructure the trigger method and open ref, then invoke trigger(open) in response to user interactions.
<script setup lang="ts">
import { useSearchDialog } from '~/composables/useSearchDialog'
const { trigger, open } = useSearchDialog()
function openSearch() {
trigger(open)
}
</script>
<template>
<button @click="openSearch" class="header-search-btn">
<CAIcon name="tabler:search" size="16" />
Search…
</button>
<!-- Globally registered or locally imported -->
<SearchDialog />
</template>
Keyboard Shortcut Integration
Bind global keyboard shortcuts to the trigger(open) method for power-user accessibility. The component supports standard patterns like Cmd+K (macOS) or Ctrl+K (Windows/Linux) to immediately surface the global search interface from any application state.
import { onMounted } from 'vue'
import { useSearchDialog } from '~/composables/useSearchDialog'
export default {
setup() {
const { trigger, open } = useSearchDialog()
onMounted(() => {
window.addEventListener('keydown', (e) => {
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
e.preventDefault()
trigger(open)
}
})
})
},
}
Extending Global Search with Custom Groups
Beyond the router-derived navigation items, extend the searchGroups ref to include external documentation, API endpoints, or application-specific commands. Push new group objects containing a name and an items array, where each item specifies its execution logic through the action property.
import { useSearchDialog } from '~/composables/useSearchDialog'
const { searchGroups } = useSearchDialog()
const documentationGroup = {
name: 'Documentation',
items: [
{
iconName: 'tabler:book',
iconImage: null,
key: 'docs-getting-started',
title: 'Getting Started Guide',
label: 'Docs – Getting Started',
action: () => window.open('https://example.com/docs', '_blank')
},
{
iconName: 'tabler:api',
iconImage: null,
key: 'docs-api',
title: 'API Reference',
label: 'Docs – API Reference',
action: () => window.open('https://example.com/api', '_blank')
}
]
}
// Add to the reactive search index
searchGroups.value.push(documentationGroup)
Direct Component Usage
For scenarios requiring local state isolation rather than the global composable state, import SearchDialog directly and bind the v-model:open prop. This approach bypasses the useSearchDialog store in favor of component-level reactivity.
<template>
<div>
<button @click="isOpen = true">Open Search</button>
<SearchDialog v-model:open="isOpen" />
</div>
</template>
<script setup lang="ts">
import { ref } from 'vue'
import SearchDialog from '~/component/SearchDialog/src/SearchDialog.vue'
const isOpen = ref(false)
</script>
Summary
- The SearchDialog component at
apps/admin/src/component/SearchDialog/src/SearchDialog.vuerenders the modal interface and automatically indexes routes fromshallowMenus. - The
useSearchDialogcomposable exposesopen,trigger(open),close, and the reactivesearchGroupsarray for state management. - Search items require
key,title,label, and anactioncallback that executes upon selection, usually performingrouter.pushorwindow.open. - Invoke the dialog via
trigger(open)or by settingopen.value = true, enabling integration with keyboard shortcuts, header buttons, or programmatic events. - Custom search groups can be added to
searchGroups.valueto extend global search beyond the application router to external resources and custom commands.
Frequently Asked Questions
How do I open the SearchDialog programmatically without a button click?
Import the useSearchDialog composable from ~/composables/useSearchDialog and call trigger(open) or set open.value = true directly inside any function, lifecycle hook, or API response handler. This pattern enables opening the global search from keyboard events, websocket messages, or automated workflows anywhere in the application.
Can I search content that is not part of the Vue Router configuration?
Yes. While the component automatically generates search items from the router's shallowMenus, you can extend the searchGroups ref returned by useSearchDialog with custom groups containing items for external links, documentation pages, or specific application actions. Each custom item must provide a unique key, display text, and an action callback.
What happens when a user selects a search result?
The SearchDialog.vue component executes the selected item's action callback function and immediately sets the open state to false, closing the modal. For navigation items, this typically invokes router.push to navigate to the target page, while custom items might open external URLs or trigger application-specific functions.
Where are the TypeScript interfaces for search items defined?
The type definitions for SearchResultItem and related interfaces reside in apps/admin/src/component/SearchDialog/src/types.ts. These interfaces specify the required properties including key: string, title: string, label: string, optional iconName and iconImage, and the mandatory action: () => void function signature.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →