Is there a free trial?
Trial availability is listed on the current pricing page.
ASSET_SPEC // SEARCHABLE_FAQ
A powerful FAQ interface with a real-time search filter to help users find answers instantly.
4 results
Trial availability is listed on the current pricing page.
Cancellation options and effective dates are shown in account settings.
Available plan changes and their effective dates are shown in billing settings.
Current team pricing and eligibility are listed on the pricing page.
Use the searchable FAQ when your collection is large enough that scrolling becomes painful. Live filtering paired with a polite live region keeps the experience accessible as the result count updates.
<section class="mx-auto max-w-4xl px-4 py-12" data-searchable-faq>
<div class="mb-10">
<h2 class="text-3xl font-bold text-gray-900">How can we help?</h2>
<div class="mt-6 relative">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg aria-hidden="true" class="h-5 w-5 text-gray-400" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
</div>
<label class="sr-only" for="faq-search">Search frequently asked questions</label>
<input
id="faq-search"
type="search"
placeholder="Search for answers..."
data-faq-search
class="block w-full pl-10 pr-3 py-3 border border-gray-300 rounded-lg leading-5 bg-white placeholder-gray-500 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-blue-500 sm:text-sm transition duration-150 ease-in-out"
/>
</div>
<p class="sr-only" aria-live="polite" data-faq-status>1 result</p>
</div>
<div class="space-y-6" data-faq-results>
<article class="bg-white p-6 rounded-xl border border-gray-100 shadow-sm hover:shadow-md transition-shadow" data-faq-item>
<h3 class="text-lg font-semibold text-gray-900">How to use search?</h3>
<p class="mt-3 text-gray-600">Just start typing keywords to filter the list of questions instantly.</p>
</article>
<article class="bg-white p-6 rounded-xl border border-gray-100 shadow-sm hover:shadow-md transition-shadow" data-faq-item>
<h3 class="text-lg font-semibold text-gray-900">Is it real-time?</h3>
<p class="mt-3 text-gray-600">Yes, the results update immediately as you type in the search bar.</p>
</article>
</div>
</section>
<script>
const root = document.querySelector('[data-searchable-faq]');
const input = root.querySelector('[data-faq-search]');
const items = [...root.querySelectorAll('[data-faq-item]')];
const status = root.querySelector('[data-faq-status]');
input.addEventListener('input', () => {
const query = input.value.trim().toLowerCase();
let visibleCount = 0;
items.forEach((item) => {
const matches = item.textContent.toLowerCase().includes(query);
item.hidden = !matches;
visibleCount += Number(matches);
});
status.textContent = `${visibleCount} ${visibleCount === 1 ? 'result' : 'results'}`;
});
</script>import React, { useState } from 'react';
import { Search } from 'lucide-react';
interface FaqItem {
id: string;
question: string;
answer: string;
}
const defaultItems = [
{ id: '1', question: 'How to use search?', answer: 'Just start typing keywords to filter the list of questions instantly.' },
{ id: '2', question: 'Is it real-time?', answer: 'Yes, the results update immediately as you type in the search bar.' }
];
export function SearchableFaq({ items = defaultItems }: { items?: FaqItem[] }) {
const [query, setQuery] = useState('');
const filteredItems = items.filter(
(item) =>
item.question.toLowerCase().includes(query.toLowerCase()) ||
item.answer.toLowerCase().includes(query.toLowerCase())
);
return (
<div className="mx-auto max-w-4xl px-4 py-12">
<div className="text-center mb-12">
<h2 className="text-4xl font-extrabold text-gray-900 tracking-tight">
Common Questions
</h2>
<div className="mt-8 max-w-xl mx-auto relative">
<div className="absolute inset-y-0 left-0 pl-4 flex items-center pointer-events-none">
<Search aria-hidden="true" className="h-5 w-5 text-gray-400" />
</div>
<label className="sr-only" htmlFor="faq-search">
Search frequently asked questions
</label>
<input
id="faq-search"
type="search"
className="block w-full pl-11 pr-4 py-4 border-gray-200 rounded-2xl shadow-sm focus:ring-2 focus:ring-blue-500 focus:border-blue-500 text-lg"
placeholder="Search questions or keywords..."
value={query}
onChange={(e) => setQuery(e.target.value)}
/>
</div>
<p className="sr-only" aria-live="polite">
{filteredItems.length} {filteredItems.length === 1 ? 'result' : 'results'}
</p>
</div>
<div className="space-y-4">
{filteredItems.length > 0 ? (
filteredItems.map((item) => (
<div
key={item.id}
className="p-6 bg-white border border-gray-100 rounded-2xl hover:border-blue-100 hover:bg-blue-50/30 transition-all"
>
<h3 className="text-lg font-bold text-gray-900">{item.question}</h3>
<p className="mt-3 text-gray-600 leading-relaxed">{item.answer}</p>
</div>
))
) : (
<div className="text-center py-12">
<p className="text-gray-500 text-lg">No matches found for "{query}"</p>
<button
onClick={() => setQuery('')}
className="mt-4 text-blue-600 font-medium hover:underline"
>
Clear search
</button>
</div>
)}
</div>
</div>
);
}