Customization

Widget Styling

Customise the look and feel of the SearchX widget to match your brand identity.


Overview

SearchX is styled through a single mechanism: a CSS file loaded by the widget after its own default styles. You override the default look by:

  1. Setting theme tokens (CSS custom properties) to change colours, typography, radii, and shadows site-wide in one place.
  2. Targeting component class names to fine-tune individual surfaces (product cards, facet panels, the popup, etc.).

There's no theme picker, no JavaScript hook for visual customisation, no separate theme store — one CSS file is the entire surface area, and everything you can change is documented on this page.

What this means in practice

You don't need to learn a new template syntax, fork the widget, or write JavaScript to restyle it. Override a couple of CSS variables and you're 80% of the way to a custom theme that still gets every future widget update.


What you can customise

  • Brand colour palette — primary scale, neutral scale, status colour. Cascades everywhere automatically.
  • Typography — font family and base size.
  • Shape language — border radii (small, medium, pill), border widths, shadows.
  • Animation timing — global transition duration.
  • Per-component appearance — every visible surface has a stable class name you can target with normal CSS rules. The selectors are listed in Component CSS classes below.
  • Element visibility — hide any control with display: none.
  • Grid layout — switch the products grid to a different column count or change the gap.

What you can't customise

  • The HTML markup of the widget. You can't reshape the DOM, add new buttons inside cards, or move the price next to the title. If your design needs that level of restructuring, talk to us first — it usually means a setting needs to exist.
  • Behavioural logic. CSS controls appearance. Behaviour (which facets are shown, what the popup contains, how pagination works, etc.) is configured through the SDK settings, not CSS.
  • Translations. Text strings are configured through Localization, not CSS — don't try to swap labels with content: overrides, they won't survive a re-render.
  • !important-free overrides every time. Most overrides win on natural specificity, but a small number of layout rules ship with !important to protect against aggressive host themes; you may need !important to override those.

Loading a custom theme

Create a CSS file and pass its URL to the widget via the customCSSUrl option:

SearchXSDK.init({
  // ... other config
  customCSSUrl: '/path/to/your/client-theme.css',
});

The custom CSS file loads after the default styles, so your overrides win at the same specificity without !important in most cases.


Theme tokens

A SearchX theme is organised into two layers — colour tokens and non-colour tokens. You only need to override the ones you want to change; everything else falls back to the defaults.

1. Colour tokens

The foundational colours used across the widget. Each colour has a full scale from 50 (lightest) to 950 (darkest), so a single primary scale override re-skins every active state in the widget.

:root {
  /* Neutral */
  --searchx-white: #ffffff;
  --searchx-black: #111111;

  /* Primary scale — your brand colour */
  --searchx-primary-50: #fff5f5;
  --searchx-primary-100: #ffeaea;
  --searchx-primary-200: #ffd6d6;
  --searchx-primary-300: #ffb4b4;
  --searchx-primary-400: #f28c8c;
  --searchx-primary-500: #cc5b5b;
  --searchx-primary-600: #a20808; /* Base accent — buttons, active states */
  --searchx-primary-700: #7f0606;
  --searchx-primary-800: #5f0404;
  --searchx-primary-900: #3e0202;
  --searchx-primary-950: #240101;

  /* Gray scale */
  --searchx-gray-50: #fafafa;
  --searchx-gray-100: #f5f5f5;
  --searchx-gray-200: #e5e5e5;
  --searchx-gray-300: #d4d4d4;
  --searchx-gray-400: #a3a3a3;
  --searchx-gray-500: #737373;
  --searchx-gray-600: #525252;
  --searchx-gray-700: #404040;
  --searchx-gray-800: #262626;
  --searchx-gray-900: #171717;
  --searchx-gray-950: #0a0a0a;

  /* Status */
  --searchx-danger-color: #dc2626;
}

2. Non-colour tokens

Typography, border radius, shadows, and transitions in one place.

:root {
  /* Typography */
  --sx-font-family: ui-sans-serif, system-ui, -apple-system, Segoe UI, Roboto, Arial;
  --sx-font-size-base: 16px;

  /* Border radius */
  --sx-radius-sm: 6px;
  --sx-radius-md: 12px;
  --sx-radius-pill: 999px;

  /* Borders */
  --sx-border-width: 1px;
  --sx-border-color: var(--searchx-gray-300);

  /* Shadows */
  --sx-shadow-sm: 0 2px 6px rgba(0, 0, 0, 0.06);
  --sx-shadow-md: 0 8px 24px rgba(0, 0, 0, 0.1);

  /* Transitions */
  --sx-transition: 200ms ease;
}

Component CSS classes

All SearchX components use BEM-style class names scoped under .searchx__container.searchx__theme (search bar + popup) or .searchx__page.searchx__theme (results page). Scope your overrides with one of these two prefixes so you don't accidentally restyle other parts of your site.

SelectorDescription
.searchx__formSearch bar wrapper (border, background, shadow)
.searchx__inputText input container
.searchx__input inputThe actual input element
.searchx__input input::placeholderPlaceholder text
.searchx__mobile-triggerMobile search toggle button
.sx-settings__triggerSettings gear icon (when shown)
.searchx__form-close-iconClear / close button

Autocomplete popup

SelectorDescription
.searchx__popupPopup container
.searchx__popup-results-counterResults count badge
.searchx__popup-itemIndividual product suggestion row
.searchx__popup-item-imageProduct thumbnail in the popup
.searchx__popup-item-titleProduct name in the popup
.searchx__popup-item-pricePrice in the popup
.searchx__popup-item-iconThe quick Add to Cart icon next to each suggestion
.searchx__popup-no-results-iconEmpty-state icon
.searchx__popup-no-results-titleEmpty-state message
.searchx__showcaseFeatured products grid
.searchx__suggested-linksThe "See also" promotional chips container
.searchx__suggested-linkAn individual suggested-link chip

Results page

SelectorDescription
.searchx__page-heading-titleSearch query heading
.searchx__page-heading-subtitleResults count subtitle
.searchx__page-sortingSort dropdown
.searchx__page-resultsProduct grid container
.searchx__page-itemsAlternative product grid container

Product cards

SelectorDescription
.searchx__page-itemCard wrapper
.searchx__page-item-image-wrapperImage area container
.searchx__page-item-image-containerImage container (for aspect ratio)
.searchx__page-item-imageProduct image
.searchx__page-item-image--hoverSecond image (hover reveal)
.searchx__page-item-detailsLink wrapper for image + info
.searchx__page-item-infoText info area below image
.searchx__page-item-brandBrand name
.searchx__page-item-titleProduct title
.searchx__page-item-priceCurrent price
.searchx__page-item-price--originalOriginal price (struck through on sale)
.searchx__page-item-sizesAvailable sizes
.searchx__page-item-badgeDiscount / sale badge
.searchx__page-item-buttonAdd to Cart button
.searchx__page-item-button.wishlistWishlist heart button
.searchx__page-item-actionsButton actions container

Filter sidebar (facets)

SelectorDescription
.searchx__facetsThe whole filter sidebar
.searchx__facet-blockFilter groups container
.searchx__facet-slotA single facet group (one per panel — Brand, Price, On Sale, etc.)
.searchx__facet-titleFilter group heading
.searchx__facet-listThe list of items inside a facet
.searchx__facet-itemIndividual filter option
.searchx__facet-item--activeActive / selected filter
.searchx__facet-search-inputSearch input inside a long facet
.searchx__facet-showmoreThe "Show more / Show less" button
.searchx__on-sale-rowThe single labelled checkbox inside the On Sale facet
.searchx__on-sale-countThe "(N)" count next to the On Sale label
.price-range-filterThe whole price range panel (slider + inputs + Apply button)
.price-range-filter__inputsThe min/max inputs row
.price-range-filter__inputThe individual min / max number input
.price-range-filter__applyThe circular Apply button next to the inputs
.multi-range-slider__rangePrice range slider track
.multi-range-slider__thumbPrice range slider handle
.searchx__clear-filtersThe Clear filters button at the top of the sidebar

Pagination

SelectorDescription
.sx-paginationPagination container
.sx-page-arrowPrevious / Next arrows
.sx-page-pillPage number button
.sx-page-pill.is-activeCurrent page
.sx-page-ellipsisEllipsis between pages

Mobile filter sheet

SelectorDescription
.facet-toggle-button"Filters" toggle button
.facet-sheet__controlsFilter sheet header
.facet-sheet__labelFilter labels in the sheet
.facet-sheet__selectDropdown selects in the sheet
.facet-sheet__apply"Apply" button in filter sheet

Example — minimal monochrome theme

A flat, square-corner aesthetic with no shadows — ideal for fashion or luxury brands.

:root {
  --searchx-primary-600: #222222;
  --searchx-primary-700: #111111;
  --searchx-primary-800: #0a0a0a;

  --sx-font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
  --sx-font-size-base: 14px;

  --sx-radius-sm: 0px;
  --sx-radius-md: 0px;
  --sx-radius-pill: 0px;

  --sx-shadow-sm: none;
  --sx-shadow-md: none;
}

/* Square search bar with black border */
.searchx__container.searchx__theme .searchx__form {
  border: 1px solid #000;
  border-radius: 0;
  box-shadow: none;
}

/* Uppercase placeholder */
.searchx__container.searchx__theme .searchx__input input::placeholder {
  text-transform: uppercase;
  font-size: 12px;
  letter-spacing: 0.08em;
}

/* Flat product cards with no border or shadow */
.searchx__page.searchx__theme .searchx__page-item {
  border: none !important;
  border-radius: 0 !important;
  box-shadow: none !important;
}

.searchx__page.searchx__theme .searchx__page-item:hover {
  transform: none !important;
}

/* Image zoom on hover */
.searchx__page.searchx__theme .searchx__page-item-image {
  clip-path: inset(0);
  transition: transform 500ms cubic-bezier(0.25, 0.46, 0.45, 0.94);
}

.searchx__page.searchx__theme .searchx__page-item:hover .searchx__page-item-image {
  transform: scale(1.05);
}

/* Uppercase facet titles */
.searchx__page.searchx__theme .searchx__facet-title {
  text-transform: uppercase;
  font-size: 11px;
  letter-spacing: 0.1em;
}

Example — ocean teal theme

Override only the primary scale to switch the entire accent colour:

:root {
  --searchx-primary-50: #f0fdfa;
  --searchx-primary-100: #ccfbf1;
  --searchx-primary-200: #99f6e4;
  --searchx-primary-300: #5eead4;
  --searchx-primary-400: #2dd4bf;
  --searchx-primary-500: #14b8a6;
  --searchx-primary-600: #0d9488;
  --searchx-primary-700: #0f766e;
  --searchx-primary-800: #115e59;
  --searchx-primary-900: #134e4a;
  --searchx-primary-950: #042f2e;
}

Since every interactive surface references --searchx-primary-*, a single scale change updates buttons, active filters, hover states, pagination, and sort controls.


Controlling the product grid

Override the grid layout with CSS grid:

/* 4 columns on desktop, 3 on tablet, 2 on mobile */
.searchx__page.searchx__theme .searchx__page-results,
.searchx__page.searchx__theme .searchx__page-items {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 24px 16px;
}

@media (max-width: 1024px) {
  .searchx__page.searchx__theme .searchx__page-results,
  .searchx__page.searchx__theme .searchx__page-items {
    grid-template-columns: repeat(3, 1fr);
  }
}

@media (max-width: 768px) {
  .searchx__page.searchx__theme .searchx__page-results,
  .searchx__page.searchx__theme .searchx__page-items {
    grid-template-columns: repeat(2, 1fr);
  }
}

Hover image swap

Show a second product image on hover using CSS:

/* Hide second image by default */
.searchx__page.searchx__theme .searchx__page-item-image--hover {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 320ms ease;
  z-index: 2;
}

/* Reveal on hover */
.searchx__page.searchx__theme .searchx__page-item:hover .searchx__page-item-image--hover {
  opacity: 1;
}

Hiding elements

You can hide any control with CSS:

/* Hide the Add to Cart button on cards */
.searchx__page.searchx__theme .searchx__page-item-button:not(.wishlist) {
  display: none !important;
}

/* Hide the wishlist button */
.searchx__page.searchx__theme .searchx__page-item-button.wishlist {
  display: none !important;
}

/* Hide the powered-by badge */
.searchx__powered-by {
  display: none !important;
}

Prefer the SDK toggle when one exists

For most elements there's a setting that hides them cleanly without CSS (e.g. showAddToCartButton: false). CSS-based hiding is the right call when you want to hide something that doesn't have a dedicated toggle, or when the element should disappear only for a specific theme.


Greek typography (uppercase + accent stripping)

In Greek, words written in uppercase traditionally drop their accents (e.g. ΦλεβώνΦΛΕΒΩΝ, not ΦΛΕΒΏΝ). Browsers do this automatically when CSS applies text-transform: uppercasebut only when the element carries lang="el".

The SearchX widget propagates lang from your active locale to its root container automatically, so headings, buttons, and labels driven by your locale file work correctly out of the box.

If your catalogue text is in Greek but your interface language is English (e.g. an admin previewing a Greek shop), the widget also detects Greek characters in facet item labels and stamps lang="el" on those items individually. This means an English UI can still uppercase Greek brand names correctly:

/* Uppercase brand names on cards — Greek tones strip correctly */
.searchx__page.searchx__theme .searchx__page-item-brand {
  text-transform: uppercase;
}

No additional configuration needed — this works as long as your CSS uses text-transform: uppercase (not a custom JavaScript transform).


Best practices

  1. Start with tokens. Override --searchx-primary-* and --sx-* variables first. This handles 80% of theming with minimal CSS.
  2. Scope your selectors. Always prefix with .searchx__container.searchx__theme or .searchx__page.searchx__theme to avoid affecting the rest of your page.
  3. Use the SDK toggle when one exists. If a setting hides the element, use the setting — easier to manage across themes.
  4. Test on mobile. The mobile filter sheet (.facet-sheet__*) and compact pagination (.sx-page-pill) have their own selectors.
  5. Respect specificity. Custom CSS loads after the defaults so equal-specificity rules win. Reach for !important only when overriding a layout safeguard (the inputs row in the price range filter is one of these).

Previous
Suggested Links