diff --git a/resources/js/components/AppHeader.vue b/resources/js/components/AppHeader.vue
index 3a59df4..07bd84b 100644
--- a/resources/js/components/AppHeader.vue
+++ b/resources/js/components/AppHeader.vue
@@ -1,18 +1,20 @@
@@ -105,9 +149,10 @@ async function openMenuForSearch(): Promise {
+import { provide, ref } from 'vue';
import AppFooter from '@/components/AppFooter.vue';
import AppHeader from '@/components/AppHeader.vue';
import AppNav from '@/components/AppNav.vue';
+import { pluginSearchKey } from '@/lib/pluginSearch';
+
+provide(pluginSearchKey, ref(''));
diff --git a/resources/js/lib/pluginSearch.ts b/resources/js/lib/pluginSearch.ts
new file mode 100644
index 0000000..0b5d9f4
--- /dev/null
+++ b/resources/js/lib/pluginSearch.ts
@@ -0,0 +1,36 @@
+import type { InjectionKey, Ref } from 'vue';
+import type { Plugin } from '@/types';
+import { scoreSearchResult } from '@/utils/formatting';
+
+/**
+ * The header search box and the homepage plugin list share one query string.
+ *
+ * On the homepage the query filters the list in place; everywhere else the
+ * header keeps showing its own results dropdown. The ref is provided by
+ * AppLayout rather than living at module scope so that it is created per app
+ * instance — module state would be shared across requests under SSR.
+ */
+export const pluginSearchKey: InjectionKey[> =
+ Symbol('pluginSearch');
+
+/**
+ * Whether a plugin matches the query, using the same scoring the header
+ * dropdown uses so that filtering and searching never disagree.
+ */
+export function matchesQuery(plugin: Plugin, query: string): boolean {
+ return scoreSearchResult(plugin, query) > 0;
+}
+
+/**
+ * Filters while preserving the caller's ordering — the homepage sorts by the
+ * column the user picked, which must survive filtering.
+ */
+export function filterPlugins(plugins: Plugin[], query: string): Plugin[] {
+ const trimmed = query.trim();
+
+ if (!trimmed) {
+ return plugins;
+ }
+
+ return plugins.filter((plugin) => matchesQuery(plugin, trimmed));
+}
diff --git a/resources/js/pages/Index.vue b/resources/js/pages/Index.vue
index 3e83c29..2311f3a 100644
--- a/resources/js/pages/Index.vue
+++ b/resources/js/pages/Index.vue
@@ -1,10 +1,11 @@
]