Skip to content
On this pageStep 1: Enable Search on a Collection
  1. Step 1: Enable Search on a Collection
  2. Step 2: Add the LiveSearch Component
  3. Programmatic Search with search()
  4. Search Result Shape
  5. Cmd+K Keyboard Shortcut
  6. CSS Theming

EmDash Full-Text Search: Setup and Usage

Ben 3 min read

Search is one of those features that sounds simple until you actually have to build it. Index the content, run queries, highlight matches, keep it fast. In practice that's a non-trivial amount of infrastructure. EmDash ships it out of the box via SQLite FTS5 — no third-party service, no index sync jobs, no extra cost.

Here's everything you need to go from zero to a working search experience on your EmDash site.

Step 1: Enable Search on a Collection

Collections opt into search in seed.json by adding "search" to their supports array. Individual fields then opt into indexing via "searchable": true.

{
  "collections": [
    {
      "name": "posts",
      "label": "Posts",
      "supports": ["drafts", "revisions", "search", "seo"],
      "fields": [
        {
          "slug": "title",
          "label": "Title",
          "type": "string",
          "searchable": true
        },
        {
          "slug": "content",
          "label": "Content",
          "type": "portableText",
          "searchable": true
        },
        {
          "slug": "excerpt",
          "label": "Excerpt",
          "type": "text",
          "searchable": false
        }
      ]
    }
  ]
}

Only fields marked searchable: true are indexed. For portableText fields, EmDash extracts plain text from the block array automatically before indexing.

Step 2: Add the LiveSearch Component

The LiveSearch component is a React island. Import it from emdash/ui/search and drop it anywhere in your layout. It ships with keyboard support (Cmd+K to open) and snippet highlighting out of the box.

---
import LiveSearch from 'emdash/ui/search';
---

<!-- Place in your header or wherever search should appear -->
<LiveSearch
  client:load
  placeholder="Search articles..."
  collections={['posts', 'docs']}
/>

The collections prop scopes results to the collections you specify. Omit it to search across all search-enabled collections. The component manages its own open/close state and renders into a modal overlay.

Programmatic Search with search()

For server-side search — custom results pages, RSS feeds filtered by query, API routes — use the search() function imported from emdash.

import { search } from 'emdash';

const query = Astro.url.searchParams.get('q') ?? '';

const { results, cacheHint } = await search(query, {
  collections: ['posts'],
  limit: 20,
});

// Apply cache hint so invalidation works on re-publish
Astro.cache.set(cacheHint);

Search Result Shape

Each result in the array has the following fields. The snippet field is the most useful for display — it contains the matched passage with matching terms wrapped in <mark> tags.

FieldTypeDescription
collectionstringSlug of the collection this result belongs to
idstring (ULID)Database ID of the matching entry
titlestringTitle field value of the matching entry
slugstringURL slug for linking to the matching entry
snippetstring (HTML)Matched passage with <mark> highlights around matched terms
scorenumberFTS5 relevance score (higher = more relevant)

Cmd+K Keyboard Shortcut

The LiveSearch component registers a Cmd+K (Mac) / Ctrl+K (Windows/Linux) listener automatically when rendered with client:load. No additional setup needed. The shortcut opens the search modal and focuses the input.

CSS Theming

The search UI is styled via CSS custom properties. Override them in your global.css to match your design system. Key variables include --emdash-search-bg, --emdash-search-border, --emdash-search-highlight, and --emdash-search-text. The modal overlay color is --emdash-search-overlay.

SQLite FTS5 means search is co-located with your content. No sync lag, no API quota, no third-party dependency to manage. It just works.

With search enabled and LiveSearch dropped into your layout, you have a fully functional search experience in under 10 minutes. The programmatic API gives you everything you need for custom results pages and filtered feeds on top of the same index.

Read: Build Your First EmDash Website