Skip to content

Faq Chat

FAQ as a chat: suggested question chips on the left; picking one adds a gradient user bubble and, after a typing indicator, a glass answer bubble in the conversation panel.

glass/section/faq-chat
Open ↗

Source

"use client";

import { useState } from "react";
import { cn } from "@/lib/utils";

export interface FaqChatProps {
  eyebrow?: string;
  title?: string;
  items?: { question: string; answer: string }[];
  className?: string;
}

const GLASS = "da-stroke bg-da-surface backdrop-blur-da backdrop-saturate-150";

const DEFAULT_ITEMS = [
  { question: "Does everyone on the call need Halo?", answer: "Nope — only the person who invites Halo. Everyone else just gets the recap." },
  { question: "Can Halo skip the small talk?", answer: "Yes. Recaps focus on decisions and actions; you can also pause recording any time from the call." },
  { question: "Will it work with our Google Workspace SSO?", answer: "Yes, Google and Microsoft SSO on every plan, SAML on Business." },
  { question: "Can I try it before paying?", answer: "Every workspace starts with a 14-day Team trial. No card needed." },
];

/** FAQ as a conversation: question chips; clicking one appends the question as a user bubble and Halo’s answer as a glass bubble (with typing dots). */
export function FaqChat({ eyebrow = "Ask us anything", title = "Questions? Halo has answers.", items = DEFAULT_ITEMS, className }: FaqChatProps) {
  const [asked, setAsked] = useState<number[]>([0]);
  const [typing, setTyping] = useState(false);

  const ask = (i: number) => {
    if (asked.includes(i) || typing) return;
    setTyping(true);
    setAsked((a) => [...a, i]);
    const reduce = window.matchMedia("(prefers-reduced-motion: reduce)").matches;
    window.setTimeout(() => setTyping(false), reduce ? 0 : 700);
  };

  return (
    <section aria-labelledby="glass-faq-chat-title" className={cn("da-section text-da-fg", className)}>
      <div className="da-container grid gap-10 lg:grid-cols-[1fr_1.3fr]">
        <div>
          <p className="text-sm font-semibold text-da-primary">{eyebrow}</p>
          <h2
            id="glass-faq-chat-title"
            className="mt-3 font-da-display text-[clamp(2rem,4.5vw,3.25rem)] leading-[1.08] font-semibold tracking-da-display text-balance"
          >
            {title}
          </h2>
          <ul className="mt-8 flex flex-wrap gap-2" aria-label="Suggested questions">
            {items.map((it, i) => (
              <li key={it.question}>
                <button
                  type="button"
                  disabled={asked.includes(i)}
                  onClick={() => ask(i)}
                  className={cn(
                    "da-focus da-transition rounded-da-pill px-4 py-2 text-left text-sm font-medium shadow-da-sm hover:-translate-y-0.5 disabled:opacity-50 disabled:hover:translate-y-0",
                    GLASS,
                  )}
                >
                  {it.question}
                </button>
              </li>
            ))}
          </ul>
        </div>
        <div className={cn("flex min-h-[420px] flex-col gap-3 rounded-da-lg p-5 shadow-da-lg", GLASS)} role="log" aria-live="polite" aria-label="Answers">
          {asked.map((i, k) => {
            const it = items[i]!;
            const last = k === asked.length - 1;
            return (
              <div key={i} className="flex flex-col gap-3">
                <p className="max-w-[85%] self-end rounded-da-lg rounded-br-da-sm bg-gradient-to-r from-da-primary to-da-accent px-4 py-2.5 text-[15px] text-da-primary-fg shadow-da-sm">
                  {it.question}
                </p>
                {last && typing ? (
                  <p aria-label="Halo is typing" className="flex w-fit gap-1 rounded-da-lg rounded-bl-da-sm bg-da-surface px-4 py-3.5">
                    {[0, 1, 2].map((d) => (
                      <span key={d} className="size-1.5 animate-bounce rounded-full bg-da-muted-fg" style={{ animationDelay: `${d * 120}ms` }} />
                    ))}
                  </p>
                ) : (
                  <p className="max-w-[85%] self-start rounded-da-lg rounded-bl-da-sm bg-da-surface px-4 py-2.5 text-[15px] shadow-da-sm transition-[opacity,translate] duration-(--da-duration) starting:translate-y-1 starting:opacity-0">
                    {it.answer}
                  </p>
                )}
              </div>
            );
          })}
          {asked.length === items.length && !typing && (
            <p className="mt-auto text-center text-xs text-da-muted-fg">That’s everything — email hello@halo.app for more.</p>
          )}
        </div>
      </div>
    </section>
  );
}

export default FaqChat;

modules/glass/section/faq-chat/index.tsx

Props

PropTypeDefaultDescription
eyebrow / titlestring—Header.
items{ question, answer }[]—Q&As (first one is pre-asked).
classNamestring—Classes.

Other faq variants in Glass

FAQ in other art directions

FAQ Accordion

Two-column FAQ: sticky title + support CTA on the left, numbered accordion cards on the right with a yellow plus that rotates into an ink cross when open. Built on Radix Accordion.

BrutalistFAQ

FAQ Categories

Help-center style FAQ: topic buttons with counts on the left (stacked on desktop, wrapped on mobile), and a ruled accordion on the right whose open question floods yellow.

BrutalistFAQ

FAQ Grid

Always-open FAQ grid: ruled cells (1/2/3 columns) with a yellow question-mark square, uppercase question and answer, closed by a full-width ink contact row. No interaction needed.

BrutalistFAQ

FAQ Search

Searchable FAQ: a huge ruled search field that presses in on focus, live result count, and native <details> cards with tags; a pink empty state points to support.

BrutalistFAQ

Faq Grid

All answers visible at once: a three-column grid of short questions and answers under a header, followed by two support link cards (documentation, talk to us).

MinimalFAQ

Faq List

Centered single-column FAQ built on native details/summary (zero JS): hairline dividers, a plus icon that rotates into a cross when open, and a contact line underneath.

MinimalFAQ

FAQ Split

Two-column FAQ: title, description and support link on the left, hairline-divided Radix accordion on the right with a rotating chevron and a smooth height + fade expand.

MinimalFAQ

Faq Tabs

FAQ grouped by category behind an underline tab bar (Radix Tabs, with counts); the active category shows every question and answer in a two-column definition list.

MinimalFAQ

Faq Inline

Ultra-compact FAQ: short questions and one-line answers flowing as a 3-column grid of mono question labels over large answers — scannable in seconds.

Mono CleanFAQ

Faq List

Numbered accordion FAQ in a ruled list: mono index + question, a +/− glyph that swaps, answer indented under the question; left column holds the label and title.

Mono CleanFAQ

Faq Split

Always-open FAQ as a two-column definition list (question left in medium weight, answer right in muted text) on hairline rows, followed by a mono contact line.

Mono CleanFAQ

Faq Tabs

FAQ grouped by topic with text tabs (Radix Tabs) underlined in ink when active, and each topic’s answers as a ruled definition list.

Mono CleanFAQ

Faq Accordion

Two-column FAQ: heading + description + contact link on the left, bordered Radix accordion with plus icons rotating to × on the right.

Neo CorporateFAQ

Faq Security

Security & compliance FAQ: dark-tinted certification cards (SOC 2, ISO 27001, GDPR, PCI) with shield icons, then security questions as native <details> disclosure rows.

Neo CorporateFAQ

Faq Sidebar

Help-center style FAQ: a vertical category nav (left, becomes horizontal scroll chips on mobile) and the selected category’s questions as an open definition list.

Neo CorporateFAQ

Faq Support

Compact 2×3 grid of short Q&As followed by three bordered support channel cards (docs, chat, dedicated support).

Neo CorporateFAQ

Faq Columns

Editorial FAQ: serif title and intro in a narrow left column, questions as a two-column definition list on the right separated by warm hairlines.

Organic SoftFAQ

Faq Contact

FAQ beside a contact card: native disclosure list on the left, and a clay-tinted card with a sprouting-leaf illustration, email and chat buttons on the right.

Organic SoftFAQ

Faq Search

Searchable FAQ: rounded search field plus topic pills filter a list of questions (native details), with a friendly empty state and live result count.

Organic SoftFAQ

Faq Soft

Soft accordion: each question is its own rounded paper pill-card that turns sage when open, with a round plus that rotates into a cross; generous spacing.

Organic SoftFAQ

Faq Columns

All-visible FAQ: sticky intro with a peach “Chat with us” pill on the left, six Q&As in a 2-column grid with round lavender number badges on the right.

Soft FlatFAQ

Faq Help

Help-center FAQ: lavender panel with a friendly greeting, big white search pill and popular-search chips; matching answers show as white cards with a peach empty state.

Soft FlatFAQ

Faq Pills

Single-column FAQ of rounded white blocks on native details/summary; the open item turns lavender and its round chevron button flips and fills periwinkle.

Soft FlatFAQ

Faq Tinted

FAQ by topic: three big pastel topic buttons (emoji + label) switch the list of white Q&A cards below, which fades in on change.

Soft FlatFAQ