<script setup lang="ts">
import { ref } from 'vue'
import { SearchInput } from '@hina-ui/vue'
const query = ref('Spice and Wolf')
</script>
<template>
<SearchInput v-model="query" aria-label="Search" placeholder="Search works" class="w-72" />
</template>
Usage
import { SearchInput } from '@hina-ui/vue'
The field starts with a search icon and shows a clear button at the end once it has content, with v-model bound to the query. Enter emits search with the current value and Esc clears it. Attributes it does not declare land on the input.
Last submitted: none
<script setup lang="ts">
import { ref } from 'vue'
import { SearchInput, Stack, Text } from '@hina-ui/vue'
const query = ref('')
const submitted = ref('')
</script>
<template>
<Stack class="w-72">
<SearchInput
v-model="query"
aria-label="Search"
placeholder="Search works"
@search="submitted = $event"
/>
<Text tone="muted">Last submitted: {{ submitted || 'none' }}</Text>
</Stack>
</template>
Examples
Loading
loading swaps the search icon for a spinner while a search request is in flight.
<script setup lang="ts">
import { SearchInput } from '@hina-ui/vue'
</script>
<template>
<SearchInput model-value="Spice" loading aria-label="Search" class="w-72" />
</template>
Sizes
Three sizes, matching the input.
<script setup lang="ts">
import { SearchInput, Stack } from '@hina-ui/vue'
</script>
<template>
<Stack class="w-72">
<SearchInput size="sm" model-value="Spice" aria-label="Small" />
<SearchInput size="md" model-value="Spice" aria-label="Medium" />
<SearchInput size="lg" model-value="Spice" aria-label="Large" />
</Stack>
</template>
Variants
primary has a border, background and shadow; secondary uses a tinted background; bare is transparent, without a border, shadow, hover fill or container focus ring. Size and padding keep their existing settings.
bare preserves the disabled state and aria-invalid; FormField can display the error message. Action buttons keep their own hover and keyboard focus feedback.
<script setup lang="ts">
import { SearchInput, Stack } from '@hina-ui/vue'
</script>
<template>
<Stack class="w-full max-w-xs">
<SearchInput variant="primary" aria-label="primary" placeholder="primary" />
<SearchInput variant="secondary" aria-label="secondary" placeholder="secondary" />
<SearchInput variant="bare" aria-label="bare" placeholder="bare" />
</Stack>
</template>
States
disabled prevents editing. With clearable off the clear button is never shown.
<script setup lang="ts">
import { SearchInput, Stack } from '@hina-ui/vue'
</script>
<template>
<Stack class="w-72">
<SearchInput disabled model-value="Spice" aria-label="Disabled" />
<SearchInput :clearable="false" model-value="Spice" aria-label="Without clear button" />
</Stack>
</template>
In a form
Inside a FormField the label points at the input, and the error message is rendered by the field; validation rules and submission belong to the Form, and Enter to submit and the submit button keep their default behavior.
<script setup lang="ts">
import { reactive, ref } from 'vue'
import * as v from 'valibot'
import { Button, Form, FormField, SearchInput, Text } from '@hina-ui/vue'
const schema = v.object({
keyword: v.pipe(
v.string('Enter a keyword'),
v.trim(),
v.nonEmpty('Enter a keyword'),
v.minLength(2, 'At least 2 characters'),
),
})
const values = reactive({ keyword: '' })
const result = ref('')
async function search(data: unknown) {
await new Promise(resolve => setTimeout(resolve, 600))
result.value = (data as { keyword: string }).keyword
}
</script>
<template>
<Form v-slot="{ submitting }" :values="values" :rules="schema" class="w-80" @submit="search">
<FormField name="keyword" label="Search works">
<SearchInput v-model="values.keyword" placeholder="Title or alias" />
</FormField>
<Button type="submit" :loading="submitting" class="self-start">Search</Button>
<Text v-if="result" tone="muted" size="sm">Searching for "{{ result }}".</Text>
</Form>
</template>
Behaviour
- The clear button only appears with content and when not disabled; clicking it does not blur the text area.
- Esc clears only when there is content and does nothing otherwise.
- Hover, focus and disabled behave the same as Input.
Accessibility
- The text area is
type="search", so mobile keyboards show a search action key. - The clear button is reachable with Tab and named from the locale pack. The root sets
aria-busywhileloading. - Pair it with a
labelelement or anaria-labelfor its name.
API
Props
| Prop | Type | Default | Description |
|---|---|---|---|
modelValue | string | '' | The query |
clearable | boolean | true | Whether the clear button is shown |
loading | boolean | false | Whether the spinner is shown |
variant | 'primary' | 'secondary' | 'bare' | 'primary' | Variant |
size | 'sm' | 'md' | 'lg' | 'md' | Size |
disabled | boolean | false | Whether the field is disabled |
class | string | — | Classes appended to the root element |
| Event | Payload | Description |
|---|---|---|
update:modelValue | value: string | The query changed |
search | value: string | Enter submitted the query |
clear | — | The query was cleared |