# FAQ 07

> Split FAQ: a heading, lead and numbered topic index on the start side; picking a topic opens its answer in the single-open accordion on the end side.

A shadcn/ui block from the [@hirael](https://hirael.com) registry, listed on [shadcn.exchange](https://shadcn.exchange/r/hirael/faq-07).

- Page, with a live preview: https://shadcn.exchange/r/hirael/faq-07
- Screenshot: https://abzjhwgwpdpz7ua5.public.blob.vercel-storage.com/shots/hirael/faq-07-light-29bb1fa1e48f8fb6.png
- Registry item: https://hirael.com/r/faq-07.json
- Categories: blocks, faq
- Listed: 2026-10-13, source last changed 2026-10-13

## Install

```bash
npx shadcn@latest add https://hirael.com/r/faq-07.json
```

Run it in a project that has shadcn/ui set up. It adds the files below and installs what they depend on.

## Dependencies

- Registry items: `https://hirael.com/r/accordion.json`

## Files

### `registry/hirael/bases/radix/blocks/faq-07/faq-07.tsx`

```tsx
// FAQ 07 from Hirael <https://hirael.com/blocks/faqs/faq-07>
// MIT · Mohammad Shehadeh · https://github.com/MohammadShehadeh/hirael

'use client';

import * as React from 'react';

import { cn } from '@/lib/utils';
import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from '@/registry/hirael/bases/radix/ui/accordion';

const ENTER =
  'animate-in fade-in slide-in-from-bottom-4 duration-500 ease-[cubic-bezier(0.22,1,0.36,1)] fill-mode-both motion-reduce:animate-none';

const stagger = (index: number, step = 60): React.CSSProperties => ({ animationDelay: `${index * step}ms` });

const QUESTIONS = [
  {
    value: 'config',
    topic: 'Existing configuration',
    question: 'Do I have to give up my existing configuration?',
    answer:
      'No. The importer reads the workflow files already in your repo and renders them as a graph. Edits flow both ways, and the files stay in git.',
  },
  {
    value: 'free',
    topic: 'The free plan',
    question: 'What does the free plan actually include?',
    answer:
      'The full editor, two concurrent runs and 500 run minutes a month. It is not a trial; small projects can stay on it forever.',
  },
  {
    value: 'runners',
    topic: 'Runners',
    question: 'Where do the runs execute?',
    answer:
      'On managed runners by default. Self-hosted runners are in progress for workloads that need to stay inside your network.',
  },
  {
    value: 'secrets',
    topic: 'Secrets',
    question: 'How are secrets handled?',
    answer:
      'Secrets are scoped to environments and encrypted at rest. A step only receives the secrets of the environment it deploys to, and values never appear in logs.',
  },
  {
    value: 'migrate',
    topic: 'Leaving later',
    question: 'Can I leave without rewriting anything?',
    answer:
      'Yes. Because the graph is stored as standard workflow files in your repo, turning the editor off leaves you with configuration any runner understands.',
  },
];

const formatIndex = (index: number) => String(index + 1).padStart(2, '0');

const Faq07 = () => {
  const [open, setOpen] = React.useState<string>(QUESTIONS[0].value);

  return (
    <section data-slot="faq" className="bg-background py-20 sm:py-28">
      <div className="mx-auto grid w-full max-w-6xl grid-cols-1 gap-10 px-6 md:grid-cols-[minmax(0,18rem)_1fr] md:gap-16 md:px-10">
        <div data-slot="faq-intro" className="flex flex-col gap-4">
          <span className={cn(ENTER, 'text-xs text-muted-foreground uppercase')}>Migrating</span>
          <h2
            style={stagger(1, 70)}
            className={cn(ENTER, 'font-serif text-3xl font-medium tracking-tight text-balance md:text-4xl')}
          >
            Before you move your pipelines
          </h2>
          <p style={stagger(2, 70)} className={cn(ENTER, 'max-w-md text-sm text-muted-foreground md:text-base')}>
            The short version of what teams ask before switching. Pick a topic to open its answer.
          </p>

          <nav
            data-slot="faq-index"
            aria-label="Topics"
            style={stagger(3, 70)}
            className={cn(ENTER, 'mt-4 hidden flex-col border-s border-border md:flex')}
          >
            {QUESTIONS.map((q, i) => {
              const active = open === q.value;

              return (
                <button
                  key={q.value}
                  type="button"
                  aria-current={active ? 'true' : undefined}
                  data-active={active || undefined}
                  onClick={() => setOpen(q.value)}
                  className="group relative flex items-baseline gap-3 py-2 ps-4 text-start text-sm text-muted-foreground transition-colors duration-150 outline-none hover:text-foreground focus-visible:text-foreground data-active:text-foreground"
                >
                  <span
                    aria-hidden
                    className="absolute inset-y-1 -start-px w-px origin-top scale-y-0 bg-foreground transition-transform duration-250 ease-[cubic-bezier(0.22,1,0.36,1)] group-data-active:scale-y-100 motion-reduce:transition-none"
                  />
                  <span className="text-xs tabular-nums transition-colors group-data-active:text-primary">
                    {formatIndex(i)}
                  </span>
                  {q.topic}
                </button>
              );
            })}
          </nav>
        </div>

        <div data-slot="faq-list" style={stagger(3, 70)} className={cn(ENTER, 'border-y border-border')}>
          <Accordion type="single" collapsible value={open} onValueChange={setOpen}>
            {QUESTIONS.map((q, i) => (
              <AccordionItem key={q.value} value={q.value}>
                <AccordionTrigger>
                  <span className="flex items-baseline gap-4 text-base">
                    <span className="text-xs text-muted-foreground tabular-nums">{formatIndex(i)}</span>
                    <span>{q.question}</span>
                  </span>
                </AccordionTrigger>
                <AccordionContent className="ms-9 max-w-2xl">
                  <span className="text-muted-foreground">{q.answer}</span>
                </AccordionContent>
              </AccordionItem>
            ))}
          </Accordion>
        </div>
      </div>
    </section>
  );
};

export default Faq07;
```
