How to Implement Result Highlighting with Customizable Boundaries and Ellipsis in FlexSearch

To implement result highlighting in FlexSearch, pass a highlight option to your search query containing a template string or a HighlightOptions object that configures boundaries, ellipsis, and clipping behavior.

FlexSearch provides a powerful highlighting engine that enriches search results with contextual snippets of the original text. According to the nextapps-de/flexsearch source code, the highlighting system lives in src/document/highlight.js and is driven by the HighlightOptions type defined in src/type.js. This implementation allows you to control exactly how much text surrounds each match, how overlaps are handled, and how truncation is indicated.

Understanding the Highlighting Engine

The core highlighting logic resides in the highlight_fields function within src/document/highlight.js. This routine processes search results by:

  1. Parsing templates to extract opening and closing markup surrounding the $1 placeholder (lines 42-52)
  2. Recording match positions to track where terms appear in the original text
  3. Applying boundary constraints to limit snippet length using either numeric values or HighlightBoundaryOptions objects
  4. Inserting ellipsis at truncation points with customizable strings or markup templates

The engine automatically activates when a search request contains a highlight option and the index supports document storage (SUPPORT_STORE) and highlighting (SUPPORT_HIGHLIGHTING).

Configuring Highlight Options

The HighlightOptions type (defined in src/type.js lines 299-304) provides granular control over snippet generation.

Template Configuration

The template property defines the markup wrapped around matched terms. It must contain $1 where the matched text should appear:

  • Simple: "<b>$1</b>"
  • With CSS classes: "<mark class='highlight'>$1</mark>"

Boundary Control with HighlightBoundaryOptions

The boundary property limits how much context appears around matches. It accepts:

  • Number: Total character count (default is 9e5, effectively unlimited)
  • HighlightBoundaryOptions object: Fine-grained control with before, after, and total properties

When clip is true (default), the snippet is trimmed to respect boundary limits. When false, the original text is preserved and ellipsis is added only at the edges.

Ellipsis Customization

The ellipsis property controls truncation indicators:

  • String: Custom text (default is "...")
  • Boolean: false removes ellipsis entirely
  • HighlightEllipsisOptions object: Custom template with template (containing $1) and pattern properties for advanced markup

Merging Consecutive Matches

Set merge: true to collapse adjacent highlighted fragments into a single block. This produces cleaner output when multiple search terms appear close together by replacing consecutive markup blocks with a single space.

Practical Implementation Examples

Basic Template Highlighting

Enable highlighting with a simple string template when searching a Document index:

const index = new Document({
  document: {
    store: true,
    index: [{ field: "title", tokenize: "forward" }]
  }
});

index.add({ id: 1, title: "Carmencita" });
index.add({ id: 2, title: "Le clown et ses chiens" });

const result = index.search({
  query: "karmen or clown",
  enrich: true,
  highlight: "<b>$1</b>"
});

// Result contains highlighted snippets:
// { id: 1, doc: {...}, highlight: "<b>Carmen</b>cita" }
// { id: 2, doc: {...}, highlight: "Le <b>clown</b> et ses chiens" }

Custom Boundaries and Clipping

Limit snippet length to 80 characters with automatic clipping:

const result = index.search({
  query: "sit amet",
  pluck: "title",
  highlight: {
    template: "<b>$1</b>",
    boundary: 80,
    clip: true
  }
});

Each result will contain at most 80 characters, with ellipsis automatically added on both sides when content is truncated.

Custom Ellipsis Markup

Apply custom styling to truncation indicators:

const result = index.search({
  query: "sit amet",
  pluck: "title",
  highlight: {
    template: "<b>$1</b>",
    boundary: 32,
    ellipsis: {
      template: "<i>$1</i>",
      pattern: "..."
    },
    clip: true
  }
});

This produces output like: <i>...</i><b>sit</b> <b>amet</b>, con<b>set</b>etur<i>...</i>.

Merged Highlight Blocks

Combine adjacent matches into single highlighted regions:

const result = index.search({
  query: "karmen or clown",
  enrich: true,
  merge: true,
  highlight: "<b>$1</b>"
});

When multiple terms appear consecutively, they merge into one continuous <b> block rather than separate markup instances.

Fine-Grained Boundary Control

Use HighlightBoundaryOptions for precise control over context windows:

const result = index.search({
  query: "akusam",
  enrich: true,
  highlight: {
    template: "<b>$1</b>",
    boundary: { before: 5, after: 5, total: 50 },
    clip: true,
    ellipsis: false
  }
});

This configuration shows exactly 5 characters before and after each match while keeping the total snippet under 50 characters, with no ellipsis markers.

Summary

  • Enable highlighting by passing a highlight option to index.search(), either as a template string or full HighlightOptions object.
  • Control snippet length using the boundary property with numeric values or HighlightBoundaryOptions objects containing before, after, and total constraints.
  • Manage truncation with the clip boolean and customize or remove ellipsis using the ellipsis property (string, boolean, or HighlightEllipsisOptions object).
  • Merge adjacent matches by setting merge: true to produce cleaner, consolidated highlight blocks.
  • Reference implementation in src/document/highlight.js handles template parsing, boundary calculations, and ellipsis insertion automatically when document storage and highlighting support are enabled.

Frequently Asked Questions

How do I remove the ellipsis entirely from highlighted snippets?

Set the ellipsis property to false in your HighlightOptions configuration. This prevents the engine from inserting any truncation markers, even when content exceeds the specified boundary limits.

What is the difference between clip: true and clip: false in FlexSearch highlighting?

When clip is true (the default), the snippet is trimmed to strictly respect the boundary limits, with ellipsis added where text is removed. When clip is false, the original text is preserved and ellipsis is only added at the beginning or end of the snippet if the content extends beyond the boundary window.

Can I use different boundary lengths for text before and after the matched term?

Yes, pass a HighlightBoundaryOptions object to the boundary property instead of a number. Specify before for characters preceding the match, after for characters following it, and optionally total to constrain the overall snippet length regardless of individual match positions.

Where does FlexSearch store the highlighted output in the search results?

When highlighting is enabled, the engine stores the processed snippet in the highlight property of each result object. If you use enrich: true, this appears alongside the doc property containing the full document; otherwise, it appears in the standard result structure returned by the search method.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →