Kindhire FAQ FAQ Block - Let's templates
Unlock every premium block and template with All-Access from $20 / 3 months, cancel anytime. Get All-Access
All blocks
Free FAQ

Kindhire FAQ

A faq block extracted from the Kindhire template, available in Tailwind CSS and Bootstrap.

0 2
Kindhire FAQ preview
kindhire.html
<!DOCTYPE html>
<html lang="en">
<head>
  <script>
    window.FontAwesomeConfig = { autoReplaceSvg: 'nest' };
  </script>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Kindhire FAQ | Tailwind CSS UI Block</title>
  <meta name="description" content="A faq block extracted from the Kindhire template, available in Tailwind CSS and Bootstrap.">
  <meta name="keywords" content="Kindhire, Tailwind CSS template, HTML website template, business template, inclusive hiring, accessible job board, disability employment, recruitment platform, remote jobs website, employer page">
  <meta name="author" content="Let's templates">
  <link rel="canonical" href="">

  <meta property="og:type" content="product">
  <meta property="og:site_name" content="Let's templates">
  <meta property="og:locale" content="en_US">
  <meta property="og:url" content="">
  <meta property="og:title" content="Kindhire | Tailwind CSS Business Template">
  <meta property="og:description" content="A warm, accessible Tailwind CSS business template for inclusive hiring platforms, with arch portraits, a story carousel and a live job matcher.">
  <meta property="og:image" content="">
  <meta property="og:image:alt" content="Kindhire template preview">

  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:url" content="">
  <meta name="twitter:title" content="Kindhire | Tailwind CSS Business Template">
  <meta name="twitter:description" content="A warm, accessible Tailwind CSS business template for inclusive hiring platforms, with arch portraits, a story carousel and a live job matcher.">
  <meta name="twitter:image" content="">
  <meta name="twitter:image:alt" content="Kindhire template preview">
  <script src="https://cdn.tailwindcss.com/3.4.17"></script>
  <link rel="preconnect" href="https://fonts.googleapis.com">
  <link href="https://fonts.googleapis.com/css2?family=Fraunces:opsz,wght@9..144,700;9..144,800&family=Urbanist:wght@400;500;600;700&display=swap" rel="stylesheet">
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: { paper: '#f4f4f2', ink: '#141414', royal: { DEFAULT: '#0b4ea2', dark: '#083a7a', soft: '#dfe9f7' }, coral: { DEFAULT: '#f4846a', soft: '#fde3dc' }, leaf: { DEFAULT: '#3aa52a', soft: '#dff1db' }, sun: '#ffc928' },
          fontFamily: { sans: ['Urbanist', 'sans-serif'], serif: ['Fraunces', 'serif'] }
        }
      }
    }
  </script>
  <style>
    @view-transition { navigation: auto; }
    ::view-transition-old(root) { animation: 180ms ease-out both page-fade-out; }
    ::view-transition-new(root) { animation: 220ms ease-in both page-fade-in; }
    @keyframes page-fade-out { to { opacity: 0; } }
    @keyframes page-fade-in { from { opacity: 0; } }
    html { scroll-behavior: smooth; }
    [hidden] { display: none !important; }
    .wiggle { animation: wiggle 5s ease-in-out infinite; transform-origin: center; }
    @keyframes wiggle { 50% { rotate: 6deg; } }
    .logos { animation: logos 34s linear infinite; }
    .logos:hover { animation-play-state: paused; }
    @keyframes logos { to { transform: translateX(-50%); } }
    .ring-fill { transition: stroke-dashoffset .7s ease; }
    .timeline-fill { transform-origin: top; }
    .story { transition: opacity .4s ease; }
    .reveal-ready [data-reveal] { opacity: 0; transform: translateY(24px); transition: opacity .6s ease, transform .6s ease; transition-delay: var(--reveal-delay, 0ms); }
    .reveal-ready [data-reveal].is-visible { opacity: 1; transform: none; }
    @media (prefers-reduced-motion: reduce) {
      html { scroll-behavior: auto; }
      .wiggle, .logos { animation: none; }
      .ring-fill, .story { transition: none; }
      ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
    }
  </style>
</head>
<body class="bg-paper font-sans text-ink antialiased">
<% active_page = "index" %>
<% nav = { "platform" => "Platform", "jobs" => "Jobs", "employers" => "For employers", "stories" => "Stories", "about" => "About", "contact" => "Contact" } %>
<% { "index" => "Home" }.merge(nav).each do |slug, label| %>
<% active = active_page == slug %>
<% end %>
<% arches = [["1507003211169-0a1dd7228f2d", "Smiling man in a white T-shirt", "Marco", "QA tester", "bg-royal", "halo", "lg:mt-0"], ["1580489944761-15a19d654956", "Smiling woman with her hair tied up", "Lina", "web designer", "bg-coral", "burst", "lg:mt-36"], ["1599566150163-29194dcaad36", "Young man with glasses and a beard", "Sam", "content moderator", "bg-leaf", "zigzag", "lg:mt-0"]] %>
<% arches.each_with_index do |(photo, alt, name, role, color, doodle, offset), index| %>
<% if index == 1 %>
<% end %>
<% if doodle == "halo" %>
<% elsif doodle == "burst" %>
<% else %>
<% end %>
<% unless index == 1 %>
<% else %>
<% end %>
<% end %>
<% stories = [["Elena Ruiz", "38, works from Lisbon, uses a wheelchair", "Moderating content is calm, focused work, and I can split my hours however my body needs. Two hours in the morning, two in the evening. My team checks in, never checks up.", "1573497019940-1c28c88b4f3e", "bg-royal"], ["Daniel Okafor", "29, works from Leeds, hard of hearing", "Every meeting has live captions and everything important is written down. For the first time I'm judged on my work, not on how fast I catch what people say.", "1500648767791-00dcc994a43e", "bg-coral"], ["Mei Tanaka", "34, works from Osaka, chronic fatigue", "Flexible deadlines changed everything. I design on good days and rest on hard ones, and nobody makes me explain myself.", "1573497019236-17f8177b81e8", "bg-leaf"]] %>
<% stories.each_with_index do |(name, meta, quote, photo, color), index| %>
<% end %>
<% stories.each_with_index do |story, index| %>
<% end %>
<% skills = [["design", "Design"], ["writing", "Writing"], ["support", "Customer support"], ["testing", "Software testing"], ["data", "Data entry"], ["moderation", "Moderation"]] %>
<% needs = [["remote", "Fully remote", "fa-house-laptop"], ["flexible", "Flexible hours", "fa-clock"], ["captions", "Captioned meetings", "fa-closed-captioning"], ["reader", "Screen-reader friendly", "fa-universal-access"]] %>
<% jobs = [["Junior UI designer", "Brightfield Studio", "design", "remote flexible reader", "$38–44K", "bg-coral-soft"], ["Support specialist", "Parcelpoint", "support", "remote captions flexible", "$32–36K", "bg-royal-soft"], ["QA tester", "Northgate Apps", "testing", "remote reader captions flexible", "$40–48K", "bg-leaf-soft"], ["Content moderator", "Openstream", "moderation", "remote flexible", "$30–34K", "bg-royal-soft"], ["Copywriter", "Hearthline", "writing", "remote flexible captions", "$36–42K", "bg-coral-soft"], ["Data assistant", "Clearpath Health", "data", "flexible reader", "$29–33K", "bg-leaf-soft"]] %>
<% skills.each_with_index do |(id, label), index| %>
<% end %>
<% needs.each_with_index do |(id, label, icon), index| %>
<% end %>
<% jobs.each do |title, company, skill, tags, salary, tone| %>
<% needs.each do |id, label, icon| %>
<% if tags.include?(id) %>
<% end %>
<% end %>
<% end %>
<% steps = [["Sign up in your own way", "Online, by phone, by text or over a sign language video call.", "fa-hand"], ["Free skills check", "A relaxed chat with a career coach about what you enjoy and what you need.", "fa-comments"], ["Paid training", "Six weeks of online training, paid from day one, at your own pace.", "fa-graduation-cap"], ["Your first role", "We introduce you to an employer who has already set up your accommodations.", "fa-briefcase"], ["Ongoing support", "A coach checks in every month for your first year, and more if you want.", "fa-heart"]] %>
<% steps.each_with_index do |(title, text, icon), index| %>
<% end %>
<% rings = [[92, "still in work after a year", "#0b4ea2"], [78, "work fully from home", "#f4846a"], [64, "promoted within two years", "#3aa52a"]] %>
<% rings.each do |value, label, color| %>
<% end %>
<% partners = [["fa-leaf", "Brightfield"], ["fa-box", "Parcelpoint"], ["fa-compass", "Northgate"], ["fa-water", "Openstream"], ["fa-fire", "Hearthline"], ["fa-heart-pulse", "Clearpath"], ["fa-mountain", "Highbank"]] %>
<% (partners + partners).each_with_index do |(icon, name), index| %>
<% end %>
<% faqs = [["Does it cost anything?", "No. Kindhire is free for job seekers, forever. Employers pay us when they hire."], ["What if I can only work a few hours?", "Plenty of our roles start at 10 hours a week. Tell us your limit and we'll respect it."], ["Will my benefits be affected?", "Our advisers help you check how earnings affect any support you receive before you accept an offer."], ["Can someone help me fill in the forms?", "Yes. A coach can do it with you over the phone, by video or by text."]] %>
<!-- block:start faq -->
  <section class="mx-auto grid max-w-7xl gap-12 px-5 py-24 md:px-10 lg:grid-cols-[1fr_1.3fr]" data-chat>
    <div>
      <h2 class="font-serif text-4xl font-bold leading-tight tracking-tight md:text-6xl">Ask us anything</h2>
      <p class="mt-4 text-lg text-ink/70">Tap a question and our team will answer.</p>
      <div class="mt-8 flex flex-wrap gap-2">
        <% faqs.each do |question, answer| %>
          <button type="button" data-chat-question data-answer="<%= answer %>" class="rounded-full border-2 border-royal/20 bg-white px-4 py-2.5 text-left font-medium transition hover:border-royal"><%= question %></button>
        <% end %>
      </div>
    </div>
    <div class="flex h-[28rem] flex-col rounded-[2.5rem] bg-white p-6 shadow-sm">
      <div class="flex items-center gap-3 border-b border-ink/10 pb-4">
        <img src="https://images.unsplash.com/photo-1580489944761-15a19d654956?auto=format&fit=crop&w=96&h=96&q=70" alt="" class="h-11 w-11 rounded-full object-cover">
        <p><span class="block font-bold">Lina from Kindhire</span><span class="flex items-center gap-1.5 text-sm text-leaf"><span class="h-2 w-2 rounded-full bg-leaf"></span>Online now</span></p>
      </div>
      <ol data-chat-log class="flex flex-1 flex-col justify-end gap-3 overflow-y-auto pt-4" aria-live="polite">
        <li class="max-w-[85%] rounded-3xl rounded-bl-md bg-paper px-5 py-3">Hi! What would you like to know?</li>
      </ol>
    </div>
  </section>
  <!-- block:end faq -->
<script>
    const reducedMotion = matchMedia('(prefers-reduced-motion: reduce)').matches;
    const watchMotion = !reducedMotion && !navigator.webdriver && 'IntersectionObserver' in window;

    document.querySelectorAll('[data-menu-toggle]').forEach((button) => {
      const menu = document.getElementById(button.getAttribute('aria-controls'));
      const close = menu.querySelector('[data-menu-close]');
      const set = (open) => { menu.hidden = !open; button.setAttribute('aria-expanded', String(open)); document.body.style.overflow = open ? 'hidden' : ''; (open ? close : button).focus(); };
      button.addEventListener('click', () => set(menu.hidden));
      close.addEventListener('click', () => set(false));
      document.addEventListener('keydown', (event) => { if (event.key === 'Escape' && !menu.hidden) set(false); });
    });

    document.querySelectorAll('[data-carousel]').forEach((root) => {
      const slides = [...root.querySelectorAll('[data-slide]')];
      const dots = [...root.querySelectorAll('[data-carousel-dot]')];
      let current = 0;
      const show = (index) => {
        current = (index + slides.length) % slides.length;
        slides.forEach((slide, i) => { slide.hidden = i !== current; });
        dots.forEach((dot, i) => dot.setAttribute('aria-current', String(i === current)));
      };
      root.querySelectorAll('[data-carousel-prev]').forEach((button) => button.addEventListener('click', () => show(current - 1)));
      root.querySelectorAll('[data-carousel-next]').forEach((button) => button.addEventListener('click', () => show(current + 1)));
      dots.forEach((dot, i) => dot.addEventListener('click', () => show(i)));
      root.addEventListener('keydown', (event) => { if (event.key === 'ArrowLeft') show(current - 1); if (event.key === 'ArrowRight') show(current + 1); });
    });

    document.querySelectorAll('[data-matcher]').forEach((root) => {
      const jobs = [...root.querySelectorAll('[data-job]')];
      const isOn = (el) => el.getAttribute('aria-pressed') === 'true' || el.selected === true || el.checked === true;
      const paint = () => {
        const skills = [...root.querySelectorAll('[data-skill]:not([data-job])')].filter(isOn).map((el) => el.dataset.skill);
        const needs = [...root.querySelectorAll('[data-need]')].filter(isOn).map((el) => el.dataset.need);
        let shown = 0;
        jobs.forEach((job) => {
          const match = (!skills.length || skills.includes(job.dataset.skill)) && needs.every((need) => job.dataset.needs.split(' ').includes(need));
          job.hidden = !match;
          if (match) shown += 1;
        });
        root.querySelector('[data-match-count]').textContent = shown;
        root.querySelector('[data-match-empty]').hidden = shown > 0;
      };
      root.querySelectorAll('[data-skill]:not([data-job])').forEach((chip) => chip.addEventListener('click', () => { if (chip.hasAttribute('aria-pressed')) chip.setAttribute('aria-pressed', String(chip.getAttribute('aria-pressed') !== 'true')); requestAnimationFrame(paint); }));
      root.addEventListener('change', paint);
      if (window.customElements) customElements.whenDefined('md-filter-chip').then(() => requestAnimationFrame(paint));
      paint();
    });

    document.querySelectorAll('[data-timeline]').forEach((root) => {
      const fill = root.querySelector('[data-timeline-fill]');
      if (!watchMotion) return;
      const update = () => {
        const box = root.getBoundingClientRect();
        fill.style.transform = `scaleY(${Math.min(1, Math.max(0, (innerHeight * 0.6 - box.top) / box.height))})`;
      };
      update();
      addEventListener('scroll', update, { passive: true });
    });

    document.querySelectorAll('[data-rings]').forEach((root) => {
      const rings = root.querySelectorAll('[data-ring]');
      if (!watchMotion) return;
      rings.forEach((ring) => { ring.style.strokeDashoffset = 326.73; });
      const observer = new IntersectionObserver((entries) => {
        if (!entries.some((entry) => entry.isIntersecting)) return;
        rings.forEach((ring) => { ring.style.strokeDashoffset = 326.73 * (1 - Number(ring.dataset.ring) / 100); });
        observer.disconnect();
      }, { threshold: 0.3 });
      observer.observe(root);
    });

    document.querySelectorAll('[data-chat]').forEach((root) => {
      const log = root.querySelector('[data-chat-log]');
      const add = (text, mine) => {
        const item = document.createElement('li');
        item.className = mine ? 'ml-auto max-w-[85%] rounded-3xl rounded-br-md bg-royal px-5 py-3 text-white' : 'max-w-[85%] rounded-3xl rounded-bl-md bg-paper px-5 py-3';
        item.textContent = text;
        log.append(item);
        log.scrollTop = log.scrollHeight;
      };
      root.querySelectorAll('[data-chat-question]').forEach((button) => button.addEventListener('click', () => {
        add(button.dataset.label || button.textContent.trim(), true);
        setTimeout(() => add(button.dataset.answer, false), reducedMotion ? 0 : 450);
      }));
    });

    document.querySelectorAll('[data-hover-list]').forEach((root) => {
      const image = root.querySelector('[data-hover-image]');
      root.querySelectorAll('[data-hover-row]').forEach((row) => {
        const show = () => { image.src = row.dataset.image; image.alt = row.dataset.alt; root.querySelectorAll('[data-hover-row]').forEach((other) => other.setAttribute('aria-current', String(other === row))); };
        row.addEventListener('mouseenter', show);
        row.addEventListener('focus', show);
        row.addEventListener('click', show);
      });
    });

    document.querySelectorAll('[data-job-board]').forEach((root) => {
      const list = root.querySelector('[data-board-list]');
      const items = [...list.children];
      const search = root.querySelector('[data-board-search]');
      const sort = root.querySelector('[data-board-sort]');
      const apply = () => {
        const query = String(search.value || '').trim().toLowerCase();
        const sorted = [...items].sort((a, b) => sort.value === 'salary' ? b.dataset.salary - a.dataset.salary : sort.value === 'hours' ? a.dataset.hours - b.dataset.hours : b.dataset.date - a.dataset.date);
        let shown = 0;
        sorted.forEach((item) => { const match = !query || item.textContent.toLowerCase().includes(query); item.hidden = !match; if (match) shown += 1; list.append(item); });
        root.querySelector('[data-board-count]').textContent = shown;
        root.querySelector('[data-board-empty]').hidden = shown > 0;
      };
      search.addEventListener('input', apply);
      sort.addEventListener('change', apply);
      const initial = new URLSearchParams(location.search).get('q');
      if (initial) search.value = initial;
      apply();
    });

    document.querySelectorAll('[data-calculator]').forEach((root) => {
      const money = (value) => `$${Math.round(value).toLocaleString('en-US')}`;
      const paint = () => {
        const hires = Number(root.querySelector('[data-hires]').value);
        const salary = Number(root.querySelector('[data-salary]').value);
        const fee = hires * salary * 0.08;
        const credit = hires * Math.min(salary * 0.25, 9600);
        root.querySelector('[data-hires-label]').textContent = hires;
        root.querySelector('[data-salary-label]').textContent = money(salary);
        root.querySelector('[data-fee]').textContent = money(fee);
        root.querySelector('[data-credit]').textContent = `−${money(credit)}`;
        root.querySelector('[data-net]').textContent = money(Math.max(0, fee - credit));
      };
      root.addEventListener('input', paint);
      paint();
    });

    document.querySelectorAll('[data-chat-form]').forEach((form) => {
      const log = form.querySelector('[data-chat-log]');
      const steps = [...form.querySelectorAll('[data-chat-step]')];
      const status = form.querySelector('[data-form-status]');
      let current = 0;
      const say = (text, mine) => {
        const bubble = document.createElement('li');
        bubble.className = mine ? 'ml-auto max-w-[85%] rounded-3xl rounded-br-md bg-royal px-5 py-3 text-white' : 'max-w-[85%] rounded-3xl rounded-bl-md bg-paper px-5 py-3';
        bubble.textContent = text;
        log.append(bubble);
        log.scrollTop = log.scrollHeight;
      };
      const show = (index) => steps.forEach((step, i) => { step.hidden = i !== index; });
      const field = (step) => step.querySelector('input, select, textarea, md-outlined-text-field, md-outlined-select');
      form.addEventListener('submit', (event) => {
        event.preventDefault();
        const input = field(steps[current]);
        if (!input.checkValidity() || !String(input.value || '').trim()) { status.textContent = form.dataset.error; input.focus(); return; }
        status.textContent = '';
        say(String(input.value), true);
        current += 1;
        if (current < steps.length) { say(steps[current].dataset.question, false); show(current); field(steps[current]).focus(); }
        else { say(form.dataset.success, false); show(-1); }
      });
      show(0);
    });

    document.querySelectorAll('[data-contact-form]').forEach((form) => {
      form.addEventListener('submit', (event) => {
        event.preventDefault();
        const status = form.querySelector('[data-form-status]');
        if (!form.checkValidity()) {
          status.textContent = form.dataset.error;
          form.querySelector(':invalid')?.focus();
          return;
        }
        status.textContent = form.dataset.success;
        form.reset();
      });
    });

    document.querySelectorAll('[data-current-year]').forEach((el) => { el.textContent = new Date().getFullYear(); });

    (() => {
      const items = document.querySelectorAll('[data-reveal]');
      if (!items.length || !watchMotion) return;
      document.documentElement.classList.add('reveal-ready');
      const observer = new IntersectionObserver((entries) => {
        entries.forEach((entry) => {
          if (!entry.isIntersecting) return;
          entry.target.classList.add('is-visible');
          observer.unobserve(entry.target);
        });
      }, { rootMargin: '0px 0px -10% 0px' });
      items.forEach((item) => observer.observe(item));
    })();
  </script>
</body>
</html>

From this template

Kindhire screenshot

Business

Kindhire

Unlimited access to all products

Unlock the entire library of premium templates and blocks. Renews automatically, cancel anytime.

$20 / 3 months or $60 / year
Get Unlimited Access