Skip to content
W WRNexusJS
core component

PublicSearch

Reusable public search component.

@wrnexus/ui 0.2.6715 props0 slots4 events

Usage

Components are auto-discovered. Use the component directly in any .wrn view:

<PublicSearch
  query="query"
  placeholder="Search..."
  label="Search"
  action="action"
  method="get"
/>

Legacy mount name: data-component="PublicSearch".

Props and attributes

PropTypeRequirementDefault
classstringOptional""
querystringOptional""
placeholderstringOptional"Search..."
labelstringOptional"Search"
actionstringOptional""
methodstringOptional"get"
namestringOptional"q"
buttonLabelstringOptional""
clearLabelstringOptional"Clear search"
sizestringOptional"default"
centeredbooleanOptionalfalse
fullWidthbooleanOptionalfalse
showShortcutbooleanOptionalfalse
shortcutLabelstringOptional"⌘ K"
suggestionsstringOptional[]

Slots

This component does not declare a slot.

Events

  • input
  • focus
  • blur
  • click

Source contract

Installed source: components/PublicSearch.wrn

component PublicSearch {
    props {
        class: string = ""
        query = ""

        placeholder = "Search..."
        label = "Search"

        action = ""
        method = "get"
        name = "q"

        buttonLabel = ""
        clearLabel = "Clear search"

        size = "default"
        centered = false
        fullWidth = false

        showShortcut = false
        shortcutLabel = "⌘ K"

        suggestions = []
    }

    state searchValue = query
    state focused = false

    view {
        <div
            class="w-full {class}"
            class:max-w-2xl="!fullWidth"
            class:mx-auto="centered"
        >
        <form
                action="{action}"
                method="{method}"
                role="search"
                class="w-full"
            >
        <label
                    for="public-search-input"
                    class="sr-only"
                >
                    {label}
                </label>
        <div
                    class=" group relative flex w-full items-center rounded-2xl border bg-white shadow-sm transition-all duration-200 dark:bg-white/5 {focused ? 'border-indigo-400 ring-4 ring-indigo-500/10 dark:border-indigo-500/50 dark:ring-indigo-500/10' : 'border-slate-200 hover:border-slate-300 dark:border-white/10 dark:hover:border-white/20' } {size === 'compact' ? 'min-h-11' : size === 'large' ? 'min-h-14' : 'min-h-12' } "
                >
        <!-- Search icon -->
        <span class=" pointer-events-none absolute left-4 text-slate-400 transition group-focus-within:text-indigo-600 dark:text-slate-500 dark:group-focus-within:text-indigo-400 {size === 'large' ? 'h-5 w-5' : 'h-4.5 w-4.5'} icon-[lucide--search] " aria-hidden="true" >
        </span>
        <!-- Input -->
        <input
                        id="public-search-input"
                        type="search"
                        name="{name}"
                        value="{searchValue}"
                        placeholder="{placeholder}"
                        autocomplete="off"
                        @input="searchValue = event.target.value"
                        @focus="focused = true"
                        @blur="focused = false"
                        class=" min-w-0 flex-1 bg-transparent text-slate-950 outline-none placeholder:text-slate-400 dark:text-white dark:placeholder:text-slate-500 {size === 'compact' ? 'h-11 pl-11 pr-3 text-sm' : size === 'large' ? 'h-14 pl-12 pr-4 text-base' : 'h-12 pl-11 pr-4 text-sm' } "
                    />
        <!-- Keyboard shortcut -->
        <span
                        class="mr-3 hidden shrink-0 items-center rounded-md border border-slate-200 bg-slate-50 px-2 py-1 text-[11px] font-semibold text-slate-400 dark:border-white/10 dark:bg-white/5 dark:text-slate-500 sm:inline-flex"
                        class:hidden="!showShortcut || searchValue !== ''"
                    >
                        {shortcutLabel}
                    </span>
        <!-- Clear button -->
        <button
                        type="button"
                        @click="searchValue = ''"
                        aria-label="{clearLabel}"
                        class="mr-2 grid h-8 w-8 shrink-0 place-items-center rounded-lg text-slate-400 transition hover:bg-slate-100 hover:text-slate-700 focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 dark:text-slate-500 dark:hover:bg-white/10 dark:hover:text-slate-200"
                        class:hidden="searchValue === ''"
                    >
        <span class="icon-[lucide--x] h-4 w-4" aria-hidden="true" >
        </span>
        </button>
        <!-- Submit button -->
        <button
                        type="submit"
                        class=" mr-1.5 shrink-0 items-center justify-center gap-2 rounded-xl bg-indigo-600 font-bold text-white shadow-lg shadow-indigo-600/20 transition hover:-translate-y-0.5 hover:bg-indigo-500 hover:shadow-xl focus:outline-none focus-visible:ring-2 focus-visible:ring-indigo-500 focus-visible:ring-offset-2 dark:focus-visible:ring-offset-slate-900 {size === 'compact' ? 'h-9 px-3 text-xs' : size === 'large' ? 'h-11 px-5 text-sm' : 'h-10 px-4 text-sm' } "
                        class:hidden="buttonLabel === ''"
                        class:inline-flex="buttonLabel !== ''"
                    >
                        {buttonLabel}

                        <span class="icon-[lucide--arrow-right] h-4 w-4" aria-hidden="true" >
        </span>
        </button>
        </div>
        </form>
        <!-- Suggested searches -->
        <div
                class="mt-4 flex flex-wrap items-center gap-2"
                class:hidden="suggestions.length === 0"
                class:justify-center="centered"
                class:justify-start="!centered"
            >
        <span class="mr-1 text-xs font-medium text-slate-500 dark:text-slate-400">
                    Popular:
                </span>

                {#each suggestions.slice(0, 5) as suggestion}
                <a
                    href="{suggestion.href}"
                    class="inline-flex items-center gap-1.5 rounded-full border border-slate-200 bg-white px-3 py-1.5 text-xs font-semibold text-slate-600 shadow-sm transition hover:-translate-y-0.5 hover:border-indigo-300 hover:bg-indigo-50 hover:text-indigo-700 dark:border-white/10 dark:bg-white/5 dark:text-slate-300 dark:hover:border-indigo-500/30 dark:hover:bg-indigo-500/10 dark:hover:text-indigo-300"
                >
        <span class="{suggestion.iconClass} h-3.5 w-3.5" aria-hidden="true" class:hidden="suggestion.iconClass === ''" >
        </span>

                    {suggestion.label}
                </a>
                {/each}
            </div>
        </div>
    }
}