All posts

How chip-based search works

Most note apps give you a search bar that filters by title or full-text. Glifo uses a different model: structured filter chips that compose into complex queries. Type #blog, press Enter, and you get a persistent chip — not a text search that disappears when you clear the input.

The chip model

Each chip is a typed filter with a specific behavior:

PrefixTypeBehavior
#tagTag includeNotes with this tag
-#tagTag excludeNotes without this tag
/folderFolder scopeNotes in this folder
modified:weekDate filterModified within timeframe
is:untaggedStatusNotes matching a condition
has:codeContentNotes containing specific content
type:drawingTypeFilter by item type

Chips are parsed from the search input when you press Enter. The prefix determines the chip type, and the rest becomes the value.

Composition rules

Multiple chips combine with AND logic:

#blog  -#draft  modified:month

This means: notes tagged "blog", NOT tagged "draft", modified this month.

Within a single tag chip, multiple values combine with OR:

#blog,tutorial

This means: notes tagged "blog" OR "tutorial".

The distinction matters. AND between chips narrows results. OR within a chip widens them. Together, they let you express queries like "recent blog posts or tutorials, excluding drafts" without a query language.

Saved views

Any combination of chips can be saved as a named view. Views persist across sessions and appear in the sidebar. This turns a complex filter like #project /Work -#archived modified:month into a single click.

The implementation

The search engine runs entirely on the frontend (part of the React layer). Each chip type maps to a filter function:

function matchesChip(note: Note, chip: SearchChip): boolean {
  switch (chip.type) {
    case 'tag':
      return chip.values.some(v => note.tags.includes(v));
    case 'tag-exclude':
      return !chip.values.some(v => note.tags.includes(v));
    case 'folder':
      return note.folder === chip.value;
    case 'modified':
      return isWithinDateRange(note.modified, chip.value);
    // ...
  }
}

Notes pass through all chips sequentially. If any chip rejects a note, it's filtered out. This makes the system both simple to implement and predictable to use.

Free text

If you type something that doesn't match a chip prefix, it becomes a free-text filter — matching against note titles and content. Free text chips also compose with AND, so you can combine structured filters with keyword search.


The chip model works because it mirrors how people actually think about their notes: "my blog posts from this month" maps directly to #blog modified:month. No boolean operators to remember, no query syntax to learn. See keyboard shortcuts for the full list of search operators.