Kindhire Navbar Navbar 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 Navbar

Kindhire Navbar

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

0 1
Kindhire Navbar 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 Navbar | Tailwind CSS UI Block</title>
  <meta name="description" content="A navbar 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" } %>
<!-- block:start navbar -->
  <header class="relative z-40">
    <nav class="mx-auto grid max-w-7xl grid-cols-[1fr_auto_1fr] items-center gap-4 px-5 py-6 md:px-10 md:py-8" aria-label="Main">
      <button type="button" data-menu-toggle aria-controls="site-menu" aria-expanded="false" class="flex w-fit items-center gap-3 rounded-full py-2 pr-3 text-lg font-medium transition hover:text-royal"><i class="fa-solid fa-bars text-xl" aria-hidden="true"></i><span class="hidden sm:inline">Menu</span><span class="sr-only sm:hidden">Open menu</span></button>
      <a href="index.html" class="flex items-center gap-1.5 text-xl font-bold tracking-tight md:text-2xl" aria-label="Kindhire home">
        <svg class="h-8 w-9" viewBox="0 0 36 32" aria-hidden="true"><path d="M2 30 16 6l14 24Z" fill="#0b4ea2"/><path d="M14 30l9-15 11 15Z" fill="#0b4ea2" opacity=".75"/><path d="M8 4l1 2.4L11.5 7 9 7.6 8 10 7 7.6 4.5 7 7 6.4Z" fill="#f4846a"/></svg>
        <span><span class="text-royal">KIND</span><span class="text-coral">HIRE</span></span>
      </a>
      <a href="platform.html" class="justify-self-end rounded-full border-2 border-royal px-5 py-2.5 font-semibold text-royal transition hover:bg-royal hover:text-white md:px-8 md:py-3">Platform</a>
    </nav>
    <div id="site-menu" hidden class="fixed inset-0 z-50 overflow-y-auto bg-royal text-white">
      <div class="mx-auto flex min-h-full max-w-7xl flex-col px-5 py-6 md:px-10 md:py-8">
        <button type="button" data-menu-close class="flex w-fit items-center gap-3 rounded-full py-2 pr-3 text-lg font-medium hover:text-sun"><i class="fa-solid fa-xmark text-xl" aria-hidden="true"></i>Close</button>
        <div class="my-auto grid gap-12 py-12 lg:grid-cols-[1.4fr_1fr] lg:items-center">
          <ul class="grid gap-2">
            <% { "index" => "Home" }.merge(nav).each do |slug, label| %>
              <% active = active_page == slug %>
              <li><a href="<%= slug %>.html" <%= 'aria-current="page"'.html_safe if active %> class="font-serif text-5xl font-bold transition md:text-7xl <%= active ? 'text-sun underline decoration-coral decoration-4 underline-offset-8' : 'hover:text-sun' %>"><%= label %></a></li>
            <% end %>
          </ul>
          <div class="hidden rounded-[2rem] bg-white/10 p-8 lg:block">
            <p class="font-serif text-3xl font-bold">Need help signing up?</p>
            <p class="mt-3 text-lg text-white/80">Call us, text us or book a video call with sign language. We're here weekdays 8–20.</p>
            <a href="contact.html" class="mt-6 inline-flex rounded-full bg-sun px-6 py-3 font-semibold text-ink">Get in touch</a>
          </div>
        </div>
      </div>
    </div>
  </header>
  <!-- block:end navbar -->
<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