> ## Documentation Index
> Fetch the complete documentation index at: https://documentation.outpost.pub/llms.txt
> Use this file to discover all available pages before exploring further.

# Styling the Search Popup

> Override the Outpost search popup's colors, fonts, and sizing from your Ghost theme using its CSS variables and class hooks.

The Outpost search popup ships with a set of CSS variables and stable class names so you can match it to your theme. This page covers what you can target, and the rules that decide whether your override actually takes effect.

<Warning>
  Outpost's popup styles load after your theme's stylesheet, so a rule with the same specificity as Outpost's will lose. Give your selector more specificity, or override the `--ts-*` variables described below.
</Warning>

Most of the popup's appearance is set in Outpost under **Integrations and Core Connections → Integrations → TypeSense → Default display**. Start there. Use theme CSS for the parts that panel does not expose, which today includes every color other than the choice between the light and dark palettes.

<Info>
  This page describes the Outpost-hosted Typesense search popup. For turning search on, building collections, and configuring result labels, see [Typesense Integration](/integrations/typesense).
</Info>

***

## How the popup gets its styles

Outpost injects a `<style>` block into the page at runtime and sets every value through a `--ts-*` custom property on the popup's root element:

```css theme={"theme":{"light":"github-light","dark":"github-dark"}}
.outpost-typesense-popup {
  --ts-bg: #ffffff;
  --ts-text: #0f172a;
  --ts-highlight: #9fdc45;
  /* and so on */
}
```

Two of those values come from your Ghost site rather than from Outpost. `--ts-highlight` and `--ts-tab-active-bg` are both set to your Ghost **accent color**, and `--ts-font` is your Ghost theme font. Changing your accent color in Ghost changes the search popup with it.

If you ever see a `#0040ff` blue or Inter where you expected your own brand, Outpost could not read your Ghost settings and fell back to its defaults. That is a connection problem, not a styling one.

### The specificity rule

Outpost appends its `<style>` block to `<head>` at runtime, after your theme's stylesheets are already parsed. Position in the document decides ties, not load time, so a slow theme stylesheet still wins nothing. **A rule with the same specificity as Outpost's will lose.**

```css theme={"theme":{"light":"github-light","dark":"github-dark"}}
/* Does not work. Outpost defines the same selector, later. */
.typesense-hit-type { color: navy; }

/* Works. Adding a parent raises specificity. */
.typesense-hit .typesense-hit-type { color: navy; }
```

The cleanest approach is to override the variables rather than individual rules, on a selector more specific than `.outpost-typesense-popup`:

```css theme={"theme":{"light":"github-light","dark":"github-dark"}}
#typesense-search-popup.outpost-typesense-popup {
  --ts-highlight: #567f18;
  --ts-tab-active-bg: #0a145a;
  --ts-tab-active-text: #ffffff;
}
```

That single block recolors the matched-term highlight, the post and page result badges, the primary tag, and the selected collection tab, without touching Outpost's own rules.

<Warning>
  This holds for CSS in your theme stylesheet and in Ghost's **Site header** code injection. CSS placed in Ghost's **Site footer** code injection renders inside `<body>`, which comes after Outpost's block, so equal-specificity rules there will win instead. Pick one field and stay in it.
</Warning>

***

## CSS variables

Set on `.outpost-typesense-popup`. The "Set by" column shows where the default comes from.

| Variable               | Controls                                                                                                | Set by                                                                                |
| ---------------------- | ------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------- |
| `--ts-bg`              | Popup background, mobile sticky header                                                                  | Color mode                                                                            |
| `--ts-text`            | Result titles, primary text, highlighted terms                                                          | Color mode                                                                            |
| `--ts-text-secondary`  | Snippets, filter labels, inactive tab text                                                              | Color mode                                                                            |
| `--ts-text-meta`       | Dates, the "by" and "in" connector text, input placeholder, close buttons, author and tag result badges | Color mode                                                                            |
| `--ts-border`          | Result dividers, results-list container border, input border, tab borders                               | Color mode                                                                            |
| `--ts-input-bg`        | Search input background, tab hover background                                                           | Color mode                                                                            |
| `--ts-overlay`         | Backdrop behind the popup                                                                               | Color mode                                                                            |
| `--ts-highlight`       | Matched-term highlight wash, post and page result badges, primary tag                                   | Ghost accent color                                                                    |
| `--ts-tab-active-bg`   | Fill of the selected collection tab                                                                     | Ghost accent color                                                                    |
| `--ts-tab-active-text` | Text of the selected collection tab                                                                     | Fixed at `#ffffff`                                                                    |
| `--ts-font`            | Font family throughout                                                                                  | Ghost theme font                                                                      |
| `--ts-radius`          | Corner radius of the container, and of the input at 75% of the value                                    | Border radius setting, or CTA design defaults when **Match my CTA design** is checked |
| `--ts-btn-radius`      | Corner radius of the collection tabs, twice `--ts-radius`                                               | Border radius setting, or CTA design defaults when **Match my CTA design** is checked |
| `--ts-title-size`      | "Search" heading size                                                                                   | Fixed at `1.25rem`                                                                    |
| `--ts-hit-title-size`  | Result title size. See the note below, this one currently has no effect                                 | Fixed at `1rem`                                                                       |
| `--ts-snippet-size`    | Snippet size                                                                                            | Fixed at `0.875rem`                                                                   |
| `--ts-meta-size`       | Metadata and tab label size                                                                             | Fixed at `0.8rem`                                                                     |

<Note>
  "Color mode" means the value comes from the light or dark palette, chosen by the **Color mode** setting on the Default display tab. Auto reads your Ghost theme's background color, and falls back to the light palette whenever Ghost does not report one, which is the common case. Set Color mode to Light or Dark explicitly if you want a predictable starting point to override.
</Note>

<Warning>
  `--ts-hit-title-size` does nothing today. The result template writes `style="font-size: 20px"` directly on every result title, and an inline style beats a stylesheet. To change the result title size you need `.typesense-hit .typesense-hit-title { font-size: 1.125rem !important; }`.
</Warning>

***

## Class hooks

### Popup structure

| Selector                                              | Element                                                                                          |
| ----------------------------------------------------- | ------------------------------------------------------------------------------------------------ |
| `#typesense-search-popup`, `.outpost-typesense-popup` | Root element. Gains `.is-open` while the popup is showing                                        |
| `.outpost-typesense-overlay`                          | Full-screen backdrop. Carries a maximum `z-index` so it clears sticky headers and cookie banners |
| `.outpost-typesense-container`                        | The panel itself. Fixed at `60vw` wide with `30px` padding                                       |
| `.outpost-typesense-header`                           | Title row. Hidden below 640px                                                                    |
| `.outpost-typesense-title`                            | The "Search" heading                                                                             |
| `.outpost-typesense-close`                            | Desktop close button                                                                             |
| `.outpost-typesense-close-mobile`                     | Close button shown only below 640px                                                              |
| `.outpost-typesense-content`                          | Scrolling body. This is the element embed mode relocates                                         |
| `.outpost-typesense-sticky`                           | Wrapper holding the input and tabs                                                               |
| `.outpost-typesense-search-row`                       | Input and mobile close button, side by side                                                      |
| `#outpost-typesense-search-box`                       | Search input container                                                                           |
| `.outpost-typesense-tabs-nav-slot`                    | Where the collection tabs end up. Also carries `.tinytabs`                                       |
| `#typesense-search-tabs`, `.typesense-search-panel`   | Container for the collection panels. Gains `.tinytabs` once search initialises                   |
| `.tabs`, `.tab`, `.tab.sel`                           | Collection tab list, a tab, the selected tab                                                     |
| `.tab-{collection}`                                   | Per-collection tab class. Each tab also carries `data-id` with the index name                    |
| `.tab-section`                                        | One collection's panel. Carries `data-name`, `data-index-name`, and an `id` of the index name    |
| `.outpost-typesense-sort`                             | Sort dropdown container                                                                          |
| `.outpost-typesense-hits`                             | Results list container. Fixed at `70vh` tall                                                     |

Both close buttons are empty in the markup and draw their glyph with `content: "\2715"` on a `::before` pseudo-element. To change the icon, override the pseudo-element rather than the button.

### A single result

| Selector                     | Element                                              |
| ---------------------------- | ---------------------------------------------------- |
| `.typesense-hit`             | Wrapper for one result, an `<article>`               |
| `.typesense-hit-title`       | Result title, an `<h1>` containing the link          |
| `.typesense-hit-meta`        | Row holding the badge, date, authors, and tags       |
| `.typesense-hit-type`        | The result label badge. Carries `data-type`          |
| `.typesense-hit-date`        | Published date, when enabled                         |
| `.typesense-hit-authors`     | Author list, when enabled                            |
| `.typesense-hit-tags`        | Tag list wrapper                                     |
| `.typesense-hit-tag-primary` | One tag. Carries `data-name` with the lowercased tag |
| `.typesense-hit-excerpt`     | Matching snippet, when enabled                       |
| `.typesense-hit mark`        | A matched search term inside a title or snippet      |

<Note>
  Result titles are `<h1>` elements. Your theme's own `h1` rules will apply for every property Outpost does not set, including `font-weight`, `line-height`, `margin-top`, and `letter-spacing`. This is the most common reason results look wrong in one theme and fine in another.
</Note>

`data-type` is `post`, `page`, `author`, or `tag`. Outpost already renders the `author` and `tag` badges in the muted metadata color; only `post` and `page` badges use the accent. `data-name` lets you style one tag differently:

```css theme={"theme":{"light":"github-light","dark":"github-dark"}}
.typesense-hit .typesense-hit-tag-primary[data-name='opinion'] {
  font-style: italic;
}
```

### Classes from InstantSearch

The popup is built on InstantSearch, which supplies `.ais-SearchBox-input`, `.ais-Hits-item`, `.ais-Pagination-*`, `.ais-Highlight-highlighted`, and `.ais-Snippet-highlighted`. Its stylesheet is loaded from a public CDN before Outpost's own block, which is worth knowing if you run a strict content security policy. These classes work, but they belong to that library rather than to Outpost and can change when it is upgraded. Prefer the `--ts-*` variables and `.typesense-*` classes where both are available.

***

## Five things that will catch you out

### 1. The tab list is moved out of the panel

`.tabs` starts inside `.typesense-search-panel`, and Outpost then moves it into `.outpost-typesense-tabs-nav-slot` so it can stay fixed above the scrolling results. This happens in both popup and embed mode. By the time your CSS applies, the tab list is no longer a descendant of the panel, and a selector rooted there silently matches nothing:

```css theme={"theme":{"light":"github-light","dark":"github-dark"}}
/* Does not work. .tabs is no longer inside .typesense-search-panel. */
.typesense-search-panel.tinytabs .tabs .tab.sel {
  background-color: #0a145a;
}
```

Target the slot instead:

```css theme={"theme":{"light":"github-light","dark":"github-dark"}}
.outpost-typesense-tabs-nav-slot .tab.sel {
  background-color: #0a145a;
  border-color: #0a145a;
  color: #ffffff;
}
```

<Tip>
  Overriding `--ts-tab-active-bg` and `--ts-tab-active-text` avoids this entirely, because the variable is read wherever the tab ends up.
</Tip>

### 2. Setting a color on a parent does not recolor the badges

`.typesense-hit-type`, `.typesense-hit-tag-primary`, `.typesense-hit-date`, and `.typesense-hit-excerpt` each set their own `color`. An element's own color always beats a color inherited from an ancestor, no matter how specific that ancestor's rule is.

```css theme={"theme":{"light":"github-light","dark":"github-dark"}}
/* Recolors only the text that inherits, such as the "in" connector.
   The badge, tags, date, and snippet all keep their own colors. */
.typesense-hit div {
  color: #6b7280;
}
```

Name the elements directly:

```css theme={"theme":{"light":"github-light","dark":"github-dark"}}
.typesense-hit .typesense-hit-type,
.typesense-hit .typesense-hit-tag-primary {
  color: #6b7280;
  border-color: #6b7280;
}
```

### 3. Some values are inline styles, so only `!important` beats them

The result template writes a few styles directly onto elements. Inline styles outrank any stylesheet rule, so these need `!important`:

* `font-size: 20px` on `.typesense-hit-title`
* `display: flex; flex-direction: row; gap: 1em` on the row holding the thumbnail and text
* `max-width: 90px` on the thumbnail wrapper, which is an unclassed `div` you can only reach structurally, as in `.typesense-hit div > a > img`

The collection panels are also shown and hidden with an inline `display`, so giving the active panel `display: grid` needs `!important` too.

### 4. A single-collection site hides every `.tabs` element on the page

When a site has only one collection there are no tabs to show, and Outpost ships a rule to hide them:

```css theme={"theme":{"light":"github-light","dark":"github-dark"}}
.tabs { display: none !important; }
```

That selector is not scoped to the popup. If your theme uses `.tabs` for a component of its own, that component will disappear on every page once search loads. Rename your class, or scope your own rule more specifically and mark it `!important`.

### 5. Embed mode has none of these variables

If search is configured to render inline on a page rather than as a popup, Outpost moves `.outpost-typesense-content` into your container. It is then no longer inside `.outpost-typesense-popup`, which is the only element the `--ts-*` variables are declared on. Every variable becomes undefined, and every rule Outpost scopes to `.outpost-typesense-popup`, including the whole mobile layout, stops matching.

For embed mode, declare the variables on your own container:

```css theme={"theme":{"light":"github-light","dark":"github-dark"}}
#my-search-container {
  --ts-bg: #ffffff;
  --ts-text: #0f172a;
  --ts-text-secondary: #334155;
  --ts-text-meta: #64748b;
  --ts-border: #eef0f3;
  --ts-input-bg: #f5f6f8;
  --ts-highlight: #567f18;
  --ts-tab-active-bg: #0a145a;
  --ts-tab-active-text: #ffffff;
  --ts-radius: 4px;
  --ts-btn-radius: 8px;
}
```

***

## Check your contrast

<Warning>
  Because `--ts-highlight` and `--ts-tab-active-bg` follow your Ghost accent color, a light accent produces low-contrast badges, tags, and tab labels. A light green accent such as `#9fdc45` gives roughly 1.6:1 against white, well below the 4.5:1 that WCAG AA asks of body text.
</Warning>

The accent fails in both directions: it is used as text on the badges and tags, and as the fill behind the selected tab's fixed white label. If your accent color is light, darken `--ts-highlight` so badges and tags stay readable, and set `--ts-tab-active-text` to a dark color so it holds up against the still-light tab fill:

```css theme={"theme":{"light":"github-light","dark":"github-dark"}}
#typesense-search-popup.outpost-typesense-popup {
  --ts-highlight: #567f18; /* 4.7:1 on white */
  --ts-tab-active-text: #111827; /* keep at least 4.5:1 against your tab fill */
}
```

The matched-term highlight is not a contrast risk. It uses the accent only as a faint background wash and keeps the text at `--ts-text`.

<Note>
  If your popup can render in dark mode, check your replacement against both backgrounds. The dark palette's background is `#1a1f2e`, where `#567f18` drops to about 3:1. Either pick a value that clears 4.5:1 on both, or scope separate overrides to each color mode.
</Note>

***

## Where to put the CSS

* **Your theme stylesheet**, if you build the theme yourself. Keep the rules in one clearly named block so they survive future theme updates.
* **Ghost code injection**, under **Settings → Code injection → Site header** in Ghost admin, wrapped in a `<style>` tag. Use this when you do not control the theme source.

Both load before Outpost's injected styles, so the specificity rule applies to both. The **Site footer** field behaves differently, as noted above.

***

## FAQ

<AccordionGroup>
  <Accordion title="Why is my CSS being ignored?">
    Outpost's styles load after your theme's, so a rule with the same specificity loses the tie. Add a parent element to your selector, for example `.typesense-hit .typesense-hit-type` instead of `.typesense-hit-type`. Overriding the `--ts-*` variables on `#typesense-search-popup.outpost-typesense-popup` avoids the problem. If the value you are fighting is an inline style, such as the result title's font size, you need `!important`.
  </Accordion>

  <Accordion title="Can I change the search colors in Outpost instead of in CSS?">
    Not yet, beyond choosing Light, Dark, or Auto under **Default display**. The accent color comes from your Ghost accent color, and the remaining colors come from the fixed light and dark palettes. Theme CSS is the way to change them today.
  </Accordion>

  <Accordion title="Why are my search result badges hard to read?">
    Post and page badges use your Ghost accent color. If that color is light, it will not have enough contrast on a white background. Either darken your Ghost accent color, which changes your whole site, or override `--ts-highlight` for the popup only. Author and tag badges are unaffected, as they already use the muted metadata color.
  </Accordion>

  <Accordion title="Why did my tab styling stop working?">
    Outpost moves the tab list into `.outpost-typesense-tabs-nav-slot` so it can stay fixed above the results. If your selector expects `.tabs` to sit inside `.typesense-search-panel`, it no longer matches. Target the slot, or override `--ts-tab-active-bg` and `--ts-tab-active-text` instead.
  </Accordion>

  <Accordion title="A component in my theme disappeared after search loaded. Why?">
    If your site runs a single collection, Outpost hides the tab bar with an unscoped `.tabs { display: none !important }` rule, which also hides any element of your own that uses the `tabs` class. Rename your class, or scope your own rule more specifically and mark it `!important`.
  </Accordion>

  <Accordion title="Do these class names change between releases?">
    The `--ts-*` variables and the `.outpost-typesense-*` and `.typesense-*` classes are the intended styling surface and are kept stable. The `.tabs`, `.tab`, and `.sel` classes come from the tab library Outpost bundles, and the `.ais-*` classes from InstantSearch. Both can change when those libraries are upgraded.
  </Accordion>
</AccordionGroup>

***

## Related resources

<CardGroup cols={2}>
  <Card title="Typesense Integration" icon="magnifying-glass" href="/integrations/typesense">
    Turn on search, build collections, and configure result labels.
  </Card>

  <Card title="Ghost Theme Integration" icon="code" href="/developers/theme-integration">
    Add the Outpost script and integration partials to your theme.
  </Card>

  <Card title="Contact Support" icon="envelope" href="https://outpost.pub/contact">
    Contact the Outpost team for help with search styling.
  </Card>
</CardGroup>
