Free
Navbar
Emberlyn Navbar
A navbar block extracted from the Emberlyn template, available in Tailwind CSS and Bootstrap.
0
1
A navbar block extracted from the Emberlyn template, available in Tailwind CSS and Bootstrap.
<!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>Emberlyn Navbar | Tailwind CSS UI Block</title>
<meta name="description" content="A navbar block extracted from the Emberlyn template, available in Tailwind CSS and Bootstrap.">
<meta name="keywords" content="Emberlyn, Tailwind CSS template, HTML website template, portfolio template, wedding photographer website, photography portfolio, elopement photographer, photo studio template, editorial portfolio">
<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="Emberlyn | Tailwind CSS Portfolio Template">
<meta property="og:description" content="A quiet, editorial Tailwind CSS portfolio template for wedding photographers, with a black-and-white hero slider, a staggered journal and a date availability calendar.">
<meta property="og:image" content="">
<meta property="og:image:alt" content="Emberlyn template preview">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:url" content="">
<meta name="twitter:title" content="Emberlyn | Tailwind CSS Portfolio Template">
<meta name="twitter:description" content="A quiet, editorial Tailwind CSS portfolio template for wedding photographers, with a black-and-white hero slider, a staggered journal and a date availability calendar.">
<meta name="twitter:image" content="">
<meta name="twitter:image:alt" content="Emberlyn 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=Cormorant+Garamond:wght@400;500;600&family=Mrs+Saint+Delafield&family=Playfair+Display:wght@400;500&family=Poppins:wght@300;400;500&display=swap" rel="stylesheet">
<script>
tailwind.config = {
theme: {
extend: {
colors: { paper: '#f7f6f2', sand: '#efede8', sage: { DEFAULT: '#5f6c5f', deep: '#4b564b' }, ink: '#232323', mute: '#707070' },
fontFamily: { sans: ['Poppins', 'sans-serif'], serif: ['Playfair Display', 'serif'], caps: ['Cormorant Garamond', 'serif'], script: ['Mrs Saint Delafield', 'cursive'] }
}
}
}
</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; }
.slide { transition: opacity .7s ease, transform 6s ease; }
.slide:not(.is-active) { opacity: 0; }
.slide.is-active { transform: scale(1.04); }
.notch { clip-path: polygon(0 0, 100% 0, 100% calc(100% - 1.25rem), calc(50% + 1.25rem) calc(100% - 1.25rem), 50% 100%, calc(50% - 1.25rem) calc(100% - 1.25rem), 0 calc(100% - 1.25rem)); }
.reveal-ready [data-reveal] { opacity: 0; transform: translateY(24px); transition: opacity .7s ease, transform .7s 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; }
.slide { transition: none; }
.slide.is-active { transform: none; }
::view-transition-old(root), ::view-transition-new(root) { animation: none; }
}
</style>
</head>
<body class="bg-paper font-sans font-light text-ink antialiased">
<!-- preview canvas: shows overlay navbars on the original hero surface -->
<div class="block-preview-canvas bg-ink" style="position:relative;min-height:12rem">
<% active_page = "index" %>
<% left_nav = { "about" => "meet us", "story" => "our story", "services" => "services" } %>
<% right_nav = { "portfolio" => "portfolio", "blog" => "the journal", "contact" => "hire us" } %>
<!-- block:start navbar -->
<header class="absolute inset-x-0 top-0 z-40 text-white">
<nav class="mx-auto flex max-w-6xl items-center justify-between px-5 py-6 md:px-10 lg:grid lg:grid-cols-[1fr_auto_1fr] lg:gap-16" aria-label="Main">
<ul class="hidden items-center justify-end gap-12 text-[13px] lg:flex">
<% left_nav.each do |slug, label| %>
<% active = active_page == slug %>
<li><a href="<%= slug %>.html" <%= 'aria-current="page"'.html_safe if active %> class="border-b pb-1 transition <%= active ? 'border-white' : 'border-transparent text-white/80 hover:text-white' %>"><%= label %></a></li>
<% end %>
</ul>
<a href="index.html" class="grid h-16 w-16 place-items-center rounded-full border border-white/70 font-serif text-2xl italic tracking-tight" aria-label="Emberlyn home">EM</a>
<ul class="hidden items-center gap-12 text-[13px] lg:flex">
<% right_nav.each do |slug, label| %>
<% active = active_page == slug %>
<li><a href="<%= slug %>.html" <%= 'aria-current="page"'.html_safe if active %> class="border-b pb-1 transition <%= active ? 'border-white' : 'border-transparent text-white/80 hover:text-white' %>"><%= label %></a></li>
<% end %>
</ul>
<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-white/60 lg:hidden"><i class="fa-solid fa-bars" aria-hidden="true"></i></button>
</nav>
<div id="mobile-menu" class="hidden px-5 pb-6 lg:hidden">
<ul class="grid gap-1 bg-paper p-4 text-ink shadow-xl">
<% { "index" => "home" }.merge(left_nav).merge(right_nav).each do |slug, label| %>
<% active = active_page == slug %>
<li><a href="<%= slug %>.html" <%= 'aria-current="page"'.html_safe if active %> class="block px-3 py-2.5 font-caps text-xl <%= active ? 'bg-sand font-semibold' : 'hover:bg-sand' %>"><%= label %></a></li>
<% end %>
</ul>
</div>
</header>
<!-- block:end navbar -->
</div>
<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-slider]').forEach((slider) => {
const slides = [...slider.querySelectorAll('[data-slide]')];
const dots = [...slider.querySelectorAll('[data-slider-dot]')];
let current = 0;
let timer;
const show = (index) => {
current = (index + slides.length) % slides.length;
slides.forEach((slide, i) => {
slide.classList.toggle('is-active', i === current);
slide.toggleAttribute('aria-hidden', i !== current);
});
dots.forEach((dot, i) => dot.setAttribute('aria-pressed', String(i === current)));
};
const restart = () => {
clearInterval(timer);
if (!matchMedia('(prefers-reduced-motion: reduce)').matches) timer = setInterval(() => show(current + 1), 6000);
};
slider.querySelector('[data-slider-prev]')?.addEventListener('click', () => { show(current - 1); restart(); });
slider.querySelector('[data-slider-next]')?.addEventListener('click', () => { show(current + 1); restart(); });
dots.forEach((dot, i) => dot.addEventListener('click', () => { show(i); restart(); }));
restart();
});
document.querySelectorAll('[data-carousel]').forEach((carousel) => {
const slides = [...carousel.querySelectorAll('[data-carousel-slide]')];
const index = carousel.querySelector('[data-carousel-index]');
let current = 0;
const show = (next) => {
current = (next + slides.length) % slides.length;
slides.forEach((slide, i) => { slide.hidden = i !== current; });
if (index) index.textContent = current + 1;
};
carousel.querySelector('[data-carousel-prev]')?.addEventListener('click', () => show(current - 1));
carousel.querySelector('[data-carousel-next]')?.addEventListener('click', () => show(current + 1));
});
document.querySelectorAll('[data-hover-list]').forEach((list) => {
const preview = list.querySelector('[data-hover-preview]');
if (!preview || !matchMedia('(hover: hover)').matches) return;
list.querySelectorAll('[data-hover-item]').forEach((item) => {
item.addEventListener('mouseenter', () => { preview.src = item.dataset.image; preview.style.opacity = '1'; });
item.addEventListener('mouseleave', () => { preview.style.opacity = '0'; });
item.addEventListener('mousemove', (event) => { preview.style.transform = `translate(${event.clientX + 28}px, ${event.clientY - 90}px) rotate(-3deg)`; });
});
});
document.querySelectorAll('[data-availability]').forEach((root) => {
const months = [...root.querySelectorAll('[data-month]')];
const label = root.querySelector('[data-month-label]');
const prev = root.querySelector('[data-month-prev]');
const next = root.querySelector('[data-month-next]');
const summary = root.querySelector('[data-availability-summary]');
const note = root.querySelector('[data-availability-note]');
let current = 0;
const showMonth = (index) => {
current = Math.max(0, Math.min(months.length - 1, index));
months.forEach((month, i) => { month.hidden = i !== current; });
label.textContent = months[current].dataset.month;
prev.disabled = current === 0;
next.disabled = current === months.length - 1;
};
prev.addEventListener('click', () => showMonth(current - 1));
next.addEventListener('click', () => showMonth(current + 1));
root.addEventListener('click', (event) => {
const day = event.target.closest('[data-day]');
if (!day || day.disabled) return;
root.querySelectorAll('[data-day]').forEach((other) => other.setAttribute('aria-pressed', String(other === day)));
summary.textContent = `${day.dataset.day} is free`;
note.textContent = 'Lovely choice. Hold it now and I will keep it for you for seven days.';
});
showMonth(0);
});
document.querySelectorAll('[data-filter-group]').forEach((group) => {
const items = document.querySelectorAll(group.dataset.filterGroup);
group.querySelectorAll('[data-filter]').forEach((chip) => {
chip.addEventListener('click', () => {
group.querySelectorAll('[data-filter]').forEach((other) => other.setAttribute('aria-pressed', String(other === chip)));
items.forEach((item) => { item.hidden = chip.dataset.filter !== 'all' && item.dataset.role !== chip.dataset.filter; });
});
});
});
document.querySelectorAll('[data-lightbox]').forEach((dialog) => {
const image = dialog.querySelector('img');
const caption = dialog.querySelector('[data-lightbox-caption]');
document.querySelectorAll('[data-lightbox-open]').forEach((button) => {
button.addEventListener('click', () => {
image.src = button.dataset.full;
image.alt = button.querySelector('img')?.alt || '';
caption.textContent = button.dataset.caption;
dialog.showModal();
});
});
dialog.addEventListener('click', (event) => { if (event.target === dialog) dialog.close(); });
});
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]');
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>
Portfolio
Unlock the entire library of premium templates and blocks. Renews automatically, cancel anytime.