Autocomplete — OutfitKit
Autocomplete
Input con sugerencias filtradas. Combina search + lista de opciones agrupadas. Soporta marcado de coincidencias con <mark>.
Buscar producto · filtrado reactivo
Productos · resultados
Categorías · 1 resultado
Sin resultados
<div data-signals="{ q: 'mar' }">
<div class="autocomplete"
style="width:380px;">
<div class="search">
<span class="search-icon"><iconify-icon icon="lucide:search" width="16" height="16"></iconify-icon></span>
<input type="search" class="input" name="q" placeholder="Buscar producto…" data-bind:value="$q"/>
</div>
<div class="autocomplete-list">
<div class="autocomplete-group" data-show="['marmelada de naranja amarga 250g','mariscada congelada 1kg','café marroquí 500g'].filter(t => t.includes($q.toLowerCase())).length > 0">
Productos · <span data-text="['marmelada de naranja amarga 250g','mariscada congelada 1kg','café marroquí 500g'].filter(t => t.includes($q.toLowerCase())).length"></span> resultados
</div>
<button class="autocomplete-opt" aria-selected="true" data-show="'marmelada de naranja amarga 250g'.includes($q.toLowerCase())">
<svg class="autocomplete-opt-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18"/></svg>
<span>Marmelada de naranja amarga 250g</span>
<span class="autocomplete-opt-meta">SKU 0184</span>
</button>
<button class="autocomplete-opt" data-show="'mariscada congelada 1kg'.includes($q.toLowerCase())">
<svg class="autocomplete-opt-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18"/></svg>
<span>Mariscada congelada 1kg</span>
<span class="autocomplete-opt-meta">SKU 0327</span>
</button>
<button class="autocomplete-opt" data-show="'café marroquí 500g'.includes($q.toLowerCase())">
<svg class="autocomplete-opt-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18"/></svg>
<span>Café marroquí 500g</span>
<span class="autocomplete-opt-meta">SKU 0904</span>
</button>
<div class="autocomplete-group" data-show="'mariscos y pescados frescos'.includes($q.toLowerCase())">Categorías · 1 resultado</div>
<button class="autocomplete-opt" data-show="'mariscos y pescados frescos'.includes($q.toLowerCase())">
<svg class="autocomplete-opt-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 7h18M3 12h18M3 17h18"/></svg>
<span>Mariscos y pescados frescos</span>
<span class="autocomplete-opt-meta">42 SKUs</span>
</button>
<div class="autocomplete-empty" data-show="!['marmelada de naranja amarga 250g','mariscada congelada 1kg','café marroquí 500g','mariscos y pescados frescos'].some(t => t.includes($q.toLowerCase()))">Sin resultados</div>
</div>
</div>
</div>
{% from "autocomplete.jinja" import autocomplete %}
<div data-signals="{ q: 'mar' }">
{% call autocomplete(width="380px") %}
<div class="search">
<span class="search-icon"><iconify-icon icon="lucide:search" width="16" height="16"></iconify-icon></span>
<input type="search" class="input" name="q" placeholder="Buscar producto…" data-bind:value="$q"/>
</div>
<div class="autocomplete-list">
<div class="autocomplete-group" data-show="['marmelada de naranja amarga 250g','mariscada congelada 1kg','café marroquí 500g'].filter(t => t.includes($q.toLowerCase())).length > 0">
Productos · <span data-text="['marmelada de naranja amarga 250g','mariscada congelada 1kg','café marroquí 500g'].filter(t => t.includes($q.toLowerCase())).length"></span> resultados
</div>
<button class="autocomplete-opt" aria-selected="true" data-show="'marmelada de naranja amarga 250g'.includes($q.toLowerCase())">
<svg class="autocomplete-opt-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18"/></svg>
<span>Marmelada de naranja amarga 250g</span>
<span class="autocomplete-opt-meta">SKU 0184</span>
</button>
<button class="autocomplete-opt" data-show="'mariscada congelada 1kg'.includes($q.toLowerCase())">
<svg class="autocomplete-opt-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18"/></svg>
<span>Mariscada congelada 1kg</span>
<span class="autocomplete-opt-meta">SKU 0327</span>
</button>
<button class="autocomplete-opt" data-show="'café marroquí 500g'.includes($q.toLowerCase())">
<svg class="autocomplete-opt-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M3 9h18"/></svg>
<span>Café marroquí 500g</span>
<span class="autocomplete-opt-meta">SKU 0904</span>
</button>
<div class="autocomplete-group" data-show="'mariscos y pescados frescos'.includes($q.toLowerCase())">Categorías · 1 resultado</div>
<button class="autocomplete-opt" data-show="'mariscos y pescados frescos'.includes($q.toLowerCase())">
<svg class="autocomplete-opt-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M3 7h18M3 12h18M3 17h18"/></svg>
<span>Mariscos y pescados frescos</span>
<span class="autocomplete-opt-meta">42 SKUs</span>
</button>
<div class="autocomplete-empty" data-show="!['marmelada de naranja amarga 250g','mariscada congelada 1kg','café marroquí 500g','mariscos y pescados frescos'].some(t => t.includes($q.toLowerCase()))">Sin resultados</div>
</div>
{% endcall %}
</div>
<div data-signals="{ q: 'mar' }">
<Autocomplete width="380px">
<div class="search">
<span class="search-icon"><iconify-icon icon="lucide:search" width="16" height="16"></iconify-icon></span>
<input type="search" class="input" name="q" placeholder="Buscar producto…" data-bind:value="$q"/>
</div>
<div class="autocomplete-list">
<div class="autocomplete-group" data-show="['marmelada de naranja amarga 250g','mariscada congelada 1kg','café marroquí 500g'].filter(t => t.includes($q.toLowerCase())).length > 0">
Productos · <span data-text="['marmelada de naranja amarga 250g','mariscada congelada 1kg','café marroquí 500g'].filter(t => t.includes($q.toLowerCase())).length"></span> resultados
</div>
<button class="autocomplete-opt" aria-selected="true" data-show="'marmelada de naranja amarga 250g'.includes($q.toLowerCase())">
<span>Marmelada de naranja amarga 250g</span>
</button>
<button class="autocomplete-opt" data-show="'mariscada congelada 1kg'.includes($q.toLowerCase())">
<span>Mariscada congelada 1kg</span>
</button>
<button class="autocomplete-opt" data-show="'café marroquí 500g'.includes($q.toLowerCase())">
<span>Café marroquí 500g</span>
</button>
<div class="autocomplete-group" data-show="'mariscos y pescados frescos'.includes($q.toLowerCase())">Categorías · 1 resultado</div>
<button class="autocomplete-opt" data-show="'mariscos y pescados frescos'.includes($q.toLowerCase())">
<span>Mariscos y pescados frescos</span>
</button>
<div class="autocomplete-empty" data-show="!['marmelada de naranja amarga 250g','mariscada congelada 1kg','café marroquí 500g','mariscos y pescados frescos'].some(t => t.includes($q.toLowerCase()))">Sin resultados</div>
</div>
</Autocomplete>
</div>
Install the Jinja addon and import the component:
pip install outfitkit
Then in your template:
{% from "<component>.jinja" import <component> %}
{{ <component>(...) }}
Or with JinjaX:
<Component ... />
Datastar — filtrado reactivo
Sugerencias
Texto:
<div data-signals="{ q: 'man', open: true, items: ['Manzana golden 1kg','Mango Tommy Atkins','Mantequilla pasiega 250g','Manchego curado 200g','Queso de cabra'] }">
<div class="autocomplete"
style="width:380px;">
<div class="search">
<span class="search-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg></span>
<input class="input" type="search" placeholder="Buscar…" data-bind:q data-on:focus="$open = true"/>
</div>
<div class="autocomplete-list" data-show="$open">
<div class="autocomplete-group">Sugerencias</div>
<template data-for="item in $items.filter(x => x.toLowerCase().includes($q.toLowerCase()))">
<button class="autocomplete-opt">
<span data-text="item"></span>
</button>
</template>
</div>
</div>
<div style="margin-top:8px;font-size:13px;color:var(--ink-3);">
Texto: <code data-text="$q"></code>
</div>
</div>
{% from "autocomplete.jinja" import autocomplete %}
<div data-signals="{ q: 'man', open: true, items: ['Manzana golden 1kg','Mango Tommy Atkins','Mantequilla pasiega 250g','Manchego curado 200g','Queso de cabra'] }">
{% call autocomplete(width="380px") %}
<div class="search">
<span class="search-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg></span>
<input class="input" type="search" placeholder="Buscar…" data-bind:q data-on:focus="$open = true"/>
</div>
<div class="autocomplete-list" data-show="$open">
<div class="autocomplete-group">Sugerencias</div>
<template data-for="item in $items.filter(x => x.toLowerCase().includes($q.toLowerCase()))">
<button class="autocomplete-opt">
<span data-text="item"></span>
</button>
</template>
</div>
{% endcall %}
<div style="margin-top:8px;font-size:13px;color:var(--ink-3);">
Texto: <code data-text="$q"></code>
</div>
</div>
<div data-signals="{ q: 'man', open: true, items: ['Manzana golden 1kg','Mango Tommy Atkins','Mantequilla pasiega 250g','Manchego curado 200g','Queso de cabra'] }">
<Autocomplete width="380px">
<div class="search">
<span class="search-icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg></span>
<input class="input" type="search" placeholder="Buscar…" data-bind:q data-on:focus="$open = true"/>
</div>
<div class="autocomplete-list" data-show="$open">
<div class="autocomplete-group">Sugerencias</div>
<template data-for="item in $items.filter(x => x.toLowerCase().includes($q.toLowerCase()))">
<button class="autocomplete-opt">
<span data-text="item"></span>
</button>
</template>
</div>
</Autocomplete>
<div style="margin-top:8px;font-size:13px;color:var(--ink-3);">
Texto: <code data-text="$q"></code>
</div>
</div>
Install the Jinja addon and import the component:
pip install outfitkit
Then in your template:
{% from "<component>.jinja" import <component> %}
{{ <component>(...) }}
Or with JinjaX:
<Component ... />
API
| Prop | Tipo | Default | Descripción |
|---|---|---|---|
width | str | None | Ancho CSS opcional (ej. "380px"). |
attrs | dict | None | Atributos extra. |
Slot: input (típicamente search) y .ok-autocomplete-list con __group y __opt.