Skip to content

Search modal

BlockCSS + PrelineLive search: app-wired

A full-screen command-palette-style search: a button opens a centered dialog with an input, a recent / results list, and an empty state. Preline handles open/close; the design system provides the markup and styling. The live filtering is wired by your app (see the dependency note).

Search modal
Open ↗
blocks/search-modal.html
<div class="flex justify-center p-2">
<button type="button" class="button-secondary" data-hs-overlay="#search-modal">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M3 10a7 7 0 1 0 14 0a7 7 0 1 0 -14 0" />
<path d="M21 21l-6 -6" />
</svg>
<span>Search</span>
</button>
</div>
<!-- overlay (hidden until the button opens it via Preline) -->
<div
id="search-modal"
class="hs-overlay hs-overlay-backdrop pointer-events-none fixed inset-0 z-1000 hidden search-modal bg-background/40 backdrop-blur-sm"
role="dialog"
tabindex="-1"
aria-labelledby="search-modal-label"
data-search-modal
>
<button type="button" class="search-modal-close" aria-label="Close search" data-hs-overlay="#search-modal">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M18 6l-12 12" />
<path d="M6 6l12 12" />
</svg>
</button>
<div class="hs-overlay-animation-target search-modal-panel" data-search-modal-panel>
<div class="search-dialog" data-search-dialog data-state="recent">
<section class="search-input-group" data-search-input-group>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M3 10a7 7 0 1 0 14 0a7 7 0 1 0 -14 0" />
<path d="M21 21l-6 -6" />
</svg>
<input type="text" class="search-field" data-search-input placeholder="Search…" />
<button type="button" class="search-clear" data-search-clear aria-label="Clear">
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M18 6l-12 12" />
<path d="M6 6l12 12" />
</svg>
</button>
</section>
<div class="search-body" data-search-body>
<p class="search-recent-label" data-search-recent-label>Recent</p>
<ul class="search-list" data-search-list>
<a href="#" class="search-link text-foreground-subtle [&_svg]:size-5">
<span class="search-text text-foreground">Add exchange rate</span>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M9 6l6 6l-6 6" />
</svg>
</a>
<a href="#" class="search-link text-foreground-subtle [&_svg]:size-5">
<span class="search-text text-foreground">Accounts</span>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M9 6l6 6l-6 6" />
</svg>
</a>
<a href="#" class="search-link text-foreground-subtle [&_svg]:size-5">
<span class="search-text text-foreground">Cashier dashboard</span>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
>
<path d="M9 6l6 6l-6 6" />
</svg>
</a>
</ul>
</div>
</div>
</div>
</div>

A trigger button opens the overlay by id; inside, the dialog carries state attributes that CSS uses to show/hide parts (you, or the search script, toggle them):

<!-- trigger -->
<button type="button" class="button-secondary" data-hs-overlay="#search-modal">Search</button>
<!-- overlay -->
<div id="search-modal" class="search-modal hs-overlay hidden … " data-search-modal>
<button class="search-modal-close" data-hs-overlay="#search-modal"><!-- × --></button>
<div class="search-modal-panel hs-overlay-animation-target" data-search-modal-panel>
<div class="search-dialog" data-search-dialog data-state="recent">
<section class="search-input-group" data-search-input-group>
<!-- search icon -->
<input type="text" class="search-field" data-search-input placeholder="Search…" />
<button type="button" class="search-clear" data-search-clear><!-- × --></button>
</section>
<div class="search-body" data-search-body>
<p class="search-recent-label" data-search-recent-label>Recent</p>
<ul class="search-list" data-search-list>
<a href="#" class="search-link"><span class="search-text">Accounts</span><!-- › --></a>
</ul>
<div class="search-empty" data-search-empty></div>
</div>
</div>
</div>
</div>

The same trigger pattern powers the shell’s search action — its rail button is just another data-hs-overlay="#search-modal".

Attribute (on [data-search-dialog]) Meaning Variant
data-state="recent|results" Which mode the body shows.
data-empty No items in the current mode. search-empty: / search-filled:
data-has-query The input has text (reveals the clear button). search-has-query: / search-no-query:

search-modal, search-modal-panel, search-dialog, search-input-group, search-field, search-body, search-recent-label, search-list, search-link, search-empty, search-clear, search-modal-close.