Open Search Button

@use 'sprucecss/scss/spruce' as *;

.search-trigger {
  @include clear-btn;
  @include transition($property: 'border-color, box-shadow');
  align-items: center;
  background-color: color('background', 'form');
  border: config('border-width-base', $display) solid color('border', 'form');
  border-radius: config('border-radius', $form-control);
  color: color('muted');
  display: inline-flex;
  gap: spacer('xs');
  min-inline-size: 14rem;
  padding: spacer('xxs') spacer('xxs') spacer('xxs') spacer('s');

  &:hover {
    border-color: color('primary');
  }

  &:focus-visible {
    @include short-ring('input');
  }

  &__icon {
    block-size: 1rem;
    flex-shrink: 0;
    inline-size: 1rem;
  }

  &__caption {
    flex-grow: 1;
    text-align: start;
  }

  &__shortcut {
    background-color: color-alpha('primary', 0.08);
    border: config('border-width-base', $display) solid color('border');
    border-radius: radius('sm');
    box-shadow: none;
    color: color('text');
    font-size: 0.75rem;
    padding: 0.2em 0.5em;
  }
}

.search-trigger-status {
  color: color('muted');
  font-size: config('font-size-sm', $typography);
  margin-block-start: spacer('s');
}
<button class="search-trigger" type="button" data-search-trigger>
    <svg class="search-trigger__icon" aria-hidden="true" focusable="false" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle cx="11" cy="11" r="7"/><path d="m21 21-4.3-4.3"/></svg>
    <span class="search-trigger__caption">Search</span>
    <kbd class="search-trigger__shortcut" aria-hidden="true" data-search-trigger-shortcut>Ctrl K</kbd>
</button>
<p class="search-trigger-status" aria-live="polite" data-search-trigger-status></p>
(() => {
  const buttons = document.querySelectorAll('[data-search-trigger]');
  const isMac = /Mac|iPhone|iPad/.test(navigator.userAgentData?.platform ?? navigator.platform);

  // Show the shortcut of the current platform.
  if (isMac) {
    document.querySelectorAll('[data-search-trigger-shortcut]').forEach((shortcut) => { shortcut.textContent = '⌘ K'; });
  }

  buttons.forEach((button) => {
    button.addEventListener('click', () => {
      // Replace this with your search dialog (like the Command Palette component).
      document.dispatchEvent(new CustomEvent('search:open'));
      const status = document.querySelector('[data-search-trigger-status]');
      if (status) status.textContent = 'The search would open now.';
    });
  });

  // Bind the shortcut only to a trigger that opts in with data-shortcut (one per page).
  const shortcutButton = document.querySelector('[data-search-trigger][data-shortcut]');

  if (shortcutButton) {
    document.addEventListener('keydown', (event) => {
      if (event.key.toLowerCase() === 'k' && (event.ctrlKey || event.metaKey)) {
        event.preventDefault();
        shortcutButton.click();
      }
    });
  }
})();

Open Search Button

A search trigger that looks like a field: it opens your search dialog on click or with the Ctrl + K (⌘ + K on macOS) shortcut, and shows the shortcut as a hint.

Anatomy

  • .search-trigger is a button that opens the search. It looks like an input, because that's what people look for, but it isn't one: typing starts in the dialog.
  • .search-trigger__icon, .search-trigger__caption ("Search") and .search-trigger__shortcut (a kbd with the hint).

Accessibility

  • The accessible name is "Search"; the shortcut hint is hidden from screen readers (aria-hidden="true"). When you bind the shortcut, expose it with aria-keyshortcuts="Control+K Meta+K":
<button class="search-trigger" type="button" aria-keyshortcuts="Control+K Meta+K" data-search-trigger data-shortcut>…</button>
  • Earlier versions used a "Ctrl K" button as the trigger, which gave it a confusing name. Now the whole control is one button with a clear name.
  • The shortcut uses Ctrl/⌘ + K, a common convention that doesn't collide with typing.

Technical Details

  • The block class is .search-trigger (it was .open-search, which is also used by many site headers).

  • Vanilla JavaScript. The script swaps the hint to "⌘ K" on Apple devices and dispatches a search:open event on the document on click.

  • Add data-shortcut to the trigger to bind the keyboard shortcut (only one per page). The demo leaves it out, because this site's own search already uses Ctrl + K. Connect it to your dialog, like the Command Palette.

  • The control uses the form tokens (background, border, radius and focus ring), so it matches the inputs in every style.

Documentation

Learn about Spruce CSS through our extensive documentation.

Components

Explore our UI library of accessible components built with Spruce CSS.

Blocks and Pages

Full-width page blocks and complete page templates, ready to copy.

Find us on GitHub

Did you find a bug? Have an idea or a question? Please open an issue to help us develop the project.