Tressa 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

Tressa Navbar

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

0 1
Tressa Navbar preview
tressa.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>Tressa Navbar | Tailwind CSS UI Block</title>
  <meta name="description" content="A navbar block extracted from the Tressa template, available in Tailwind CSS and Bootstrap.">
  <meta name="keywords" content="Tressa, Tailwind CSS template, HTML website template, hair salon template, hair studio, hairdresser website, balayage, keratin treatment, salon booking">
  <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="Tressa | Tailwind CSS Health & Fitness Template">
  <meta property="og:description" content="A clean, minimal Tailwind CSS hair salon template with numbered services, a work gallery, stylist profiles and service packages.">
  <meta property="og:image" content="">
  <meta property="og:image:alt" content="Tressa template preview">

  <meta name="twitter:card" content="summary_large_image">
  <meta name="twitter:url" content="">
  <meta name="twitter:title" content="Tressa | Tailwind CSS Health & Fitness Template">
  <meta name="twitter:description" content="A clean, minimal Tailwind CSS hair salon template with numbered services, a work gallery, stylist profiles and service packages.">
  <meta name="twitter:image" content="">
  <meta name="twitter:image:alt" content="Tressa 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=Inter:wght@300;400;500;600&display=swap" rel="stylesheet">
  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: { ink: '#111827', mist: '#f8f9fb', line: '#e5e7eb' },
          fontFamily: { sans: ['Inter', 'sans-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; }
    .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; }
      ::view-transition-old(root), ::view-transition-new(root) { animation: none; }
    }
  </style>
</head>
<body class="bg-white font-sans text-ink antialiased">
<% active_page = "index" %>
<!-- block:start navbar -->
  <header class="sticky top-0 z-40 border-b border-line/70 bg-white/95 backdrop-blur">
    <nav class="mx-auto flex max-w-6xl items-center justify-between gap-6 px-5 py-5 md:px-8" aria-label="Main">
      <div class="flex items-center gap-12">
        <a href="index.html" class="text-xl font-medium tracking-tight">Tressa Studio</a>
        <ul class="hidden items-center gap-10 text-[15px] text-ink/70 lg:flex">
          <% { "services" => "Services", "work" => "Work", "team" => "Team", "contact" => "Contact" }.each do |slug, label| %>
            <% active = active_page == slug %>
            <li><a href="<%= slug %>.html" <%= 'aria-current="page"'.html_safe if active %> class="<%= active ? 'font-medium text-ink underline underline-offset-8' : 'hover:text-ink' %>"><%= label %></a></li>
          <% end %>
        </ul>
      </div>
      <div class="flex items-center gap-3">
        <a href="contact.html" class="hidden border border-ink px-5 py-2.5 text-[15px] font-medium transition hover:bg-ink hover:text-white sm:inline-block">Book Appointment</a>
        <button type="button" data-menu-toggle aria-controls="mobile-menu" aria-expanded="false" aria-label="Open menu" class="grid h-11 w-11 place-items-center border border-line lg:hidden"><i class="fa-solid fa-bars" aria-hidden="true"></i></button>
      </div>
    </nav>
    <div id="mobile-menu" class="hidden border-t border-line px-5 pb-6 lg:hidden">
      <ul class="grid gap-1 pt-3 text-lg">
        <% { "index" => "Home", "services" => "Services", "work" => "Work", "team" => "Team", "pricing" => "Pricing", "contact" => "Contact" }.each do |slug, label| %>
          <% active = active_page == slug %>
          <li><a href="<%= slug %>.html" <%= 'aria-current="page"'.html_safe if active %> class="block px-2 py-2 <%= active ? 'bg-mist font-medium' : 'text-ink/70' %>"><%= label %></a></li>
        <% end %>
      </ul>
    </div>
  </header>
  <!-- block:end navbar -->
<script>
    document.querySelectorAll('[data-menu-toggle]').forEach((button) => {
      const menu = document.getElementById(button.getAttribute('aria-controls'));
      if (!menu) return;
      button.addEventListener('click', () => {
        const open = button.getAttribute('aria-expanded') === 'true';
        button.setAttribute('aria-expanded', String(!open));
        menu.classList.toggle('hidden', open);
      });
    });

    document.querySelectorAll('[data-filter-group]').forEach((group) => {
      const buttons = group.querySelectorAll('[data-filter]');
      buttons.forEach((button) => {
        button.addEventListener('click', () => {
          buttons.forEach((other) => {
            const active = other === button;
            other.setAttribute('aria-pressed', String(active));
            other.classList.toggle('bg-ink', active);
            other.classList.toggle('text-white', active);
          });
          document.querySelectorAll('[data-filter-item]').forEach((item) => {
            item.hidden = button.dataset.filter !== 'all' && item.dataset.category !== button.dataset.filter;
          });
        });
      });
    });

    document.querySelectorAll('[data-accordion]').forEach((accordion) => {
      const triggers = accordion.querySelectorAll('[data-accordion-trigger]');
      triggers.forEach((trigger) => {
        trigger.addEventListener('click', () => {
          const willOpen = trigger.getAttribute('aria-expanded') !== 'true';
          triggers.forEach((other) => {
            const open = other === trigger && willOpen;
            other.setAttribute('aria-expanded', String(open));
            document.getElementById(other.getAttribute('aria-controls')).classList.toggle('hidden', !open);
            other.querySelector('[data-accordion-icon]')?.classList.toggle('rotate-45', open);
          });
        });
      });
    });

    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 || 'Please complete the required fields.';
          return;
        }
        status.textContent = form.dataset.success || 'Thanks! We will be in touch soon.';
        form.reset();
      });
    });

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

    (() => {
      const counters = document.querySelectorAll('[data-count-to]');
      if (!counters.length || navigator.webdriver || matchMedia('(prefers-reduced-motion: reduce)').matches || !('IntersectionObserver' in window)) return;
      const observer = new IntersectionObserver((entries) => {
        entries.forEach(({ isIntersecting, target }) => {
          if (!isIntersecting) return;
          observer.unobserve(target);
          const end = Number(target.dataset.countTo);
          const suffix = target.dataset.countSuffix || '';
          const start = performance.now();
          const tick = (now) => {
            const progress = Math.min((now - start) / 700, 1);
            target.textContent = Math.round(end * progress) + suffix;
            if (progress < 1) requestAnimationFrame(tick);
          };
          requestAnimationFrame(tick);
        });
      }, { threshold: 0.6 });
      counters.forEach((counter) => observer.observe(counter));
    })();

    (() => {
      const items = document.querySelectorAll('[data-reveal]');
      const skip = navigator.webdriver || !('IntersectionObserver' in window) || matchMedia('(prefers-reduced-motion: reduce)').matches;
      if (!items.length || skip) 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

Tressa screenshot

Business

Tressa

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