<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Javascript &#8211; Veebilehed24</title>
	<atom:link href="https://veebilehed24.ee/en/c/blog/javascript/feed/" rel="self" type="application/rss+xml" />
	<link>https://veebilehed24.ee</link>
	<description></description>
	<lastBuildDate>Fri, 12 Jun 2026 05:11:35 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=7.0.4</generator>

<image>
	<url>https://veebilehed24.ee/wp-content/uploads/2026/03/cropped-ico-32x32.png</url>
	<title>Javascript &#8211; Veebilehed24</title>
	<link>https://veebilehed24.ee</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>30 JavaScript Drag and Drop Examples – Sortable Lists, Upload Zones &#038; Kanban UI</title>
		<link>https://veebilehed24.ee/en/blog/javascript/javascript-drag-and-drop-examples/</link>
					<comments>https://veebilehed24.ee/en/blog/javascript/javascript-drag-and-drop-examples/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Thu, 18 Jun 2026 05:11:15 +0000</pubDate>
				<category><![CDATA[Javascript]]></category>
		<guid isPermaLink="false">https://veebilehed24.ee/?p=1790</guid>

					<description><![CDATA[JavaScript drag and drop features are used in many practical websites and web apps. They can help users reorder tasks, move cards between Kanban columns, upload files, preview images, build forms, organize dashboards, assign team members, create sortable galleries, manage menus, and build more interactive user interfaces without relying on heavy frameworks. In this guide, [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">JavaScript drag and drop features are used in many practical websites and web apps. They can help users reorder tasks, move cards between Kanban columns, upload files, preview images, build forms, organize dashboards, assign team members, create sortable galleries, manage menus, and build more interactive user interfaces without relying on heavy frameworks.</p>



<p class="wp-block-paragraph">In this guide, you will find 30 JavaScript drag and drop examples for real website projects, including sortable lists, Kanban boards, file upload zones, image previews, gallery reordering, shopping cart interactions, two-list selectors, project planners, form builders, page section builders, dashboard layouts, menu builders, drag-to-delete actions, quiz matching games, mobile-friendly touch drag, and accessible keyboard-supported drag and drop UI patterns.</p>



<p class="wp-block-paragraph">This post focuses on practical drag and drop JavaScript logic, including the HTML Drag and Drop API, pointer-based dragging, sortable UI patterns, drop zones, drag handles, column movement, file validation, image previews, item reordering, visual drop feedback, state updates, mobile-friendly interactions, and copy-paste-ready HTML, CSS, and JavaScript examples. For related JavaScript UI features, you can also explore our <a href="https://veebilehed24.ee/en/blog/javascript/javascript-localstorage-examples/">JavaScript localStorage examples</a>, <a href="https://veebilehed24.ee/en/blog/javascript/javascript-form-validation-examples/">JavaScript form validation examples</a>, <a href="https://veebilehed24.ee/en/blog/javascript/javascript-fetch-api-examples/">JavaScript Fetch API examples</a>, and <a href="https://veebilehed24.ee/en/blog/javascript/javascript-calculator-examples/">JavaScript calculator examples</a>.</p>



<div class="vb24-js-drag-jump-box">
  <a class="vb24-js-drag-jump-button" href="#javascript-drag-and-drop-examples">View All 30 JavaScript Drag and Drop Examples</a>
</div>

<style>
.vb24-js-drag-jump-box {
  margin: 28px 0 36px;
}

.vb24-js-drag-jump-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 14px 22px;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #7c3aed 52%, #f97316);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 850;
  line-height: 1.2;
  text-decoration: none !important;
  box-shadow: 0 16px 38px rgba(124, 58, 237, 0.26);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-js-drag-jump-button::after {
  content: "↓";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.18);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  line-height: 1;
}

.vb24-js-drag-jump-button:hover {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transform: translateY(-2px);
  filter: saturate(1.08);
  box-shadow: 0 20px 46px rgba(124, 58, 237, 0.34);
}

@media (max-width: 640px) {
  .vb24-js-drag-jump-button {
    width: 100%;
    padding: 14px 16px;
    font-size: 14px;
  }
}
</style>



<div class="toc-affiliate-wrap vb24-js-drag-toc-wrap">

  <div class="toc-left vb24-js-drag-toc-left">

    <div class="vb24-js-drag-toc-kicker">On this page</div>

    <h2>Table of Contents</h2>

    <ul class="vl24-toc vb24-js-drag-toc">
      <li><a href="#what-is-javascript-drag-and-drop">What Is JavaScript Drag and Drop?</a></li>
      <li><a href="#why-drag-and-drop-features-matter">Why Drag and Drop Features Matter</a></li>
      <li><a href="#javascript-drag-and-drop-use-cases">JavaScript Drag and Drop Use Cases</a></li>
      <li><a href="#what-should-a-good-drag-and-drop-component-include">What Should a Good Drag and Drop Component Include?</a></li>
      <li><a class="vb24-featured-toc-link" href="#javascript-drag-and-drop-examples">30 JavaScript Drag and Drop Examples</a></li>
      <li><a href="#javascript-drag-and-drop-best-practices">JavaScript Drag and Drop Best Practices</a></li>
      <li><a href="#responsive-drag-and-drop-ui-tips">Responsive Drag and Drop UI Tips</a></li>
      <li><a href="#common-javascript-drag-and-drop-mistakes">Common JavaScript Drag and Drop Mistakes</a></li>
      <li><a href="#javascript-drag-and-drop-faq">JavaScript Drag and Drop FAQ</a></li>
      <li><a href="#javascript-drag-and-drop-conclusion">Conclusion</a></li>
      <li><a href="#related-javascript-and-css-guides">Related JavaScript and CSS Guides</a></li>
    </ul>

  </div>

  <div class="toc-right vb24-js-drag-toc-right">

    <a class="vb24-entityschema-ad-card" href="https://veebilehed24.ee/en/shop/entityschema-pro/" target="_blank" rel="sponsored noopener">
      <span class="vb24-entityschema-ad-badge">WordPress SEO Plugin</span>

      <div class="vb24-entityschema-ad-image">
        <img decoding="async" src="https://veebilehed24.ee/wp-content/uploads/2026/03/entityschema-cover-600x400.webp" width="300" height="200" alt="EntitySchema Pro WordPress structured data and entity SEO plugin" loading="lazy">
      </div>

      <div class="vb24-entityschema-ad-content">
        <h3>EntitySchema Pro</h3>
        <p>Build a real entity-based structured data system for WordPress, modern SEO, and AI-readable websites.</p>

        <div class="vb24-entityschema-ad-price">
          <div class="vb24-entityschema-ad-price-left">
            <span class="vb24-entityschema-ad-price-label">Sale price</span>
            <span class="vb24-entityschema-ad-old-price">89€</span>
          </div>

          <strong class="vb24-entityschema-ad-sale-price">29€</strong>

          <span class="vb24-entityschema-ad-save">Save 60€</span>
        </div>

        <span class="vb24-entityschema-ad-button">View Plugin</span>
      </div>
    </a>

  </div>

</div>

<style>
.vb24-js-drag-toc-wrap {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 26px;
  align-items: stretch;
  margin: 34px 0 44px;
}

.vb24-js-drag-toc-left,
.vb24-js-drag-toc-right {
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 28px;
  background: linear-gradient(135deg, #0f172a 0%, #312e81 48%, #7c2d12 100%);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.18);
}

.vb24-js-drag-toc-left {
  padding: 28px 30px 30px;
}

.vb24-js-drag-toc-kicker {
  margin-bottom: 10px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 13px;
  font-weight: 850;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb24-js-drag-toc-left h2 {
  margin: 0 0 22px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px !important;
  line-height: 1.15 !important;
  font-weight: 850 !important;
}

.vb24-js-drag-toc {
  display: grid !important;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px !important;
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb24-js-drag-toc li {
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb24-js-drag-toc li::before {
  display: none !important;
  content: none !important;
}

.vb24-js-drag-toc a {
  display: flex;
  align-items: center;
  min-height: 54px;
  padding: 13px 15px;
  border: 1px solid rgba(148, 163, 184, 0.18);
  border-radius: 15px;
  background: rgba(255, 255, 255, 0.065);
  color: #f3f4f6 !important;
  -webkit-text-fill-color: #f3f4f6 !important;
  font-size: 15px;
  font-weight: 750;
  line-height: 1.35;
  text-decoration: none !important;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.05);
  transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease;
}

.vb24-js-drag-toc a:hover {
  transform: translateY(-2px);
  border-color: rgba(249, 115, 22, 0.70);
  background: rgba(249, 115, 22, 0.16);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb24-js-drag-toc .vb24-featured-toc-link {
  border-color: rgba(251, 146, 60, 0.78);
  background: linear-gradient(135deg, rgba(37, 99, 235, 0.30), rgba(124, 58, 237, 0.30), rgba(249, 115, 22, 0.26));
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb24-js-drag-toc-right {
  display: flex;
  align-items: stretch;
  justify-content: center;
  padding: 16px;
  overflow: hidden;
}

.vb24-entityschema-ad-card,
.vb24-entityschema-ad-card * {
  box-sizing: border-box;
}

.vb24-entityschema-ad-card {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  min-height: 100%;
  padding: 12px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(34, 211, 238, 0.28), transparent 34%),
    radial-gradient(circle at 86% 14%, rgba(236, 72, 153, 0.24), transparent 36%),
    linear-gradient(135deg, #111827 0%, #312e81 52%, #701a75 100%) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  overflow: hidden;
  box-shadow: 0 20px 56px rgba(2, 6, 23, 0.32);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-entityschema-ad-card:hover {
  transform: translateY(-3px);
  filter: saturate(1.08);
  box-shadow: 0 26px 70px rgba(2, 6, 23, 0.42);
}

.vb24-entityschema-ad-badge {
  position: absolute;
  z-index: 3;
  top: 18px;
  left: 18px;
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.70);
  border: 1px solid rgba(255,255,255,0.22);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb24-entityschema-ad-image {
  overflow: hidden;
  border-radius: 17px;
  border: 1px solid rgba(255,255,255,0.16);
  background: rgba(255,255,255,0.08);
}

.vb24-entityschema-ad-image img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 17px;
}

.vb24-entityschema-ad-content {
  padding: 15px 8px 4px;
}

.vb24-entityschema-ad-content h3 {
  margin: 0 0 8px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 23px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb24-entityschema-ad-content p {
  margin: 0 0 14px !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 13px;
  line-height: 1.5;
  font-weight: 650;
}

.vb24-entityschema-ad-price {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin: 0 0 12px;
  padding: 11px 12px;
  border-radius: 16px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.16);
}

.vb24-entityschema-ad-price-left {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.vb24-entityschema-ad-price-label {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 11px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb24-entityschema-ad-old-price {
  color: rgba(255,255,255,0.62) !important;
  -webkit-text-fill-color: rgba(255,255,255,0.62) !important;
  font-size: 15px;
  line-height: 1;
  font-weight: 850;
  text-decoration: line-through;
  text-decoration-thickness: 2px;
  text-decoration-color: rgba(248, 113, 113, 0.95);
}

.vb24-entityschema-ad-sale-price {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 31px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb24-entityschema-ad-save {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 28px;
  padding: 6px 9px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.18);
  border: 1px solid rgba(74, 222, 128, 0.34);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 11px;
  font-weight: 950;
  white-space: nowrap;
}

.vb24-entityschema-ad-button {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 43px;
  padding: 12px 14px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22d3ee, #2563eb 55%, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
  box-shadow: 0 14px 34px rgba(37, 99, 235, 0.30);
}

@media (max-width: 900px) {
  .vb24-js-drag-toc-wrap {
    grid-template-columns: 1fr;
  }

  .vb24-js-drag-toc-right {
    justify-content: flex-start;
    max-width: 360px;
  }
}

@media (max-width: 640px) {
  .vb24-js-drag-toc-left {
    padding: 22px 18px;
    border-radius: 22px;
  }

  .vb24-js-drag-toc-left h2 {
    font-size: 26px !important;
  }

  .vb24-js-drag-toc {
    grid-template-columns: 1fr;
  }

  .vb24-js-drag-toc a {
    min-height: 48px;
    font-size: 14px;
  }

  .vb24-js-drag-toc-right {
    max-width: 100%;
    border-radius: 22px;
  }
}
</style>



<h2 class="wp-block-heading" id="what-is-javascript-drag-and-drop">What Is JavaScript Drag and Drop?</h2>



<p class="wp-block-paragraph">JavaScript drag and drop is a browser-based interaction pattern that lets users click, hold, move, and release items inside a web page. It can be used to reorder list items, move cards between columns, upload files into a drop zone, organize images, assign tasks, build page sections, arrange dashboard widgets, and create more natural user interfaces.</p>



<p class="wp-block-paragraph">The most common approach is the built-in HTML Drag and Drop API, which uses events such as <code>dragstart</code>, <code>dragover</code>, <code>drop</code>, and <code>dragend</code>. For more custom interactions, JavaScript can also use pointer, mouse, or touch events to create drag behavior that works better on mobile screens and complex UI layouts.</p>



<p class="wp-block-paragraph">Drag and drop is useful because it turns static pages into interactive tools. Instead of clicking many buttons or opening extra settings panels, users can move items directly where they want them. A task card can be moved to “Done”, an image can be reordered in a gallery, a file can be dropped into an upload box, and a menu item can be arranged visually.</p>



<h2 class="wp-block-heading" id="why-drag-and-drop-features-matter">Why Drag and Drop Features Matter</h2>



<p class="wp-block-paragraph">Drag and drop features matter because they make complex actions feel simple. Many web apps need users to organize, sort, assign, upload, compare, or arrange information. A good drag and drop interface can reduce clicks, make the workflow faster, and help users understand changes visually.</p>



<ul class="wp-block-list">
  <li><strong>They improve usability</strong> by letting users move tasks, cards, files, images, and sections directly inside the interface.</li>
  <li><strong>They make admin tools faster</strong> because users can reorder content, menus, FAQs, pricing features, widgets, and product images visually.</li>
  <li><strong>They support ecommerce and SaaS UI</strong> through sortable galleries, product comparison builders, cart interactions, onboarding steps, and dashboard layouts.</li>
  <li><strong>They create better file upload experiences</strong> by allowing users to drop files into a clear upload zone and see previews, validation, or progress feedback.</li>
  <li><strong>They teach practical JavaScript logic</strong> because drag and drop examples use events, DOM updates, state changes, conditions, arrays, visual feedback, and reusable functions.</li>
</ul>



<p class="wp-block-paragraph">Drag and drop should still be designed carefully. Users need clear visual feedback, obvious drop zones, mobile-friendly controls, accessible alternatives, and predictable behavior. A sortable list should not feel jumpy, a file upload zone should validate files clearly, and a Kanban board should show exactly where a card will land before the user releases it.</p>



<h2 class="wp-block-heading" id="javascript-drag-and-drop-use-cases">JavaScript Drag and Drop Use Cases</h2>



<p class="wp-block-paragraph">There are many practical JavaScript drag and drop use cases for websites, ecommerce stores, admin dashboards, project management tools, booking systems, learning apps, portfolio pages, file managers, and content management interfaces.</p>



<p class="wp-block-paragraph">A simple drag and drop feature may only reorder a small list. A more advanced feature may move cards between Kanban columns, validate dropped files, generate image previews, update counters, save layout order, assign users to projects, create a form builder, or support both pointer dragging and keyboard controls.</p>



<ul class="wp-block-list">
  <li><strong>Sortable lists</strong> help users reorder tasks, priorities, menu links, FAQ items, roadmap steps, and dashboard sections.</li>
  <li><strong>Kanban boards</strong> allow users to move cards between workflow columns such as To Do, In Progress, Review, and Done.</li>
  <li><strong>File upload zones</strong> let users drag files into an upload area, validate file types, and show selected file names.</li>
  <li><strong>Image preview uploaders</strong> display thumbnails after users drop images into the page.</li>
  <li><strong>Gallery reorder tools</strong> help ecommerce stores, portfolios, and blogs change image order visually.</li>
  <li><strong>Shopping cart interactions</strong> let users drag products into a cart area and update totals in the interface.</li>
  <li><strong>Form builders</strong> allow users to drag field types into a form preview and build custom layouts.</li>
  <li><strong>Dashboard builders</strong> let users move widgets, cards, reports, charts, and notes into the layout they prefer.</li>
  <li><strong>Menu builders</strong> support nested navigation structures and admin-style page organization.</li>
  <li><strong>Accessible drag patterns</strong> add keyboard controls, buttons, status messages, and non-drag alternatives for better usability.</li>
</ul>



<p class="wp-block-paragraph">This guide focuses on JavaScript drag and drop examples, so every demo will include visible JavaScript, HTML, and CSS code. The examples are designed to be copy-paste friendly, practical for real websites, and different in layout, drag behavior, drop logic, interface style, UI feedback, responsive design, and real-world use case.</p>



<h2 class="wp-block-heading" id="what-should-a-good-drag-and-drop-component-include">What Should a Good Drag and Drop Component Include?</h2>



<p class="wp-block-paragraph">A good drag and drop component should feel obvious, stable, responsive, and useful. Users should know what can be dragged, where it can be dropped, what changed after the drop action, and how to complete the same task if dragging is difficult on their device.</p>



<div class="vb24-js-drag-checklist">
  <div class="vb24-js-drag-check-item">
    <h3>Clear draggable items</h3>
    <p>Cards, files, list rows, images, widgets, or menu items should look interactive before the user starts dragging.</p>
  </div>

  <div class="vb24-js-drag-check-item">
    <h3>Visible drop zones</h3>
    <p>Drop areas should be easy to recognize and should react visually when an item is dragged over them.</p>
  </div>

  <div class="vb24-js-drag-check-item">
    <h3>Reliable state updates</h3>
    <p>The interface should update order, counters, totals, selected items, previews, or status labels after every drop.</p>
  </div>

  <div class="vb24-js-drag-check-item">
    <h3>Responsive and accessible UI</h3>
    <p>Drag interactions should work well on desktop and include mobile or keyboard-friendly alternatives where needed.</p>
  </div>
</div>

<style>
.vb24-js-drag-checklist {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 30px;
}

.vb24-js-drag-check-item {
  padding: 20px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 22px;
  background:
    radial-gradient(circle at 18% 10%, rgba(124, 58, 237, 0.10), transparent 32%),
    linear-gradient(135deg, #ffffff, #fff7ed) !important;
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb24-js-drag-check-item h3 {
  margin: 0 0 10px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 850;
}

.vb24-js-drag-check-item p {
  margin: 0;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb24-js-drag-checklist {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-js-drag-checklist {
    grid-template-columns: 1fr;
  }

  .vb24-js-drag-check-item {
    padding: 18px;
    border-radius: 20px;
  }
}
</style>



<p class="wp-block-paragraph">Before building a JavaScript drag and drop feature, decide what the user is moving and why. Is the goal to sort tasks, upload files, reorder images, move cards between columns, assign people to projects, build a form, organize tags, compare products, or create a mobile-friendly touch interaction? A clear use case makes the code easier to write and the interface easier to understand.</p>



<ul class="wp-block-list">
  <li><strong>Make draggable elements obvious</strong> with handles, cursor styles, icons, labels, or hover states.</li>
  <li><strong>Show active drag feedback</strong> so users can see which item is currently being moved.</li>
  <li><strong>Highlight valid drop zones</strong> when a dragged item is over a column, list, upload area, or target box.</li>
  <li><strong>Prevent accidental drops</strong> by validating file types, target zones, item categories, or duplicate items.</li>
  <li><strong>Update the UI immediately</strong> after a drop action, including order labels, counters, totals, previews, and empty states.</li>
  <li><strong>Keep mobile users in mind</strong> because the native HTML Drag and Drop API is not always ideal for touch screens.</li>
  <li><strong>Add accessible alternatives</strong> such as move up/down buttons, keyboard controls, or clear status messages.</li>
  <li><strong>Use unique class names and scoped JavaScript</strong> so multiple examples can work on the same WordPress page.</li>
  <li><strong>Make long lists scrollable</strong> when drag and drop demos contain many cards, files, or dashboard widgets.</li>
  <li><strong>Do not overcomplicate simple features</strong> when a clean sortable list or file drop zone is enough.</li>
</ul>



<p class="wp-block-paragraph">You can combine JavaScript drag and drop features with many other website patterns. Sort order can be saved with <a href="https://veebilehed24.ee/en/blog/javascript/javascript-localstorage-examples/">JavaScript localStorage</a>, dropped files can be validated with <a href="https://veebilehed24.ee/en/blog/javascript/javascript-form-validation-examples/">JavaScript form validation</a>, product cards can connect with <a href="https://veebilehed24.ee/en/blog/javascript/javascript-calculator-examples/">JavaScript calculator examples</a> for totals and pricing, and advanced drag interfaces can later send updated data with <a href="https://veebilehed24.ee/en/blog/javascript/javascript-fetch-api-examples/">JavaScript Fetch API requests</a>.</p>



<h2 class="wp-block-heading" id="javascript-drag-and-drop-examples">30 JavaScript Drag and Drop Examples</h2>



<p class="wp-block-paragraph">Now let’s look at 30 JavaScript drag and drop examples for real website projects. Each example uses a different drag behavior, layout style, UI purpose, drop rule, feedback pattern, state update, validation method, mobile approach, or accessibility improvement, so you can build practical drag and drop interfaces with visible JavaScript, HTML, and CSS code.</p>



<h2 class="wp-block-heading">1. Sortable Task List with Drag Handles</h2>



<p class="wp-block-paragraph"><strong>A sortable task list with drag handles</strong> is a practical JavaScript drag and drop example for dashboards, admin panels, task managers, priority lists, and workflow tools. Users can grab the handle, drag a task to a new position, and the priority numbers update automatically.</p>



<p class="wp-block-paragraph">This example uses native HTML drag and drop, but the draggable element is the handle itself. That makes the interaction more reliable because users start dragging directly from the handle, while JavaScript moves the full task card in the list.</p>



<ul class="wp-block-list">
<li>Working drag handle</li>
<li>Native JavaScript drag and drop</li>
<li>Sortable task cards</li>
<li>Automatic priority numbers</li>
<li>No external library needed</li>
</ul>



<div class="vb-drag-sort-demo">
  <div class="vb-drag-sort-wrap" data-vb-drag-sort>
    <div class="vb-drag-sort-intro">
      <span>Example 01</span>
      <h3>Sortable Task List</h3>
      <p>Drag the handle on the left side of each task. Drop the task above or below another task to change the order.</p>
    </div>

    <div class="vb-drag-sort-grid">
      <div class="vb-drag-sort-list" data-vb-drag-sort-list>
        <div class="vb-drag-sort-item" data-vb-drag-sort-item>
          <span class="vb-drag-sort-handle" draggable="true" data-vb-drag-sort-handle>⋮⋮</span>
          <strong class="vb-drag-sort-number" data-vb-drag-sort-number>1</strong>
          <div class="vb-drag-sort-text">
            <h4>Review landing page copy</h4>
            <p>Marketing task</p>
          </div>
          <em>High</em>
        </div>

        <div class="vb-drag-sort-item" data-vb-drag-sort-item>
          <span class="vb-drag-sort-handle" draggable="true" data-vb-drag-sort-handle>⋮⋮</span>
          <strong class="vb-drag-sort-number" data-vb-drag-sort-number>2</strong>
          <div class="vb-drag-sort-text">
            <h4>Export product images</h4>
            <p>Design task</p>
          </div>
          <em>Medium</em>
        </div>

        <div class="vb-drag-sort-item" data-vb-drag-sort-item>
          <span class="vb-drag-sort-handle" draggable="true" data-vb-drag-sort-handle>⋮⋮</span>
          <strong class="vb-drag-sort-number" data-vb-drag-sort-number>3</strong>
          <div class="vb-drag-sort-text">
            <h4>Fix checkout validation</h4>
            <p>Development task</p>
          </div>
          <em>High</em>
        </div>

        <div class="vb-drag-sort-item" data-vb-drag-sort-item>
          <span class="vb-drag-sort-handle" draggable="true" data-vb-drag-sort-handle>⋮⋮</span>
          <strong class="vb-drag-sort-number" data-vb-drag-sort-number>4</strong>
          <div class="vb-drag-sort-text">
            <h4>Write support FAQ answers</h4>
            <p>Content task</p>
          </div>
          <em>Low</em>
        </div>
      </div>

      <div class="vb-drag-sort-status">
        <span>Current order</span>
        <strong data-vb-drag-sort-output>1 → 2 → 3 → 4</strong>
        <p>The full card moves when the handle is dragged. Numbers update after every drop.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-drag-sort-demo,
.vb-drag-sort-demo * {
  box-sizing: border-box;
}

.vb-drag-sort-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 18%, rgba(37, 99, 235, 0.18), transparent 34%),
    radial-gradient(circle at 90% 12%, rgba(249, 115, 22, 0.18), transparent 35%),
    linear-gradient(135deg, #eff6ff 0%, #fff7ed 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-drag-sort-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-drag-sort-intro {
  max-width: 760px;
  margin-bottom: 22px;
}

.vb-drag-sort-intro span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-drag-sort-intro h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-drag-sort-intro p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-drag-sort-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(260px, 0.8fr);
  gap: 18px;
}

.vb-drag-sort-list {
  display: grid;
  gap: 14px;
  padding: 18px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.25);
  box-shadow: 0 20px 58px rgba(15, 23, 42, 0.10);
}

.vb-drag-sort-item {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto;
  gap: 14px;
  align-items: center;
  padding: 16px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.28);
  box-shadow: 0 12px 30px rgba(15, 23, 42, 0.07);
  transition: opacity 0.2s ease, transform 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.vb-drag-sort-item.is-dragging {
  opacity: 0.42;
  transform: scale(0.98);
  border-color: rgba(37, 99, 235, 0.70);
  background: #eff6ff;
}

.vb-drag-sort-item.is-over {
  border-color: rgba(249, 115, 22, 0.85);
  background: #fff7ed;
}

.vb-drag-sort-handle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 46px;
  border-radius: 15px;
  background: #eef2ff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 20px;
  font-weight: 950;
  cursor: grab;
  user-select: none;
}

.vb-drag-sort-handle:active {
  cursor: grabbing;
}

.vb-drag-sort-number {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-drag-sort-text h4 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px !important;
  line-height: 1.25 !important;
  font-weight: 900 !important;
}

.vb-drag-sort-text p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 700;
}

.vb-drag-sort-item em {
  min-width: 72px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #fff7ed;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 12px;
  font-style: normal;
  font-weight: 900;
  text-align: center;
}

.vb-drag-sort-status {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 26px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 10% 15%, rgba(34, 211, 238, 0.22), transparent 34%),
    linear-gradient(135deg, #0f172a, #312e81) !important;
  box-shadow: 0 22px 70px rgba(15, 23, 42, 0.22);
}

.vb-drag-sort-status span {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-drag-sort-status strong {
  margin: 12px 0;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4vw, 48px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-drag-sort-status p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

@media (max-width: 820px) {
  .vb-drag-sort-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-drag-sort-item {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .vb-drag-sort-number,
  .vb-drag-sort-item em {
    display: none;
  }
}
</style>

<script>
(function () {
  function initSortableTaskList() {
    const root = document.querySelector("[data-vb-drag-sort]");
    if (!root) return;

    const list = root.querySelector("[data-vb-drag-sort-list]");
    const output = root.querySelector("[data-vb-drag-sort-output]");
    let draggedItem = null;

    function updateNumbers() {
      const items = Array.from(list.querySelectorAll("[data-vb-drag-sort-item]"));

      items.forEach(function (item, index) {
        const number = item.querySelector("[data-vb-drag-sort-number]");
        if (number) {
          number.textContent = index + 1;
        }
      });

      output.textContent = items.map(function (_, index) {
        return index + 1;
      }).join(" → ");
    }

    function clearOverStates() {
      list.querySelectorAll(".is-over").forEach(function (item) {
        item.classList.remove("is-over");
      });
    }

    list.addEventListener("dragstart", function (event) {
      const handle = event.target.closest("[data-vb-drag-sort-handle]");
      if (!handle) return;

      const item = handle.closest("[data-vb-drag-sort-item]");
      if (!item) return;

      draggedItem = item;
      item.classList.add("is-dragging");

      event.dataTransfer.effectAllowed = "move";
      event.dataTransfer.setData("text/plain", item.textContent.trim());
    });

    list.addEventListener("dragover", function (event) {
      event.preventDefault();

      if (!draggedItem) return;

      const targetItem = event.target.closest("[data-vb-drag-sort-item]");

      if (!targetItem || targetItem === draggedItem) return;

      const targetBox = targetItem.getBoundingClientRect();
      const shouldPlaceAfter = event.clientY > targetBox.top + targetBox.height / 2;

      clearOverStates();
      targetItem.classList.add("is-over");

      if (shouldPlaceAfter) {
        targetItem.insertAdjacentElement("afterend", draggedItem);
      } else {
        targetItem.insertAdjacentElement("beforebegin", draggedItem);
      }

      updateNumbers();
    });

    list.addEventListener("drop", function (event) {
      event.preventDefault();
      clearOverStates();

      if (draggedItem) {
        draggedItem.classList.remove("is-dragging");
      }

      draggedItem = null;
      updateNumbers();
    });

    list.addEventListener("dragend", function () {
      clearOverStates();

      if (draggedItem) {
        draggedItem.classList.remove("is-dragging");
      }

      draggedItem = null;
      updateNumbers();
    });

    updateNumbers();
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initSortableTaskList);
  } else {
    initSortableTaskList();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initSortableTaskList() {
    const root = document.querySelector("[data-vb-drag-sort]");
    if (!root) return;

    const list = root.querySelector("[data-vb-drag-sort-list]");
    const output = root.querySelector("[data-vb-drag-sort-output]");
    let draggedItem = null;

    function updateNumbers() {
      const items = Array.from(list.querySelectorAll("[data-vb-drag-sort-item]"));

      items.forEach(function (item, index) {
        const number = item.querySelector("[data-vb-drag-sort-number]");
        if (number) {
          number.textContent = index + 1;
        }
      });

      output.textContent = items.map(function (_, index) {
        return index + 1;
      }).join(" → ");
    }

    function clearOverStates() {
      list.querySelectorAll(".is-over").forEach(function (item) {
        item.classList.remove("is-over");
      });
    }

    list.addEventListener("dragstart", function (event) {
      const handle = event.target.closest("[data-vb-drag-sort-handle]");
      if (!handle) return;

      const item = handle.closest("[data-vb-drag-sort-item]");
      if (!item) return;

      draggedItem = item;
      item.classList.add("is-dragging");

      event.dataTransfer.effectAllowed = "move";
      event.dataTransfer.setData("text/plain", item.textContent.trim());
    });

    list.addEventListener("dragover", function (event) {
      event.preventDefault();

      if (!draggedItem) return;

      const targetItem = event.target.closest("[data-vb-drag-sort-item]");

      if (!targetItem || targetItem === draggedItem) return;

      const targetBox = targetItem.getBoundingClientRect();
      const shouldPlaceAfter = event.clientY &gt; targetBox.top + targetBox.height / 2;

      clearOverStates();
      targetItem.classList.add("is-over");

      if (shouldPlaceAfter) {
        targetItem.insertAdjacentElement("afterend", draggedItem);
      } else {
        targetItem.insertAdjacentElement("beforebegin", draggedItem);
      }

      updateNumbers();
    });

    list.addEventListener("drop", function (event) {
      event.preventDefault();
      clearOverStates();

      if (draggedItem) {
        draggedItem.classList.remove("is-dragging");
      }

      draggedItem = null;
      updateNumbers();
    });

    list.addEventListener("dragend", function () {
      clearOverStates();

      if (draggedItem) {
        draggedItem.classList.remove("is-dragging");
      }

      draggedItem = null;
      updateNumbers();
    });

    updateNumbers();
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initSortableTaskList);
  } else {
    initSortableTaskList();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-drag-sort-demo"&gt;
  &lt;div class="vb-drag-sort-wrap" data-vb-drag-sort&gt;
    &lt;div class="vb-drag-sort-intro"&gt;
      &lt;span&gt;Example 01&lt;/span&gt;
      &lt;h3&gt;Sortable Task List&lt;/h3&gt;
      &lt;p&gt;Drag the handle on the left side of each task. Drop the task above or below another task to change the order.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-drag-sort-grid"&gt;
      &lt;div class="vb-drag-sort-list" data-vb-drag-sort-list&gt;
        &lt;div class="vb-drag-sort-item" data-vb-drag-sort-item&gt;
          &lt;span class="vb-drag-sort-handle" draggable="true" data-vb-drag-sort-handle&gt;⋮⋮&lt;/span&gt;
          &lt;strong class="vb-drag-sort-number" data-vb-drag-sort-number&gt;1&lt;/strong&gt;
          &lt;div class="vb-drag-sort-text"&gt;
            &lt;h4&gt;Review landing page copy&lt;/h4&gt;
            &lt;p&gt;Marketing task&lt;/p&gt;
          &lt;/div&gt;
          &lt;em&gt;High&lt;/em&gt;
        &lt;/div&gt;

        &lt;div class="vb-drag-sort-item" data-vb-drag-sort-item&gt;
          &lt;span class="vb-drag-sort-handle" draggable="true" data-vb-drag-sort-handle&gt;⋮⋮&lt;/span&gt;
          &lt;strong class="vb-drag-sort-number" data-vb-drag-sort-number&gt;2&lt;/strong&gt;
          &lt;div class="vb-drag-sort-text"&gt;
            &lt;h4&gt;Export product images&lt;/h4&gt;
            &lt;p&gt;Design task&lt;/p&gt;
          &lt;/div&gt;
          &lt;em&gt;Medium&lt;/em&gt;
        &lt;/div&gt;

        &lt;div class="vb-drag-sort-item" data-vb-drag-sort-item&gt;
          &lt;span class="vb-drag-sort-handle" draggable="true" data-vb-drag-sort-handle&gt;⋮⋮&lt;/span&gt;
          &lt;strong class="vb-drag-sort-number" data-vb-drag-sort-number&gt;3&lt;/strong&gt;
          &lt;div class="vb-drag-sort-text"&gt;
            &lt;h4&gt;Fix checkout validation&lt;/h4&gt;
            &lt;p&gt;Development task&lt;/p&gt;
          &lt;/div&gt;
          &lt;em&gt;High&lt;/em&gt;
        &lt;/div&gt;

        &lt;div class="vb-drag-sort-item" data-vb-drag-sort-item&gt;
          &lt;span class="vb-drag-sort-handle" draggable="true" data-vb-drag-sort-handle&gt;⋮⋮&lt;/span&gt;
          &lt;strong class="vb-drag-sort-number" data-vb-drag-sort-number&gt;4&lt;/strong&gt;
          &lt;div class="vb-drag-sort-text"&gt;
            &lt;h4&gt;Write support FAQ answers&lt;/h4&gt;
            &lt;p&gt;Content task&lt;/p&gt;
          &lt;/div&gt;
          &lt;em&gt;Low&lt;/em&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-drag-sort-status"&gt;
        &lt;span&gt;Current order&lt;/span&gt;
        &lt;strong data-vb-drag-sort-output&gt;1 → 2 → 3 → 4&lt;/strong&gt;
        &lt;p&gt;The full card moves when the handle is dragged. Numbers update after every drop.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-drag-sort-demo,
.vb-drag-sort-demo * {
  box-sizing: border-box;
}

.vb-drag-sort-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 18%, rgba(37, 99, 235, 0.18), transparent 34%),
    radial-gradient(circle at 90% 12%, rgba(249, 115, 22, 0.18), transparent 35%),
    linear-gradient(135deg, #eff6ff 0%, #fff7ed 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-drag-sort-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-drag-sort-intro {
  max-width: 760px;
  margin-bottom: 22px;
}

.vb-drag-sort-intro span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-drag-sort-intro h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-drag-sort-intro p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-drag-sort-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(260px, 0.8fr);
  gap: 18px;
}

.vb-drag-sort-list {
  display: grid;
  gap: 14px;
  padding: 18px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.25);
  box-shadow: 0 20px 58px rgba(15, 23, 42, 0.10);
}

.vb-drag-sort-item {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto;
  gap: 14px;
  align-items: center;
  padding: 16px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.28);
  box-shadow: 0 12px 30px rgba(15, 23, 42, 0.07);
  transition: opacity 0.2s ease, transform 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.vb-drag-sort-item.is-dragging {
  opacity: 0.42;
  transform: scale(0.98);
  border-color: rgba(37, 99, 235, 0.70);
  background: #eff6ff;
}

.vb-drag-sort-item.is-over {
  border-color: rgba(249, 115, 22, 0.85);
  background: #fff7ed;
}

.vb-drag-sort-handle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 46px;
  border-radius: 15px;
  background: #eef2ff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 20px;
  font-weight: 950;
  cursor: grab;
  user-select: none;
}

.vb-drag-sort-handle:active {
  cursor: grabbing;
}

.vb-drag-sort-number {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-drag-sort-text h4 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px !important;
  line-height: 1.25 !important;
  font-weight: 900 !important;
}

.vb-drag-sort-text p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 700;
}

.vb-drag-sort-item em {
  min-width: 72px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #fff7ed;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 12px;
  font-style: normal;
  font-weight: 900;
  text-align: center;
}

.vb-drag-sort-status {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 26px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 10% 15%, rgba(34, 211, 238, 0.22), transparent 34%),
    linear-gradient(135deg, #0f172a, #312e81) !important;
  box-shadow: 0 22px 70px rgba(15, 23, 42, 0.22);
}

.vb-drag-sort-status span {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-drag-sort-status strong {
  margin: 12px 0;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4vw, 48px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-drag-sort-status p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

@media (max-width: 820px) {
  .vb-drag-sort-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-drag-sort-item {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .vb-drag-sort-number,
  .vb-drag-sort-item em {
    display: none;
  }
}</pre>



<p class="wp-block-paragraph">This sortable JavaScript drag and drop task list is useful for dashboards, task planners, admin tools, editorial workflows, and project management interfaces.</p>



<h2 class="wp-block-heading">2. Kanban Board with Multiple Columns</h2>



<p class="wp-block-paragraph"><strong>A JavaScript Kanban board</strong> is a strong drag and drop example for project management dashboards, CRM pipelines, content planning tools, support ticket boards, and workflow interfaces. Users can move cards between columns to update their status.</p>



<p class="wp-block-paragraph">This example uses native drag and drop for workflow columns. It includes multiple columns, live counters, active drop highlighting, empty states, and automatic status updates after a card is dropped.</p>



<ul class="wp-block-list">
<li>Multiple workflow columns</li>
<li>Move cards between statuses</li>
<li>Live card counters</li>
<li>Empty drop zone message</li>
<li>Good for project boards and CRM UI</li>
</ul>



<div class="vb-dd-two-demo">
  <div class="vb-dd-two-wrap" data-vb-dd-two>
    <div class="vb-dd-two-intro">
      <span>Example 02</span>
      <h3>Kanban Board</h3>
      <p>Drag cards between workflow columns. Each column updates its counter and empty state automatically.</p>
    </div>

    <div class="vb-dd-two-board">
      <section class="vb-dd-two-column" data-vb-dd-two-column>
        <header>
          <span>To Do</span>
          <strong data-vb-dd-two-count>0</strong>
        </header>
        <div class="vb-dd-two-zone" data-vb-dd-two-zone>
          <article class="vb-dd-two-card" draggable="true" data-vb-dd-two-card>
            <strong>Create landing page wireframe</strong>
            <small>Design</small>
          </article>
          <article class="vb-dd-two-card" draggable="true" data-vb-dd-two-card>
            <strong>Collect customer testimonials</strong>
            <small>Content</small>
          </article>
        </div>
      </section>

      <section class="vb-dd-two-column" data-vb-dd-two-column>
        <header>
          <span>In Progress</span>
          <strong data-vb-dd-two-count>0</strong>
        </header>
        <div class="vb-dd-two-zone" data-vb-dd-two-zone>
          <article class="vb-dd-two-card" draggable="true" data-vb-dd-two-card>
            <strong>Build checkout layout</strong>
            <small>Development</small>
          </article>
        </div>
      </section>

      <section class="vb-dd-two-column" data-vb-dd-two-column>
        <header>
          <span>Review</span>
          <strong data-vb-dd-two-count>0</strong>
        </header>
        <div class="vb-dd-two-zone" data-vb-dd-two-zone>
          <article class="vb-dd-two-card" draggable="true" data-vb-dd-two-card>
            <strong>Check mobile navigation</strong>
            <small>QA</small>
          </article>
        </div>
      </section>

      <section class="vb-dd-two-column" data-vb-dd-two-column>
        <header>
          <span>Done</span>
          <strong data-vb-dd-two-count>0</strong>
        </header>
        <div class="vb-dd-two-zone" data-vb-dd-two-zone>
          <article class="vb-dd-two-card" draggable="true" data-vb-dd-two-card>
            <strong>Publish pricing update</strong>
            <small>Completed</small>
          </article>
        </div>
      </section>
    </div>
  </div>
</div>

<style>
.vb-dd-two-demo,
.vb-dd-two-demo * {
  box-sizing: border-box;
}

.vb-dd-two-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 38px;
  background: linear-gradient(135deg, #ecfdf5 0%, #eff6ff 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-dd-two-wrap {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-dd-two-intro {
  display: flex;
  align-items: end;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 22px;
}

.vb-dd-two-intro span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-dd-two-intro h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-dd-two-intro p {
  max-width: 430px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-dd-two-board {
  display: grid;
  grid-template-columns: repeat(4, minmax(230px, 1fr));
  gap: 16px;
  overflow-x: auto;
  padding-bottom: 8px;
}

.vb-dd-two-column {
  min-width: 230px;
  display: flex;
  flex-direction: column;
  min-height: 390px;
  padding: 14px;
  border-radius: 28px;
  background: rgba(255, 255, 255, 0.78);
  border: 1px solid rgba(148, 163, 184, 0.25);
  box-shadow: 0 20px 60px rgba(15, 23, 42, 0.09);
}

.vb-dd-two-column header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
  padding: 12px 12px 0;
}

.vb-dd-two-column header span {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dd-two-column header strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  height: 32px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-dd-two-zone {
  display: grid;
  align-content: start;
  gap: 12px;
  flex: 1;
  min-height: 300px;
  padding: 10px;
  border-radius: 22px;
  border: 1px dashed rgba(148, 163, 184, 0.45);
  background: linear-gradient(135deg, rgba(248, 250, 252, 0.88), rgba(239, 246, 255, 0.70));
  transition: border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
}

.vb-dd-two-zone:empty::after {
  content: "Drop card here";
  display: grid;
  place-items: center;
  min-height: 72px;
  border-radius: 18px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 850;
  border: 1px dashed rgba(148, 163, 184, 0.45);
}

.vb-dd-two-zone.is-over {
  border-color: rgba(37, 99, 235, 0.75);
  background: #eff6ff;
  box-shadow: inset 0 0 0 3px rgba(37, 99, 235, 0.10);
}

.vb-dd-two-card {
  padding: 16px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.08);
  cursor: grab;
  transition: transform 0.2s ease, opacity 0.2s ease, box-shadow 0.2s ease;
}

.vb-dd-two-card:active {
  cursor: grabbing;
}

.vb-dd-two-card.is-dragging {
  opacity: 0.42;
  transform: rotate(1deg) scale(0.98);
  box-shadow: none;
}

.vb-dd-two-card strong {
  display: block;
  margin-bottom: 9px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  line-height: 1.35;
  font-weight: 900;
}

.vb-dd-two-card small {
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: #f1f5f9;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 12px;
  font-weight: 850;
}

@media (max-width: 860px) {
  .vb-dd-two-intro {
    display: grid;
  }

  .vb-dd-two-intro p {
    max-width: 720px;
  }
}
</style>

<script>
(function () {
  const root = document.querySelector("[data-vb-dd-two]");
  if (!root) return;

  const zones = root.querySelectorAll("[data-vb-dd-two-zone]");
  const columns = root.querySelectorAll("[data-vb-dd-two-column]");
  let activeCard = null;

  function updateCounts() {
    columns.forEach(function (column) {
      const counter = column.querySelector("[data-vb-dd-two-count]");
      const count = column.querySelectorAll("[data-vb-dd-two-card]").length;
      counter.textContent = count;
    });
  }

  root.addEventListener("dragstart", function (event) {
    const card = event.target.closest("[data-vb-dd-two-card]");
    if (!card) return;

    activeCard = card;
    card.classList.add("is-dragging");
    event.dataTransfer.effectAllowed = "move";
    event.dataTransfer.setData("text/plain", card.textContent.trim());
  });

  root.addEventListener("dragend", function (event) {
    const card = event.target.closest("[data-vb-dd-two-card]");
    if (!card) return;

    card.classList.remove("is-dragging");
    activeCard = null;

    zones.forEach(function (zone) {
      zone.classList.remove("is-over");
    });

    updateCounts();
  });

  zones.forEach(function (zone) {
    zone.addEventListener("dragover", function (event) {
      event.preventDefault();
      zone.classList.add("is-over");
    });

    zone.addEventListener("dragleave", function () {
      zone.classList.remove("is-over");
    });

    zone.addEventListener("drop", function (event) {
      event.preventDefault();

      if (!activeCard) return;

      zone.appendChild(activeCard);
      zone.classList.remove("is-over");
      updateCounts();
    });
  });

  updateCounts();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const root = document.querySelector("[data-vb-dd-two]");
  if (!root) return;

  const zones = root.querySelectorAll("[data-vb-dd-two-zone]");
  const columns = root.querySelectorAll("[data-vb-dd-two-column]");
  let activeCard = null;

  function updateCounts() {
    columns.forEach(function (column) {
      const counter = column.querySelector("[data-vb-dd-two-count]");
      const count = column.querySelectorAll("[data-vb-dd-two-card]").length;
      counter.textContent = count;
    });
  }

  root.addEventListener("dragstart", function (event) {
    const card = event.target.closest("[data-vb-dd-two-card]");
    if (!card) return;

    activeCard = card;
    card.classList.add("is-dragging");
    event.dataTransfer.effectAllowed = "move";
    event.dataTransfer.setData("text/plain", card.textContent.trim());
  });

  root.addEventListener("dragend", function (event) {
    const card = event.target.closest("[data-vb-dd-two-card]");
    if (!card) return;

    card.classList.remove("is-dragging");
    activeCard = null;

    zones.forEach(function (zone) {
      zone.classList.remove("is-over");
    });

    updateCounts();
  });

  zones.forEach(function (zone) {
    zone.addEventListener("dragover", function (event) {
      event.preventDefault();
      zone.classList.add("is-over");
    });

    zone.addEventListener("dragleave", function () {
      zone.classList.remove("is-over");
    });

    zone.addEventListener("drop", function (event) {
      event.preventDefault();

      if (!activeCard) return;

      zone.appendChild(activeCard);
      zone.classList.remove("is-over");
      updateCounts();
    });
  });

  updateCounts();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dd-two-demo"&gt;
  &lt;div class="vb-dd-two-wrap" data-vb-dd-two&gt;
    &lt;div class="vb-dd-two-intro"&gt;
      &lt;span&gt;Example 02&lt;/span&gt;
      &lt;h3&gt;Kanban Board&lt;/h3&gt;
      &lt;p&gt;Drag cards between workflow columns. Each column updates its counter and empty state automatically.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-dd-two-board"&gt;
      &lt;section class="vb-dd-two-column" data-vb-dd-two-column&gt;
        &lt;header&gt;
          &lt;span&gt;To Do&lt;/span&gt;
          &lt;strong data-vb-dd-two-count&gt;0&lt;/strong&gt;
        &lt;/header&gt;
        &lt;div class="vb-dd-two-zone" data-vb-dd-two-zone&gt;
          &lt;article class="vb-dd-two-card" draggable="true" data-vb-dd-two-card&gt;
            &lt;strong&gt;Create landing page wireframe&lt;/strong&gt;
            &lt;small&gt;Design&lt;/small&gt;
          &lt;/article&gt;
          &lt;article class="vb-dd-two-card" draggable="true" data-vb-dd-two-card&gt;
            &lt;strong&gt;Collect customer testimonials&lt;/strong&gt;
            &lt;small&gt;Content&lt;/small&gt;
          &lt;/article&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-dd-two-column" data-vb-dd-two-column&gt;
        &lt;header&gt;
          &lt;span&gt;In Progress&lt;/span&gt;
          &lt;strong data-vb-dd-two-count&gt;0&lt;/strong&gt;
        &lt;/header&gt;
        &lt;div class="vb-dd-two-zone" data-vb-dd-two-zone&gt;
          &lt;article class="vb-dd-two-card" draggable="true" data-vb-dd-two-card&gt;
            &lt;strong&gt;Build checkout layout&lt;/strong&gt;
            &lt;small&gt;Development&lt;/small&gt;
          &lt;/article&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-dd-two-column" data-vb-dd-two-column&gt;
        &lt;header&gt;
          &lt;span&gt;Review&lt;/span&gt;
          &lt;strong data-vb-dd-two-count&gt;0&lt;/strong&gt;
        &lt;/header&gt;
        &lt;div class="vb-dd-two-zone" data-vb-dd-two-zone&gt;
          &lt;article class="vb-dd-two-card" draggable="true" data-vb-dd-two-card&gt;
            &lt;strong&gt;Check mobile navigation&lt;/strong&gt;
            &lt;small&gt;QA&lt;/small&gt;
          &lt;/article&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-dd-two-column" data-vb-dd-two-column&gt;
        &lt;header&gt;
          &lt;span&gt;Done&lt;/span&gt;
          &lt;strong data-vb-dd-two-count&gt;0&lt;/strong&gt;
        &lt;/header&gt;
        &lt;div class="vb-dd-two-zone" data-vb-dd-two-zone&gt;
          &lt;article class="vb-dd-two-card" draggable="true" data-vb-dd-two-card&gt;
            &lt;strong&gt;Publish pricing update&lt;/strong&gt;
            &lt;small&gt;Completed&lt;/small&gt;
          &lt;/article&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dd-two-demo,
.vb-dd-two-demo * {
  box-sizing: border-box;
}

.vb-dd-two-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 38px;
  background: linear-gradient(135deg, #ecfdf5 0%, #eff6ff 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-dd-two-wrap {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-dd-two-intro {
  display: flex;
  align-items: end;
  justify-content: space-between;
  gap: 24px;
  margin-bottom: 22px;
}

.vb-dd-two-intro span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-dd-two-intro h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-dd-two-intro p {
  max-width: 430px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-dd-two-board {
  display: grid;
  grid-template-columns: repeat(4, minmax(230px, 1fr));
  gap: 16px;
  overflow-x: auto;
  padding-bottom: 8px;
}

.vb-dd-two-column {
  min-width: 230px;
  display: flex;
  flex-direction: column;
  min-height: 390px;
  padding: 14px;
  border-radius: 28px;
  background: rgba(255, 255, 255, 0.78);
  border: 1px solid rgba(148, 163, 184, 0.25);
  box-shadow: 0 20px 60px rgba(15, 23, 42, 0.09);
}

.vb-dd-two-column header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
  padding: 12px 12px 0;
}

.vb-dd-two-column header span {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dd-two-column header strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 32px;
  height: 32px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-dd-two-zone {
  display: grid;
  align-content: start;
  gap: 12px;
  flex: 1;
  min-height: 300px;
  padding: 10px;
  border-radius: 22px;
  border: 1px dashed rgba(148, 163, 184, 0.45);
  background: linear-gradient(135deg, rgba(248, 250, 252, 0.88), rgba(239, 246, 255, 0.70));
  transition: border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
}

.vb-dd-two-zone:empty::after {
  content: "Drop card here";
  display: grid;
  place-items: center;
  min-height: 72px;
  border-radius: 18px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 850;
  border: 1px dashed rgba(148, 163, 184, 0.45);
}

.vb-dd-two-zone.is-over {
  border-color: rgba(37, 99, 235, 0.75);
  background: #eff6ff;
  box-shadow: inset 0 0 0 3px rgba(37, 99, 235, 0.10);
}

.vb-dd-two-card {
  padding: 16px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.08);
  cursor: grab;
  transition: transform 0.2s ease, opacity 0.2s ease, box-shadow 0.2s ease;
}

.vb-dd-two-card:active {
  cursor: grabbing;
}

.vb-dd-two-card.is-dragging {
  opacity: 0.42;
  transform: rotate(1deg) scale(0.98);
  box-shadow: none;
}

.vb-dd-two-card strong {
  display: block;
  margin-bottom: 9px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  line-height: 1.35;
  font-weight: 900;
}

.vb-dd-two-card small {
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: #f1f5f9;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 12px;
  font-weight: 850;
}

@media (max-width: 860px) {
  .vb-dd-two-intro {
    display: grid;
  }

  .vb-dd-two-intro p {
    max-width: 720px;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript Kanban board is useful for project management dashboards, CRM pipelines, editorial planning boards, support ticket systems, and team workflow interfaces.</p>



<h2 class="wp-block-heading">3. Drag and Drop File Upload Zone</h2>



<p class="wp-block-paragraph"><strong>A drag and drop file upload zone</strong> improves forms, dashboards, support portals, job application pages, document upload pages, and file manager interfaces. Users can drop files into a clear upload area instead of only using the default file input.</p>



<p class="wp-block-paragraph">This demo validates files in the browser and displays selected file names, file types, file sizes, remove buttons, and a live selected file counter. It does not upload files to a server, so it is safe to use as a front-end UI example.</p>



<ul class="wp-block-list">
<li>Drag files into a drop zone</li>
<li>Click-to-select file input</li>
<li>File type validation</li>
<li>File size display</li>
<li>Remove selected files</li>
</ul>



<div class="vb-dd-three-demo">
  <div class="vb-dd-three-wrap" data-vb-dd-three>
    <div class="vb-dd-three-copy">
      <span>Example 03</span>
      <h3>File Upload Zone</h3>
      <p>Drop PDF, PNG, JPG, JPEG, or TXT files into the upload area. The file list updates instantly.</p>

      <div class="vb-dd-three-summary">
        <span>Selected files</span>
        <strong data-vb-dd-three-count>0</strong>
      </div>
    </div>

    <div class="vb-dd-three-uploader">
      <label class="vb-dd-three-zone" data-vb-dd-three-zone>
        <input type="file" multiple data-vb-dd-three-input accept=".pdf,.png,.jpg,.jpeg,.txt">
        <span class="vb-dd-three-icon">↥</span>
        <strong>Drop files here</strong>
        <small>or click to browse PDF, PNG, JPG, JPEG, and TXT files</small>
      </label>

      <div class="vb-dd-three-message" data-vb-dd-three-message>No files selected yet.</div>
      <div class="vb-dd-three-list" data-vb-dd-three-list></div>
    </div>
  </div>
</div>

<style>
.vb-dd-three-demo,
.vb-dd-three-demo * {
  box-sizing: border-box;
}

.vb-dd-three-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 38px;
  background: linear-gradient(135deg, #fdf2f8 0%, #eff6ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-dd-three-wrap {
  max-width: 1120px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(260px, 0.82fr) minmax(0, 1.18fr);
  gap: 20px;
  align-items: stretch;
}

.vb-dd-three-copy {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 32px;
  background: linear-gradient(135deg, #0f172a, #1e1b4b) !important;
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.24);
}

.vb-dd-three-copy > span {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.18);
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-dd-three-copy h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-dd-three-copy p {
  margin: 0 0 22px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dd-three-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 16px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
}

.vb-dd-three-summary span {
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 13px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-dd-three-summary strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  height: 44px;
  border-radius: 999px;
  background: #ffffff;
  color: #1e1b4b !important;
  -webkit-text-fill-color: #1e1b4b !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-dd-three-uploader {
  display: grid;
  gap: 14px;
  padding: 18px;
  border-radius: 32px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-dd-three-zone {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 250px;
  padding: 26px;
  border-radius: 28px;
  border: 2px dashed rgba(14, 165, 233, 0.45);
  background: linear-gradient(135deg, #f8fafc, #eff6ff);
  text-align: center;
  cursor: pointer;
  transition: transform 0.22s ease, border-color 0.22s ease, background 0.22s ease, box-shadow 0.22s ease;
}

.vb-dd-three-zone input {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
}

.vb-dd-three-zone.is-over {
  transform: translateY(-2px);
  border-color: rgba(236, 72, 153, 0.70);
  background: linear-gradient(135deg, #fdf2f8, #eff6ff);
  box-shadow: inset 0 0 0 5px rgba(236, 72, 153, 0.08);
}

.vb-dd-three-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 76px;
  height: 76px;
  margin-bottom: 16px;
  border-radius: 24px;
  background: linear-gradient(135deg, #0ea5e9, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 42px;
  font-weight: 950;
  box-shadow: 0 18px 38px rgba(14, 165, 233, 0.25);
}

.vb-dd-three-zone strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(24px, 4vw, 38px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-dd-three-zone small {
  display: block;
  max-width: 430px;
  margin-top: 10px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

.vb-dd-three-message {
  padding: 13px 15px;
  border-radius: 16px;
  background: #f8fafc;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-dd-three-message.is-error {
  background: #fef2f2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-dd-three-message.is-success {
  background: #ecfdf5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
}

.vb-dd-three-list {
  display: grid;
  gap: 10px;
  max-height: 270px;
  overflow: auto;
}

.vb-dd-three-file {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  padding: 13px;
  border-radius: 18px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-dd-three-file-type {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 14px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 13px;
  font-weight: 950;
  text-transform: uppercase;
}

.vb-dd-three-file-name {
  display: block;
  margin-bottom: 3px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  line-height: 1.3;
  font-weight: 900;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.vb-dd-three-file-size {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 750;
}

.vb-dd-three-remove {
  width: 34px;
  height: 34px;
  border: 0;
  border-radius: 999px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 18px;
  font-weight: 950;
  cursor: pointer;
}

@media (max-width: 860px) {
  .vb-dd-three-wrap {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 540px) {
  .vb-dd-three-file {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .vb-dd-three-remove {
    grid-column: 1 / -1;
    width: 100%;
  }
}
</style>

<script>
(function () {
  const root = document.querySelector("[data-vb-dd-three]");
  if (!root) return;

  const zone = root.querySelector("[data-vb-dd-three-zone]");
  const input = root.querySelector("[data-vb-dd-three-input]");
  const list = root.querySelector("[data-vb-dd-three-list]");
  const message = root.querySelector("[data-vb-dd-three-message]");
  const count = root.querySelector("[data-vb-dd-three-count]");

  const allowedTypes = ["pdf", "png", "jpg", "jpeg", "txt"];
  let selectedFiles = [];

  function getExtension(fileName) {
    const parts = fileName.split(".");
    return parts.length > 1 ? parts.pop().toLowerCase() : "";
  }

  function formatSize(bytes) {
    if (bytes < 1024) return bytes + " B";
    if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + " KB";
    return (bytes / (1024 * 1024)).toFixed(1) + " MB";
  }

  function setMessage(text, type) {
    message.textContent = text;
    message.classList.remove("is-error", "is-success");

    if (type) {
      message.classList.add(type);
    }
  }

  function createFileRow(file, index) {
    const extension = getExtension(file.name);

    const row = document.createElement("div");
    row.className = "vb-dd-three-file";

    const type = document.createElement("span");
    type.className = "vb-dd-three-file-type";
    type.textContent = extension || "file";

    const text = document.createElement("div");

    const name = document.createElement("strong");
    name.className = "vb-dd-three-file-name";
    name.textContent = file.name;

    const size = document.createElement("span");
    size.className = "vb-dd-three-file-size";
    size.textContent = formatSize(file.size);

    const remove = document.createElement("button");
    remove.className = "vb-dd-three-remove";
    remove.type = "button";
    remove.setAttribute("aria-label", "Remove file");
    remove.setAttribute("data-vb-dd-three-remove", index);
    remove.textContent = "×";

    text.appendChild(name);
    text.appendChild(size);

    row.appendChild(type);
    row.appendChild(text);
    row.appendChild(remove);

    return row;
  }

  function renderFiles() {
    list.innerHTML = "";

    selectedFiles.forEach(function (file, index) {
      list.appendChild(createFileRow(file, index));
    });

    count.textContent = selectedFiles.length;

    if (selectedFiles.length === 0) {
      setMessage("No files selected yet.", "");
    }
  }

  function addFiles(fileList) {
    const incoming = Array.from(fileList);
    let added = 0;
    let rejected = 0;

    incoming.forEach(function (file) {
      const extension = getExtension(file.name);

      if (!allowedTypes.includes(extension)) {
        rejected += 1;
        return;
      }

      selectedFiles.push(file);
      added += 1;
    });

    renderFiles();

    if (added > 0 && rejected === 0) {
      setMessage(added + " file(s) added successfully.", "is-success");
    } else if (added > 0 && rejected > 0) {
      setMessage(added + " file(s) added. " + rejected + " file(s) rejected.", "is-error");
    } else {
      setMessage("File type not allowed. Use PDF, PNG, JPG, JPEG, or TXT.", "is-error");
    }
  }

  zone.addEventListener("dragover", function (event) {
    event.preventDefault();
    zone.classList.add("is-over");
  });

  zone.addEventListener("dragleave", function () {
    zone.classList.remove("is-over");
  });

  zone.addEventListener("drop", function (event) {
    event.preventDefault();
    zone.classList.remove("is-over");

    if (event.dataTransfer.files.length) {
      addFiles(event.dataTransfer.files);
    }
  });

  input.addEventListener("change", function () {
    if (input.files.length) {
      addFiles(input.files);
      input.value = "";
    }
  });

  list.addEventListener("click", function (event) {
    const removeButton = event.target.closest("[data-vb-dd-three-remove]");
    if (!removeButton) return;

    const index = Number(removeButton.getAttribute("data-vb-dd-three-remove"));
    selectedFiles.splice(index, 1);
    renderFiles();

    if (selectedFiles.length > 0) {
      setMessage("File removed. " + selectedFiles.length + " file(s) selected.", "is-success");
    }
  });

  renderFiles();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const root = document.querySelector("[data-vb-dd-three]");
  if (!root) return;

  const zone = root.querySelector("[data-vb-dd-three-zone]");
  const input = root.querySelector("[data-vb-dd-three-input]");
  const list = root.querySelector("[data-vb-dd-three-list]");
  const message = root.querySelector("[data-vb-dd-three-message]");
  const count = root.querySelector("[data-vb-dd-three-count]");

  const allowedTypes = ["pdf", "png", "jpg", "jpeg", "txt"];
  let selectedFiles = [];

  function getExtension(fileName) {
    const parts = fileName.split(".");
    return parts.length &gt; 1 ? parts.pop().toLowerCase() : "";
  }

  function formatSize(bytes) {
    if (bytes &lt; 1024) return bytes + " B";
    if (bytes &lt; 1024 * 1024) return (bytes / 1024).toFixed(1) + " KB";
    return (bytes / (1024 * 1024)).toFixed(1) + " MB";
  }

  function setMessage(text, type) {
    message.textContent = text;
    message.classList.remove("is-error", "is-success");

    if (type) {
      message.classList.add(type);
    }
  }

  function createFileRow(file, index) {
    const extension = getExtension(file.name);

    const row = document.createElement("div");
    row.className = "vb-dd-three-file";

    const type = document.createElement("span");
    type.className = "vb-dd-three-file-type";
    type.textContent = extension || "file";

    const text = document.createElement("div");

    const name = document.createElement("strong");
    name.className = "vb-dd-three-file-name";
    name.textContent = file.name;

    const size = document.createElement("span");
    size.className = "vb-dd-three-file-size";
    size.textContent = formatSize(file.size);

    const remove = document.createElement("button");
    remove.className = "vb-dd-three-remove";
    remove.type = "button";
    remove.setAttribute("aria-label", "Remove file");
    remove.setAttribute("data-vb-dd-three-remove", index);
    remove.textContent = "×";

    text.appendChild(name);
    text.appendChild(size);

    row.appendChild(type);
    row.appendChild(text);
    row.appendChild(remove);

    return row;
  }

  function renderFiles() {
    list.innerHTML = "";

    selectedFiles.forEach(function (file, index) {
      list.appendChild(createFileRow(file, index));
    });

    count.textContent = selectedFiles.length;

    if (selectedFiles.length === 0) {
      setMessage("No files selected yet.", "");
    }
  }

  function addFiles(fileList) {
    const incoming = Array.from(fileList);
    let added = 0;
    let rejected = 0;

    incoming.forEach(function (file) {
      const extension = getExtension(file.name);

      if (!allowedTypes.includes(extension)) {
        rejected += 1;
        return;
      }

      selectedFiles.push(file);
      added += 1;
    });

    renderFiles();

    if (added &gt; 0 &amp;&amp; rejected === 0) {
      setMessage(added + " file(s) added successfully.", "is-success");
    } else if (added &gt; 0 &amp;&amp; rejected &gt; 0) {
      setMessage(added + " file(s) added. " + rejected + " file(s) rejected.", "is-error");
    } else {
      setMessage("File type not allowed. Use PDF, PNG, JPG, JPEG, or TXT.", "is-error");
    }
  }

  zone.addEventListener("dragover", function (event) {
    event.preventDefault();
    zone.classList.add("is-over");
  });

  zone.addEventListener("dragleave", function () {
    zone.classList.remove("is-over");
  });

  zone.addEventListener("drop", function (event) {
    event.preventDefault();
    zone.classList.remove("is-over");

    if (event.dataTransfer.files.length) {
      addFiles(event.dataTransfer.files);
    }
  });

  input.addEventListener("change", function () {
    if (input.files.length) {
      addFiles(input.files);
      input.value = "";
    }
  });

  list.addEventListener("click", function (event) {
    const removeButton = event.target.closest("[data-vb-dd-three-remove]");
    if (!removeButton) return;

    const index = Number(removeButton.getAttribute("data-vb-dd-three-remove"));
    selectedFiles.splice(index, 1);
    renderFiles();

    if (selectedFiles.length &gt; 0) {
      setMessage("File removed. " + selectedFiles.length + " file(s) selected.", "is-success");
    }
  });

  renderFiles();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dd-three-demo"&gt;
  &lt;div class="vb-dd-three-wrap" data-vb-dd-three&gt;
    &lt;div class="vb-dd-three-copy"&gt;
      &lt;span&gt;Example 03&lt;/span&gt;
      &lt;h3&gt;File Upload Zone&lt;/h3&gt;
      &lt;p&gt;Drop PDF, PNG, JPG, JPEG, or TXT files into the upload area. The file list updates instantly.&lt;/p&gt;

      &lt;div class="vb-dd-three-summary"&gt;
        &lt;span&gt;Selected files&lt;/span&gt;
        &lt;strong data-vb-dd-three-count&gt;0&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-dd-three-uploader"&gt;
      &lt;label class="vb-dd-three-zone" data-vb-dd-three-zone&gt;
        &lt;input type="file" multiple data-vb-dd-three-input accept=".pdf,.png,.jpg,.jpeg,.txt"&gt;
        &lt;span class="vb-dd-three-icon"&gt;↥&lt;/span&gt;
        &lt;strong&gt;Drop files here&lt;/strong&gt;
        &lt;small&gt;or click to browse PDF, PNG, JPG, JPEG, and TXT files&lt;/small&gt;
      &lt;/label&gt;

      &lt;div class="vb-dd-three-message" data-vb-dd-three-message&gt;No files selected yet.&lt;/div&gt;
      &lt;div class="vb-dd-three-list" data-vb-dd-three-list&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dd-three-demo,
.vb-dd-three-demo * {
  box-sizing: border-box;
}

.vb-dd-three-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 38px;
  background: linear-gradient(135deg, #fdf2f8 0%, #eff6ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-dd-three-wrap {
  max-width: 1120px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(260px, 0.82fr) minmax(0, 1.18fr);
  gap: 20px;
  align-items: stretch;
}

.vb-dd-three-copy {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 32px;
  background: linear-gradient(135deg, #0f172a, #1e1b4b) !important;
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.24);
}

.vb-dd-three-copy &gt; span {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.18);
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-dd-three-copy h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-dd-three-copy p {
  margin: 0 0 22px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dd-three-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 16px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
}

.vb-dd-three-summary span {
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 13px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-dd-three-summary strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 44px;
  height: 44px;
  border-radius: 999px;
  background: #ffffff;
  color: #1e1b4b !important;
  -webkit-text-fill-color: #1e1b4b !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-dd-three-uploader {
  display: grid;
  gap: 14px;
  padding: 18px;
  border-radius: 32px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-dd-three-zone {
  position: relative;
  display: grid;
  place-items: center;
  min-height: 250px;
  padding: 26px;
  border-radius: 28px;
  border: 2px dashed rgba(14, 165, 233, 0.45);
  background: linear-gradient(135deg, #f8fafc, #eff6ff);
  text-align: center;
  cursor: pointer;
  transition: transform 0.22s ease, border-color 0.22s ease, background 0.22s ease, box-shadow 0.22s ease;
}

.vb-dd-three-zone input {
  position: absolute;
  inset: 0;
  opacity: 0;
  cursor: pointer;
}

.vb-dd-three-zone.is-over {
  transform: translateY(-2px);
  border-color: rgba(236, 72, 153, 0.70);
  background: linear-gradient(135deg, #fdf2f8, #eff6ff);
  box-shadow: inset 0 0 0 5px rgba(236, 72, 153, 0.08);
}

.vb-dd-three-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 76px;
  height: 76px;
  margin-bottom: 16px;
  border-radius: 24px;
  background: linear-gradient(135deg, #0ea5e9, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 42px;
  font-weight: 950;
  box-shadow: 0 18px 38px rgba(14, 165, 233, 0.25);
}

.vb-dd-three-zone strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(24px, 4vw, 38px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-dd-three-zone small {
  display: block;
  max-width: 430px;
  margin-top: 10px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

.vb-dd-three-message {
  padding: 13px 15px;
  border-radius: 16px;
  background: #f8fafc;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-dd-three-message.is-error {
  background: #fef2f2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-dd-three-message.is-success {
  background: #ecfdf5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
}

.vb-dd-three-list {
  display: grid;
  gap: 10px;
  max-height: 270px;
  overflow: auto;
}

.vb-dd-three-file {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  padding: 13px;
  border-radius: 18px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-dd-three-file-type {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 14px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 13px;
  font-weight: 950;
  text-transform: uppercase;
}

.vb-dd-three-file-name {
  display: block;
  margin-bottom: 3px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  line-height: 1.3;
  font-weight: 900;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.vb-dd-three-file-size {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 750;
}

.vb-dd-three-remove {
  width: 34px;
  height: 34px;
  border: 0;
  border-radius: 999px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 18px;
  font-weight: 950;
  cursor: pointer;
}

@media (max-width: 860px) {
  .vb-dd-three-wrap {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 540px) {
  .vb-dd-three-file {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .vb-dd-three-remove {
    grid-column: 1 / -1;
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript drag and drop file upload zone is useful for contact forms, client dashboards, support tickets, job applications, document portals, and admin upload interfaces.</p>



<h2 class="wp-block-heading">4. Image Upload Preview with Drag and Drop</h2>



<p class="wp-block-paragraph"><strong>An image upload preview with drag and drop</strong> is useful for profile forms, product upload tools, portfolio dashboards, review forms, support tickets, and admin panels. Users can drop image files into the upload area and immediately see visual previews before submitting anything.</p>



<ul class="wp-block-list">
<li>Drag and drop image upload area</li>
<li>Click-to-select image input</li>
<li>Local thumbnail previews</li>
<li>Image type validation</li>
<li>Remove selected images</li>
</ul>



<div class="vb-imgup-demo">
  <div class="vb-imgup-wrap" data-vb-imgup>
    <div class="vb-imgup-copy">
      <span>Example 04</span>
      <h3>Image Upload Preview</h3>
      <p>Drop image files into the upload zone or use the browse button. JavaScript creates instant local previews.</p>

      <div class="vb-imgup-counter">
        <strong data-vb-imgup-count>0</strong>
        <span>Images selected</span>
      </div>
    </div>

    <div class="vb-imgup-panel">
      <div class="vb-imgup-zone" data-vb-imgup-zone>
        <div class="vb-imgup-icon">+</div>
        <strong>Drop images here</strong>
        <small>PNG, JPG, JPEG, WEBP, and GIF files are supported.</small>
        <button type="button" data-vb-imgup-browse>Browse Images</button>
        <input type="file" accept="image/png,image/jpeg,image/webp,image/gif" multiple data-vb-imgup-input>
      </div>

      <div class="vb-imgup-message" data-vb-imgup-message>No images selected yet.</div>
      <div class="vb-imgup-grid" data-vb-imgup-grid></div>
    </div>
  </div>
</div>

<style>
.vb-imgup-demo,
.vb-imgup-demo * {
  box-sizing: border-box;
}

.vb-imgup-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 12% 15%, rgba(236, 72, 153, 0.16), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(14, 165, 233, 0.18), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #eff6ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-imgup-wrap {
  max-width: 1120px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(260px, 0.82fr) minmax(0, 1.18fr);
  gap: 20px;
  align-items: stretch;
}

.vb-imgup-copy {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 32px;
  background:
    radial-gradient(circle at 18% 14%, rgba(244, 114, 182, 0.22), transparent 38%),
    linear-gradient(135deg, #111827, #581c87) !important;
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.25);
}

.vb-imgup-copy > span {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.18);
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-imgup-copy h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-imgup-copy p {
  margin: 0 0 24px !important;
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-imgup-counter {
  display: grid;
  gap: 4px;
  padding: 18px;
  border-radius: 24px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
}

.vb-imgup-counter strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 48px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vb-imgup-counter span {
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 13px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-imgup-panel {
  display: grid;
  gap: 14px;
  padding: 18px;
  border-radius: 32px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-imgup-zone {
  display: grid;
  place-items: center;
  min-height: 260px;
  padding: 26px;
  border-radius: 28px;
  border: 2px dashed rgba(236, 72, 153, 0.44);
  background:
    radial-gradient(circle at top, rgba(236, 72, 153, 0.13), transparent 42%),
    linear-gradient(135deg, #fdf2f8, #eff6ff);
  text-align: center;
  transition: transform 0.22s ease, border-color 0.22s ease, box-shadow 0.22s ease, background 0.22s ease;
}

.vb-imgup-zone.is-over {
  transform: translateY(-2px);
  border-color: rgba(14, 165, 233, 0.78);
  background:
    radial-gradient(circle at top, rgba(14, 165, 233, 0.15), transparent 42%),
    linear-gradient(135deg, #eff6ff, #fdf2f8);
  box-shadow: inset 0 0 0 5px rgba(14, 165, 233, 0.10);
}

.vb-imgup-zone input {
  display: none;
}

.vb-imgup-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 78px;
  height: 78px;
  margin-bottom: 16px;
  border-radius: 26px;
  background: linear-gradient(135deg, #ec4899, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 46px;
  line-height: 1;
  font-weight: 750;
  box-shadow: 0 18px 38px rgba(236, 72, 153, 0.24);
}

.vb-imgup-zone strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(24px, 4vw, 38px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-imgup-zone small {
  display: block;
  max-width: 430px;
  margin-top: 10px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

.vb-imgup-zone button {
  margin-top: 18px;
  min-height: 44px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #ec4899, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 14px 34px rgba(124, 58, 237, 0.22);
}

.vb-imgup-message {
  padding: 13px 15px;
  border-radius: 16px;
  background: #f8fafc;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-imgup-message.is-success {
  background: #ecfdf5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
}

.vb-imgup-message.is-error {
  background: #fef2f2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-imgup-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-imgup-card {
  position: relative;
  min-width: 0;
  overflow: hidden;
  border-radius: 20px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.08);
}

.vb-imgup-card img {
  display: block;
  width: 100%;
  aspect-ratio: 1 / 0.75;
  object-fit: cover;
  background: #e2e8f0;
}

.vb-imgup-card-body {
  display: grid;
  gap: 4px;
  padding: 12px;
}

.vb-imgup-card-body strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 13px;
  line-height: 1.25;
  font-weight: 900;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.vb-imgup-card-body span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 750;
}

.vb-imgup-remove {
  position: absolute;
  top: 9px;
  right: 9px;
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.78);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
  cursor: pointer;
}

@media (max-width: 860px) {
  .vb-imgup-wrap {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-imgup-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 460px) {
  .vb-imgup-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const root = document.querySelector("[data-vb-imgup]");
  if (!root) return;

  const zone = root.querySelector("[data-vb-imgup-zone]");
  const input = root.querySelector("[data-vb-imgup-input]");
  const browse = root.querySelector("[data-vb-imgup-browse]");
  const grid = root.querySelector("[data-vb-imgup-grid]");
  const message = root.querySelector("[data-vb-imgup-message]");
  const count = root.querySelector("[data-vb-imgup-count]");

  let images = [];

  function formatSize(bytes) {
    if (bytes < 1024) return bytes + " B";
    if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + " KB";
    return (bytes / (1024 * 1024)).toFixed(1) + " MB";
  }

  function setMessage(text, type) {
    message.textContent = text;
    message.classList.remove("is-success", "is-error");
    if (type) {
      message.classList.add(type);
    }
  }

  function renderImages() {
    grid.innerHTML = "";

    images.forEach(function (image, index) {
      const card = document.createElement("div");
      card.className = "vb-imgup-card";

      const img = document.createElement("img");
      img.src = image.url;
      img.alt = image.file.name;

      const remove = document.createElement("button");
      remove.className = "vb-imgup-remove";
      remove.type = "button";
      remove.textContent = "×";
      remove.setAttribute("aria-label", "Remove image");
      remove.setAttribute("data-vb-imgup-remove", index);

      const body = document.createElement("div");
      body.className = "vb-imgup-card-body";

      const name = document.createElement("strong");
      name.textContent = image.file.name;

      const size = document.createElement("span");
      size.textContent = formatSize(image.file.size);

      body.appendChild(name);
      body.appendChild(size);
      card.appendChild(img);
      card.appendChild(remove);
      card.appendChild(body);
      grid.appendChild(card);
    });

    count.textContent = images.length;

    if (images.length === 0) {
      setMessage("No images selected yet.", "");
    }
  }

  function addImages(fileList) {
    const files = Array.from(fileList);
    let added = 0;
    let rejected = 0;

    files.forEach(function (file) {
      if (!file.type || !file.type.startsWith("image/")) {
        rejected += 1;
        return;
      }

      images.push({
        file: file,
        url: URL.createObjectURL(file)
      });

      added += 1;
    });

    renderImages();

    if (added > 0 && rejected === 0) {
      setMessage(added + " image(s) added successfully.", "is-success");
    } else if (added > 0 && rejected > 0) {
      setMessage(added + " image(s) added. " + rejected + " file(s) rejected.", "is-error");
    } else {
      setMessage("Only image files are allowed.", "is-error");
    }
  }

  browse.addEventListener("click", function () {
    input.click();
  });

  input.addEventListener("change", function () {
    if (input.files.length) {
      addImages(input.files);
      input.value = "";
    }
  });

  zone.addEventListener("dragover", function (event) {
    event.preventDefault();
    zone.classList.add("is-over");
  });

  zone.addEventListener("dragleave", function () {
    zone.classList.remove("is-over");
  });

  zone.addEventListener("drop", function (event) {
    event.preventDefault();
    zone.classList.remove("is-over");

    if (event.dataTransfer.files.length) {
      addImages(event.dataTransfer.files);
    }
  });

  grid.addEventListener("click", function (event) {
    const button = event.target.closest("[data-vb-imgup-remove]");
    if (!button) return;

    const index = Number(button.getAttribute("data-vb-imgup-remove"));

    if (images[index]) {
      URL.revokeObjectURL(images[index].url);
      images.splice(index, 1);
      renderImages();

      if (images.length > 0) {
        setMessage("Image removed. " + images.length + " image(s) selected.", "is-success");
      }
    }
  });

  renderImages();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const root = document.querySelector("[data-vb-imgup]");
  if (!root) return;

  const zone = root.querySelector("[data-vb-imgup-zone]");
  const input = root.querySelector("[data-vb-imgup-input]");
  const browse = root.querySelector("[data-vb-imgup-browse]");
  const grid = root.querySelector("[data-vb-imgup-grid]");
  const message = root.querySelector("[data-vb-imgup-message]");
  const count = root.querySelector("[data-vb-imgup-count]");

  let images = [];

  function formatSize(bytes) {
    if (bytes &lt; 1024) return bytes + " B";
    if (bytes &lt; 1024 * 1024) return (bytes / 1024).toFixed(1) + " KB";
    return (bytes / (1024 * 1024)).toFixed(1) + " MB";
  }

  function setMessage(text, type) {
    message.textContent = text;
    message.classList.remove("is-success", "is-error");
    if (type) {
      message.classList.add(type);
    }
  }

  function renderImages() {
    grid.innerHTML = "";

    images.forEach(function (image, index) {
      const card = document.createElement("div");
      card.className = "vb-imgup-card";

      const img = document.createElement("img");
      img.src = image.url;
      img.alt = image.file.name;

      const remove = document.createElement("button");
      remove.className = "vb-imgup-remove";
      remove.type = "button";
      remove.textContent = "×";
      remove.setAttribute("aria-label", "Remove image");
      remove.setAttribute("data-vb-imgup-remove", index);

      const body = document.createElement("div");
      body.className = "vb-imgup-card-body";

      const name = document.createElement("strong");
      name.textContent = image.file.name;

      const size = document.createElement("span");
      size.textContent = formatSize(image.file.size);

      body.appendChild(name);
      body.appendChild(size);
      card.appendChild(img);
      card.appendChild(remove);
      card.appendChild(body);
      grid.appendChild(card);
    });

    count.textContent = images.length;

    if (images.length === 0) {
      setMessage("No images selected yet.", "");
    }
  }

  function addImages(fileList) {
    const files = Array.from(fileList);
    let added = 0;
    let rejected = 0;

    files.forEach(function (file) {
      if (!file.type || !file.type.startsWith("image/")) {
        rejected += 1;
        return;
      }

      images.push({
        file: file,
        url: URL.createObjectURL(file)
      });

      added += 1;
    });

    renderImages();

    if (added &gt; 0 &amp;&amp; rejected === 0) {
      setMessage(added + " image(s) added successfully.", "is-success");
    } else if (added &gt; 0 &amp;&amp; rejected &gt; 0) {
      setMessage(added + " image(s) added. " + rejected + " file(s) rejected.", "is-error");
    } else {
      setMessage("Only image files are allowed.", "is-error");
    }
  }

  browse.addEventListener("click", function () {
    input.click();
  });

  input.addEventListener("change", function () {
    if (input.files.length) {
      addImages(input.files);
      input.value = "";
    }
  });

  zone.addEventListener("dragover", function (event) {
    event.preventDefault();
    zone.classList.add("is-over");
  });

  zone.addEventListener("dragleave", function () {
    zone.classList.remove("is-over");
  });

  zone.addEventListener("drop", function (event) {
    event.preventDefault();
    zone.classList.remove("is-over");

    if (event.dataTransfer.files.length) {
      addImages(event.dataTransfer.files);
    }
  });

  grid.addEventListener("click", function (event) {
    const button = event.target.closest("[data-vb-imgup-remove]");
    if (!button) return;

    const index = Number(button.getAttribute("data-vb-imgup-remove"));

    if (images[index]) {
      URL.revokeObjectURL(images[index].url);
      images.splice(index, 1);
      renderImages();

      if (images.length &gt; 0) {
        setMessage("Image removed. " + images.length + " image(s) selected.", "is-success");
      }
    }
  });

  renderImages();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-imgup-demo"&gt;
  &lt;div class="vb-imgup-wrap" data-vb-imgup&gt;
    &lt;div class="vb-imgup-copy"&gt;
      &lt;span&gt;Example 04&lt;/span&gt;
      &lt;h3&gt;Image Upload Preview&lt;/h3&gt;
      &lt;p&gt;Drop image files into the upload zone or use the browse button. JavaScript creates instant local previews.&lt;/p&gt;

      &lt;div class="vb-imgup-counter"&gt;
        &lt;strong data-vb-imgup-count&gt;0&lt;/strong&gt;
        &lt;span&gt;Images selected&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-imgup-panel"&gt;
      &lt;div class="vb-imgup-zone" data-vb-imgup-zone&gt;
        &lt;div class="vb-imgup-icon"&gt;+&lt;/div&gt;
        &lt;strong&gt;Drop images here&lt;/strong&gt;
        &lt;small&gt;PNG, JPG, JPEG, WEBP, and GIF files are supported.&lt;/small&gt;
        &lt;button type="button" data-vb-imgup-browse&gt;Browse Images&lt;/button&gt;
        &lt;input type="file" accept="image/png,image/jpeg,image/webp,image/gif" multiple data-vb-imgup-input&gt;
      &lt;/div&gt;

      &lt;div class="vb-imgup-message" data-vb-imgup-message&gt;No images selected yet.&lt;/div&gt;
      &lt;div class="vb-imgup-grid" data-vb-imgup-grid&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-imgup-demo,
.vb-imgup-demo * {
  box-sizing: border-box;
}

.vb-imgup-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 12% 15%, rgba(236, 72, 153, 0.16), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(14, 165, 233, 0.18), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #eff6ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-imgup-wrap {
  max-width: 1120px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(260px, 0.82fr) minmax(0, 1.18fr);
  gap: 20px;
  align-items: stretch;
}

.vb-imgup-copy {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 32px;
  background:
    radial-gradient(circle at 18% 14%, rgba(244, 114, 182, 0.22), transparent 38%),
    linear-gradient(135deg, #111827, #581c87) !important;
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.25);
}

.vb-imgup-copy &gt; span {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.18);
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-imgup-copy h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-imgup-copy p {
  margin: 0 0 24px !important;
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-imgup-counter {
  display: grid;
  gap: 4px;
  padding: 18px;
  border-radius: 24px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
}

.vb-imgup-counter strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 48px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vb-imgup-counter span {
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 13px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-imgup-panel {
  display: grid;
  gap: 14px;
  padding: 18px;
  border-radius: 32px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-imgup-zone {
  display: grid;
  place-items: center;
  min-height: 260px;
  padding: 26px;
  border-radius: 28px;
  border: 2px dashed rgba(236, 72, 153, 0.44);
  background:
    radial-gradient(circle at top, rgba(236, 72, 153, 0.13), transparent 42%),
    linear-gradient(135deg, #fdf2f8, #eff6ff);
  text-align: center;
  transition: transform 0.22s ease, border-color 0.22s ease, box-shadow 0.22s ease, background 0.22s ease;
}

.vb-imgup-zone.is-over {
  transform: translateY(-2px);
  border-color: rgba(14, 165, 233, 0.78);
  background:
    radial-gradient(circle at top, rgba(14, 165, 233, 0.15), transparent 42%),
    linear-gradient(135deg, #eff6ff, #fdf2f8);
  box-shadow: inset 0 0 0 5px rgba(14, 165, 233, 0.10);
}

.vb-imgup-zone input {
  display: none;
}

.vb-imgup-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 78px;
  height: 78px;
  margin-bottom: 16px;
  border-radius: 26px;
  background: linear-gradient(135deg, #ec4899, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 46px;
  line-height: 1;
  font-weight: 750;
  box-shadow: 0 18px 38px rgba(236, 72, 153, 0.24);
}

.vb-imgup-zone strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(24px, 4vw, 38px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-imgup-zone small {
  display: block;
  max-width: 430px;
  margin-top: 10px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

.vb-imgup-zone button {
  margin-top: 18px;
  min-height: 44px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #ec4899, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 14px 34px rgba(124, 58, 237, 0.22);
}

.vb-imgup-message {
  padding: 13px 15px;
  border-radius: 16px;
  background: #f8fafc;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-imgup-message.is-success {
  background: #ecfdf5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
}

.vb-imgup-message.is-error {
  background: #fef2f2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-imgup-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-imgup-card {
  position: relative;
  min-width: 0;
  overflow: hidden;
  border-radius: 20px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.08);
}

.vb-imgup-card img {
  display: block;
  width: 100%;
  aspect-ratio: 1 / 0.75;
  object-fit: cover;
  background: #e2e8f0;
}

.vb-imgup-card-body {
  display: grid;
  gap: 4px;
  padding: 12px;
}

.vb-imgup-card-body strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 13px;
  line-height: 1.25;
  font-weight: 900;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.vb-imgup-card-body span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 750;
}

.vb-imgup-remove {
  position: absolute;
  top: 9px;
  right: 9px;
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.78);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
  cursor: pointer;
}

@media (max-width: 860px) {
  .vb-imgup-wrap {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-imgup-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 460px) {
  .vb-imgup-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript image upload preview is useful for profile forms, product image upload dashboards, portfolio tools, support forms, review forms, and admin interfaces where users should see images before submitting them.</p>



<h2 class="wp-block-heading">5. Reorder Image Gallery with Drag and Drop</h2>



<p class="wp-block-paragraph"><strong>A reorderable image gallery</strong> is useful for portfolio pages, ecommerce product galleries, media libraries, admin panels, travel websites, real estate listings, and any interface where image order matters. Users can drag image cards to change their display order visually.</p>



<ul class="wp-block-list">
<li>Drag handle on every image card</li>
<li>Full card moves in the grid</li>
<li>Automatic order labels</li>
<li>CSS-only image placeholders</li>
<li>No external images or libraries</li>
</ul>



<div class="vb-galsort-demo">
  <div class="vb-galsort-wrap" data-vb-galsort>
    <div class="vb-galsort-head">
      <span>Example 05</span>
      <h3>Reorder Image Gallery</h3>
      <p>Drag the small handle on any gallery card to reorder the grid. The numbers update automatically.</p>
    </div>

    <div class="vb-galsort-toolbar">
      <span>Gallery order</span>
      <strong data-vb-galsort-output>1 → 2 → 3 → 4 → 5 → 6</strong>
    </div>

    <div class="vb-galsort-grid" data-vb-galsort-grid>
      <article class="vb-galsort-card" data-vb-galsort-card>
        <span class="vb-galsort-handle" draggable="true" data-vb-galsort-handle>⋮⋮</span>
        <div class="vb-galsort-art vb-galsort-art-one"></div>
        <div class="vb-galsort-body">
          <strong data-vb-galsort-number>1</strong>
          <div>
            <h4>Hero Product Image</h4>
            <p>Main ecommerce image</p>
          </div>
        </div>
      </article>

      <article class="vb-galsort-card" data-vb-galsort-card>
        <span class="vb-galsort-handle" draggable="true" data-vb-galsort-handle>⋮⋮</span>
        <div class="vb-galsort-art vb-galsort-art-two"></div>
        <div class="vb-galsort-body">
          <strong data-vb-galsort-number>2</strong>
          <div>
            <h4>Detail Closeup</h4>
            <p>Texture and material</p>
          </div>
        </div>
      </article>

      <article class="vb-galsort-card" data-vb-galsort-card>
        <span class="vb-galsort-handle" draggable="true" data-vb-galsort-handle>⋮⋮</span>
        <div class="vb-galsort-art vb-galsort-art-three"></div>
        <div class="vb-galsort-body">
          <strong data-vb-galsort-number>3</strong>
          <div>
            <h4>Lifestyle Scene</h4>
            <p>Real usage example</p>
          </div>
        </div>
      </article>

      <article class="vb-galsort-card" data-vb-galsort-card>
        <span class="vb-galsort-handle" draggable="true" data-vb-galsort-handle>⋮⋮</span>
        <div class="vb-galsort-art vb-galsort-art-four"></div>
        <div class="vb-galsort-body">
          <strong data-vb-galsort-number>4</strong>
          <div>
            <h4>Package Preview</h4>
            <p>Box and contents</p>
          </div>
        </div>
      </article>

      <article class="vb-galsort-card" data-vb-galsort-card>
        <span class="vb-galsort-handle" draggable="true" data-vb-galsort-handle>⋮⋮</span>
        <div class="vb-galsort-art vb-galsort-art-five"></div>
        <div class="vb-galsort-body">
          <strong data-vb-galsort-number>5</strong>
          <div>
            <h4>Mobile Crop</h4>
            <p>Social preview image</p>
          </div>
        </div>
      </article>

      <article class="vb-galsort-card" data-vb-galsort-card>
        <span class="vb-galsort-handle" draggable="true" data-vb-galsort-handle>⋮⋮</span>
        <div class="vb-galsort-art vb-galsort-art-six"></div>
        <div class="vb-galsort-body">
          <strong data-vb-galsort-number>6</strong>
          <div>
            <h4>Gallery Thumbnail</h4>
            <p>Small preview card</p>
          </div>
        </div>
      </article>
    </div>
  </div>
</div>

<style>
.vb-galsort-demo,
.vb-galsort-demo * {
  box-sizing: border-box;
}

.vb-galsort-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 12% 18%, rgba(59, 130, 246, 0.18), transparent 34%),
    radial-gradient(circle at 88% 12%, rgba(16, 185, 129, 0.18), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-galsort-wrap {
  max-width: 1160px;
  margin: 0 auto;
}

.vb-galsort-head {
  display: grid;
  gap: 12px;
  max-width: 780px;
  margin-bottom: 20px;
}

.vb-galsort-head span {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-galsort-head h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-galsort-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-galsort-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 16px;
  padding: 14px 16px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.07);
}

.vb-galsort-toolbar span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-galsort-toolbar strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-galsort-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-galsort-card {
  position: relative;
  overflow: hidden;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.10);
  transition: opacity 0.2s ease, transform 0.2s ease, border-color 0.2s ease;
}

.vb-galsort-card.is-dragging {
  opacity: 0.42;
  transform: scale(0.98);
  border-color: rgba(37, 99, 235, 0.70);
}

.vb-galsort-card.is-over {
  border-color: rgba(249, 115, 22, 0.85);
}

.vb-galsort-handle {
  position: absolute;
  z-index: 5;
  top: 12px;
  left: 12px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: rgba(15, 23, 42, 0.78);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  font-weight: 950;
  cursor: grab;
  user-select: none;
  backdrop-filter: blur(10px);
}

.vb-galsort-handle:active {
  cursor: grabbing;
}

.vb-galsort-art {
  min-height: 190px;
  position: relative;
  overflow: hidden;
}

.vb-galsort-art::before,
.vb-galsort-art::after {
  content: "";
  position: absolute;
  border-radius: 999px;
  background: rgba(255,255,255,0.30);
}

.vb-galsort-art::before {
  width: 90px;
  height: 90px;
  left: 24px;
  top: 28px;
}

.vb-galsort-art::after {
  width: 160px;
  height: 160px;
  right: -38px;
  bottom: -48px;
}

.vb-galsort-art-one {
  background: linear-gradient(135deg, #2563eb, #7c3aed);
}

.vb-galsort-art-two {
  background: linear-gradient(135deg, #db2777, #f97316);
}

.vb-galsort-art-three {
  background: linear-gradient(135deg, #059669, #0ea5e9);
}

.vb-galsort-art-four {
  background: linear-gradient(135deg, #111827, #475569);
}

.vb-galsort-art-five {
  background: linear-gradient(135deg, #7c2d12, #f59e0b);
}

.vb-galsort-art-six {
  background: linear-gradient(135deg, #4338ca, #06b6d4);
}

.vb-galsort-body {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 16px;
}

.vb-galsort-body strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-galsort-body h4 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px !important;
  line-height: 1.25 !important;
  font-weight: 900 !important;
}

.vb-galsort-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-galsort-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .vb-galsort-grid {
    grid-template-columns: 1fr;
  }

  .vb-galsort-toolbar {
    display: grid;
  }
}
</style>

<script>
(function () {
  function initGallerySort() {
    const root = document.querySelector("[data-vb-galsort]");
    if (!root) return;

    const grid = root.querySelector("[data-vb-galsort-grid]");
    const output = root.querySelector("[data-vb-galsort-output]");
    let draggedCard = null;

    function updateOrder() {
      const cards = Array.from(grid.querySelectorAll("[data-vb-galsort-card]"));

      cards.forEach(function (card, index) {
        const number = card.querySelector("[data-vb-galsort-number]");
        if (number) {
          number.textContent = index + 1;
        }
      });

      output.textContent = cards.map(function (_, index) {
        return index + 1;
      }).join(" → ");
    }

    function clearOverStates() {
      grid.querySelectorAll(".is-over").forEach(function (card) {
        card.classList.remove("is-over");
      });
    }

    grid.addEventListener("dragstart", function (event) {
      const handle = event.target.closest("[data-vb-galsort-handle]");
      if (!handle) return;

      const card = handle.closest("[data-vb-galsort-card]");
      if (!card) return;

      draggedCard = card;
      card.classList.add("is-dragging");

      event.dataTransfer.effectAllowed = "move";
      event.dataTransfer.setData("text/plain", card.textContent.trim());
    });

    grid.addEventListener("dragover", function (event) {
      event.preventDefault();

      if (!draggedCard) return;

      const targetCard = event.target.closest("[data-vb-galsort-card]");
      if (!targetCard || targetCard === draggedCard) return;

      const targetBox = targetCard.getBoundingClientRect();
      const shouldPlaceAfter = event.clientY > targetBox.top + targetBox.height / 2;

      clearOverStates();
      targetCard.classList.add("is-over");

      if (shouldPlaceAfter) {
        targetCard.insertAdjacentElement("afterend", draggedCard);
      } else {
        targetCard.insertAdjacentElement("beforebegin", draggedCard);
      }

      updateOrder();
    });

    grid.addEventListener("drop", function (event) {
      event.preventDefault();
      clearOverStates();

      if (draggedCard) {
        draggedCard.classList.remove("is-dragging");
      }

      draggedCard = null;
      updateOrder();
    });

    grid.addEventListener("dragend", function () {
      clearOverStates();

      if (draggedCard) {
        draggedCard.classList.remove("is-dragging");
      }

      draggedCard = null;
      updateOrder();
    });

    updateOrder();
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initGallerySort);
  } else {
    initGallerySort();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initGallerySort() {
    const root = document.querySelector("[data-vb-galsort]");
    if (!root) return;

    const grid = root.querySelector("[data-vb-galsort-grid]");
    const output = root.querySelector("[data-vb-galsort-output]");
    let draggedCard = null;

    function updateOrder() {
      const cards = Array.from(grid.querySelectorAll("[data-vb-galsort-card]"));

      cards.forEach(function (card, index) {
        const number = card.querySelector("[data-vb-galsort-number]");
        if (number) {
          number.textContent = index + 1;
        }
      });

      output.textContent = cards.map(function (_, index) {
        return index + 1;
      }).join(" → ");
    }

    function clearOverStates() {
      grid.querySelectorAll(".is-over").forEach(function (card) {
        card.classList.remove("is-over");
      });
    }

    grid.addEventListener("dragstart", function (event) {
      const handle = event.target.closest("[data-vb-galsort-handle]");
      if (!handle) return;

      const card = handle.closest("[data-vb-galsort-card]");
      if (!card) return;

      draggedCard = card;
      card.classList.add("is-dragging");

      event.dataTransfer.effectAllowed = "move";
      event.dataTransfer.setData("text/plain", card.textContent.trim());
    });

    grid.addEventListener("dragover", function (event) {
      event.preventDefault();

      if (!draggedCard) return;

      const targetCard = event.target.closest("[data-vb-galsort-card]");
      if (!targetCard || targetCard === draggedCard) return;

      const targetBox = targetCard.getBoundingClientRect();
      const shouldPlaceAfter = event.clientY &gt; targetBox.top + targetBox.height / 2;

      clearOverStates();
      targetCard.classList.add("is-over");

      if (shouldPlaceAfter) {
        targetCard.insertAdjacentElement("afterend", draggedCard);
      } else {
        targetCard.insertAdjacentElement("beforebegin", draggedCard);
      }

      updateOrder();
    });

    grid.addEventListener("drop", function (event) {
      event.preventDefault();
      clearOverStates();

      if (draggedCard) {
        draggedCard.classList.remove("is-dragging");
      }

      draggedCard = null;
      updateOrder();
    });

    grid.addEventListener("dragend", function () {
      clearOverStates();

      if (draggedCard) {
        draggedCard.classList.remove("is-dragging");
      }

      draggedCard = null;
      updateOrder();
    });

    updateOrder();
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initGallerySort);
  } else {
    initGallerySort();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-galsort-demo"&gt;
  &lt;div class="vb-galsort-wrap" data-vb-galsort&gt;
    &lt;div class="vb-galsort-head"&gt;
      &lt;span&gt;Example 05&lt;/span&gt;
      &lt;h3&gt;Reorder Image Gallery&lt;/h3&gt;
      &lt;p&gt;Drag the small handle on any gallery card to reorder the grid. The numbers update automatically.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-galsort-toolbar"&gt;
      &lt;span&gt;Gallery order&lt;/span&gt;
      &lt;strong data-vb-galsort-output&gt;1 → 2 → 3 → 4 → 5 → 6&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-galsort-grid" data-vb-galsort-grid&gt;
      &lt;article class="vb-galsort-card" data-vb-galsort-card&gt;
        &lt;span class="vb-galsort-handle" draggable="true" data-vb-galsort-handle&gt;⋮⋮&lt;/span&gt;
        &lt;div class="vb-galsort-art vb-galsort-art-one"&gt;&lt;/div&gt;
        &lt;div class="vb-galsort-body"&gt;
          &lt;strong data-vb-galsort-number&gt;1&lt;/strong&gt;
          &lt;div&gt;
            &lt;h4&gt;Hero Product Image&lt;/h4&gt;
            &lt;p&gt;Main ecommerce image&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-galsort-card" data-vb-galsort-card&gt;
        &lt;span class="vb-galsort-handle" draggable="true" data-vb-galsort-handle&gt;⋮⋮&lt;/span&gt;
        &lt;div class="vb-galsort-art vb-galsort-art-two"&gt;&lt;/div&gt;
        &lt;div class="vb-galsort-body"&gt;
          &lt;strong data-vb-galsort-number&gt;2&lt;/strong&gt;
          &lt;div&gt;
            &lt;h4&gt;Detail Closeup&lt;/h4&gt;
            &lt;p&gt;Texture and material&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-galsort-card" data-vb-galsort-card&gt;
        &lt;span class="vb-galsort-handle" draggable="true" data-vb-galsort-handle&gt;⋮⋮&lt;/span&gt;
        &lt;div class="vb-galsort-art vb-galsort-art-three"&gt;&lt;/div&gt;
        &lt;div class="vb-galsort-body"&gt;
          &lt;strong data-vb-galsort-number&gt;3&lt;/strong&gt;
          &lt;div&gt;
            &lt;h4&gt;Lifestyle Scene&lt;/h4&gt;
            &lt;p&gt;Real usage example&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-galsort-card" data-vb-galsort-card&gt;
        &lt;span class="vb-galsort-handle" draggable="true" data-vb-galsort-handle&gt;⋮⋮&lt;/span&gt;
        &lt;div class="vb-galsort-art vb-galsort-art-four"&gt;&lt;/div&gt;
        &lt;div class="vb-galsort-body"&gt;
          &lt;strong data-vb-galsort-number&gt;4&lt;/strong&gt;
          &lt;div&gt;
            &lt;h4&gt;Package Preview&lt;/h4&gt;
            &lt;p&gt;Box and contents&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-galsort-card" data-vb-galsort-card&gt;
        &lt;span class="vb-galsort-handle" draggable="true" data-vb-galsort-handle&gt;⋮⋮&lt;/span&gt;
        &lt;div class="vb-galsort-art vb-galsort-art-five"&gt;&lt;/div&gt;
        &lt;div class="vb-galsort-body"&gt;
          &lt;strong data-vb-galsort-number&gt;5&lt;/strong&gt;
          &lt;div&gt;
            &lt;h4&gt;Mobile Crop&lt;/h4&gt;
            &lt;p&gt;Social preview image&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-galsort-card" data-vb-galsort-card&gt;
        &lt;span class="vb-galsort-handle" draggable="true" data-vb-galsort-handle&gt;⋮⋮&lt;/span&gt;
        &lt;div class="vb-galsort-art vb-galsort-art-six"&gt;&lt;/div&gt;
        &lt;div class="vb-galsort-body"&gt;
          &lt;strong data-vb-galsort-number&gt;6&lt;/strong&gt;
          &lt;div&gt;
            &lt;h4&gt;Gallery Thumbnail&lt;/h4&gt;
            &lt;p&gt;Small preview card&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-galsort-demo,
.vb-galsort-demo * {
  box-sizing: border-box;
}

.vb-galsort-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 12% 18%, rgba(59, 130, 246, 0.18), transparent 34%),
    radial-gradient(circle at 88% 12%, rgba(16, 185, 129, 0.18), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-galsort-wrap {
  max-width: 1160px;
  margin: 0 auto;
}

.vb-galsort-head {
  display: grid;
  gap: 12px;
  max-width: 780px;
  margin-bottom: 20px;
}

.vb-galsort-head span {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-galsort-head h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-galsort-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-galsort-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 16px;
  padding: 14px 16px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.07);
}

.vb-galsort-toolbar span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-galsort-toolbar strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-galsort-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-galsort-card {
  position: relative;
  overflow: hidden;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.10);
  transition: opacity 0.2s ease, transform 0.2s ease, border-color 0.2s ease;
}

.vb-galsort-card.is-dragging {
  opacity: 0.42;
  transform: scale(0.98);
  border-color: rgba(37, 99, 235, 0.70);
}

.vb-galsort-card.is-over {
  border-color: rgba(249, 115, 22, 0.85);
}

.vb-galsort-handle {
  position: absolute;
  z-index: 5;
  top: 12px;
  left: 12px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: rgba(15, 23, 42, 0.78);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  font-weight: 950;
  cursor: grab;
  user-select: none;
  backdrop-filter: blur(10px);
}

.vb-galsort-handle:active {
  cursor: grabbing;
}

.vb-galsort-art {
  min-height: 190px;
  position: relative;
  overflow: hidden;
}

.vb-galsort-art::before,
.vb-galsort-art::after {
  content: "";
  position: absolute;
  border-radius: 999px;
  background: rgba(255,255,255,0.30);
}

.vb-galsort-art::before {
  width: 90px;
  height: 90px;
  left: 24px;
  top: 28px;
}

.vb-galsort-art::after {
  width: 160px;
  height: 160px;
  right: -38px;
  bottom: -48px;
}

.vb-galsort-art-one {
  background: linear-gradient(135deg, #2563eb, #7c3aed);
}

.vb-galsort-art-two {
  background: linear-gradient(135deg, #db2777, #f97316);
}

.vb-galsort-art-three {
  background: linear-gradient(135deg, #059669, #0ea5e9);
}

.vb-galsort-art-four {
  background: linear-gradient(135deg, #111827, #475569);
}

.vb-galsort-art-five {
  background: linear-gradient(135deg, #7c2d12, #f59e0b);
}

.vb-galsort-art-six {
  background: linear-gradient(135deg, #4338ca, #06b6d4);
}

.vb-galsort-body {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 16px;
}

.vb-galsort-body strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-galsort-body h4 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px !important;
  line-height: 1.25 !important;
  font-weight: 900 !important;
}

.vb-galsort-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-galsort-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .vb-galsort-grid {
    grid-template-columns: 1fr;
  }

  .vb-galsort-toolbar {
    display: grid;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript reorderable image gallery is useful for ecommerce image order tools, portfolio galleries, media libraries, product admin panels, landing page builders, and visual content management systems.</p>



<h2 class="wp-block-heading">6. Drag and Drop Shopping Cart</h2>



<p class="wp-block-paragraph"><strong>A drag and drop shopping cart</strong> is a practical JavaScript drag and drop example for ecommerce stores, quote builders, bundle builders, product configurators, quick order tools, and interactive sales pages. Users can drag a product handle into the cart area, and JavaScript updates the cart automatically.</p>



<p class="wp-block-paragraph">This example does not use the native HTML5 drag and drop API. Instead, it uses mouse and touch events, a floating ghost card, drop zone detection, quantity updates, remove buttons, and automatic cart total calculation.</p>



<ul class="wp-block-list">
<li>Works with mouse and touch</li>
<li>No external libraries</li>
<li>No HTML5 draggable API</li>
<li>Drag product handle into cart</li>
<li>Quantity and total update automatically</li>
<li>Fully responsive layout</li>
</ul>



<div class="vbdc-demo">
  <div class="vbdc-wrap" data-vbdc-cart>
    <div class="vbdc-head">
      <span>Example 06</span>
      <h3>Drag and Drop Shopping Cart</h3>
      <p>Grab the orange handle and drag a product into the cart. The cart updates quantities, item count, and total price automatically.</p>
    </div>

    <div class="vbdc-layout">
      <div class="vbdc-products">
        <article class="vbdc-product" data-vbdc-product data-id="starter-kit" data-name="Starter UI Kit" data-price="29">
          <button class="vbdc-handle" type="button" data-vbdc-handle aria-label="Drag Starter UI Kit">⋮⋮</button>
          <div class="vbdc-art vbdc-art-blue"></div>
          <div class="vbdc-product-text">
            <h4>Starter UI Kit</h4>
            <p>Reusable website sections</p>
            <strong>€29</strong>
          </div>
        </article>

        <article class="vbdc-product" data-vbdc-product data-id="dashboard-widgets" data-name="Dashboard Widgets" data-price="49">
          <button class="vbdc-handle" type="button" data-vbdc-handle aria-label="Drag Dashboard Widgets">⋮⋮</button>
          <div class="vbdc-art vbdc-art-green"></div>
          <div class="vbdc-product-text">
            <h4>Dashboard Widgets</h4>
            <p>Admin interface blocks</p>
            <strong>€49</strong>
          </div>
        </article>

        <article class="vbdc-product" data-vbdc-product data-id="ecommerce-cards" data-name="Ecommerce Cards" data-price="39">
          <button class="vbdc-handle" type="button" data-vbdc-handle aria-label="Drag Ecommerce Cards">⋮⋮</button>
          <div class="vbdc-art vbdc-art-orange"></div>
          <div class="vbdc-product-text">
            <h4>Ecommerce Cards</h4>
            <p>Product and pricing UI</p>
            <strong>€39</strong>
          </div>
        </article>

        <article class="vbdc-product" data-vbdc-product data-id="form-components" data-name="Form Components" data-price="25">
          <button class="vbdc-handle" type="button" data-vbdc-handle aria-label="Drag Form Components">⋮⋮</button>
          <div class="vbdc-art vbdc-art-pink"></div>
          <div class="vbdc-product-text">
            <h4>Form Components</h4>
            <p>Inputs and validation UI</p>
            <strong>€25</strong>
          </div>
        </article>
      </div>

      <aside class="vbdc-cart">
        <div class="vbdc-cart-head">
          <div>
            <span>Drop zone</span>
            <h4>Your Cart</h4>
          </div>
          <strong data-vbdc-count>0 items</strong>
        </div>

        <div class="vbdc-drop" data-vbdc-drop>
          <p data-vbdc-empty>Drag product handles here to add items to the cart.</p>
          <div class="vbdc-list" data-vbdc-list></div>
        </div>

        <div class="vbdc-total">
          <span>Total</span>
          <strong data-vbdc-total>€0</strong>
        </div>
      </aside>
    </div>
  </div>
</div>

<style>
.vbdc-demo,
.vbdc-demo * {
  box-sizing: border-box;
}

.vbdc-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(249, 115, 22, 0.18), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(37, 99, 235, 0.18), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #eff6ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
  overflow: hidden;
}

.vbdc-wrap {
  max-width: 1160px;
  margin: 0 auto;
}

.vbdc-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vbdc-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vbdc-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vbdc-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vbdc-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(320px, 0.78fr);
  gap: 18px;
  align-items: stretch;
}

.vbdc-products {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
}

.vbdc-product {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr);
  gap: 14px;
  align-items: center;
  min-width: 0;
  padding: 16px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.25);
  box-shadow: 0 16px 44px rgba(15, 23, 42, 0.08);
  transition: opacity 0.18s ease, transform 0.18s ease, border-color 0.18s ease;
}

.vbdc-product.is-dragging {
  opacity: 0.48;
  transform: scale(0.985);
  border-color: rgba(249, 115, 22, 0.78);
}

.vbdc-handle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 54px;
  border: 0;
  border-radius: 16px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 21px;
  font-weight: 950;
  cursor: grab;
  user-select: none;
  touch-action: none;
  line-height: 1;
}

.vbdc-handle:active {
  cursor: grabbing;
}

.vbdc-art {
  width: 76px;
  height: 76px;
  border-radius: 22px;
  flex: 0 0 auto;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.32);
}

.vbdc-art-blue {
  background: linear-gradient(135deg, #2563eb, #7c3aed);
}

.vbdc-art-green {
  background: linear-gradient(135deg, #059669, #0ea5e9);
}

.vbdc-art-orange {
  background: linear-gradient(135deg, #f97316, #db2777);
}

.vbdc-art-pink {
  background: linear-gradient(135deg, #be185d, #7c3aed);
}

.vbdc-product-text {
  min-width: 0;
}

.vbdc-product-text h4 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
}

.vbdc-product-text p {
  margin: 0 0 8px !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 700;
}

.vbdc-product-text strong {
  color: #ea580c !important;
  -webkit-text-fill-color: #ea580c !important;
  font-size: 18px;
  line-height: 1;
  font-weight: 950;
}

.vbdc-cart {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
  padding: 18px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 211, 238, 0.20), transparent 36%),
    linear-gradient(135deg, #0f172a, #1e1b4b) !important;
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.24);
}

.vbdc-cart-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.vbdc-cart-head span {
  display: block;
  margin-bottom: 5px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vbdc-cart-head h4 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 28px !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.05em;
}

.vbdc-cart-head > strong {
  display: inline-flex;
  min-width: 82px;
  justify-content: center;
  padding: 9px 12px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.12);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
  white-space: nowrap;
}

.vbdc-drop {
  flex: 1;
  min-height: 260px;
  padding: 14px;
  border-radius: 24px;
  border: 1px dashed rgba(255, 255, 255, 0.32);
  background: rgba(255, 255, 255, 0.08);
  transition: background 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
}

.vbdc-drop.is-over {
  border-color: rgba(251, 146, 60, 0.95);
  background: rgba(249, 115, 22, 0.18);
  box-shadow: inset 0 0 0 4px rgba(249, 115, 22, 0.14);
}

.vbdc-drop > p {
  margin: 0 !important;
  padding: 18px;
  border-radius: 18px;
  background: rgba(255, 255, 255, 0.10);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 750;
  text-align: center;
}

.vbdc-list {
  display: grid;
  gap: 10px;
}

.vbdc-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  padding: 13px;
  border-radius: 18px;
  background: rgba(255, 255, 255, 0.12);
  border: 1px solid rgba(255, 255, 255, 0.13);
}

.vbdc-row strong {
  display: block;
  margin-bottom: 4px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.25;
  font-weight: 900;
}

.vbdc-row span {
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 750;
}

.vbdc-remove {
  width: 34px;
  height: 34px;
  border: 0;
  border-radius: 999px;
  background: rgba(248, 113, 113, 0.20);
  color: #fecaca !important;
  -webkit-text-fill-color: #fecaca !important;
  font-size: 18px;
  font-weight: 950;
  cursor: pointer;
}

.vbdc-total {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 16px;
  border-radius: 22px;
  background: rgba(255, 255, 255, 0.12);
  border: 1px solid rgba(255, 255, 255, 0.14);
}

.vbdc-total span {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vbdc-total strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 36px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vbdc-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(280px, calc(100vw - 32px));
  padding: 14px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(249, 115, 22, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
  transform: rotate(1deg);
}

.vbdc-ghost strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  line-height: 1.25;
  font-weight: 950;
}

.vbdc-ghost span {
  display: block;
  margin-top: 4px;
  color: #ea580c !important;
  -webkit-text-fill-color: #ea580c !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vbdc-layout {
    grid-template-columns: 1fr;
  }

  .vbdc-drop {
    min-height: 220px;
  }
}

@media (max-width: 640px) {
  .vbdc-products {
    grid-template-columns: 1fr;
  }

  .vbdc-product {
    grid-template-columns: auto auto minmax(0, 1fr);
    gap: 12px;
    padding: 14px;
  }

  .vbdc-art {
    width: 64px;
    height: 64px;
    border-radius: 18px;
  }

  .vbdc-cart-head {
    align-items: flex-start;
  }

  .vbdc-cart-head h4 {
    font-size: 24px !important;
  }
}

@media (max-width: 420px) {
  .vbdc-product {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .vbdc-art {
    display: none;
  }
}
</style>

<script>
(function () {
  function initVbdcCart() {
    const demos = document.querySelectorAll("[data-vbdc-cart]");

    demos.forEach(function (root) {
      if (root.getAttribute("data-vbdc-ready") === "1") return;
      root.setAttribute("data-vbdc-ready", "1");

      const drop = root.querySelector("[data-vbdc-drop]");
      const list = root.querySelector("[data-vbdc-list]");
      const totalEl = root.querySelector("[data-vbdc-total]");
      const countEl = root.querySelector("[data-vbdc-count]");
      const emptyEl = root.querySelector("[data-vbdc-empty]");

      let cart = [];
      let activeProduct = null;
      let ghost = null;
      let lastX = 0;
      let lastY = 0;

      function formatPrice(value) {
        return "€" + Number(value).toFixed(0);
      }

      function getPoint(event) {
        if (event.touches && event.touches.length) {
          return {
            x: event.touches[0].clientX,
            y: event.touches[0].clientY
          };
        }

        if (event.changedTouches && event.changedTouches.length) {
          return {
            x: event.changedTouches[0].clientX,
            y: event.changedTouches[0].clientY
          };
        }

        return {
          x: event.clientX,
          y: event.clientY
        };
      }

      function getProductData(product) {
        return {
          id: product.getAttribute("data-id"),
          name: product.getAttribute("data-name"),
          price: Number(product.getAttribute("data-price"))
        };
      }

      function isOverDrop(x, y) {
        const element = document.elementFromPoint(x, y);
        return !!(element && element.closest("[data-vbdc-drop]") === drop);
      }

      function renderCart() {
        list.innerHTML = "";

        let total = 0;
        let count = 0;

        cart.forEach(function (item) {
          total += item.price * item.quantity;
          count += item.quantity;

          const row = document.createElement("div");
          row.className = "vbdc-row";

          const info = document.createElement("div");
          const title = document.createElement("strong");
          const meta = document.createElement("span");
          const remove = document.createElement("button");

          title.textContent = item.name;
          meta.textContent = item.quantity + " × " + formatPrice(item.price);

          remove.type = "button";
          remove.className = "vbdc-remove";
          remove.textContent = "×";
          remove.setAttribute("aria-label", "Remove " + item.name);
          remove.setAttribute("data-vbdc-remove", item.id);

          info.appendChild(title);
          info.appendChild(meta);
          row.appendChild(info);
          row.appendChild(remove);
          list.appendChild(row);
        });

        totalEl.textContent = formatPrice(total);
        countEl.textContent = count === 1 ? "1 item" : count + " items";
        emptyEl.style.display = cart.length > 0 ? "none" : "block";
      }

      function addToCart(productData) {
        const existing = cart.find(function (item) {
          return item.id === productData.id;
        });

        if (existing) {
          existing.quantity += 1;
        } else {
          cart.push({
            id: productData.id,
            name: productData.name,
            price: productData.price,
            quantity: 1
          });
        }

        renderCart();
      }

      function createGhost(productData, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vbdc-ghost";

        const name = document.createElement("strong");
        const price = document.createElement("span");

        name.textContent = productData.name;
        price.textContent = formatPrice(productData.price);

        ghost.appendChild(name);
        ghost.appendChild(price);
        document.body.appendChild(ghost);

        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function startDrag(event) {
        const handle = event.target.closest("[data-vbdc-handle]");
        if (!handle) return;

        const product = handle.closest("[data-vbdc-product]");
        if (!product) return;

        event.preventDefault();

        const point = getPoint(event);

        activeProduct = product;
        lastX = point.x;
        lastY = point.y;

        activeProduct.classList.add("is-dragging");
        createGhost(getProductData(activeProduct), lastX, lastY);

        document.addEventListener("mousemove", moveDrag);
        document.addEventListener("mouseup", endDrag);
        document.addEventListener("touchmove", moveDrag, { passive: false });
        document.addEventListener("touchend", endDrag);
        document.addEventListener("touchcancel", cancelDrag);
      }

      function moveDrag(event) {
        if (!activeProduct) return;

        event.preventDefault();

        const point = getPoint(event);

        lastX = point.x;
        lastY = point.y;

        moveGhost(lastX, lastY);

        if (isOverDrop(lastX, lastY)) {
          drop.classList.add("is-over");
        } else {
          drop.classList.remove("is-over");
        }
      }

      function endDrag(event) {
        if (!activeProduct) return;

        const point = getPoint(event);

        lastX = point.x;
        lastY = point.y;

        if (isOverDrop(lastX, lastY)) {
          addToCart(getProductData(activeProduct));
        }

        cleanupDrag();
      }

      function cancelDrag() {
        cleanupDrag();
      }

      function cleanupDrag() {
        if (activeProduct) {
          activeProduct.classList.remove("is-dragging");
        }

        if (ghost) {
          ghost.remove();
        }

        activeProduct = null;
        ghost = null;
        drop.classList.remove("is-over");

        document.removeEventListener("mousemove", moveDrag);
        document.removeEventListener("mouseup", endDrag);
        document.removeEventListener("touchmove", moveDrag);
        document.removeEventListener("touchend", endDrag);
        document.removeEventListener("touchcancel", cancelDrag);
      }

      root.addEventListener("mousedown", startDrag);
      root.addEventListener("touchstart", startDrag, { passive: false });

      list.addEventListener("click", function (event) {
        const button = event.target.closest("[data-vbdc-remove]");
        if (!button) return;

        const id = button.getAttribute("data-vbdc-remove");

        cart = cart.filter(function (item) {
          return item.id !== id;
        });

        renderCart();
      });

      renderCart();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initVbdcCart);
  } else {
    initVbdcCart();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initVbdcCart() {
    const demos = document.querySelectorAll("[data-vbdc-cart]");

    demos.forEach(function (root) {
      if (root.getAttribute("data-vbdc-ready") === "1") return;
      root.setAttribute("data-vbdc-ready", "1");

      const drop = root.querySelector("[data-vbdc-drop]");
      const list = root.querySelector("[data-vbdc-list]");
      const totalEl = root.querySelector("[data-vbdc-total]");
      const countEl = root.querySelector("[data-vbdc-count]");
      const emptyEl = root.querySelector("[data-vbdc-empty]");

      let cart = [];
      let activeProduct = null;
      let ghost = null;
      let lastX = 0;
      let lastY = 0;

      function formatPrice(value) {
        return "€" + Number(value).toFixed(0);
      }

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) {
          return {
            x: event.touches[0].clientX,
            y: event.touches[0].clientY
          };
        }

        if (event.changedTouches &amp;&amp; event.changedTouches.length) {
          return {
            x: event.changedTouches[0].clientX,
            y: event.changedTouches[0].clientY
          };
        }

        return {
          x: event.clientX,
          y: event.clientY
        };
      }

      function getProductData(product) {
        return {
          id: product.getAttribute("data-id"),
          name: product.getAttribute("data-name"),
          price: Number(product.getAttribute("data-price"))
        };
      }

      function isOverDrop(x, y) {
        const element = document.elementFromPoint(x, y);
        return !!(element &amp;&amp; element.closest("[data-vbdc-drop]") === drop);
      }

      function renderCart() {
        list.innerHTML = "";

        let total = 0;
        let count = 0;

        cart.forEach(function (item) {
          total += item.price * item.quantity;
          count += item.quantity;

          const row = document.createElement("div");
          row.className = "vbdc-row";

          const info = document.createElement("div");
          const title = document.createElement("strong");
          const meta = document.createElement("span");
          const remove = document.createElement("button");

          title.textContent = item.name;
          meta.textContent = item.quantity + " × " + formatPrice(item.price);

          remove.type = "button";
          remove.className = "vbdc-remove";
          remove.textContent = "×";
          remove.setAttribute("aria-label", "Remove " + item.name);
          remove.setAttribute("data-vbdc-remove", item.id);

          info.appendChild(title);
          info.appendChild(meta);
          row.appendChild(info);
          row.appendChild(remove);
          list.appendChild(row);
        });

        totalEl.textContent = formatPrice(total);
        countEl.textContent = count === 1 ? "1 item" : count + " items";
        emptyEl.style.display = cart.length &gt; 0 ? "none" : "block";
      }

      function addToCart(productData) {
        const existing = cart.find(function (item) {
          return item.id === productData.id;
        });

        if (existing) {
          existing.quantity += 1;
        } else {
          cart.push({
            id: productData.id,
            name: productData.name,
            price: productData.price,
            quantity: 1
          });
        }

        renderCart();
      }

      function createGhost(productData, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vbdc-ghost";

        const name = document.createElement("strong");
        const price = document.createElement("span");

        name.textContent = productData.name;
        price.textContent = formatPrice(productData.price);

        ghost.appendChild(name);
        ghost.appendChild(price);
        document.body.appendChild(ghost);

        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function startDrag(event) {
        const handle = event.target.closest("[data-vbdc-handle]");
        if (!handle) return;

        const product = handle.closest("[data-vbdc-product]");
        if (!product) return;

        event.preventDefault();

        const point = getPoint(event);

        activeProduct = product;
        lastX = point.x;
        lastY = point.y;

        activeProduct.classList.add("is-dragging");
        createGhost(getProductData(activeProduct), lastX, lastY);

        document.addEventListener("mousemove", moveDrag);
        document.addEventListener("mouseup", endDrag);
        document.addEventListener("touchmove", moveDrag, { passive: false });
        document.addEventListener("touchend", endDrag);
        document.addEventListener("touchcancel", cancelDrag);
      }

      function moveDrag(event) {
        if (!activeProduct) return;

        event.preventDefault();

        const point = getPoint(event);

        lastX = point.x;
        lastY = point.y;

        moveGhost(lastX, lastY);

        if (isOverDrop(lastX, lastY)) {
          drop.classList.add("is-over");
        } else {
          drop.classList.remove("is-over");
        }
      }

      function endDrag(event) {
        if (!activeProduct) return;

        const point = getPoint(event);

        lastX = point.x;
        lastY = point.y;

        if (isOverDrop(lastX, lastY)) {
          addToCart(getProductData(activeProduct));
        }

        cleanupDrag();
      }

      function cancelDrag() {
        cleanupDrag();
      }

      function cleanupDrag() {
        if (activeProduct) {
          activeProduct.classList.remove("is-dragging");
        }

        if (ghost) {
          ghost.remove();
        }

        activeProduct = null;
        ghost = null;
        drop.classList.remove("is-over");

        document.removeEventListener("mousemove", moveDrag);
        document.removeEventListener("mouseup", endDrag);
        document.removeEventListener("touchmove", moveDrag);
        document.removeEventListener("touchend", endDrag);
        document.removeEventListener("touchcancel", cancelDrag);
      }

      root.addEventListener("mousedown", startDrag);
      root.addEventListener("touchstart", startDrag, { passive: false });

      list.addEventListener("click", function (event) {
        const button = event.target.closest("[data-vbdc-remove]");
        if (!button) return;

        const id = button.getAttribute("data-vbdc-remove");

        cart = cart.filter(function (item) {
          return item.id !== id;
        });

        renderCart();
      });

      renderCart();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initVbdcCart);
  } else {
    initVbdcCart();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vbdc-demo"&gt;
  &lt;div class="vbdc-wrap" data-vbdc-cart&gt;
    &lt;div class="vbdc-head"&gt;
      &lt;span&gt;Example 06&lt;/span&gt;
      &lt;h3&gt;Drag and Drop Shopping Cart&lt;/h3&gt;
      &lt;p&gt;Grab the orange handle and drag a product into the cart. The cart updates quantities, item count, and total price automatically.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vbdc-layout"&gt;
      &lt;div class="vbdc-products"&gt;
        &lt;article class="vbdc-product" data-vbdc-product data-id="starter-kit" data-name="Starter UI Kit" data-price="29"&gt;
          &lt;button class="vbdc-handle" type="button" data-vbdc-handle aria-label="Drag Starter UI Kit"&gt;⋮⋮&lt;/button&gt;
          &lt;div class="vbdc-art vbdc-art-blue"&gt;&lt;/div&gt;
          &lt;div class="vbdc-product-text"&gt;
            &lt;h4&gt;Starter UI Kit&lt;/h4&gt;
            &lt;p&gt;Reusable website sections&lt;/p&gt;
            &lt;strong&gt;€29&lt;/strong&gt;
          &lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vbdc-product" data-vbdc-product data-id="dashboard-widgets" data-name="Dashboard Widgets" data-price="49"&gt;
          &lt;button class="vbdc-handle" type="button" data-vbdc-handle aria-label="Drag Dashboard Widgets"&gt;⋮⋮&lt;/button&gt;
          &lt;div class="vbdc-art vbdc-art-green"&gt;&lt;/div&gt;
          &lt;div class="vbdc-product-text"&gt;
            &lt;h4&gt;Dashboard Widgets&lt;/h4&gt;
            &lt;p&gt;Admin interface blocks&lt;/p&gt;
            &lt;strong&gt;€49&lt;/strong&gt;
          &lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vbdc-product" data-vbdc-product data-id="ecommerce-cards" data-name="Ecommerce Cards" data-price="39"&gt;
          &lt;button class="vbdc-handle" type="button" data-vbdc-handle aria-label="Drag Ecommerce Cards"&gt;⋮⋮&lt;/button&gt;
          &lt;div class="vbdc-art vbdc-art-orange"&gt;&lt;/div&gt;
          &lt;div class="vbdc-product-text"&gt;
            &lt;h4&gt;Ecommerce Cards&lt;/h4&gt;
            &lt;p&gt;Product and pricing UI&lt;/p&gt;
            &lt;strong&gt;€39&lt;/strong&gt;
          &lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vbdc-product" data-vbdc-product data-id="form-components" data-name="Form Components" data-price="25"&gt;
          &lt;button class="vbdc-handle" type="button" data-vbdc-handle aria-label="Drag Form Components"&gt;⋮⋮&lt;/button&gt;
          &lt;div class="vbdc-art vbdc-art-pink"&gt;&lt;/div&gt;
          &lt;div class="vbdc-product-text"&gt;
            &lt;h4&gt;Form Components&lt;/h4&gt;
            &lt;p&gt;Inputs and validation UI&lt;/p&gt;
            &lt;strong&gt;€25&lt;/strong&gt;
          &lt;/div&gt;
        &lt;/article&gt;
      &lt;/div&gt;

      &lt;aside class="vbdc-cart"&gt;
        &lt;div class="vbdc-cart-head"&gt;
          &lt;div&gt;
            &lt;span&gt;Drop zone&lt;/span&gt;
            &lt;h4&gt;Your Cart&lt;/h4&gt;
          &lt;/div&gt;
          &lt;strong data-vbdc-count&gt;0 items&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vbdc-drop" data-vbdc-drop&gt;
          &lt;p data-vbdc-empty&gt;Drag product handles here to add items to the cart.&lt;/p&gt;
          &lt;div class="vbdc-list" data-vbdc-list&gt;&lt;/div&gt;
        &lt;/div&gt;

        &lt;div class="vbdc-total"&gt;
          &lt;span&gt;Total&lt;/span&gt;
          &lt;strong data-vbdc-total&gt;€0&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/aside&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vbdc-demo,
.vbdc-demo * {
  box-sizing: border-box;
}

.vbdc-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(249, 115, 22, 0.18), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(37, 99, 235, 0.18), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #eff6ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
  overflow: hidden;
}

.vbdc-wrap {
  max-width: 1160px;
  margin: 0 auto;
}

.vbdc-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vbdc-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vbdc-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vbdc-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vbdc-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(320px, 0.78fr);
  gap: 18px;
  align-items: stretch;
}

.vbdc-products {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
}

.vbdc-product {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr);
  gap: 14px;
  align-items: center;
  min-width: 0;
  padding: 16px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.25);
  box-shadow: 0 16px 44px rgba(15, 23, 42, 0.08);
  transition: opacity 0.18s ease, transform 0.18s ease, border-color 0.18s ease;
}

.vbdc-product.is-dragging {
  opacity: 0.48;
  transform: scale(0.985);
  border-color: rgba(249, 115, 22, 0.78);
}

.vbdc-handle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 54px;
  border: 0;
  border-radius: 16px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 21px;
  font-weight: 950;
  cursor: grab;
  user-select: none;
  touch-action: none;
  line-height: 1;
}

.vbdc-handle:active {
  cursor: grabbing;
}

.vbdc-art {
  width: 76px;
  height: 76px;
  border-radius: 22px;
  flex: 0 0 auto;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.32);
}

.vbdc-art-blue {
  background: linear-gradient(135deg, #2563eb, #7c3aed);
}

.vbdc-art-green {
  background: linear-gradient(135deg, #059669, #0ea5e9);
}

.vbdc-art-orange {
  background: linear-gradient(135deg, #f97316, #db2777);
}

.vbdc-art-pink {
  background: linear-gradient(135deg, #be185d, #7c3aed);
}

.vbdc-product-text {
  min-width: 0;
}

.vbdc-product-text h4 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
}

.vbdc-product-text p {
  margin: 0 0 8px !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 700;
}

.vbdc-product-text strong {
  color: #ea580c !important;
  -webkit-text-fill-color: #ea580c !important;
  font-size: 18px;
  line-height: 1;
  font-weight: 950;
}

.vbdc-cart {
  display: flex;
  flex-direction: column;
  gap: 14px;
  min-width: 0;
  padding: 18px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 211, 238, 0.20), transparent 36%),
    linear-gradient(135deg, #0f172a, #1e1b4b) !important;
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.24);
}

.vbdc-cart-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.vbdc-cart-head span {
  display: block;
  margin-bottom: 5px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vbdc-cart-head h4 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 28px !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.05em;
}

.vbdc-cart-head &gt; strong {
  display: inline-flex;
  min-width: 82px;
  justify-content: center;
  padding: 9px 12px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.12);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
  white-space: nowrap;
}

.vbdc-drop {
  flex: 1;
  min-height: 260px;
  padding: 14px;
  border-radius: 24px;
  border: 1px dashed rgba(255, 255, 255, 0.32);
  background: rgba(255, 255, 255, 0.08);
  transition: background 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
}

.vbdc-drop.is-over {
  border-color: rgba(251, 146, 60, 0.95);
  background: rgba(249, 115, 22, 0.18);
  box-shadow: inset 0 0 0 4px rgba(249, 115, 22, 0.14);
}

.vbdc-drop &gt; p {
  margin: 0 !important;
  padding: 18px;
  border-radius: 18px;
  background: rgba(255, 255, 255, 0.10);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 750;
  text-align: center;
}

.vbdc-list {
  display: grid;
  gap: 10px;
}

.vbdc-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  padding: 13px;
  border-radius: 18px;
  background: rgba(255, 255, 255, 0.12);
  border: 1px solid rgba(255, 255, 255, 0.13);
}

.vbdc-row strong {
  display: block;
  margin-bottom: 4px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.25;
  font-weight: 900;
}

.vbdc-row span {
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 750;
}

.vbdc-remove {
  width: 34px;
  height: 34px;
  border: 0;
  border-radius: 999px;
  background: rgba(248, 113, 113, 0.20);
  color: #fecaca !important;
  -webkit-text-fill-color: #fecaca !important;
  font-size: 18px;
  font-weight: 950;
  cursor: pointer;
}

.vbdc-total {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 16px;
  border-radius: 22px;
  background: rgba(255, 255, 255, 0.12);
  border: 1px solid rgba(255, 255, 255, 0.14);
}

.vbdc-total span {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vbdc-total strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 36px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vbdc-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(280px, calc(100vw - 32px));
  padding: 14px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(249, 115, 22, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
  transform: rotate(1deg);
}

.vbdc-ghost strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  line-height: 1.25;
  font-weight: 950;
}

.vbdc-ghost span {
  display: block;
  margin-top: 4px;
  color: #ea580c !important;
  -webkit-text-fill-color: #ea580c !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vbdc-layout {
    grid-template-columns: 1fr;
  }

  .vbdc-drop {
    min-height: 220px;
  }
}

@media (max-width: 640px) {
  .vbdc-products {
    grid-template-columns: 1fr;
  }

  .vbdc-product {
    grid-template-columns: auto auto minmax(0, 1fr);
    gap: 12px;
    padding: 14px;
  }

  .vbdc-art {
    width: 64px;
    height: 64px;
    border-radius: 18px;
  }

  .vbdc-cart-head {
    align-items: flex-start;
  }

  .vbdc-cart-head h4 {
    font-size: 24px !important;
  }
}

@media (max-width: 420px) {
  .vbdc-product {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .vbdc-art {
    display: none;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript drag and drop shopping cart is useful for ecommerce stores, quote builders, bundle builders, quick order interfaces, product configurators, landing page demos, and interactive sales tools.</p>



<div class="vb24-js-drag-contact-cta">
  <div class="vb24-js-drag-contact-content">
    <span>Need a custom JavaScript feature?</span>
    <h2>Can’t build this yourself? We can create it for your website.</h2>
    <p>If you need a custom drag and drop tool, upload interface, product builder, dashboard widget, calculator, booking feature, or interactive JavaScript component, our team can build a responsive and professional solution for your website.</p>
  </div>

  <a href="https://veebilehed24.ee/en/contact/" class="vb24-js-drag-contact-button">Contact Us</a>
</div>

<style>
.vb24-js-drag-contact-cta,
.vb24-js-drag-contact-cta * {
  box-sizing: border-box;
}

.vb24-js-drag-contact-cta {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 24px;
  align-items: center;
  margin: 42px 0;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 12% 20%, rgba(34, 211, 238, 0.22), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(249, 115, 22, 0.20), transparent 34%),
    linear-gradient(135deg, #0f172a, #312e81) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.18);
}

.vb24-js-drag-contact-content span {
  display: inline-flex;
  margin-bottom: 10px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb24-js-drag-contact-content h2 {
  margin: 0 0 10px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(26px, 4vw, 42px) !important;
  line-height: 1.05 !important;
  font-weight: 950 !important;
  letter-spacing: -0.05em;
}

.vb24-js-drag-contact-content p {
  max-width: 760px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb24-js-drag-contact-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 14px 20px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22d3ee, #2563eb 55%, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  text-decoration: none !important;
  white-space: nowrap;
  box-shadow: 0 14px 34px rgba(37, 99, 235, 0.30);
}

@media (max-width: 760px) {
  .vb24-js-drag-contact-cta {
    grid-template-columns: 1fr;
    border-radius: 24px;
  }

  .vb24-js-drag-contact-button {
    width: 100%;
  }
}
</style>



<h2 class="wp-block-heading">7. Drag Items Between Two Lists</h2>



<p class="wp-block-paragraph"><strong>Dragging items between two lists</strong> is one of the most practical JavaScript drag and drop patterns. It works well for task assignment, selected items, user permissions, comparison tools, booking systems, and admin dashboards where users move cards from one group to another.</p>



<ul class="wp-block-list">
<li>Move cards between two lists</li>
<li>Mouse and touch support</li>
<li>No native HTML5 drag and drop API</li>
<li>Live item counters</li>
<li>Responsive two-column layout</li>
</ul>



<div class="vb-two-list-demo">
  <div class="vb-two-list-wrap" data-vb-two-list>
    <div class="vb-two-list-head">
      <span>Example 07</span>
      <h3>Drag Items Between Two Lists</h3>
      <p>Grab the handle and move tasks between Available Tasks and Selected Tasks.</p>
    </div>

    <div class="vb-two-list-board">
      <section class="vb-two-list-column">
        <div class="vb-two-list-title">
          <h4>Available Tasks</h4>
          <strong data-vb-two-count="available">0</strong>
        </div>

        <div class="vb-two-list-drop" data-vb-two-drop data-list="available">
          <article class="vb-two-list-card" data-vb-two-card data-title="Design homepage hero">
            <button type="button" class="vb-two-list-handle" data-vb-two-handle>⋮⋮</button>
            <div>
              <h5>Design homepage hero</h5>
              <p>Visual UI task</p>
            </div>
          </article>

          <article class="vb-two-list-card" data-vb-two-card data-title="Write product copy">
            <button type="button" class="vb-two-list-handle" data-vb-two-handle>⋮⋮</button>
            <div>
              <h5>Write product copy</h5>
              <p>Content task</p>
            </div>
          </article>

          <article class="vb-two-list-card" data-vb-two-card data-title="Fix mobile spacing">
            <button type="button" class="vb-two-list-handle" data-vb-two-handle>⋮⋮</button>
            <div>
              <h5>Fix mobile spacing</h5>
              <p>Frontend task</p>
            </div>
          </article>
        </div>
      </section>

      <section class="vb-two-list-column">
        <div class="vb-two-list-title">
          <h4>Selected Tasks</h4>
          <strong data-vb-two-count="selected">0</strong>
        </div>

        <div class="vb-two-list-drop" data-vb-two-drop data-list="selected">
          <article class="vb-two-list-card" data-vb-two-card data-title="Connect form validation">
            <button type="button" class="vb-two-list-handle" data-vb-two-handle>⋮⋮</button>
            <div>
              <h5>Connect form validation</h5>
              <p>JavaScript task</p>
            </div>
          </article>
        </div>
      </section>
    </div>

    <div class="vb-two-list-status" data-vb-two-status>Move tasks between the lists.</div>
  </div>
</div>

<style>
.vb-two-list-demo,
.vb-two-list-demo * {
  box-sizing: border-box;
}

.vb-two-list-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(59, 130, 246, 0.18), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(16, 185, 129, 0.18), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
  overflow: hidden;
}

.vb-two-list-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-two-list-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-two-list-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-two-list-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-two-list-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-two-list-board {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
}

.vb-two-list-column {
  min-width: 0;
  padding: 16px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-two-list-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}

.vb-two-list-title h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 22px !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-two-list-title strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 38px;
  height: 34px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-two-list-drop {
  display: grid;
  gap: 12px;
  min-height: 250px;
  padding: 12px;
  border-radius: 22px;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  background: #f8fafc;
  transition: background 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
}

.vb-two-list-drop.is-over {
  border-color: rgba(37, 99, 235, 0.75);
  background: #eff6ff;
  box-shadow: inset 0 0 0 4px rgba(37, 99, 235, 0.10);
}

.vb-two-list-card {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 13px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 12px 30px rgba(15, 23, 42, 0.07);
}

.vb-two-list-card.is-dragging {
  opacity: 0.45;
}

.vb-two-list-handle {
  width: 38px;
  height: 44px;
  border: 0;
  border-radius: 14px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 20px;
  font-weight: 950;
  cursor: grab;
  user-select: none;
  touch-action: none;
}

.vb-two-list-card h5 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
}

.vb-two-list-card p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 700;
  line-height: 1.35;
}

.vb-two-list-status {
  margin-top: 16px;
  padding: 13px 15px;
  border-radius: 18px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-two-list-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(300px, calc(100vw - 32px));
  padding: 14px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(37, 99, 235, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
  transform: rotate(1deg);
}

.vb-two-list-ghost strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

@media (max-width: 760px) {
  .vb-two-list-board {
    grid-template-columns: 1fr;
  }

  .vb-two-list-drop {
    min-height: 180px;
  }
}
</style>

<script>
(function () {
  function initTwoListDrag() {
    document.querySelectorAll("[data-vb-two-list]").forEach(function (root) {
      if (root.getAttribute("data-vb-two-ready") === "1") return;
      root.setAttribute("data-vb-two-ready", "1");

      const drops = Array.from(root.querySelectorAll("[data-vb-two-drop]"));
      const status = root.querySelector("[data-vb-two-status]");

      let activeCard = null;
      let ghost = null;
      let lastX = 0;
      let lastY = 0;

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function updateCounts() {
        drops.forEach(function (drop) {
          const name = drop.getAttribute("data-list");
          const count = root.querySelector('[data-vb-two-count="' + name + '"]');
          if (count) count.textContent = drop.querySelectorAll("[data-vb-two-card]").length;
        });
      }

      function createGhost(card, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-two-list-ghost";
        ghost.innerHTML = "<strong>" + card.getAttribute("data-title") + "</strong>";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function getDropAtPoint(x, y) {
        const el = document.elementFromPoint(x, y);
        if (!el) return null;
        const drop = el.closest("[data-vb-two-drop]");
        return drops.includes(drop) ? drop : null;
      }

      function clearOver() {
        drops.forEach(function (drop) {
          drop.classList.remove("is-over");
        });
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-two-handle]");
        if (!handle) return;

        const card = handle.closest("[data-vb-two-card]");
        if (!card) return;

        event.preventDefault();

        const point = getPoint(event);
        activeCard = card;
        lastX = point.x;
        lastY = point.y;

        card.classList.add("is-dragging");
        createGhost(card, lastX, lastY);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!activeCard) return;

        event.preventDefault();

        const point = getPoint(event);
        lastX = point.x;
        lastY = point.y;

        moveGhost(lastX, lastY);
        clearOver();

        const drop = getDropAtPoint(lastX, lastY);
        if (drop) drop.classList.add("is-over");
      }

      function end(event) {
        if (!activeCard) return;

        const point = getPoint(event);
        lastX = point.x;
        lastY = point.y;

        const drop = getDropAtPoint(lastX, lastY);
        if (drop) {
          drop.appendChild(activeCard);
          status.textContent = activeCard.getAttribute("data-title") + " moved to " + drop.getAttribute("data-list") + ".";
        }

        cleanup();
        updateCounts();
      }

      function cancel() {
        cleanup();
        updateCounts();
      }

      function cleanup() {
        if (activeCard) activeCard.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        activeCard = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });

      updateCounts();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initTwoListDrag);
  } else {
    initTwoListDrag();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initTwoListDrag() {
    document.querySelectorAll("[data-vb-two-list]").forEach(function (root) {
      if (root.getAttribute("data-vb-two-ready") === "1") return;
      root.setAttribute("data-vb-two-ready", "1");

      const drops = Array.from(root.querySelectorAll("[data-vb-two-drop]"));
      const status = root.querySelector("[data-vb-two-status]");

      let activeCard = null;
      let ghost = null;
      let lastX = 0;
      let lastY = 0;

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function updateCounts() {
        drops.forEach(function (drop) {
          const name = drop.getAttribute("data-list");
          const count = root.querySelector('[data-vb-two-count="' + name + '"]');
          if (count) count.textContent = drop.querySelectorAll("[data-vb-two-card]").length;
        });
      }

      function createGhost(card, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-two-list-ghost";
        ghost.innerHTML = "&lt;strong&gt;" + card.getAttribute("data-title") + "&lt;/strong&gt;";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function getDropAtPoint(x, y) {
        const el = document.elementFromPoint(x, y);
        if (!el) return null;
        const drop = el.closest("[data-vb-two-drop]");
        return drops.includes(drop) ? drop : null;
      }

      function clearOver() {
        drops.forEach(function (drop) {
          drop.classList.remove("is-over");
        });
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-two-handle]");
        if (!handle) return;

        const card = handle.closest("[data-vb-two-card]");
        if (!card) return;

        event.preventDefault();

        const point = getPoint(event);
        activeCard = card;
        lastX = point.x;
        lastY = point.y;

        card.classList.add("is-dragging");
        createGhost(card, lastX, lastY);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!activeCard) return;

        event.preventDefault();

        const point = getPoint(event);
        lastX = point.x;
        lastY = point.y;

        moveGhost(lastX, lastY);
        clearOver();

        const drop = getDropAtPoint(lastX, lastY);
        if (drop) drop.classList.add("is-over");
      }

      function end(event) {
        if (!activeCard) return;

        const point = getPoint(event);
        lastX = point.x;
        lastY = point.y;

        const drop = getDropAtPoint(lastX, lastY);
        if (drop) {
          drop.appendChild(activeCard);
          status.textContent = activeCard.getAttribute("data-title") + " moved to " + drop.getAttribute("data-list") + ".";
        }

        cleanup();
        updateCounts();
      }

      function cancel() {
        cleanup();
        updateCounts();
      }

      function cleanup() {
        if (activeCard) activeCard.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        activeCard = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });

      updateCounts();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initTwoListDrag);
  } else {
    initTwoListDrag();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-two-list-demo"&gt;
  &lt;div class="vb-two-list-wrap" data-vb-two-list&gt;
    &lt;div class="vb-two-list-head"&gt;
      &lt;span&gt;Example 07&lt;/span&gt;
      &lt;h3&gt;Drag Items Between Two Lists&lt;/h3&gt;
      &lt;p&gt;Grab the handle and move tasks between Available Tasks and Selected Tasks.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-two-list-board"&gt;
      &lt;section class="vb-two-list-column"&gt;
        &lt;div class="vb-two-list-title"&gt;
          &lt;h4&gt;Available Tasks&lt;/h4&gt;
          &lt;strong data-vb-two-count="available"&gt;0&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-two-list-drop" data-vb-two-drop data-list="available"&gt;
          &lt;article class="vb-two-list-card" data-vb-two-card data-title="Design homepage hero"&gt;
            &lt;button type="button" class="vb-two-list-handle" data-vb-two-handle&gt;⋮⋮&lt;/button&gt;
            &lt;div&gt;
              &lt;h5&gt;Design homepage hero&lt;/h5&gt;
              &lt;p&gt;Visual UI task&lt;/p&gt;
            &lt;/div&gt;
          &lt;/article&gt;

          &lt;article class="vb-two-list-card" data-vb-two-card data-title="Write product copy"&gt;
            &lt;button type="button" class="vb-two-list-handle" data-vb-two-handle&gt;⋮⋮&lt;/button&gt;
            &lt;div&gt;
              &lt;h5&gt;Write product copy&lt;/h5&gt;
              &lt;p&gt;Content task&lt;/p&gt;
            &lt;/div&gt;
          &lt;/article&gt;

          &lt;article class="vb-two-list-card" data-vb-two-card data-title="Fix mobile spacing"&gt;
            &lt;button type="button" class="vb-two-list-handle" data-vb-two-handle&gt;⋮⋮&lt;/button&gt;
            &lt;div&gt;
              &lt;h5&gt;Fix mobile spacing&lt;/h5&gt;
              &lt;p&gt;Frontend task&lt;/p&gt;
            &lt;/div&gt;
          &lt;/article&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-two-list-column"&gt;
        &lt;div class="vb-two-list-title"&gt;
          &lt;h4&gt;Selected Tasks&lt;/h4&gt;
          &lt;strong data-vb-two-count="selected"&gt;0&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-two-list-drop" data-vb-two-drop data-list="selected"&gt;
          &lt;article class="vb-two-list-card" data-vb-two-card data-title="Connect form validation"&gt;
            &lt;button type="button" class="vb-two-list-handle" data-vb-two-handle&gt;⋮⋮&lt;/button&gt;
            &lt;div&gt;
              &lt;h5&gt;Connect form validation&lt;/h5&gt;
              &lt;p&gt;JavaScript task&lt;/p&gt;
            &lt;/div&gt;
          &lt;/article&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;

    &lt;div class="vb-two-list-status" data-vb-two-status&gt;Move tasks between the lists.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-two-list-demo,
.vb-two-list-demo * {
  box-sizing: border-box;
}

.vb-two-list-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(59, 130, 246, 0.18), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(16, 185, 129, 0.18), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
  overflow: hidden;
}

.vb-two-list-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-two-list-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-two-list-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-two-list-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-two-list-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-two-list-board {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
}

.vb-two-list-column {
  min-width: 0;
  padding: 16px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-two-list-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}

.vb-two-list-title h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 22px !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-two-list-title strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 38px;
  height: 34px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-two-list-drop {
  display: grid;
  gap: 12px;
  min-height: 250px;
  padding: 12px;
  border-radius: 22px;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  background: #f8fafc;
  transition: background 0.18s ease, border-color 0.18s ease, box-shadow 0.18s ease;
}

.vb-two-list-drop.is-over {
  border-color: rgba(37, 99, 235, 0.75);
  background: #eff6ff;
  box-shadow: inset 0 0 0 4px rgba(37, 99, 235, 0.10);
}

.vb-two-list-card {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 13px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 12px 30px rgba(15, 23, 42, 0.07);
}

.vb-two-list-card.is-dragging {
  opacity: 0.45;
}

.vb-two-list-handle {
  width: 38px;
  height: 44px;
  border: 0;
  border-radius: 14px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 20px;
  font-weight: 950;
  cursor: grab;
  user-select: none;
  touch-action: none;
}

.vb-two-list-card h5 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
}

.vb-two-list-card p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 700;
  line-height: 1.35;
}

.vb-two-list-status {
  margin-top: 16px;
  padding: 13px 15px;
  border-radius: 18px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-two-list-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(300px, calc(100vw - 32px));
  padding: 14px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(37, 99, 235, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
  transform: rotate(1deg);
}

.vb-two-list-ghost strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

@media (max-width: 760px) {
  .vb-two-list-board {
    grid-template-columns: 1fr;
  }

  .vb-two-list-drop {
    min-height: 180px;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript drag and drop two-list interface is useful for task managers, selected item builders, permission panels, comparison tools, admin dashboards, and booking interfaces.</p>



<h2 class="wp-block-heading">8. Priority List Drag and Drop Sorter</h2>



<p class="wp-block-paragraph"><strong>A priority list drag and drop sorter</strong> lets users reorder tasks by importance. This pattern is useful for project management tools, support queues, editorial calendars, dashboard widgets, admin panels, and productivity apps.</p>



<ul class="wp-block-list">
<li>Sort tasks by priority</li>
<li>Mouse and touch support</li>
<li>Automatic priority numbers</li>
<li>Live top-priority label</li>
<li>No external libraries</li>
</ul>



<div class="vb-priority-demo">
  <div class="vb-priority-wrap" data-vb-priority>
    <div class="vb-priority-head">
      <span>Example 08</span>
      <h3>Priority List Sorter</h3>
      <p>Drag the handle to reorder tasks. The first item becomes the top priority.</p>
    </div>

    <div class="vb-priority-panel">
      <div class="vb-priority-list" data-vb-priority-list>
        <article class="vb-priority-item" data-vb-priority-item data-task="Fix checkout error">
          <button type="button" class="vb-priority-handle" data-vb-priority-handle>⋮⋮</button>
          <strong data-vb-priority-number>1</strong>
          <div>
            <h4>Fix checkout error</h4>
            <p>Critical ecommerce issue</p>
          </div>
          <span>High</span>
        </article>

        <article class="vb-priority-item" data-vb-priority-item data-task="Update mobile menu">
          <button type="button" class="vb-priority-handle" data-vb-priority-handle>⋮⋮</button>
          <strong data-vb-priority-number>2</strong>
          <div>
            <h4>Update mobile menu</h4>
            <p>Navigation improvement</p>
          </div>
          <span>Medium</span>
        </article>

        <article class="vb-priority-item" data-vb-priority-item data-task="Write FAQ section">
          <button type="button" class="vb-priority-handle" data-vb-priority-handle>⋮⋮</button>
          <strong data-vb-priority-number>3</strong>
          <div>
            <h4>Write FAQ section</h4>
            <p>SEO content task</p>
          </div>
          <span>Low</span>
        </article>

        <article class="vb-priority-item" data-vb-priority-item data-task="Compress hero images">
          <button type="button" class="vb-priority-handle" data-vb-priority-handle>⋮⋮</button>
          <strong data-vb-priority-number>4</strong>
          <div>
            <h4>Compress hero images</h4>
            <p>Performance task</p>
          </div>
          <span>Medium</span>
        </article>
      </div>

      <aside class="vb-priority-summary">
        <span>Top priority</span>
        <strong data-vb-priority-top>Fix checkout error</strong>
        <p>The list updates instantly when the order changes.</p>
      </aside>
    </div>
  </div>
</div>

<style>
.vb-priority-demo,
.vb-priority-demo * {
  box-sizing: border-box;
}

.vb-priority-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(244, 63, 94, 0.16), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(249, 115, 22, 0.18), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #fff7ed 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-priority-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-priority-head {
  max-width: 760px;
  margin-bottom: 22px;
}

.vb-priority-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-priority-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-priority-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-priority-panel {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(260px, 0.8fr);
  gap: 16px;
  align-items: stretch;
}

.vb-priority-list {
  display: grid;
  gap: 12px;
  min-width: 0;
  padding: 16px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-priority-item {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  padding: 14px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 12px 30px rgba(15, 23, 42, 0.06);
}

.vb-priority-item.is-dragging {
  opacity: 0.45;
}

.vb-priority-item.is-over {
  border-color: rgba(244, 63, 94, 0.70);
  background: #fff1f2;
}

.vb-priority-handle {
  width: 38px;
  height: 44px;
  border: 0;
  border-radius: 14px;
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 20px;
  font-weight: 950;
  cursor: grab;
  user-select: none;
  touch-action: none;
}

.vb-priority-item > strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-priority-item h4 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
}

.vb-priority-item p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 700;
}

.vb-priority-item span {
  padding: 7px 10px;
  border-radius: 999px;
  background: #fff7ed;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 12px;
  font-weight: 900;
  white-space: nowrap;
}

.vb-priority-summary {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 26px;
  border-radius: 28px;
  background:
    radial-gradient(circle at 16% 16%, rgba(251, 146, 60, 0.22), transparent 36%),
    linear-gradient(135deg, #0f172a, #7f1d1d) !important;
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.20);
}

.vb-priority-summary span {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-priority-summary strong {
  margin: 12px 0;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(26px, 4vw, 44px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-priority-summary p {
  margin: 0 !important;
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-priority-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(320px, calc(100vw - 32px));
  padding: 14px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(244, 63, 94, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
}

.vb-priority-ghost strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-priority-panel {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-priority-item {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .vb-priority-item > strong,
  .vb-priority-item span {
    display: none;
  }
}
</style>

<script>
(function () {
  function initPrioritySort() {
    document.querySelectorAll("[data-vb-priority]").forEach(function (root) {
      if (root.getAttribute("data-vb-priority-ready") === "1") return;
      root.setAttribute("data-vb-priority-ready", "1");

      const list = root.querySelector("[data-vb-priority-list]");
      const top = root.querySelector("[data-vb-priority-top]");

      let activeItem = null;
      let ghost = null;
      let lastX = 0;
      let lastY = 0;

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function updateList() {
        const items = Array.from(list.querySelectorAll("[data-vb-priority-item]"));
        items.forEach(function (item, index) {
          const number = item.querySelector("[data-vb-priority-number]");
          if (number) number.textContent = index + 1;
        });

        if (items[0]) {
          top.textContent = items[0].getAttribute("data-task");
        }
      }

      function createGhost(item, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-priority-ghost";
        ghost.innerHTML = "<strong>" + item.getAttribute("data-task") + "</strong>";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function clearOver() {
        list.querySelectorAll(".is-over").forEach(function (item) {
          item.classList.remove("is-over");
        });
      }

      function reorderAtPoint(x, y) {
        const el = document.elementFromPoint(x, y);
        const target = el ? el.closest("[data-vb-priority-item]") : null;

        if (!target || target === activeItem || !list.contains(target)) return;

        const rect = target.getBoundingClientRect();
        const after = y > rect.top + rect.height / 2;

        clearOver();
        target.classList.add("is-over");

        if (after) {
          target.insertAdjacentElement("afterend", activeItem);
        } else {
          target.insertAdjacentElement("beforebegin", activeItem);
        }

        updateList();
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-priority-handle]");
        if (!handle) return;

        const item = handle.closest("[data-vb-priority-item]");
        if (!item) return;

        event.preventDefault();

        const point = getPoint(event);
        activeItem = item;
        lastX = point.x;
        lastY = point.y;

        item.classList.add("is-dragging");
        createGhost(item, lastX, lastY);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!activeItem) return;

        event.preventDefault();

        const point = getPoint(event);
        lastX = point.x;
        lastY = point.y;

        moveGhost(lastX, lastY);
        reorderAtPoint(lastX, lastY);
      }

      function end() {
        cleanup();
        updateList();
      }

      function cancel() {
        cleanup();
        updateList();
      }

      function cleanup() {
        if (activeItem) activeItem.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        clearOver();
        activeItem = null;
        ghost = null;

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });

      updateList();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initPrioritySort);
  } else {
    initPrioritySort();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initPrioritySort() {
    document.querySelectorAll("[data-vb-priority]").forEach(function (root) {
      if (root.getAttribute("data-vb-priority-ready") === "1") return;
      root.setAttribute("data-vb-priority-ready", "1");

      const list = root.querySelector("[data-vb-priority-list]");
      const top = root.querySelector("[data-vb-priority-top]");

      let activeItem = null;
      let ghost = null;
      let lastX = 0;
      let lastY = 0;

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function updateList() {
        const items = Array.from(list.querySelectorAll("[data-vb-priority-item]"));
        items.forEach(function (item, index) {
          const number = item.querySelector("[data-vb-priority-number]");
          if (number) number.textContent = index + 1;
        });

        if (items[0]) {
          top.textContent = items[0].getAttribute("data-task");
        }
      }

      function createGhost(item, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-priority-ghost";
        ghost.innerHTML = "&lt;strong&gt;" + item.getAttribute("data-task") + "&lt;/strong&gt;";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function clearOver() {
        list.querySelectorAll(".is-over").forEach(function (item) {
          item.classList.remove("is-over");
        });
      }

      function reorderAtPoint(x, y) {
        const el = document.elementFromPoint(x, y);
        const target = el ? el.closest("[data-vb-priority-item]") : null;

        if (!target || target === activeItem || !list.contains(target)) return;

        const rect = target.getBoundingClientRect();
        const after = y &gt; rect.top + rect.height / 2;

        clearOver();
        target.classList.add("is-over");

        if (after) {
          target.insertAdjacentElement("afterend", activeItem);
        } else {
          target.insertAdjacentElement("beforebegin", activeItem);
        }

        updateList();
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-priority-handle]");
        if (!handle) return;

        const item = handle.closest("[data-vb-priority-item]");
        if (!item) return;

        event.preventDefault();

        const point = getPoint(event);
        activeItem = item;
        lastX = point.x;
        lastY = point.y;

        item.classList.add("is-dragging");
        createGhost(item, lastX, lastY);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!activeItem) return;

        event.preventDefault();

        const point = getPoint(event);
        lastX = point.x;
        lastY = point.y;

        moveGhost(lastX, lastY);
        reorderAtPoint(lastX, lastY);
      }

      function end() {
        cleanup();
        updateList();
      }

      function cancel() {
        cleanup();
        updateList();
      }

      function cleanup() {
        if (activeItem) activeItem.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        clearOver();
        activeItem = null;
        ghost = null;

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });

      updateList();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initPrioritySort);
  } else {
    initPrioritySort();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-priority-demo"&gt;
  &lt;div class="vb-priority-wrap" data-vb-priority&gt;
    &lt;div class="vb-priority-head"&gt;
      &lt;span&gt;Example 08&lt;/span&gt;
      &lt;h3&gt;Priority List Sorter&lt;/h3&gt;
      &lt;p&gt;Drag the handle to reorder tasks. The first item becomes the top priority.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-priority-panel"&gt;
      &lt;div class="vb-priority-list" data-vb-priority-list&gt;
        &lt;article class="vb-priority-item" data-vb-priority-item data-task="Fix checkout error"&gt;
          &lt;button type="button" class="vb-priority-handle" data-vb-priority-handle&gt;⋮⋮&lt;/button&gt;
          &lt;strong data-vb-priority-number&gt;1&lt;/strong&gt;
          &lt;div&gt;
            &lt;h4&gt;Fix checkout error&lt;/h4&gt;
            &lt;p&gt;Critical ecommerce issue&lt;/p&gt;
          &lt;/div&gt;
          &lt;span&gt;High&lt;/span&gt;
        &lt;/article&gt;

        &lt;article class="vb-priority-item" data-vb-priority-item data-task="Update mobile menu"&gt;
          &lt;button type="button" class="vb-priority-handle" data-vb-priority-handle&gt;⋮⋮&lt;/button&gt;
          &lt;strong data-vb-priority-number&gt;2&lt;/strong&gt;
          &lt;div&gt;
            &lt;h4&gt;Update mobile menu&lt;/h4&gt;
            &lt;p&gt;Navigation improvement&lt;/p&gt;
          &lt;/div&gt;
          &lt;span&gt;Medium&lt;/span&gt;
        &lt;/article&gt;

        &lt;article class="vb-priority-item" data-vb-priority-item data-task="Write FAQ section"&gt;
          &lt;button type="button" class="vb-priority-handle" data-vb-priority-handle&gt;⋮⋮&lt;/button&gt;
          &lt;strong data-vb-priority-number&gt;3&lt;/strong&gt;
          &lt;div&gt;
            &lt;h4&gt;Write FAQ section&lt;/h4&gt;
            &lt;p&gt;SEO content task&lt;/p&gt;
          &lt;/div&gt;
          &lt;span&gt;Low&lt;/span&gt;
        &lt;/article&gt;

        &lt;article class="vb-priority-item" data-vb-priority-item data-task="Compress hero images"&gt;
          &lt;button type="button" class="vb-priority-handle" data-vb-priority-handle&gt;⋮⋮&lt;/button&gt;
          &lt;strong data-vb-priority-number&gt;4&lt;/strong&gt;
          &lt;div&gt;
            &lt;h4&gt;Compress hero images&lt;/h4&gt;
            &lt;p&gt;Performance task&lt;/p&gt;
          &lt;/div&gt;
          &lt;span&gt;Medium&lt;/span&gt;
        &lt;/article&gt;
      &lt;/div&gt;

      &lt;aside class="vb-priority-summary"&gt;
        &lt;span&gt;Top priority&lt;/span&gt;
        &lt;strong data-vb-priority-top&gt;Fix checkout error&lt;/strong&gt;
        &lt;p&gt;The list updates instantly when the order changes.&lt;/p&gt;
      &lt;/aside&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-priority-demo,
.vb-priority-demo * {
  box-sizing: border-box;
}

.vb-priority-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(244, 63, 94, 0.16), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(249, 115, 22, 0.18), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #fff7ed 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-priority-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-priority-head {
  max-width: 760px;
  margin-bottom: 22px;
}

.vb-priority-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-priority-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-priority-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-priority-panel {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(260px, 0.8fr);
  gap: 16px;
  align-items: stretch;
}

.vb-priority-list {
  display: grid;
  gap: 12px;
  min-width: 0;
  padding: 16px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-priority-item {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  padding: 14px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 12px 30px rgba(15, 23, 42, 0.06);
}

.vb-priority-item.is-dragging {
  opacity: 0.45;
}

.vb-priority-item.is-over {
  border-color: rgba(244, 63, 94, 0.70);
  background: #fff1f2;
}

.vb-priority-handle {
  width: 38px;
  height: 44px;
  border: 0;
  border-radius: 14px;
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 20px;
  font-weight: 950;
  cursor: grab;
  user-select: none;
  touch-action: none;
}

.vb-priority-item &gt; strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-priority-item h4 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
}

.vb-priority-item p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 700;
}

.vb-priority-item span {
  padding: 7px 10px;
  border-radius: 999px;
  background: #fff7ed;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 12px;
  font-weight: 900;
  white-space: nowrap;
}

.vb-priority-summary {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 26px;
  border-radius: 28px;
  background:
    radial-gradient(circle at 16% 16%, rgba(251, 146, 60, 0.22), transparent 36%),
    linear-gradient(135deg, #0f172a, #7f1d1d) !important;
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.20);
}

.vb-priority-summary span {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-priority-summary strong {
  margin: 12px 0;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(26px, 4vw, 44px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-priority-summary p {
  margin: 0 !important;
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-priority-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(320px, calc(100vw - 32px));
  padding: 14px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(244, 63, 94, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
}

.vb-priority-ghost strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-priority-panel {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-priority-item {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .vb-priority-item &gt; strong,
  .vb-priority-item span {
    display: none;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript priority list sorter is useful for project dashboards, task managers, admin queues, editorial calendars, support boards, and productivity interfaces.</p>



<h2 class="wp-block-heading">9. Drag and Drop Team Member Assignment Board</h2>



<p class="wp-block-paragraph"><strong>A team member assignment board</strong> lets users drag people into different departments, projects, or work groups. This is a useful JavaScript drag and drop pattern for HR dashboards, project management apps, team planning tools, CRM systems, and admin panels.</p>



<ul class="wp-block-list">
<li>Drag team members into project columns</li>
<li>Mouse and touch support</li>
<li>Column counters update automatically</li>
<li>Works without external libraries</li>
<li>Responsive project board layout</li>
</ul>



<div class="vb-team-demo">
  <div class="vb-team-wrap" data-vb-team>
    <div class="vb-team-head">
      <span>Example 09</span>
      <h3>Team Assignment Board</h3>
      <p>Drag team members into the correct project column. Counters update after every assignment.</p>
    </div>

    <div class="vb-team-board">
      <section class="vb-team-pool">
        <div class="vb-team-section-title">
          <h4>Team Members</h4>
          <strong data-vb-team-count="pool">0</strong>
        </div>

        <div class="vb-team-drop" data-vb-team-drop data-team-zone="pool">
          <article class="vb-team-card" data-vb-team-card data-person="Mia">
            <button type="button" data-vb-team-handle>⋮⋮</button>
            <span>MI</span>
            <div>
              <h5>Mia</h5>
              <p>UI Designer</p>
            </div>
          </article>

          <article class="vb-team-card" data-vb-team-card data-person="Leo">
            <button type="button" data-vb-team-handle>⋮⋮</button>
            <span>LE</span>
            <div>
              <h5>Leo</h5>
              <p>Frontend Developer</p>
            </div>
          </article>

          <article class="vb-team-card" data-vb-team-card data-person="Sara">
            <button type="button" data-vb-team-handle>⋮⋮</button>
            <span>SA</span>
            <div>
              <h5>Sara</h5>
              <p>SEO Specialist</p>
            </div>
          </article>
        </div>
      </section>

      <section class="vb-team-projects">
        <div class="vb-team-column">
          <div class="vb-team-section-title">
            <h4>Website Redesign</h4>
            <strong data-vb-team-count="redesign">0</strong>
          </div>
          <div class="vb-team-drop" data-vb-team-drop data-team-zone="redesign"></div>
        </div>

        <div class="vb-team-column">
          <div class="vb-team-section-title">
            <h4>SEO Campaign</h4>
            <strong data-vb-team-count="seo">0</strong>
          </div>
          <div class="vb-team-drop" data-vb-team-drop data-team-zone="seo"></div>
        </div>
      </section>
    </div>

    <div class="vb-team-status" data-vb-team-status>Assign team members by dragging them into a project column.</div>
  </div>
</div>

<style>
.vb-team-demo,
.vb-team-demo * {
  box-sizing: border-box;
}

.vb-team-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(124, 58, 237, 0.16), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(14, 165, 233, 0.18), transparent 34%),
    linear-gradient(135deg, #f5f3ff 0%, #ecfeff 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-team-wrap {
  max-width: 1160px;
  margin: 0 auto;
}

.vb-team-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-team-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-team-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-team-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-team-board {
  display: grid;
  grid-template-columns: minmax(280px, 0.8fr) minmax(0, 1.2fr);
  gap: 16px;
}

.vb-team-pool,
.vb-team-column {
  min-width: 0;
  padding: 16px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-team-projects {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
}

.vb-team-section-title {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: center;
  margin-bottom: 14px;
}

.vb-team-section-title h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-team-section-title strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 38px;
  height: 34px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-team-drop {
  display: grid;
  align-content: start;
  gap: 12px;
  min-height: 270px;
  padding: 12px;
  border-radius: 22px;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  background: #f8fafc;
}

.vb-team-drop.is-over {
  border-color: rgba(124, 58, 237, 0.78);
  background: #f5f3ff;
  box-shadow: inset 0 0 0 4px rgba(124, 58, 237, 0.10);
}

.vb-team-card {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 13px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 12px 30px rgba(15, 23, 42, 0.07);
}

.vb-team-card.is-dragging {
  opacity: 0.45;
}

.vb-team-card button {
  width: 36px;
  height: 42px;
  border: 0;
  border-radius: 14px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 20px;
  font-weight: 950;
  cursor: grab;
  user-select: none;
  touch-action: none;
}

.vb-team-card > span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: linear-gradient(135deg, #7c3aed, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-team-card h5 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
}

.vb-team-card p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 700;
}

.vb-team-status {
  margin-top: 16px;
  padding: 13px 15px;
  border-radius: 18px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-team-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(300px, calc(100vw - 32px));
  padding: 14px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(124, 58, 237, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
}

.vb-team-ghost strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

@media (max-width: 940px) {
  .vb-team-board {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 700px) {
  .vb-team-projects {
    grid-template-columns: 1fr;
  }

  .vb-team-drop {
    min-height: 180px;
  }
}

@media (max-width: 420px) {
  .vb-team-card {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .vb-team-card > span {
    display: none;
  }
}
</style>

<script>
(function () {
  function initTeamBoard() {
    document.querySelectorAll("[data-vb-team]").forEach(function (root) {
      if (root.getAttribute("data-vb-team-ready") === "1") return;
      root.setAttribute("data-vb-team-ready", "1");

      const drops = Array.from(root.querySelectorAll("[data-vb-team-drop]"));
      const status = root.querySelector("[data-vb-team-status]");

      let activeCard = null;
      let ghost = null;
      let lastX = 0;
      let lastY = 0;

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function updateCounts() {
        drops.forEach(function (drop) {
          const zone = drop.getAttribute("data-team-zone");
          const count = root.querySelector('[data-vb-team-count="' + zone + '"]');
          if (count) count.textContent = drop.querySelectorAll("[data-vb-team-card]").length;
        });
      }

      function createGhost(card, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-team-ghost";
        ghost.innerHTML = "<strong>" + card.getAttribute("data-person") + "</strong>";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function getDropAtPoint(x, y) {
        const el = document.elementFromPoint(x, y);
        if (!el) return null;
        const drop = el.closest("[data-vb-team-drop]");
        return drops.includes(drop) ? drop : null;
      }

      function clearOver() {
        drops.forEach(function (drop) {
          drop.classList.remove("is-over");
        });
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-team-handle]");
        if (!handle) return;

        const card = handle.closest("[data-vb-team-card]");
        if (!card) return;

        event.preventDefault();

        const point = getPoint(event);

        activeCard = card;
        lastX = point.x;
        lastY = point.y;

        activeCard.classList.add("is-dragging");
        createGhost(activeCard, lastX, lastY);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!activeCard) return;

        event.preventDefault();

        const point = getPoint(event);
        lastX = point.x;
        lastY = point.y;

        moveGhost(lastX, lastY);
        clearOver();

        const drop = getDropAtPoint(lastX, lastY);
        if (drop) drop.classList.add("is-over");
      }

      function end(event) {
        if (!activeCard) return;

        const point = getPoint(event);
        lastX = point.x;
        lastY = point.y;

        const drop = getDropAtPoint(lastX, lastY);

        if (drop) {
          drop.appendChild(activeCard);
          status.textContent = activeCard.getAttribute("data-person") + " assigned to " + drop.getAttribute("data-team-zone") + ".";
        }

        cleanup();
        updateCounts();
      }

      function cancel() {
        cleanup();
        updateCounts();
      }

      function cleanup() {
        if (activeCard) activeCard.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        activeCard = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });

      updateCounts();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initTeamBoard);
  } else {
    initTeamBoard();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initTeamBoard() {
    document.querySelectorAll("[data-vb-team]").forEach(function (root) {
      if (root.getAttribute("data-vb-team-ready") === "1") return;
      root.setAttribute("data-vb-team-ready", "1");

      const drops = Array.from(root.querySelectorAll("[data-vb-team-drop]"));
      const status = root.querySelector("[data-vb-team-status]");

      let activeCard = null;
      let ghost = null;
      let lastX = 0;
      let lastY = 0;

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function updateCounts() {
        drops.forEach(function (drop) {
          const zone = drop.getAttribute("data-team-zone");
          const count = root.querySelector('[data-vb-team-count="' + zone + '"]');
          if (count) count.textContent = drop.querySelectorAll("[data-vb-team-card]").length;
        });
      }

      function createGhost(card, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-team-ghost";
        ghost.innerHTML = "&lt;strong&gt;" + card.getAttribute("data-person") + "&lt;/strong&gt;";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function getDropAtPoint(x, y) {
        const el = document.elementFromPoint(x, y);
        if (!el) return null;
        const drop = el.closest("[data-vb-team-drop]");
        return drops.includes(drop) ? drop : null;
      }

      function clearOver() {
        drops.forEach(function (drop) {
          drop.classList.remove("is-over");
        });
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-team-handle]");
        if (!handle) return;

        const card = handle.closest("[data-vb-team-card]");
        if (!card) return;

        event.preventDefault();

        const point = getPoint(event);

        activeCard = card;
        lastX = point.x;
        lastY = point.y;

        activeCard.classList.add("is-dragging");
        createGhost(activeCard, lastX, lastY);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!activeCard) return;

        event.preventDefault();

        const point = getPoint(event);
        lastX = point.x;
        lastY = point.y;

        moveGhost(lastX, lastY);
        clearOver();

        const drop = getDropAtPoint(lastX, lastY);
        if (drop) drop.classList.add("is-over");
      }

      function end(event) {
        if (!activeCard) return;

        const point = getPoint(event);
        lastX = point.x;
        lastY = point.y;

        const drop = getDropAtPoint(lastX, lastY);

        if (drop) {
          drop.appendChild(activeCard);
          status.textContent = activeCard.getAttribute("data-person") + " assigned to " + drop.getAttribute("data-team-zone") + ".";
        }

        cleanup();
        updateCounts();
      }

      function cancel() {
        cleanup();
        updateCounts();
      }

      function cleanup() {
        if (activeCard) activeCard.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        activeCard = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });

      updateCounts();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initTeamBoard);
  } else {
    initTeamBoard();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-team-demo"&gt;
  &lt;div class="vb-team-wrap" data-vb-team&gt;
    &lt;div class="vb-team-head"&gt;
      &lt;span&gt;Example 09&lt;/span&gt;
      &lt;h3&gt;Team Assignment Board&lt;/h3&gt;
      &lt;p&gt;Drag team members into the correct project column. Counters update after every assignment.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-team-board"&gt;
      &lt;section class="vb-team-pool"&gt;
        &lt;div class="vb-team-section-title"&gt;
          &lt;h4&gt;Team Members&lt;/h4&gt;
          &lt;strong data-vb-team-count="pool"&gt;0&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-team-drop" data-vb-team-drop data-team-zone="pool"&gt;
          &lt;article class="vb-team-card" data-vb-team-card data-person="Mia"&gt;
            &lt;button type="button" data-vb-team-handle&gt;⋮⋮&lt;/button&gt;
            &lt;span&gt;MI&lt;/span&gt;
            &lt;div&gt;
              &lt;h5&gt;Mia&lt;/h5&gt;
              &lt;p&gt;UI Designer&lt;/p&gt;
            &lt;/div&gt;
          &lt;/article&gt;

          &lt;article class="vb-team-card" data-vb-team-card data-person="Leo"&gt;
            &lt;button type="button" data-vb-team-handle&gt;⋮⋮&lt;/button&gt;
            &lt;span&gt;LE&lt;/span&gt;
            &lt;div&gt;
              &lt;h5&gt;Leo&lt;/h5&gt;
              &lt;p&gt;Frontend Developer&lt;/p&gt;
            &lt;/div&gt;
          &lt;/article&gt;

          &lt;article class="vb-team-card" data-vb-team-card data-person="Sara"&gt;
            &lt;button type="button" data-vb-team-handle&gt;⋮⋮&lt;/button&gt;
            &lt;span&gt;SA&lt;/span&gt;
            &lt;div&gt;
              &lt;h5&gt;Sara&lt;/h5&gt;
              &lt;p&gt;SEO Specialist&lt;/p&gt;
            &lt;/div&gt;
          &lt;/article&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-team-projects"&gt;
        &lt;div class="vb-team-column"&gt;
          &lt;div class="vb-team-section-title"&gt;
            &lt;h4&gt;Website Redesign&lt;/h4&gt;
            &lt;strong data-vb-team-count="redesign"&gt;0&lt;/strong&gt;
          &lt;/div&gt;
          &lt;div class="vb-team-drop" data-vb-team-drop data-team-zone="redesign"&gt;&lt;/div&gt;
        &lt;/div&gt;

        &lt;div class="vb-team-column"&gt;
          &lt;div class="vb-team-section-title"&gt;
            &lt;h4&gt;SEO Campaign&lt;/h4&gt;
            &lt;strong data-vb-team-count="seo"&gt;0&lt;/strong&gt;
          &lt;/div&gt;
          &lt;div class="vb-team-drop" data-vb-team-drop data-team-zone="seo"&gt;&lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;

    &lt;div class="vb-team-status" data-vb-team-status&gt;Assign team members by dragging them into a project column.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-team-demo,
.vb-team-demo * {
  box-sizing: border-box;
}

.vb-team-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(124, 58, 237, 0.16), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(14, 165, 233, 0.18), transparent 34%),
    linear-gradient(135deg, #f5f3ff 0%, #ecfeff 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-team-wrap {
  max-width: 1160px;
  margin: 0 auto;
}

.vb-team-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-team-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-team-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-team-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-team-board {
  display: grid;
  grid-template-columns: minmax(280px, 0.8fr) minmax(0, 1.2fr);
  gap: 16px;
}

.vb-team-pool,
.vb-team-column {
  min-width: 0;
  padding: 16px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-team-projects {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
}

.vb-team-section-title {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: center;
  margin-bottom: 14px;
}

.vb-team-section-title h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-team-section-title strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 38px;
  height: 34px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-team-drop {
  display: grid;
  align-content: start;
  gap: 12px;
  min-height: 270px;
  padding: 12px;
  border-radius: 22px;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  background: #f8fafc;
}

.vb-team-drop.is-over {
  border-color: rgba(124, 58, 237, 0.78);
  background: #f5f3ff;
  box-shadow: inset 0 0 0 4px rgba(124, 58, 237, 0.10);
}

.vb-team-card {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 13px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 12px 30px rgba(15, 23, 42, 0.07);
}

.vb-team-card.is-dragging {
  opacity: 0.45;
}

.vb-team-card button {
  width: 36px;
  height: 42px;
  border: 0;
  border-radius: 14px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 20px;
  font-weight: 950;
  cursor: grab;
  user-select: none;
  touch-action: none;
}

.vb-team-card &gt; span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: linear-gradient(135deg, #7c3aed, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-team-card h5 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
}

.vb-team-card p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 700;
}

.vb-team-status {
  margin-top: 16px;
  padding: 13px 15px;
  border-radius: 18px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-team-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(300px, calc(100vw - 32px));
  padding: 14px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(124, 58, 237, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
}

.vb-team-ghost strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

@media (max-width: 940px) {
  .vb-team-board {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 700px) {
  .vb-team-projects {
    grid-template-columns: 1fr;
  }

  .vb-team-drop {
    min-height: 180px;
  }
}

@media (max-width: 420px) {
  .vb-team-card {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .vb-team-card &gt; span {
    display: none;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript team assignment board is useful for HR tools, project planning dashboards, admin panels, CRM interfaces, team management apps, and task assignment systems.</p>



<h2 class="wp-block-heading">10. Calendar Event Drag and Drop Planner</h2>



<p class="wp-block-paragraph"><strong>A calendar event drag and drop planner</strong> is useful for booking tools, editorial calendars, appointment systems, project planning dashboards, and event scheduling interfaces. Users can drag events into different day columns and instantly see how the schedule changes.</p>



<ul class="wp-block-list">
<li>Drag events between calendar days</li>
<li>Mouse and touch support</li>
<li>Live day counters</li>
<li>Different layout from previous examples</li>
<li>No external libraries</li>
</ul>



<div class="vb-calplan-demo">
  <div class="vb-calplan-wrap" data-vb-calplan>
    <div class="vb-calplan-head">
      <span>Example 10</span>
      <h3>Calendar Event Planner</h3>
      <p>Drag each event card into a weekday column to build a simple visual schedule.</p>
    </div>

    <div class="vb-calplan-grid">
      <aside class="vb-calplan-sidebar">
        <div class="vb-calplan-sidebar-top">
          <span>Unscheduled</span>
          <strong data-vb-calplan-count="unscheduled">0</strong>
        </div>

        <div class="vb-calplan-drop vb-calplan-pool" data-vb-calplan-drop data-day="unscheduled">
          <article class="vb-calplan-event" data-vb-calplan-event data-title="Client Call">
            <button type="button" data-vb-calplan-handle>⋮⋮</button>
            <div>
              <strong>Client Call</strong>
              <span>30 min meeting</span>
            </div>
          </article>

          <article class="vb-calplan-event" data-vb-calplan-event data-title="Publish Blog Post">
            <button type="button" data-vb-calplan-handle>⋮⋮</button>
            <div>
              <strong>Publish Blog Post</strong>
              <span>Content task</span>
            </div>
          </article>

          <article class="vb-calplan-event" data-vb-calplan-event data-title="Design Review">
            <button type="button" data-vb-calplan-handle>⋮⋮</button>
            <div>
              <strong>Design Review</strong>
              <span>UI feedback</span>
            </div>
          </article>
        </div>
      </aside>

      <section class="vb-calplan-calendar">
        <div class="vb-calplan-day">
          <div class="vb-calplan-day-head">
            <h4>Monday</h4>
            <span data-vb-calplan-count="monday">0</span>
          </div>
          <div class="vb-calplan-drop" data-vb-calplan-drop data-day="monday"></div>
        </div>

        <div class="vb-calplan-day">
          <div class="vb-calplan-day-head">
            <h4>Tuesday</h4>
            <span data-vb-calplan-count="tuesday">0</span>
          </div>
          <div class="vb-calplan-drop" data-vb-calplan-drop data-day="tuesday"></div>
        </div>

        <div class="vb-calplan-day">
          <div class="vb-calplan-day-head">
            <h4>Wednesday</h4>
            <span data-vb-calplan-count="wednesday">0</span>
          </div>
          <div class="vb-calplan-drop" data-vb-calplan-drop data-day="wednesday"></div>
        </div>

        <div class="vb-calplan-day">
          <div class="vb-calplan-day-head">
            <h4>Thursday</h4>
            <span data-vb-calplan-count="thursday">0</span>
          </div>
          <div class="vb-calplan-drop" data-vb-calplan-drop data-day="thursday"></div>
        </div>

        <div class="vb-calplan-day">
          <div class="vb-calplan-day-head">
            <h4>Friday</h4>
            <span data-vb-calplan-count="friday">0</span>
          </div>
          <div class="vb-calplan-drop" data-vb-calplan-drop data-day="friday"></div>
        </div>
      </section>
    </div>

    <div class="vb-calplan-status" data-vb-calplan-status>Drag an event into a day column.</div>
  </div>
</div>

<style>
.vb-calplan-demo,
.vb-calplan-demo * {
  box-sizing: border-box;
}

.vb-calplan-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(14, 165, 233, 0.18), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(99, 102, 241, 0.18), transparent 34%),
    linear-gradient(135deg, #ecfeff 0%, #eef2ff 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
  overflow: hidden;
}

.vb-calplan-wrap {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-calplan-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-calplan-head > span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #cffafe;
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calplan-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-calplan-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calplan-grid {
  display: grid;
  grid-template-columns: minmax(260px, 0.35fr) minmax(0, 1fr);
  gap: 16px;
  align-items: stretch;
}

.vb-calplan-sidebar,
.vb-calplan-day {
  min-width: 0;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 16px 44px rgba(15, 23, 42, 0.08);
}

.vb-calplan-sidebar {
  padding: 16px;
}

.vb-calplan-sidebar-top,
.vb-calplan-day-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.vb-calplan-sidebar-top span {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-calplan-sidebar-top strong,
.vb-calplan-day-head span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 34px;
  height: 32px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-calplan-calendar {
  display: grid;
  grid-template-columns: repeat(5, minmax(160px, 1fr));
  gap: 12px;
  overflow-x: auto;
  padding-bottom: 4px;
}

.vb-calplan-day {
  padding: 14px;
}

.vb-calplan-day-head h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
}

.vb-calplan-drop {
  display: grid;
  align-content: start;
  gap: 10px;
  min-height: 280px;
  padding: 10px;
  border-radius: 20px;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  background: #f8fafc;
}

.vb-calplan-pool {
  min-height: 340px;
}

.vb-calplan-drop.is-over {
  border-color: rgba(14, 165, 233, 0.80);
  background: #ecfeff;
  box-shadow: inset 0 0 0 4px rgba(14, 165, 233, 0.10);
}

.vb-calplan-event {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  padding: 11px;
  border-radius: 16px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 10px 24px rgba(15, 23, 42, 0.06);
}

.vb-calplan-event.is-dragging {
  opacity: 0.45;
}

.vb-calplan-event button {
  width: 34px;
  height: 40px;
  border: 0;
  border-radius: 13px;
  background: #cffafe;
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 18px;
  font-weight: 950;
  cursor: grab;
  user-select: none;
  touch-action: none;
}

.vb-calplan-event strong {
  display: block;
  margin-bottom: 3px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 13px;
  line-height: 1.25;
  font-weight: 950;
}

.vb-calplan-event span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 700;
}

.vb-calplan-status {
  margin-top: 16px;
  padding: 13px 15px;
  border-radius: 18px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-calplan-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(280px, calc(100vw - 32px));
  padding: 13px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(14, 165, 233, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
}

.vb-calplan-ghost strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vb-calplan-grid {
    grid-template-columns: 1fr;
  }

  .vb-calplan-calendar {
    grid-template-columns: repeat(5, minmax(190px, 1fr));
  }
}

@media (max-width: 520px) {
  .vb-calplan-demo {
    padding: 16px;
    border-radius: 24px;
  }
}
</style>

<script>
(function () {
  function initCalendarPlanner() {
    document.querySelectorAll("[data-vb-calplan]").forEach(function (root) {
      if (root.getAttribute("data-vb-calplan-ready") === "1") return;
      root.setAttribute("data-vb-calplan-ready", "1");

      const drops = Array.from(root.querySelectorAll("[data-vb-calplan-drop]"));
      const status = root.querySelector("[data-vb-calplan-status]");
      let activeEvent = null;
      let ghost = null;
      let lastX = 0;
      let lastY = 0;

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function updateCounts() {
        drops.forEach(function (drop) {
          const day = drop.getAttribute("data-day");
          const count = root.querySelector('[data-vb-calplan-count="' + day + '"]');
          if (count) count.textContent = drop.querySelectorAll("[data-vb-calplan-event]").length;
        });
      }

      function createGhost(card, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-calplan-ghost";
        ghost.innerHTML = "<strong>" + card.getAttribute("data-title") + "</strong>";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function getDropAtPoint(x, y) {
        const el = document.elementFromPoint(x, y);
        if (!el) return null;
        const drop = el.closest("[data-vb-calplan-drop]");
        return drops.includes(drop) ? drop : null;
      }

      function clearOver() {
        drops.forEach(function (drop) {
          drop.classList.remove("is-over");
        });
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-calplan-handle]");
        if (!handle) return;

        const card = handle.closest("[data-vb-calplan-event]");
        if (!card) return;

        event.preventDefault();

        const point = getPoint(event);
        activeEvent = card;
        lastX = point.x;
        lastY = point.y;

        activeEvent.classList.add("is-dragging");
        createGhost(activeEvent, lastX, lastY);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!activeEvent) return;

        event.preventDefault();

        const point = getPoint(event);
        lastX = point.x;
        lastY = point.y;

        moveGhost(lastX, lastY);
        clearOver();

        const drop = getDropAtPoint(lastX, lastY);
        if (drop) drop.classList.add("is-over");
      }

      function end(event) {
        if (!activeEvent) return;

        const point = getPoint(event);
        const drop = getDropAtPoint(point.x, point.y);

        if (drop) {
          drop.appendChild(activeEvent);
          status.textContent = activeEvent.getAttribute("data-title") + " moved to " + drop.getAttribute("data-day") + ".";
        }

        cleanup();
        updateCounts();
      }

      function cancel() {
        cleanup();
        updateCounts();
      }

      function cleanup() {
        if (activeEvent) activeEvent.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        activeEvent = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateCounts();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initCalendarPlanner);
  } else {
    initCalendarPlanner();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initCalendarPlanner() {
    document.querySelectorAll("[data-vb-calplan]").forEach(function (root) {
      if (root.getAttribute("data-vb-calplan-ready") === "1") return;
      root.setAttribute("data-vb-calplan-ready", "1");

      const drops = Array.from(root.querySelectorAll("[data-vb-calplan-drop]"));
      const status = root.querySelector("[data-vb-calplan-status]");
      let activeEvent = null;
      let ghost = null;
      let lastX = 0;
      let lastY = 0;

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function updateCounts() {
        drops.forEach(function (drop) {
          const day = drop.getAttribute("data-day");
          const count = root.querySelector('[data-vb-calplan-count="' + day + '"]');
          if (count) count.textContent = drop.querySelectorAll("[data-vb-calplan-event]").length;
        });
      }

      function createGhost(card, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-calplan-ghost";
        ghost.innerHTML = "&lt;strong&gt;" + card.getAttribute("data-title") + "&lt;/strong&gt;";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function getDropAtPoint(x, y) {
        const el = document.elementFromPoint(x, y);
        if (!el) return null;
        const drop = el.closest("[data-vb-calplan-drop]");
        return drops.includes(drop) ? drop : null;
      }

      function clearOver() {
        drops.forEach(function (drop) {
          drop.classList.remove("is-over");
        });
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-calplan-handle]");
        if (!handle) return;

        const card = handle.closest("[data-vb-calplan-event]");
        if (!card) return;

        event.preventDefault();

        const point = getPoint(event);
        activeEvent = card;
        lastX = point.x;
        lastY = point.y;

        activeEvent.classList.add("is-dragging");
        createGhost(activeEvent, lastX, lastY);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!activeEvent) return;

        event.preventDefault();

        const point = getPoint(event);
        lastX = point.x;
        lastY = point.y;

        moveGhost(lastX, lastY);
        clearOver();

        const drop = getDropAtPoint(lastX, lastY);
        if (drop) drop.classList.add("is-over");
      }

      function end(event) {
        if (!activeEvent) return;

        const point = getPoint(event);
        const drop = getDropAtPoint(point.x, point.y);

        if (drop) {
          drop.appendChild(activeEvent);
          status.textContent = activeEvent.getAttribute("data-title") + " moved to " + drop.getAttribute("data-day") + ".";
        }

        cleanup();
        updateCounts();
      }

      function cancel() {
        cleanup();
        updateCounts();
      }

      function cleanup() {
        if (activeEvent) activeEvent.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        activeEvent = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateCounts();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initCalendarPlanner);
  } else {
    initCalendarPlanner();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calplan-demo"&gt;
  &lt;div class="vb-calplan-wrap" data-vb-calplan&gt;
    &lt;div class="vb-calplan-head"&gt;
      &lt;span&gt;Example 10&lt;/span&gt;
      &lt;h3&gt;Calendar Event Planner&lt;/h3&gt;
      &lt;p&gt;Drag each event card into a weekday column to build a simple visual schedule.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calplan-grid"&gt;
      &lt;aside class="vb-calplan-sidebar"&gt;
        &lt;div class="vb-calplan-sidebar-top"&gt;
          &lt;span&gt;Unscheduled&lt;/span&gt;
          &lt;strong data-vb-calplan-count="unscheduled"&gt;0&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-calplan-drop vb-calplan-pool" data-vb-calplan-drop data-day="unscheduled"&gt;
          &lt;article class="vb-calplan-event" data-vb-calplan-event data-title="Client Call"&gt;
            &lt;button type="button" data-vb-calplan-handle&gt;⋮⋮&lt;/button&gt;
            &lt;div&gt;
              &lt;strong&gt;Client Call&lt;/strong&gt;
              &lt;span&gt;30 min meeting&lt;/span&gt;
            &lt;/div&gt;
          &lt;/article&gt;

          &lt;article class="vb-calplan-event" data-vb-calplan-event data-title="Publish Blog Post"&gt;
            &lt;button type="button" data-vb-calplan-handle&gt;⋮⋮&lt;/button&gt;
            &lt;div&gt;
              &lt;strong&gt;Publish Blog Post&lt;/strong&gt;
              &lt;span&gt;Content task&lt;/span&gt;
            &lt;/div&gt;
          &lt;/article&gt;

          &lt;article class="vb-calplan-event" data-vb-calplan-event data-title="Design Review"&gt;
            &lt;button type="button" data-vb-calplan-handle&gt;⋮⋮&lt;/button&gt;
            &lt;div&gt;
              &lt;strong&gt;Design Review&lt;/strong&gt;
              &lt;span&gt;UI feedback&lt;/span&gt;
            &lt;/div&gt;
          &lt;/article&gt;
        &lt;/div&gt;
      &lt;/aside&gt;

      &lt;section class="vb-calplan-calendar"&gt;
        &lt;div class="vb-calplan-day"&gt;
          &lt;div class="vb-calplan-day-head"&gt;&lt;h4&gt;Monday&lt;/h4&gt;&lt;span data-vb-calplan-count="monday"&gt;0&lt;/span&gt;&lt;/div&gt;
          &lt;div class="vb-calplan-drop" data-vb-calplan-drop data-day="monday"&gt;&lt;/div&gt;
        &lt;/div&gt;

        &lt;div class="vb-calplan-day"&gt;
          &lt;div class="vb-calplan-day-head"&gt;&lt;h4&gt;Tuesday&lt;/h4&gt;&lt;span data-vb-calplan-count="tuesday"&gt;0&lt;/span&gt;&lt;/div&gt;
          &lt;div class="vb-calplan-drop" data-vb-calplan-drop data-day="tuesday"&gt;&lt;/div&gt;
        &lt;/div&gt;

        &lt;div class="vb-calplan-day"&gt;
          &lt;div class="vb-calplan-day-head"&gt;&lt;h4&gt;Wednesday&lt;/h4&gt;&lt;span data-vb-calplan-count="wednesday"&gt;0&lt;/span&gt;&lt;/div&gt;
          &lt;div class="vb-calplan-drop" data-vb-calplan-drop data-day="wednesday"&gt;&lt;/div&gt;
        &lt;/div&gt;

        &lt;div class="vb-calplan-day"&gt;
          &lt;div class="vb-calplan-day-head"&gt;&lt;h4&gt;Thursday&lt;/h4&gt;&lt;span data-vb-calplan-count="thursday"&gt;0&lt;/span&gt;&lt;/div&gt;
          &lt;div class="vb-calplan-drop" data-vb-calplan-drop data-day="thursday"&gt;&lt;/div&gt;
        &lt;/div&gt;

        &lt;div class="vb-calplan-day"&gt;
          &lt;div class="vb-calplan-day-head"&gt;&lt;h4&gt;Friday&lt;/h4&gt;&lt;span data-vb-calplan-count="friday"&gt;0&lt;/span&gt;&lt;/div&gt;
          &lt;div class="vb-calplan-drop" data-vb-calplan-drop data-day="friday"&gt;&lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;

    &lt;div class="vb-calplan-status" data-vb-calplan-status&gt;Drag an event into a day column.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">/* CSS is included fully in the live demo block above. */</pre>



<p class="wp-block-paragraph">This JavaScript calendar drag and drop planner is useful for booking systems, event planners, appointment tools, editorial calendars, project boards, and scheduling dashboards.</p>



<h2 class="wp-block-heading">11. Drag and Drop Form Builder</h2>



<p class="wp-block-paragraph"><strong>A drag and drop form builder</strong> lets users build a simple form layout by dragging field types into a preview area. This is useful for form plugins, admin dashboards, survey builders, quote request tools, signup builders, and no-code website editors.</p>



<ul class="wp-block-list">
<li>Drag field types into a form preview</li>
<li>Creates new fields instead of moving the original</li>
<li>Mouse and touch support</li>
<li>Live form field count</li>
<li>Unique builder-style layout</li>
</ul>



<div class="vb-formbuild-demo">
  <div class="vb-formbuild-wrap" data-vb-formbuild>
    <div class="vb-formbuild-head">
      <span>Example 11</span>
      <h3>Drag and Drop Form Builder</h3>
      <p>Drag a field type from the left panel into the form preview area.</p>
    </div>

    <div class="vb-formbuild-builder">
      <aside class="vb-formbuild-tools">
        <h4>Field blocks</h4>

        <button type="button" class="vb-formbuild-tool" data-vb-formbuild-tool data-type="text" data-label="Text Input">
          <span>TXT</span>
          <strong>Text Input</strong>
        </button>

        <button type="button" class="vb-formbuild-tool" data-vb-formbuild-tool data-type="email" data-label="Email Field">
          <span>@</span>
          <strong>Email Field</strong>
        </button>

        <button type="button" class="vb-formbuild-tool" data-vb-formbuild-tool data-type="select" data-label="Select Dropdown">
          <span>SEL</span>
          <strong>Select Dropdown</strong>
        </button>

        <button type="button" class="vb-formbuild-tool" data-vb-formbuild-tool data-type="textarea" data-label="Message Box">
          <span>MSG</span>
          <strong>Message Box</strong>
        </button>
      </aside>

      <section class="vb-formbuild-preview">
        <div class="vb-formbuild-preview-head">
          <div>
            <span>Live preview</span>
            <h4>Quote Request Form</h4>
          </div>
          <strong data-vb-formbuild-count>0 fields</strong>
        </div>

        <div class="vb-formbuild-drop" data-vb-formbuild-drop>
          <p data-vb-formbuild-empty>Drag field blocks here to build the form.</p>
          <div class="vb-formbuild-fields" data-vb-formbuild-fields></div>
        </div>
      </section>
    </div>

    <div class="vb-formbuild-status" data-vb-formbuild-status>Choose a field block and drag it into the form preview.</div>
  </div>
</div>

<style>
.vb-formbuild-demo,
.vb-formbuild-demo * {
  box-sizing: border-box;
}

.vb-formbuild-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(16, 185, 129, 0.16), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(45, 212, 191, 0.18), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #f0fdfa 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-formbuild-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-formbuild-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-formbuild-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #d1fae5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-formbuild-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-formbuild-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-formbuild-builder {
  display: grid;
  grid-template-columns: minmax(240px, 0.38fr) minmax(0, 1fr);
  gap: 16px;
  align-items: stretch;
}

.vb-formbuild-tools,
.vb-formbuild-preview {
  min-width: 0;
  padding: 16px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-formbuild-tools {
  display: grid;
  align-content: start;
  gap: 12px;
}

.vb-formbuild-tools h4,
.vb-formbuild-preview-head h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 22px !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-formbuild-tool {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  width: 100%;
  padding: 13px;
  border: 0;
  border-radius: 18px;
  background: #ecfdf5;
  cursor: grab;
  text-align: left;
  touch-action: none;
}

.vb-formbuild-tool.is-dragging {
  opacity: 0.45;
}

.vb-formbuild-tool span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: #059669;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-formbuild-tool strong {
  color: #064e3b !important;
  -webkit-text-fill-color: #064e3b !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-formbuild-preview-head {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: center;
  margin-bottom: 14px;
}

.vb-formbuild-preview-head span {
  display: block;
  margin-bottom: 5px;
  color: #059669 !important;
  -webkit-text-fill-color: #059669 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-formbuild-preview-head > strong {
  display: inline-flex;
  min-width: 88px;
  justify-content: center;
  padding: 9px 12px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-formbuild-drop {
  min-height: 390px;
  padding: 16px;
  border-radius: 24px;
  border: 1px dashed rgba(16, 185, 129, 0.55);
  background:
    linear-gradient(#f8fafc 1px, transparent 1px),
    linear-gradient(90deg, #f8fafc 1px, transparent 1px),
    #ffffff;
  background-size: 22px 22px;
}

.vb-formbuild-drop.is-over {
  border-color: rgba(5, 150, 105, 0.90);
  background-color: #ecfdf5;
  box-shadow: inset 0 0 0 4px rgba(16, 185, 129, 0.12);
}

.vb-formbuild-drop > p {
  margin: 0 !important;
  padding: 18px;
  border-radius: 18px;
  background: rgba(255,255,255,0.86);
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 750;
  text-align: center;
}

.vb-formbuild-fields {
  display: grid;
  gap: 12px;
}

.vb-formbuild-field {
  padding: 14px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.28);
  box-shadow: 0 12px 26px rgba(15, 23, 42, 0.07);
}

.vb-formbuild-field label {
  display: block;
  margin-bottom: 8px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-formbuild-field input,
.vb-formbuild-field select,
.vb-formbuild-field textarea {
  width: 100%;
  min-height: 42px;
  border: 1px solid #cbd5e1;
  border-radius: 12px;
  padding: 10px 12px;
  background: #f8fafc;
  color: #0f172a;
  font-size: 14px;
}

.vb-formbuild-field textarea {
  min-height: 90px;
  resize: vertical;
}

.vb-formbuild-status {
  margin-top: 16px;
  padding: 13px 15px;
  border-radius: 18px;
  background: #064e3b;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-formbuild-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(260px, calc(100vw - 32px));
  padding: 13px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(5, 150, 105, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
}

.vb-formbuild-ghost strong {
  color: #064e3b !important;
  -webkit-text-fill-color: #064e3b !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-formbuild-builder {
    grid-template-columns: 1fr;
  }

  .vb-formbuild-drop {
    min-height: 300px;
  }
}

@media (max-width: 480px) {
  .vb-formbuild-preview-head {
    align-items: flex-start;
    flex-direction: column;
  }
}
</style>

<script>
(function () {
  function initFormBuilder() {
    document.querySelectorAll("[data-vb-formbuild]").forEach(function (root) {
      if (root.getAttribute("data-vb-formbuild-ready") === "1") return;
      root.setAttribute("data-vb-formbuild-ready", "1");

      const drop = root.querySelector("[data-vb-formbuild-drop]");
      const fields = root.querySelector("[data-vb-formbuild-fields]");
      const empty = root.querySelector("[data-vb-formbuild-empty]");
      const count = root.querySelector("[data-vb-formbuild-count]");
      const status = root.querySelector("[data-vb-formbuild-status]");

      let activeTool = null;
      let ghost = null;
      let fieldCount = 0;

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function isOverDrop(x, y) {
        const el = document.elementFromPoint(x, y);
        return !!(el && el.closest("[data-vb-formbuild-drop]") === drop);
      }

      function updateCount() {
        const total = fields.querySelectorAll(".vb-formbuild-field").length;
        count.textContent = total === 1 ? "1 field" : total + " fields";
        empty.style.display = total ? "none" : "block";
      }

      function createField(type, label) {
        fieldCount += 1;

        const block = document.createElement("div");
        block.className = "vb-formbuild-field";

        const fieldLabel = document.createElement("label");
        fieldLabel.textContent = label + " " + fieldCount;

        let input;

        if (type === "select") {
          input = document.createElement("select");
          input.innerHTML = "<option>Option One</option><option>Option Two</option>";
        } else if (type === "textarea") {
          input = document.createElement("textarea");
          input.placeholder = "Write your message...";
        } else {
          input = document.createElement("input");
          input.type = type === "email" ? "email" : "text";
          input.placeholder = label;
        }

        block.appendChild(fieldLabel);
        block.appendChild(input);
        fields.appendChild(block);

        status.textContent = label + " added to the form preview.";
        updateCount();
      }

      function createGhost(tool, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-formbuild-ghost";
        ghost.innerHTML = "<strong>" + tool.getAttribute("data-label") + "</strong>";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function start(event) {
        const tool = event.target.closest("[data-vb-formbuild-tool]");
        if (!tool) return;

        event.preventDefault();

        const point = getPoint(event);
        activeTool = tool;
        activeTool.classList.add("is-dragging");

        createGhost(tool, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!activeTool) return;

        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);

        if (isOverDrop(point.x, point.y)) {
          drop.classList.add("is-over");
        } else {
          drop.classList.remove("is-over");
        }
      }

      function end(event) {
        if (!activeTool) return;

        const point = getPoint(event);

        if (isOverDrop(point.x, point.y)) {
          createField(activeTool.getAttribute("data-type"), activeTool.getAttribute("data-label"));
        }

        cleanup();
      }

      function cancel() {
        cleanup();
      }

      function cleanup() {
        if (activeTool) activeTool.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        activeTool = null;
        ghost = null;
        drop.classList.remove("is-over");

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateCount();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initFormBuilder);
  } else {
    initFormBuilder();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initFormBuilder() {
    document.querySelectorAll("[data-vb-formbuild]").forEach(function (root) {
      if (root.getAttribute("data-vb-formbuild-ready") === "1") return;
      root.setAttribute("data-vb-formbuild-ready", "1");

      const drop = root.querySelector("[data-vb-formbuild-drop]");
      const fields = root.querySelector("[data-vb-formbuild-fields]");
      const empty = root.querySelector("[data-vb-formbuild-empty]");
      const count = root.querySelector("[data-vb-formbuild-count]");
      const status = root.querySelector("[data-vb-formbuild-status]");

      let activeTool = null;
      let ghost = null;
      let fieldCount = 0;

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function isOverDrop(x, y) {
        const el = document.elementFromPoint(x, y);
        return !!(el &amp;&amp; el.closest("[data-vb-formbuild-drop]") === drop);
      }

      function updateCount() {
        const total = fields.querySelectorAll(".vb-formbuild-field").length;
        count.textContent = total === 1 ? "1 field" : total + " fields";
        empty.style.display = total ? "none" : "block";
      }

      function createField(type, label) {
        fieldCount += 1;

        const block = document.createElement("div");
        block.className = "vb-formbuild-field";

        const fieldLabel = document.createElement("label");
        fieldLabel.textContent = label + " " + fieldCount;

        let input;

        if (type === "select") {
          input = document.createElement("select");
          input.innerHTML = "&lt;option&gt;Option One&lt;/option&gt;&lt;option&gt;Option Two&lt;/option&gt;";
        } else if (type === "textarea") {
          input = document.createElement("textarea");
          input.placeholder = "Write your message...";
        } else {
          input = document.createElement("input");
          input.type = type === "email" ? "email" : "text";
          input.placeholder = label;
        }

        block.appendChild(fieldLabel);
        block.appendChild(input);
        fields.appendChild(block);

        status.textContent = label + " added to the form preview.";
        updateCount();
      }

      function createGhost(tool, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-formbuild-ghost";
        ghost.innerHTML = "&lt;strong&gt;" + tool.getAttribute("data-label") + "&lt;/strong&gt;";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function start(event) {
        const tool = event.target.closest("[data-vb-formbuild-tool]");
        if (!tool) return;

        event.preventDefault();

        const point = getPoint(event);
        activeTool = tool;
        activeTool.classList.add("is-dragging");

        createGhost(tool, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!activeTool) return;

        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);

        if (isOverDrop(point.x, point.y)) {
          drop.classList.add("is-over");
        } else {
          drop.classList.remove("is-over");
        }
      }

      function end(event) {
        if (!activeTool) return;

        const point = getPoint(event);

        if (isOverDrop(point.x, point.y)) {
          createField(activeTool.getAttribute("data-type"), activeTool.getAttribute("data-label"));
        }

        cleanup();
      }

      function cancel() {
        cleanup();
      }

      function cleanup() {
        if (activeTool) activeTool.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        activeTool = null;
        ghost = null;
        drop.classList.remove("is-over");

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateCount();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initFormBuilder);
  } else {
    initFormBuilder();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-formbuild-demo"&gt;
  &lt;div class="vb-formbuild-wrap" data-vb-formbuild&gt;
    &lt;div class="vb-formbuild-head"&gt;
      &lt;span&gt;Example 11&lt;/span&gt;
      &lt;h3&gt;Drag and Drop Form Builder&lt;/h3&gt;
      &lt;p&gt;Drag a field type from the left panel into the form preview area.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-formbuild-builder"&gt;
      &lt;aside class="vb-formbuild-tools"&gt;
        &lt;h4&gt;Field blocks&lt;/h4&gt;

        &lt;button type="button" class="vb-formbuild-tool" data-vb-formbuild-tool data-type="text" data-label="Text Input"&gt;
          &lt;span&gt;TXT&lt;/span&gt;
          &lt;strong&gt;Text Input&lt;/strong&gt;
        &lt;/button&gt;

        &lt;button type="button" class="vb-formbuild-tool" data-vb-formbuild-tool data-type="email" data-label="Email Field"&gt;
          &lt;span&gt;@&lt;/span&gt;
          &lt;strong&gt;Email Field&lt;/strong&gt;
        &lt;/button&gt;

        &lt;button type="button" class="vb-formbuild-tool" data-vb-formbuild-tool data-type="select" data-label="Select Dropdown"&gt;
          &lt;span&gt;SEL&lt;/span&gt;
          &lt;strong&gt;Select Dropdown&lt;/strong&gt;
        &lt;/button&gt;

        &lt;button type="button" class="vb-formbuild-tool" data-vb-formbuild-tool data-type="textarea" data-label="Message Box"&gt;
          &lt;span&gt;MSG&lt;/span&gt;
          &lt;strong&gt;Message Box&lt;/strong&gt;
        &lt;/button&gt;
      &lt;/aside&gt;

      &lt;section class="vb-formbuild-preview"&gt;
        &lt;div class="vb-formbuild-preview-head"&gt;
          &lt;div&gt;
            &lt;span&gt;Live preview&lt;/span&gt;
            &lt;h4&gt;Quote Request Form&lt;/h4&gt;
          &lt;/div&gt;
          &lt;strong data-vb-formbuild-count&gt;0 fields&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-formbuild-drop" data-vb-formbuild-drop&gt;
          &lt;p data-vb-formbuild-empty&gt;Drag field blocks here to build the form.&lt;/p&gt;
          &lt;div class="vb-formbuild-fields" data-vb-formbuild-fields&gt;&lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;

    &lt;div class="vb-formbuild-status" data-vb-formbuild-status&gt;Choose a field block and drag it into the form preview.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">/* CSS is included fully in the live demo block above. */</pre>



<p class="wp-block-paragraph">This JavaScript drag and drop form builder is useful for form plugins, survey tools, quote request builders, admin dashboards, signup forms, lead generation systems, and no-code editors.</p>



<h2 class="wp-block-heading">12. Page Section Builder with Drag and Drop</h2>



<p class="wp-block-paragraph"><strong>A page section builder with drag and drop</strong> shows how users can build a landing page layout by dragging section blocks into a page preview. This pattern is useful for website builders, landing page tools, block editors, portfolio builders, and content management dashboards.</p>



<ul class="wp-block-list">
<li>Drag page sections into a landing page preview</li>
<li>Creates visual page blocks</li>
<li>Different UI from list/card examples</li>
<li>Mouse and touch support</li>
<li>Live section count</li>
</ul>



<div class="vb-pagebuild-demo">
  <div class="vb-pagebuild-wrap" data-vb-pagebuild>
    <div class="vb-pagebuild-head">
      <span>Example 12</span>
      <h3>Page Section Builder</h3>
      <p>Drag section blocks into the page canvas to build a small landing page layout.</p>
    </div>

    <div class="vb-pagebuild-app">
      <aside class="vb-pagebuild-library">
        <h4>Sections</h4>

        <button type="button" data-vb-pagebuild-tool data-type="hero" data-label="Hero Section">
          <span>Hero</span>
          <strong>Hero Section</strong>
        </button>

        <button type="button" data-vb-pagebuild-tool data-type="features" data-label="Feature Grid">
          <span>Grid</span>
          <strong>Feature Grid</strong>
        </button>

        <button type="button" data-vb-pagebuild-tool data-type="testimonial" data-label="Testimonial">
          <span>Quote</span>
          <strong>Testimonial</strong>
        </button>

        <button type="button" data-vb-pagebuild-tool data-type="cta" data-label="CTA Section">
          <span>CTA</span>
          <strong>CTA Section</strong>
        </button>
      </aside>

      <section class="vb-pagebuild-canvas-shell">
        <div class="vb-pagebuild-canvas-head">
          <div>
            <span>Page canvas</span>
            <h4>Landing Page Draft</h4>
          </div>
          <strong data-vb-pagebuild-count>0 sections</strong>
        </div>

        <div class="vb-pagebuild-canvas" data-vb-pagebuild-drop>
          <p data-vb-pagebuild-empty>Drop page sections here.</p>
          <div class="vb-pagebuild-sections" data-vb-pagebuild-sections></div>
        </div>
      </section>
    </div>

    <div class="vb-pagebuild-status" data-vb-pagebuild-status>Drag a section into the canvas.</div>
  </div>
</div>

<style>
.vb-pagebuild-demo,
.vb-pagebuild-demo * {
  box-sizing: border-box;
}

.vb-pagebuild-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(168, 85, 247, 0.16), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(236, 72, 153, 0.16), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #fdf2f8 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-pagebuild-wrap {
  max-width: 1160px;
  margin: 0 auto;
}

.vb-pagebuild-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-pagebuild-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-pagebuild-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-pagebuild-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-pagebuild-app {
  display: grid;
  grid-template-columns: minmax(240px, 0.35fr) minmax(0, 1fr);
  gap: 16px;
}

.vb-pagebuild-library,
.vb-pagebuild-canvas-shell {
  padding: 16px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-pagebuild-library {
  display: grid;
  align-content: start;
  gap: 12px;
}

.vb-pagebuild-library h4,
.vb-pagebuild-canvas-head h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 22px !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-pagebuild-library button {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  width: 100%;
  padding: 13px;
  border: 0;
  border-radius: 18px;
  background: #faf5ff;
  cursor: grab;
  text-align: left;
  touch-action: none;
}

.vb-pagebuild-library button.is-dragging {
  opacity: 0.45;
}

.vb-pagebuild-library button span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 52px;
  height: 42px;
  padding: 0 8px;
  border-radius: 15px;
  background: #7e22ce;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-pagebuild-library button strong {
  color: #581c87 !important;
  -webkit-text-fill-color: #581c87 !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-pagebuild-canvas-head {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: center;
  margin-bottom: 14px;
}

.vb-pagebuild-canvas-head span {
  display: block;
  margin-bottom: 5px;
  color: #a21caf !important;
  -webkit-text-fill-color: #a21caf !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-pagebuild-canvas-head > strong {
  display: inline-flex;
  min-width: 104px;
  justify-content: center;
  padding: 9px 12px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-pagebuild-canvas {
  min-height: 430px;
  padding: 18px;
  border-radius: 24px;
  border: 1px dashed rgba(168, 85, 247, 0.55);
  background: #f8fafc;
}

.vb-pagebuild-canvas.is-over {
  border-color: rgba(168, 85, 247, 0.95);
  background: #faf5ff;
  box-shadow: inset 0 0 0 4px rgba(168, 85, 247, 0.12);
}

.vb-pagebuild-canvas > p {
  margin: 0 !important;
  padding: 18px;
  border-radius: 18px;
  background: #ffffff;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 750;
  text-align: center;
}

.vb-pagebuild-sections {
  display: grid;
  gap: 12px;
}

.vb-pagebuild-section {
  overflow: hidden;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 12px 28px rgba(15, 23, 42, 0.07);
}

.vb-pagebuild-section-preview {
  padding: 22px;
}

.vb-pagebuild-section-preview h5 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
}

.vb-pagebuild-section-preview p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-pagebuild-section.hero .vb-pagebuild-section-preview {
  background: linear-gradient(135deg, #111827, #7e22ce);
}

.vb-pagebuild-section.hero h5,
.vb-pagebuild-section.hero p {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-pagebuild-section.features .vb-pagebuild-section-preview {
  background: linear-gradient(135deg, #ecfeff, #ffffff);
}

.vb-pagebuild-section.testimonial .vb-pagebuild-section-preview {
  background: linear-gradient(135deg, #fdf2f8, #ffffff);
}

.vb-pagebuild-section.cta .vb-pagebuild-section-preview {
  background: linear-gradient(135deg, #f59e0b, #ec4899);
}

.vb-pagebuild-section.cta h5,
.vb-pagebuild-section.cta p {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-pagebuild-status {
  margin-top: 16px;
  padding: 13px 15px;
  border-radius: 18px;
  background: #581c87;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-pagebuild-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(280px, calc(100vw - 32px));
  padding: 13px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(168, 85, 247, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
}

.vb-pagebuild-ghost strong {
  color: #581c87 !important;
  -webkit-text-fill-color: #581c87 !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-pagebuild-app {
    grid-template-columns: 1fr;
  }

  .vb-pagebuild-canvas {
    min-height: 320px;
  }
}

@media (max-width: 480px) {
  .vb-pagebuild-canvas-head {
    align-items: flex-start;
    flex-direction: column;
  }
}
</style>

<script>
(function () {
  function initPageBuilder() {
    document.querySelectorAll("[data-vb-pagebuild]").forEach(function (root) {
      if (root.getAttribute("data-vb-pagebuild-ready") === "1") return;
      root.setAttribute("data-vb-pagebuild-ready", "1");

      const drop = root.querySelector("[data-vb-pagebuild-drop]");
      const sections = root.querySelector("[data-vb-pagebuild-sections]");
      const empty = root.querySelector("[data-vb-pagebuild-empty]");
      const count = root.querySelector("[data-vb-pagebuild-count]");
      const status = root.querySelector("[data-vb-pagebuild-status]");

      let activeTool = null;
      let ghost = null;

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function isOverDrop(x, y) {
        const el = document.elementFromPoint(x, y);
        return !!(el && el.closest("[data-vb-pagebuild-drop]") === drop);
      }

      function updateCount() {
        const total = sections.querySelectorAll(".vb-pagebuild-section").length;
        count.textContent = total === 1 ? "1 section" : total + " sections";
        empty.style.display = total ? "none" : "block";
      }

      function sectionText(type) {
        const data = {
          hero: ["Hero Section", "A bold opening section with a headline, intro text, and call to action."],
          features: ["Feature Grid", "A section for showing benefits, services, features, or product highlights."],
          testimonial: ["Testimonial", "A social proof section for reviews, quotes, customer stories, or trust signals."],
          cta: ["CTA Section", "A conversion section that asks the visitor to contact, subscribe, buy, or request a quote."]
        };

        return data[type] || ["Page Section", "A reusable page block."];
      }

      function createSection(type) {
        const text = sectionText(type);

        const section = document.createElement("article");
        section.className = "vb-pagebuild-section " + type;

        const preview = document.createElement("div");
        preview.className = "vb-pagebuild-section-preview";

        const title = document.createElement("h5");
        title.textContent = text[0];

        const paragraph = document.createElement("p");
        paragraph.textContent = text[1];

        preview.appendChild(title);
        preview.appendChild(paragraph);
        section.appendChild(preview);
        sections.appendChild(section);

        status.textContent = text[0] + " added to the page canvas.";
        updateCount();
      }

      function createGhost(tool, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-pagebuild-ghost";
        ghost.innerHTML = "<strong>" + tool.getAttribute("data-label") + "</strong>";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function start(event) {
        const tool = event.target.closest("[data-vb-pagebuild-tool]");
        if (!tool) return;

        event.preventDefault();

        const point = getPoint(event);
        activeTool = tool;
        activeTool.classList.add("is-dragging");

        createGhost(tool, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!activeTool) return;

        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);

        if (isOverDrop(point.x, point.y)) {
          drop.classList.add("is-over");
        } else {
          drop.classList.remove("is-over");
        }
      }

      function end(event) {
        if (!activeTool) return;

        const point = getPoint(event);

        if (isOverDrop(point.x, point.y)) {
          createSection(activeTool.getAttribute("data-type"));
        }

        cleanup();
      }

      function cancel() {
        cleanup();
      }

      function cleanup() {
        if (activeTool) activeTool.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        activeTool = null;
        ghost = null;
        drop.classList.remove("is-over");

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateCount();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initPageBuilder);
  } else {
    initPageBuilder();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initPageBuilder() {
    document.querySelectorAll("[data-vb-pagebuild]").forEach(function (root) {
      if (root.getAttribute("data-vb-pagebuild-ready") === "1") return;
      root.setAttribute("data-vb-pagebuild-ready", "1");

      const drop = root.querySelector("[data-vb-pagebuild-drop]");
      const sections = root.querySelector("[data-vb-pagebuild-sections]");
      const empty = root.querySelector("[data-vb-pagebuild-empty]");
      const count = root.querySelector("[data-vb-pagebuild-count]");
      const status = root.querySelector("[data-vb-pagebuild-status]");

      let activeTool = null;
      let ghost = null;

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function isOverDrop(x, y) {
        const el = document.elementFromPoint(x, y);
        return !!(el &amp;&amp; el.closest("[data-vb-pagebuild-drop]") === drop);
      }

      function updateCount() {
        const total = sections.querySelectorAll(".vb-pagebuild-section").length;
        count.textContent = total === 1 ? "1 section" : total + " sections";
        empty.style.display = total ? "none" : "block";
      }

      function sectionText(type) {
        const data = {
          hero: ["Hero Section", "A bold opening section with a headline, intro text, and call to action."],
          features: ["Feature Grid", "A section for showing benefits, services, features, or product highlights."],
          testimonial: ["Testimonial", "A social proof section for reviews, quotes, customer stories, or trust signals."],
          cta: ["CTA Section", "A conversion section that asks the visitor to contact, subscribe, buy, or request a quote."]
        };

        return data[type] || ["Page Section", "A reusable page block."];
      }

      function createSection(type) {
        const text = sectionText(type);

        const section = document.createElement("article");
        section.className = "vb-pagebuild-section " + type;

        const preview = document.createElement("div");
        preview.className = "vb-pagebuild-section-preview";

        const title = document.createElement("h5");
        title.textContent = text[0];

        const paragraph = document.createElement("p");
        paragraph.textContent = text[1];

        preview.appendChild(title);
        preview.appendChild(paragraph);
        section.appendChild(preview);
        sections.appendChild(section);

        status.textContent = text[0] + " added to the page canvas.";
        updateCount();
      }

      function createGhost(tool, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-pagebuild-ghost";
        ghost.innerHTML = "&lt;strong&gt;" + tool.getAttribute("data-label") + "&lt;/strong&gt;";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function start(event) {
        const tool = event.target.closest("[data-vb-pagebuild-tool]");
        if (!tool) return;

        event.preventDefault();

        const point = getPoint(event);
        activeTool = tool;
        activeTool.classList.add("is-dragging");

        createGhost(tool, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!activeTool) return;

        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);

        if (isOverDrop(point.x, point.y)) {
          drop.classList.add("is-over");
        } else {
          drop.classList.remove("is-over");
        }
      }

      function end(event) {
        if (!activeTool) return;

        const point = getPoint(event);

        if (isOverDrop(point.x, point.y)) {
          createSection(activeTool.getAttribute("data-type"));
        }

        cleanup();
      }

      function cancel() {
        cleanup();
      }

      function cleanup() {
        if (activeTool) activeTool.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        activeTool = null;
        ghost = null;
        drop.classList.remove("is-over");

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateCount();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initPageBuilder);
  } else {
    initPageBuilder();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-pagebuild-demo"&gt;
  &lt;div class="vb-pagebuild-wrap" data-vb-pagebuild&gt;
    &lt;div class="vb-pagebuild-head"&gt;
      &lt;span&gt;Example 12&lt;/span&gt;
      &lt;h3&gt;Page Section Builder&lt;/h3&gt;
      &lt;p&gt;Drag section blocks into the page canvas to build a small landing page layout.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-pagebuild-app"&gt;
      &lt;aside class="vb-pagebuild-library"&gt;
        &lt;h4&gt;Sections&lt;/h4&gt;

        &lt;button type="button" data-vb-pagebuild-tool data-type="hero" data-label="Hero Section"&gt;
          &lt;span&gt;Hero&lt;/span&gt;
          &lt;strong&gt;Hero Section&lt;/strong&gt;
        &lt;/button&gt;

        &lt;button type="button" data-vb-pagebuild-tool data-type="features" data-label="Feature Grid"&gt;
          &lt;span&gt;Grid&lt;/span&gt;
          &lt;strong&gt;Feature Grid&lt;/strong&gt;
        &lt;/button&gt;

        &lt;button type="button" data-vb-pagebuild-tool data-type="testimonial" data-label="Testimonial"&gt;
          &lt;span&gt;Quote&lt;/span&gt;
          &lt;strong&gt;Testimonial&lt;/strong&gt;
        &lt;/button&gt;

        &lt;button type="button" data-vb-pagebuild-tool data-type="cta" data-label="CTA Section"&gt;
          &lt;span&gt;CTA&lt;/span&gt;
          &lt;strong&gt;CTA Section&lt;/strong&gt;
        &lt;/button&gt;
      &lt;/aside&gt;

      &lt;section class="vb-pagebuild-canvas-shell"&gt;
        &lt;div class="vb-pagebuild-canvas-head"&gt;
          &lt;div&gt;
            &lt;span&gt;Page canvas&lt;/span&gt;
            &lt;h4&gt;Landing Page Draft&lt;/h4&gt;
          &lt;/div&gt;
          &lt;strong data-vb-pagebuild-count&gt;0 sections&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-pagebuild-canvas" data-vb-pagebuild-drop&gt;
          &lt;p data-vb-pagebuild-empty&gt;Drop page sections here.&lt;/p&gt;
          &lt;div class="vb-pagebuild-sections" data-vb-pagebuild-sections&gt;&lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;

    &lt;div class="vb-pagebuild-status" data-vb-pagebuild-status&gt;Drag a section into the canvas.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">/* CSS is included fully in the live demo block above. */</pre>



<p class="wp-block-paragraph">This JavaScript page section builder is useful for landing page builders, block editors, content management dashboards, portfolio tools, website builders, and no-code page creation interfaces.</p>



<div class="vb-mini-contact-cta">
  <p><strong>Need a custom interactive JavaScript feature?</strong> We can build drag and drop tools, calculators, forms, dashboards, and custom website components for your business.</p>
  <a href="https://veebilehed24.ee/en/contact/">Contact us</a>
</div>

<style>
.vb-mini-contact-cta,
.vb-mini-contact-cta * {
  box-sizing: border-box;
}

.vb-mini-contact-cta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin: 36px 0;
  padding: 16px 18px;
  border-radius: 18px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.28);
}

.vb-mini-contact-cta p {
  margin: 0 !important;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-mini-contact-cta strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-weight: 950;
}

.vb-mini-contact-cta a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 40px;
  padding: 10px 16px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 900;
  text-decoration: none !important;
  white-space: nowrap;
}

@media (max-width: 680px) {
  .vb-mini-contact-cta {
    align-items: flex-start;
    flex-direction: column;
  }
}
</style>



<h2 class="wp-block-heading">13. Drag and Drop Dashboard Widget Layout</h2>



<p class="wp-block-paragraph"><strong>A drag and drop dashboard widget layout</strong> is useful for admin dashboards, analytics panels, SaaS apps, CRM systems, reporting tools, and user profile dashboards. Users can reorder widgets to customize their own workspace.</p>



<ul class="wp-block-list">
<li>Reorder dashboard widgets</li>
<li>Mouse and touch support</li>
<li>Live layout order text</li>
<li>Responsive dashboard grid</li>
<li>No external libraries</li>
</ul>



<div class="vb-dashgrid-demo">
  <div class="vb-dashgrid-wrap" data-vb-dashgrid>
    <div class="vb-dashgrid-head">
      <span>Example 13</span>
      <h3>Dashboard Widget Layout</h3>
      <p>Drag widget handles to rearrange the dashboard layout. The order updates instantly.</p>
    </div>

    <div class="vb-dashgrid-toolbar">
      <span>Current layout</span>
      <strong data-vb-dashgrid-output>Revenue → Visitors → Tasks → Server</strong>
    </div>

    <div class="vb-dashgrid-board" data-vb-dashgrid-board>
      <article class="vb-dashgrid-widget vb-dashgrid-wide" data-vb-dashgrid-widget data-title="Revenue">
        <button type="button" data-vb-dashgrid-handle>⋮⋮</button>
        <span>Revenue</span>
        <h4>€24,860</h4>
        <p>Monthly sales performance</p>
      </article>

      <article class="vb-dashgrid-widget" data-vb-dashgrid-widget data-title="Visitors">
        <button type="button" data-vb-dashgrid-handle>⋮⋮</button>
        <span>Visitors</span>
        <h4>48.2K</h4>
        <p>Website traffic</p>
      </article>

      <article class="vb-dashgrid-widget" data-vb-dashgrid-widget data-title="Tasks">
        <button type="button" data-vb-dashgrid-handle>⋮⋮</button>
        <span>Tasks</span>
        <h4>17</h4>
        <p>Open project tasks</p>
      </article>

      <article class="vb-dashgrid-widget vb-dashgrid-dark" data-vb-dashgrid-widget data-title="Server">
        <button type="button" data-vb-dashgrid-handle>⋮⋮</button>
        <span>Server</span>
        <h4>99.9%</h4>
        <p>Uptime this month</p>
      </article>
    </div>
  </div>
</div>

<style>
.vb-dashgrid-demo,
.vb-dashgrid-demo * {
  box-sizing: border-box;
}

.vb-dashgrid-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 10% 12%, rgba(37, 99, 235, 0.16), transparent 34%),
    radial-gradient(circle at 92% 20%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #faf5ff 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-dashgrid-wrap {
  max-width: 1160px;
  margin: 0 auto;
}

.vb-dashgrid-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-dashgrid-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-dashgrid-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-dashgrid-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-dashgrid-toolbar {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: center;
  margin-bottom: 16px;
  padding: 14px 16px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.07);
}

.vb-dashgrid-toolbar span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

.vb-dashgrid-toolbar strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-dashgrid-board {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-dashgrid-widget {
  position: relative;
  min-height: 190px;
  padding: 18px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.08);
  overflow: hidden;
}

.vb-dashgrid-wide {
  grid-column: span 2;
  background:
    radial-gradient(circle at 85% 15%, rgba(37, 99, 235, 0.18), transparent 34%),
    #ffffff;
}

.vb-dashgrid-dark {
  background:
    radial-gradient(circle at 20% 10%, rgba(34, 211, 238, 0.22), transparent 34%),
    linear-gradient(135deg, #0f172a, #312e81) !important;
}

.vb-dashgrid-widget.is-dragging {
  opacity: 0.45;
}

.vb-dashgrid-widget.is-over {
  outline: 3px solid rgba(37, 99, 235, 0.28);
}

.vb-dashgrid-widget button {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 38px;
  height: 42px;
  border: 0;
  border-radius: 14px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 19px;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
}

.vb-dashgrid-widget span {
  display: inline-flex;
  margin-bottom: 24px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dashgrid-widget h4 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(30px, 5vw, 48px) !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-dashgrid-widget p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

.vb-dashgrid-dark span,
.vb-dashgrid-dark h4,
.vb-dashgrid-dark p {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dashgrid-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(280px, calc(100vw - 32px));
  padding: 14px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(37, 99, 235, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
}

.vb-dashgrid-ghost strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

@media (max-width: 940px) {
  .vb-dashgrid-board {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-dashgrid-wide {
    grid-column: span 1;
  }
}

@media (max-width: 560px) {
  .vb-dashgrid-board {
    grid-template-columns: 1fr;
  }

  .vb-dashgrid-toolbar {
    align-items: flex-start;
    flex-direction: column;
  }
}
</style>

<script>
(function () {
  function initDashboardGrid() {
    document.querySelectorAll("[data-vb-dashgrid]").forEach(function (root) {
      if (root.getAttribute("data-vb-dashgrid-ready") === "1") return;
      root.setAttribute("data-vb-dashgrid-ready", "1");

      const board = root.querySelector("[data-vb-dashgrid-board]");
      const output = root.querySelector("[data-vb-dashgrid-output]");
      let active = null;
      let ghost = null;

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function updateOutput() {
        output.textContent = Array.from(board.querySelectorAll("[data-vb-dashgrid-widget]"))
          .map(function (item) { return item.getAttribute("data-title"); })
          .join(" → ");
      }

      function createGhost(widget, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-dashgrid-ghost";
        ghost.innerHTML = "<strong>" + widget.getAttribute("data-title") + "</strong>";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function clearOver() {
        board.querySelectorAll(".is-over").forEach(function (item) {
          item.classList.remove("is-over");
        });
      }

      function reorderAt(x, y) {
        const el = document.elementFromPoint(x, y);
        const target = el ? el.closest("[data-vb-dashgrid-widget]") : null;
        if (!target || target === active || !board.contains(target)) return;

        const rect = target.getBoundingClientRect();
        const after = y > rect.top + rect.height / 2;

        clearOver();
        target.classList.add("is-over");

        if (after) {
          target.insertAdjacentElement("afterend", active);
        } else {
          target.insertAdjacentElement("beforebegin", active);
        }

        updateOutput();
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-dashgrid-handle]");
        if (!handle) return;

        const widget = handle.closest("[data-vb-dashgrid-widget]");
        if (!widget) return;

        event.preventDefault();

        const point = getPoint(event);
        active = widget;
        active.classList.add("is-dragging");
        createGhost(widget, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;
        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);
        reorderAt(point.x, point.y);
      }

      function end() {
        cleanup();
        updateOutput();
      }

      function cancel() {
        cleanup();
        updateOutput();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateOutput();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initDashboardGrid);
  } else {
    initDashboardGrid();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initDashboardGrid() {
    document.querySelectorAll("[data-vb-dashgrid]").forEach(function (root) {
      if (root.getAttribute("data-vb-dashgrid-ready") === "1") return;
      root.setAttribute("data-vb-dashgrid-ready", "1");

      const board = root.querySelector("[data-vb-dashgrid-board]");
      const output = root.querySelector("[data-vb-dashgrid-output]");
      let active = null;
      let ghost = null;

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function updateOutput() {
        output.textContent = Array.from(board.querySelectorAll("[data-vb-dashgrid-widget]"))
          .map(function (item) { return item.getAttribute("data-title"); })
          .join(" → ");
      }

      function createGhost(widget, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-dashgrid-ghost";
        ghost.innerHTML = "&lt;strong&gt;" + widget.getAttribute("data-title") + "&lt;/strong&gt;";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function clearOver() {
        board.querySelectorAll(".is-over").forEach(function (item) {
          item.classList.remove("is-over");
        });
      }

      function reorderAt(x, y) {
        const el = document.elementFromPoint(x, y);
        const target = el ? el.closest("[data-vb-dashgrid-widget]") : null;
        if (!target || target === active || !board.contains(target)) return;

        const rect = target.getBoundingClientRect();
        const after = y &gt; rect.top + rect.height / 2;

        clearOver();
        target.classList.add("is-over");

        if (after) {
          target.insertAdjacentElement("afterend", active);
        } else {
          target.insertAdjacentElement("beforebegin", active);
        }

        updateOutput();
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-dashgrid-handle]");
        if (!handle) return;

        const widget = handle.closest("[data-vb-dashgrid-widget]");
        if (!widget) return;

        event.preventDefault();

        const point = getPoint(event);
        active = widget;
        active.classList.add("is-dragging");
        createGhost(widget, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;
        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);
        reorderAt(point.x, point.y);
      }

      function end() {
        cleanup();
        updateOutput();
      }

      function cancel() {
        cleanup();
        updateOutput();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateOutput();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initDashboardGrid);
  } else {
    initDashboardGrid();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dashgrid-demo"&gt;
  &lt;div class="vb-dashgrid-wrap" data-vb-dashgrid&gt;
    &lt;div class="vb-dashgrid-head"&gt;
      &lt;span&gt;Example 13&lt;/span&gt;
      &lt;h3&gt;Dashboard Widget Layout&lt;/h3&gt;
      &lt;p&gt;Drag widget handles to rearrange the dashboard layout. The order updates instantly.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-dashgrid-toolbar"&gt;
      &lt;span&gt;Current layout&lt;/span&gt;
      &lt;strong data-vb-dashgrid-output&gt;Revenue → Visitors → Tasks → Server&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-dashgrid-board" data-vb-dashgrid-board&gt;
      &lt;article class="vb-dashgrid-widget vb-dashgrid-wide" data-vb-dashgrid-widget data-title="Revenue"&gt;
        &lt;button type="button" data-vb-dashgrid-handle&gt;⋮⋮&lt;/button&gt;
        &lt;span&gt;Revenue&lt;/span&gt;
        &lt;h4&gt;€24,860&lt;/h4&gt;
        &lt;p&gt;Monthly sales performance&lt;/p&gt;
      &lt;/article&gt;

      &lt;article class="vb-dashgrid-widget" data-vb-dashgrid-widget data-title="Visitors"&gt;
        &lt;button type="button" data-vb-dashgrid-handle&gt;⋮⋮&lt;/button&gt;
        &lt;span&gt;Visitors&lt;/span&gt;
        &lt;h4&gt;48.2K&lt;/h4&gt;
        &lt;p&gt;Website traffic&lt;/p&gt;
      &lt;/article&gt;

      &lt;article class="vb-dashgrid-widget" data-vb-dashgrid-widget data-title="Tasks"&gt;
        &lt;button type="button" data-vb-dashgrid-handle&gt;⋮⋮&lt;/button&gt;
        &lt;span&gt;Tasks&lt;/span&gt;
        &lt;h4&gt;17&lt;/h4&gt;
        &lt;p&gt;Open project tasks&lt;/p&gt;
      &lt;/article&gt;

      &lt;article class="vb-dashgrid-widget vb-dashgrid-dark" data-vb-dashgrid-widget data-title="Server"&gt;
        &lt;button type="button" data-vb-dashgrid-handle&gt;⋮⋮&lt;/button&gt;
        &lt;span&gt;Server&lt;/span&gt;
        &lt;h4&gt;99.9%&lt;/h4&gt;
        &lt;p&gt;Uptime this month&lt;/p&gt;
      &lt;/article&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dashgrid-demo,
.vb-dashgrid-demo * {
  box-sizing: border-box;
}

.vb-dashgrid-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 10% 12%, rgba(37, 99, 235, 0.16), transparent 34%),
    radial-gradient(circle at 92% 20%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #faf5ff 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-dashgrid-wrap {
  max-width: 1160px;
  margin: 0 auto;
}

.vb-dashgrid-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-dashgrid-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-dashgrid-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-dashgrid-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-dashgrid-toolbar {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: center;
  margin-bottom: 16px;
  padding: 14px 16px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.07);
}

.vb-dashgrid-toolbar span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

.vb-dashgrid-toolbar strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-dashgrid-board {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-dashgrid-widget {
  position: relative;
  min-height: 190px;
  padding: 18px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.08);
  overflow: hidden;
}

.vb-dashgrid-wide {
  grid-column: span 2;
  background:
    radial-gradient(circle at 85% 15%, rgba(37, 99, 235, 0.18), transparent 34%),
    #ffffff;
}

.vb-dashgrid-dark {
  background:
    radial-gradient(circle at 20% 10%, rgba(34, 211, 238, 0.22), transparent 34%),
    linear-gradient(135deg, #0f172a, #312e81) !important;
}

.vb-dashgrid-widget.is-dragging {
  opacity: 0.45;
}

.vb-dashgrid-widget.is-over {
  outline: 3px solid rgba(37, 99, 235, 0.28);
}

.vb-dashgrid-widget button {
  position: absolute;
  top: 14px;
  right: 14px;
  width: 38px;
  height: 42px;
  border: 0;
  border-radius: 14px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 19px;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
}

.vb-dashgrid-widget span {
  display: inline-flex;
  margin-bottom: 24px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dashgrid-widget h4 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(30px, 5vw, 48px) !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-dashgrid-widget p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

.vb-dashgrid-dark span,
.vb-dashgrid-dark h4,
.vb-dashgrid-dark p {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dashgrid-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(280px, calc(100vw - 32px));
  padding: 14px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(37, 99, 235, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
}

.vb-dashgrid-ghost strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

@media (max-width: 940px) {
  .vb-dashgrid-board {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-dashgrid-wide {
    grid-column: span 1;
  }
}

@media (max-width: 560px) {
  .vb-dashgrid-board {
    grid-template-columns: 1fr;
  }

  .vb-dashgrid-toolbar {
    align-items: flex-start;
    flex-direction: column;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript dashboard widget layout is useful for analytics dashboards, SaaS admin panels, reporting tools, CRM interfaces, and customizable user workspaces.</p>



<h2 class="wp-block-heading">14. Nested Drag and Drop Menu Builder</h2>



<p class="wp-block-paragraph"><strong>A nested drag and drop menu builder</strong> lets users move menu items into parent sections. This is useful for website navigation builders, WordPress-style menus, app sidebars, documentation menus, admin panels, and no-code content tools.</p>



<ul class="wp-block-list">
<li>Drag menu items into parent groups</li>
<li>Nested submenu zones</li>
<li>Mouse and touch support</li>
<li>Live menu structure summary</li>
<li>Responsive menu builder layout</li>
</ul>



<div class="vb-nestmenu-demo">
  <div class="vb-nestmenu-wrap" data-vb-nestmenu>
    <div class="vb-nestmenu-head">
      <span>Example 14</span>
      <h3>Nested Menu Builder</h3>
      <p>Drag loose menu items into parent menu groups to create a nested navigation structure.</p>
    </div>

    <div class="vb-nestmenu-app">
      <aside class="vb-nestmenu-palette">
        <h4>Menu Items</h4>

        <div class="vb-nestmenu-drop" data-vb-nestmenu-drop data-zone="items">
          <article class="vb-nestmenu-card" data-vb-nestmenu-card data-label="Pricing">
            <button type="button" data-vb-nestmenu-handle>⋮⋮</button>
            <strong>Pricing</strong>
          </article>

          <article class="vb-nestmenu-card" data-vb-nestmenu-card data-label="Portfolio">
            <button type="button" data-vb-nestmenu-handle>⋮⋮</button>
            <strong>Portfolio</strong>
          </article>

          <article class="vb-nestmenu-card" data-vb-nestmenu-card data-label="Support">
            <button type="button" data-vb-nestmenu-handle>⋮⋮</button>
            <strong>Support</strong>
          </article>
        </div>
      </aside>

      <section class="vb-nestmenu-tree">
        <div class="vb-nestmenu-group">
          <div class="vb-nestmenu-group-title">
            <h4>Services</h4>
            <span data-vb-nestmenu-count="services">0</span>
          </div>
          <div class="vb-nestmenu-subdrop" data-vb-nestmenu-drop data-zone="services"></div>
        </div>

        <div class="vb-nestmenu-group">
          <div class="vb-nestmenu-group-title">
            <h4>Company</h4>
            <span data-vb-nestmenu-count="company">0</span>
          </div>
          <div class="vb-nestmenu-subdrop" data-vb-nestmenu-drop data-zone="company"></div>
        </div>

        <div class="vb-nestmenu-group">
          <div class="vb-nestmenu-group-title">
            <h4>Resources</h4>
            <span data-vb-nestmenu-count="resources">0</span>
          </div>
          <div class="vb-nestmenu-subdrop" data-vb-nestmenu-drop data-zone="resources"></div>
        </div>
      </section>
    </div>

    <div class="vb-nestmenu-summary" data-vb-nestmenu-summary>Build a nested menu by dragging items into groups.</div>
  </div>
</div>

<style>
.vb-nestmenu-demo,
.vb-nestmenu-demo * {
  box-sizing: border-box;
}

.vb-nestmenu-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 10% 12%, rgba(20, 184, 166, 0.17), transparent 34%),
    radial-gradient(circle at 92% 20%, rgba(59, 130, 246, 0.17), transparent 34%),
    linear-gradient(135deg, #f0fdfa 0%, #eff6ff 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-nestmenu-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-nestmenu-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-nestmenu-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-nestmenu-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-nestmenu-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-nestmenu-app {
  display: grid;
  grid-template-columns: minmax(250px, 0.38fr) minmax(0, 1fr);
  gap: 16px;
}

.vb-nestmenu-palette,
.vb-nestmenu-tree {
  padding: 16px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-nestmenu-palette h4,
.vb-nestmenu-group-title h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-nestmenu-palette h4 {
  margin-bottom: 14px !important;
}

.vb-nestmenu-drop,
.vb-nestmenu-subdrop {
  display: grid;
  align-content: start;
  gap: 10px;
  min-height: 200px;
  padding: 12px;
  border-radius: 22px;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  background: #f8fafc;
}

.vb-nestmenu-subdrop {
  min-height: 120px;
}

.vb-nestmenu-drop.is-over,
.vb-nestmenu-subdrop.is-over {
  border-color: rgba(20, 184, 166, 0.82);
  background: #f0fdfa;
  box-shadow: inset 0 0 0 4px rgba(20, 184, 166, 0.10);
}

.vb-nestmenu-tree {
  display: grid;
  gap: 14px;
}

.vb-nestmenu-group {
  padding: 14px;
  border-radius: 24px;
  background: linear-gradient(135deg, #ffffff, #f8fafc);
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-nestmenu-group-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 12px;
}

.vb-nestmenu-group-title span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 34px;
  height: 32px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-nestmenu-card {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  padding: 12px;
  border-radius: 16px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 10px 24px rgba(15, 23, 42, 0.06);
}

.vb-nestmenu-card.is-dragging {
  opacity: 0.45;
}

.vb-nestmenu-card button {
  width: 34px;
  height: 40px;
  border: 0;
  border-radius: 13px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 18px;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
}

.vb-nestmenu-card strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-nestmenu-summary {
  margin-top: 16px;
  padding: 13px 15px;
  border-radius: 18px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-nestmenu-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(260px, calc(100vw - 32px));
  padding: 13px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(20, 184, 166, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
}

.vb-nestmenu-ghost strong {
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-nestmenu-app {
    grid-template-columns: 1fr;
  }

  .vb-nestmenu-drop,
  .vb-nestmenu-subdrop {
    min-height: 130px;
  }
}
</style>

<script>
(function () {
  function initNestedMenu() {
    document.querySelectorAll("[data-vb-nestmenu]").forEach(function (root) {
      if (root.getAttribute("data-vb-nestmenu-ready") === "1") return;
      root.setAttribute("data-vb-nestmenu-ready", "1");

      const drops = Array.from(root.querySelectorAll("[data-vb-nestmenu-drop]"));
      const summary = root.querySelector("[data-vb-nestmenu-summary]");
      let active = null;
      let ghost = null;

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function updateCounts() {
        drops.forEach(function (drop) {
          const zone = drop.getAttribute("data-zone");
          const count = root.querySelector('[data-vb-nestmenu-count="' + zone + '"]');
          if (count) count.textContent = drop.querySelectorAll("[data-vb-nestmenu-card]").length;
        });
      }

      function createSummary() {
        const groups = ["services", "company", "resources"].map(function (zone) {
          const drop = root.querySelector('[data-zone="' + zone + '"]');
          const labels = Array.from(drop.querySelectorAll("[data-vb-nestmenu-card]")).map(function (card) {
            return card.getAttribute("data-label");
          });
          return zone + ": " + (labels.length ? labels.join(", ") : "empty");
        });

        summary.textContent = groups.join(" | ");
      }

      function createGhost(card, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-nestmenu-ghost";
        ghost.innerHTML = "<strong>" + card.getAttribute("data-label") + "</strong>";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function getDropAt(x, y) {
        const el = document.elementFromPoint(x, y);
        if (!el) return null;
        const drop = el.closest("[data-vb-nestmenu-drop]");
        return drops.includes(drop) ? drop : null;
      }

      function clearOver() {
        drops.forEach(function (drop) { drop.classList.remove("is-over"); });
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-nestmenu-handle]");
        if (!handle) return;

        const card = handle.closest("[data-vb-nestmenu-card]");
        if (!card) return;

        event.preventDefault();

        const point = getPoint(event);
        active = card;
        active.classList.add("is-dragging");
        createGhost(card, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;
        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);
        clearOver();

        const drop = getDropAt(point.x, point.y);
        if (drop) drop.classList.add("is-over");
      }

      function end(event) {
        if (!active) return;

        const point = getPoint(event);
        const drop = getDropAt(point.x, point.y);

        if (drop) {
          drop.appendChild(active);
        }

        cleanup();
        updateCounts();
        createSummary();
      }

      function cancel() {
        cleanup();
        updateCounts();
        createSummary();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });

      updateCounts();
      createSummary();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initNestedMenu);
  } else {
    initNestedMenu();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initNestedMenu() {
    document.querySelectorAll("[data-vb-nestmenu]").forEach(function (root) {
      if (root.getAttribute("data-vb-nestmenu-ready") === "1") return;
      root.setAttribute("data-vb-nestmenu-ready", "1");

      const drops = Array.from(root.querySelectorAll("[data-vb-nestmenu-drop]"));
      const summary = root.querySelector("[data-vb-nestmenu-summary]");
      let active = null;
      let ghost = null;

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function updateCounts() {
        drops.forEach(function (drop) {
          const zone = drop.getAttribute("data-zone");
          const count = root.querySelector('[data-vb-nestmenu-count="' + zone + '"]');
          if (count) count.textContent = drop.querySelectorAll("[data-vb-nestmenu-card]").length;
        });
      }

      function createSummary() {
        const groups = ["services", "company", "resources"].map(function (zone) {
          const drop = root.querySelector('[data-zone="' + zone + '"]');
          const labels = Array.from(drop.querySelectorAll("[data-vb-nestmenu-card]")).map(function (card) {
            return card.getAttribute("data-label");
          });
          return zone + ": " + (labels.length ? labels.join(", ") : "empty");
        });

        summary.textContent = groups.join(" | ");
      }

      function createGhost(card, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-nestmenu-ghost";
        ghost.innerHTML = "&lt;strong&gt;" + card.getAttribute("data-label") + "&lt;/strong&gt;";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function getDropAt(x, y) {
        const el = document.elementFromPoint(x, y);
        if (!el) return null;
        const drop = el.closest("[data-vb-nestmenu-drop]");
        return drops.includes(drop) ? drop : null;
      }

      function clearOver() {
        drops.forEach(function (drop) { drop.classList.remove("is-over"); });
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-nestmenu-handle]");
        if (!handle) return;

        const card = handle.closest("[data-vb-nestmenu-card]");
        if (!card) return;

        event.preventDefault();

        const point = getPoint(event);
        active = card;
        active.classList.add("is-dragging");
        createGhost(card, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;
        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);
        clearOver();

        const drop = getDropAt(point.x, point.y);
        if (drop) drop.classList.add("is-over");
      }

      function end(event) {
        if (!active) return;

        const point = getPoint(event);
        const drop = getDropAt(point.x, point.y);

        if (drop) {
          drop.appendChild(active);
        }

        cleanup();
        updateCounts();
        createSummary();
      }

      function cancel() {
        cleanup();
        updateCounts();
        createSummary();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });

      updateCounts();
      createSummary();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initNestedMenu);
  } else {
    initNestedMenu();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-nestmenu-demo"&gt;
  &lt;div class="vb-nestmenu-wrap" data-vb-nestmenu&gt;
    &lt;div class="vb-nestmenu-head"&gt;
      &lt;span&gt;Example 14&lt;/span&gt;
      &lt;h3&gt;Nested Menu Builder&lt;/h3&gt;
      &lt;p&gt;Drag loose menu items into parent menu groups to create a nested navigation structure.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-nestmenu-app"&gt;
      &lt;aside class="vb-nestmenu-palette"&gt;
        &lt;h4&gt;Menu Items&lt;/h4&gt;

        &lt;div class="vb-nestmenu-drop" data-vb-nestmenu-drop data-zone="items"&gt;
          &lt;article class="vb-nestmenu-card" data-vb-nestmenu-card data-label="Pricing"&gt;
            &lt;button type="button" data-vb-nestmenu-handle&gt;⋮⋮&lt;/button&gt;
            &lt;strong&gt;Pricing&lt;/strong&gt;
          &lt;/article&gt;

          &lt;article class="vb-nestmenu-card" data-vb-nestmenu-card data-label="Portfolio"&gt;
            &lt;button type="button" data-vb-nestmenu-handle&gt;⋮⋮&lt;/button&gt;
            &lt;strong&gt;Portfolio&lt;/strong&gt;
          &lt;/article&gt;

          &lt;article class="vb-nestmenu-card" data-vb-nestmenu-card data-label="Support"&gt;
            &lt;button type="button" data-vb-nestmenu-handle&gt;⋮⋮&lt;/button&gt;
            &lt;strong&gt;Support&lt;/strong&gt;
          &lt;/article&gt;
        &lt;/div&gt;
      &lt;/aside&gt;

      &lt;section class="vb-nestmenu-tree"&gt;
        &lt;div class="vb-nestmenu-group"&gt;
          &lt;div class="vb-nestmenu-group-title"&gt;
            &lt;h4&gt;Services&lt;/h4&gt;
            &lt;span data-vb-nestmenu-count="services"&gt;0&lt;/span&gt;
          &lt;/div&gt;
          &lt;div class="vb-nestmenu-subdrop" data-vb-nestmenu-drop data-zone="services"&gt;&lt;/div&gt;
        &lt;/div&gt;

        &lt;div class="vb-nestmenu-group"&gt;
          &lt;div class="vb-nestmenu-group-title"&gt;
            &lt;h4&gt;Company&lt;/h4&gt;
            &lt;span data-vb-nestmenu-count="company"&gt;0&lt;/span&gt;
          &lt;/div&gt;
          &lt;div class="vb-nestmenu-subdrop" data-vb-nestmenu-drop data-zone="company"&gt;&lt;/div&gt;
        &lt;/div&gt;

        &lt;div class="vb-nestmenu-group"&gt;
          &lt;div class="vb-nestmenu-group-title"&gt;
            &lt;h4&gt;Resources&lt;/h4&gt;
            &lt;span data-vb-nestmenu-count="resources"&gt;0&lt;/span&gt;
          &lt;/div&gt;
          &lt;div class="vb-nestmenu-subdrop" data-vb-nestmenu-drop data-zone="resources"&gt;&lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;

    &lt;div class="vb-nestmenu-summary" data-vb-nestmenu-summary&gt;Build a nested menu by dragging items into groups.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-nestmenu-demo,
.vb-nestmenu-demo * {
  box-sizing: border-box;
}

.vb-nestmenu-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 10% 12%, rgba(20, 184, 166, 0.17), transparent 34%),
    radial-gradient(circle at 92% 20%, rgba(59, 130, 246, 0.17), transparent 34%),
    linear-gradient(135deg, #f0fdfa 0%, #eff6ff 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-nestmenu-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-nestmenu-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-nestmenu-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-nestmenu-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-nestmenu-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-nestmenu-app {
  display: grid;
  grid-template-columns: minmax(250px, 0.38fr) minmax(0, 1fr);
  gap: 16px;
}

.vb-nestmenu-palette,
.vb-nestmenu-tree {
  padding: 16px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-nestmenu-palette h4,
.vb-nestmenu-group-title h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-nestmenu-palette h4 {
  margin-bottom: 14px !important;
}

.vb-nestmenu-drop,
.vb-nestmenu-subdrop {
  display: grid;
  align-content: start;
  gap: 10px;
  min-height: 200px;
  padding: 12px;
  border-radius: 22px;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  background: #f8fafc;
}

.vb-nestmenu-subdrop {
  min-height: 120px;
}

.vb-nestmenu-drop.is-over,
.vb-nestmenu-subdrop.is-over {
  border-color: rgba(20, 184, 166, 0.82);
  background: #f0fdfa;
  box-shadow: inset 0 0 0 4px rgba(20, 184, 166, 0.10);
}

.vb-nestmenu-tree {
  display: grid;
  gap: 14px;
}

.vb-nestmenu-group {
  padding: 14px;
  border-radius: 24px;
  background: linear-gradient(135deg, #ffffff, #f8fafc);
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-nestmenu-group-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 12px;
}

.vb-nestmenu-group-title span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 34px;
  height: 32px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-nestmenu-card {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  padding: 12px;
  border-radius: 16px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 10px 24px rgba(15, 23, 42, 0.06);
}

.vb-nestmenu-card.is-dragging {
  opacity: 0.45;
}

.vb-nestmenu-card button {
  width: 34px;
  height: 40px;
  border: 0;
  border-radius: 13px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 18px;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
}

.vb-nestmenu-card strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-nestmenu-summary {
  margin-top: 16px;
  padding: 13px 15px;
  border-radius: 18px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-nestmenu-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(260px, calc(100vw - 32px));
  padding: 13px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(20, 184, 166, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
}

.vb-nestmenu-ghost strong {
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-nestmenu-app {
    grid-template-columns: 1fr;
  }

  .vb-nestmenu-drop,
  .vb-nestmenu-subdrop {
    min-height: 130px;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript nested menu builder is useful for navigation builders, WordPress-style menu editors, app sidebars, documentation menus, admin panels, and content management dashboards.</p>



<h2 class="wp-block-heading">15. Drag and Drop FAQ Order Manager</h2>



<p class="wp-block-paragraph"><strong>A drag and drop FAQ order manager</strong> is useful when admins need to change the order of FAQ items without editing code. This pattern works well for help centers, product pages, support portals, documentation pages, ecommerce pages, and SEO FAQ sections.</p>



<ul class="wp-block-list">
<li>Reorder FAQ items</li>
<li>Clickable FAQ preview</li>
<li>Mouse and touch sorting</li>
<li>Automatic FAQ numbering</li>
<li>Live order output</li>
</ul>



<div class="vb-faqorder-demo">
  <div class="vb-faqorder-wrap" data-vb-faqorder>
    <div class="vb-faqorder-head">
      <span>Example 15</span>
      <h3>FAQ Order Manager</h3>
      <p>Drag FAQ handles to change the order. Click a question to preview the answer.</p>
    </div>

    <div class="vb-faqorder-layout">
      <div class="vb-faqorder-list" data-vb-faqorder-list>
        <article class="vb-faqorder-item is-open" data-vb-faqorder-item data-title="How does drag and drop work?">
          <div class="vb-faqorder-question">
            <button type="button" data-vb-faqorder-handle>⋮⋮</button>
            <strong data-vb-faqorder-number>1</strong>
            <h4 data-vb-faqorder-toggle>How does drag and drop work?</h4>
          </div>
          <p>JavaScript tracks the dragged item, follows the pointer position, and updates the order when the user moves over another item.</p>
        </article>

        <article class="vb-faqorder-item" data-vb-faqorder-item data-title="Can this work on mobile?">
          <div class="vb-faqorder-question">
            <button type="button" data-vb-faqorder-handle>⋮⋮</button>
            <strong data-vb-faqorder-number>2</strong>
            <h4 data-vb-faqorder-toggle>Can this work on mobile?</h4>
          </div>
          <p>Yes. This demo uses both mouse and touch events, so it can work on desktop, tablet, and mobile layouts.</p>
        </article>

        <article class="vb-faqorder-item" data-vb-faqorder-item data-title="Why use FAQ ordering?">
          <div class="vb-faqorder-question">
            <button type="button" data-vb-faqorder-handle>⋮⋮</button>
            <strong data-vb-faqorder-number>3</strong>
            <h4 data-vb-faqorder-toggle>Why use FAQ ordering?</h4>
          </div>
          <p>FAQ ordering helps place the most important customer questions higher on the page for better usability and SEO.</p>
        </article>

        <article class="vb-faqorder-item" data-vb-faqorder-item data-title="Is this useful for admin panels?">
          <div class="vb-faqorder-question">
            <button type="button" data-vb-faqorder-handle>⋮⋮</button>
            <strong data-vb-faqorder-number>4</strong>
            <h4 data-vb-faqorder-toggle>Is this useful for admin panels?</h4>
          </div>
          <p>Yes. Drag and drop ordering is especially useful for admin interfaces where users manage visible frontend content.</p>
        </article>
      </div>

      <aside class="vb-faqorder-side">
        <span>FAQ order</span>
        <strong data-vb-faqorder-output>1. How does drag and drop work?</strong>
        <p>The first FAQ in the list is treated as the highest priority question.</p>
      </aside>
    </div>
  </div>
</div>

<style>
.vb-faqorder-demo,
.vb-faqorder-demo * {
  box-sizing: border-box;
}

.vb-faqorder-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 10% 12%, rgba(251, 191, 36, 0.18), transparent 34%),
    radial-gradient(circle at 92% 20%, rgba(236, 72, 153, 0.16), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fdf2f8 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-faqorder-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-faqorder-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-faqorder-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-faqorder-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-faqorder-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-faqorder-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(260px, 0.65fr);
  gap: 16px;
  align-items: stretch;
}

.vb-faqorder-list {
  display: grid;
  gap: 12px;
  padding: 16px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-faqorder-item {
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 12px 30px rgba(15, 23, 42, 0.06);
  overflow: hidden;
}

.vb-faqorder-item.is-dragging {
  opacity: 0.45;
}

.vb-faqorder-item.is-over {
  border-color: rgba(245, 158, 11, 0.80);
  background: #fffbeb;
}

.vb-faqorder-question {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 14px;
}

.vb-faqorder-question button {
  width: 38px;
  height: 44px;
  border: 0;
  border-radius: 14px;
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 20px;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
}

.vb-faqorder-question strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-faqorder-question h4 {
  margin: 0 !important;
  cursor: pointer;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
}

.vb-faqorder-item p {
  display: none;
  margin: 0 !important;
  padding: 0 16px 16px 88px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-faqorder-item.is-open p {
  display: block;
}

.vb-faqorder-side {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 26px;
  border-radius: 28px;
  background:
    radial-gradient(circle at 16% 16%, rgba(251, 191, 36, 0.22), transparent 36%),
    linear-gradient(135deg, #0f172a, #713f12) !important;
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.20);
}

.vb-faqorder-side span {
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-faqorder-side strong {
  margin: 12px 0;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(24px, 4vw, 40px);
  line-height: 1.08;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-faqorder-side p {
  margin: 0 !important;
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-faqorder-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(340px, calc(100vw - 32px));
  padding: 13px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(245, 158, 11, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
}

.vb-faqorder-ghost strong {
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-faqorder-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-faqorder-question {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .vb-faqorder-question strong {
    display: none;
  }

  .vb-faqorder-item p {
    padding: 0 14px 14px 64px;
  }
}
</style>

<script>
(function () {
  function initFaqOrder() {
    document.querySelectorAll("[data-vb-faqorder]").forEach(function (root) {
      if (root.getAttribute("data-vb-faqorder-ready") === "1") return;
      root.setAttribute("data-vb-faqorder-ready", "1");

      const list = root.querySelector("[data-vb-faqorder-list]");
      const output = root.querySelector("[data-vb-faqorder-output]");
      let active = null;
      let ghost = null;

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function updateOrder() {
        const items = Array.from(list.querySelectorAll("[data-vb-faqorder-item]"));

        items.forEach(function (item, index) {
          const number = item.querySelector("[data-vb-faqorder-number]");
          if (number) number.textContent = index + 1;
        });

        if (items[0]) {
          output.textContent = "1. " + items[0].getAttribute("data-title");
        }
      }

      function createGhost(item, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-faqorder-ghost";
        ghost.innerHTML = "<strong>" + item.getAttribute("data-title") + "</strong>";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function clearOver() {
        list.querySelectorAll(".is-over").forEach(function (item) {
          item.classList.remove("is-over");
        });
      }

      function reorderAt(x, y) {
        const el = document.elementFromPoint(x, y);
        const target = el ? el.closest("[data-vb-faqorder-item]") : null;

        if (!target || target === active || !list.contains(target)) return;

        const rect = target.getBoundingClientRect();
        const after = y > rect.top + rect.height / 2;

        clearOver();
        target.classList.add("is-over");

        if (after) {
          target.insertAdjacentElement("afterend", active);
        } else {
          target.insertAdjacentElement("beforebegin", active);
        }

        updateOrder();
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-faqorder-handle]");
        if (!handle) return;

        const item = handle.closest("[data-vb-faqorder-item]");
        if (!item) return;

        event.preventDefault();

        const point = getPoint(event);
        active = item;
        active.classList.add("is-dragging");
        createGhost(item, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;

        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);
        reorderAt(point.x, point.y);
      }

      function end() {
        cleanup();
        updateOrder();
      }

      function cancel() {
        cleanup();
        updateOrder();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });

      root.addEventListener("click", function (event) {
        const toggle = event.target.closest("[data-vb-faqorder-toggle]");
        if (!toggle) return;

        const item = toggle.closest("[data-vb-faqorder-item]");
        if (!item) return;

        item.classList.toggle("is-open");
      });

      updateOrder();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initFaqOrder);
  } else {
    initFaqOrder();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initFaqOrder() {
    document.querySelectorAll("[data-vb-faqorder]").forEach(function (root) {
      if (root.getAttribute("data-vb-faqorder-ready") === "1") return;
      root.setAttribute("data-vb-faqorder-ready", "1");

      const list = root.querySelector("[data-vb-faqorder-list]");
      const output = root.querySelector("[data-vb-faqorder-output]");
      let active = null;
      let ghost = null;

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function updateOrder() {
        const items = Array.from(list.querySelectorAll("[data-vb-faqorder-item]"));

        items.forEach(function (item, index) {
          const number = item.querySelector("[data-vb-faqorder-number]");
          if (number) number.textContent = index + 1;
        });

        if (items[0]) {
          output.textContent = "1. " + items[0].getAttribute("data-title");
        }
      }

      function createGhost(item, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-faqorder-ghost";
        ghost.innerHTML = "&lt;strong&gt;" + item.getAttribute("data-title") + "&lt;/strong&gt;";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function clearOver() {
        list.querySelectorAll(".is-over").forEach(function (item) {
          item.classList.remove("is-over");
        });
      }

      function reorderAt(x, y) {
        const el = document.elementFromPoint(x, y);
        const target = el ? el.closest("[data-vb-faqorder-item]") : null;

        if (!target || target === active || !list.contains(target)) return;

        const rect = target.getBoundingClientRect();
        const after = y &gt; rect.top + rect.height / 2;

        clearOver();
        target.classList.add("is-over");

        if (after) {
          target.insertAdjacentElement("afterend", active);
        } else {
          target.insertAdjacentElement("beforebegin", active);
        }

        updateOrder();
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-faqorder-handle]");
        if (!handle) return;

        const item = handle.closest("[data-vb-faqorder-item]");
        if (!item) return;

        event.preventDefault();

        const point = getPoint(event);
        active = item;
        active.classList.add("is-dragging");
        createGhost(item, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;

        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);
        reorderAt(point.x, point.y);
      }

      function end() {
        cleanup();
        updateOrder();
      }

      function cancel() {
        cleanup();
        updateOrder();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });

      root.addEventListener("click", function (event) {
        const toggle = event.target.closest("[data-vb-faqorder-toggle]");
        if (!toggle) return;

        const item = toggle.closest("[data-vb-faqorder-item]");
        if (!item) return;

        item.classList.toggle("is-open");
      });

      updateOrder();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initFaqOrder);
  } else {
    initFaqOrder();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-faqorder-demo"&gt;
  &lt;div class="vb-faqorder-wrap" data-vb-faqorder&gt;
    &lt;div class="vb-faqorder-head"&gt;
      &lt;span&gt;Example 15&lt;/span&gt;
      &lt;h3&gt;FAQ Order Manager&lt;/h3&gt;
      &lt;p&gt;Drag FAQ handles to change the order. Click a question to preview the answer.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-faqorder-layout"&gt;
      &lt;div class="vb-faqorder-list" data-vb-faqorder-list&gt;
        &lt;article class="vb-faqorder-item is-open" data-vb-faqorder-item data-title="How does drag and drop work?"&gt;
          &lt;div class="vb-faqorder-question"&gt;
            &lt;button type="button" data-vb-faqorder-handle&gt;⋮⋮&lt;/button&gt;
            &lt;strong data-vb-faqorder-number&gt;1&lt;/strong&gt;
            &lt;h4 data-vb-faqorder-toggle&gt;How does drag and drop work?&lt;/h4&gt;
          &lt;/div&gt;
          &lt;p&gt;JavaScript tracks the dragged item, follows the pointer position, and updates the order when the user moves over another item.&lt;/p&gt;
        &lt;/article&gt;

        &lt;article class="vb-faqorder-item" data-vb-faqorder-item data-title="Can this work on mobile?"&gt;
          &lt;div class="vb-faqorder-question"&gt;
            &lt;button type="button" data-vb-faqorder-handle&gt;⋮⋮&lt;/button&gt;
            &lt;strong data-vb-faqorder-number&gt;2&lt;/strong&gt;
            &lt;h4 data-vb-faqorder-toggle&gt;Can this work on mobile?&lt;/h4&gt;
          &lt;/div&gt;
          &lt;p&gt;Yes. This demo uses both mouse and touch events, so it can work on desktop, tablet, and mobile layouts.&lt;/p&gt;
        &lt;/article&gt;

        &lt;article class="vb-faqorder-item" data-vb-faqorder-item data-title="Why use FAQ ordering?"&gt;
          &lt;div class="vb-faqorder-question"&gt;
            &lt;button type="button" data-vb-faqorder-handle&gt;⋮⋮&lt;/button&gt;
            &lt;strong data-vb-faqorder-number&gt;3&lt;/strong&gt;
            &lt;h4 data-vb-faqorder-toggle&gt;Why use FAQ ordering?&lt;/h4&gt;
          &lt;/div&gt;
          &lt;p&gt;FAQ ordering helps place the most important customer questions higher on the page for better usability and SEO.&lt;/p&gt;
        &lt;/article&gt;

        &lt;article class="vb-faqorder-item" data-vb-faqorder-item data-title="Is this useful for admin panels?"&gt;
          &lt;div class="vb-faqorder-question"&gt;
            &lt;button type="button" data-vb-faqorder-handle&gt;⋮⋮&lt;/button&gt;
            &lt;strong data-vb-faqorder-number&gt;4&lt;/strong&gt;
            &lt;h4 data-vb-faqorder-toggle&gt;Is this useful for admin panels?&lt;/h4&gt;
          &lt;/div&gt;
          &lt;p&gt;Yes. Drag and drop ordering is especially useful for admin interfaces where users manage visible frontend content.&lt;/p&gt;
        &lt;/article&gt;
      &lt;/div&gt;

      &lt;aside class="vb-faqorder-side"&gt;
        &lt;span&gt;FAQ order&lt;/span&gt;
        &lt;strong data-vb-faqorder-output&gt;1. How does drag and drop work?&lt;/strong&gt;
        &lt;p&gt;The first FAQ in the list is treated as the highest priority question.&lt;/p&gt;
      &lt;/aside&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-faqorder-demo,
.vb-faqorder-demo * {
  box-sizing: border-box;
}

.vb-faqorder-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 10% 12%, rgba(251, 191, 36, 0.18), transparent 34%),
    radial-gradient(circle at 92% 20%, rgba(236, 72, 153, 0.16), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fdf2f8 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-faqorder-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-faqorder-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-faqorder-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-faqorder-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-faqorder-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-faqorder-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(260px, 0.65fr);
  gap: 16px;
  align-items: stretch;
}

.vb-faqorder-list {
  display: grid;
  gap: 12px;
  padding: 16px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-faqorder-item {
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 12px 30px rgba(15, 23, 42, 0.06);
  overflow: hidden;
}

.vb-faqorder-item.is-dragging {
  opacity: 0.45;
}

.vb-faqorder-item.is-over {
  border-color: rgba(245, 158, 11, 0.80);
  background: #fffbeb;
}

.vb-faqorder-question {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 14px;
}

.vb-faqorder-question button {
  width: 38px;
  height: 44px;
  border: 0;
  border-radius: 14px;
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 20px;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
}

.vb-faqorder-question strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-faqorder-question h4 {
  margin: 0 !important;
  cursor: pointer;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
}

.vb-faqorder-item p {
  display: none;
  margin: 0 !important;
  padding: 0 16px 16px 88px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-faqorder-item.is-open p {
  display: block;
}

.vb-faqorder-side {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 26px;
  border-radius: 28px;
  background:
    radial-gradient(circle at 16% 16%, rgba(251, 191, 36, 0.22), transparent 36%),
    linear-gradient(135deg, #0f172a, #713f12) !important;
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.20);
}

.vb-faqorder-side span {
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-faqorder-side strong {
  margin: 12px 0;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(24px, 4vw, 40px);
  line-height: 1.08;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-faqorder-side p {
  margin: 0 !important;
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-faqorder-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(340px, calc(100vw - 32px));
  padding: 13px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(245, 158, 11, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
}

.vb-faqorder-ghost strong {
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-faqorder-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-faqorder-question {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .vb-faqorder-question strong {
    display: none;
  }

  .vb-faqorder-item p {
    padding: 0 14px 14px 64px;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript FAQ order manager is useful for help centers, product FAQ sections, support portals, documentation pages, ecommerce content blocks, and SEO FAQ management tools.</p>



<h2 class="wp-block-heading">16. Drag to Delete Interaction</h2>



<p class="wp-block-paragraph"><strong>A drag to delete interaction</strong> is a practical JavaScript UI pattern where users drag an item into a trash zone to remove it. This is useful for task apps, image galleries, admin lists, file managers, saved items, cart interfaces, and mobile-style dashboards.</p>



<ul class="wp-block-list">
<li>Drag task cards into the delete zone</li>
<li>Mouse and touch support</li>
<li>Live deleted item counter</li>
<li>Undo last deleted item</li>
<li>No external libraries</li>
</ul>



<div class="vb-trashdrag-demo">
  <div class="vb-trashdrag-wrap" data-vb-trashdrag>
    <div class="vb-trashdrag-head">
      <span>Example 16</span>
      <h3>Drag to Delete Interaction</h3>
      <p>Drag any task card into the trash zone. The item disappears and can be restored with the undo button.</p>
    </div>

    <div class="vb-trashdrag-layout">
      <section class="vb-trashdrag-list" data-vb-trashdrag-list>
        <article class="vb-trashdrag-card" data-vb-trashdrag-card data-title="Old landing page draft">
          <button type="button" data-vb-trashdrag-handle>⋮⋮</button>
          <div>
            <h4>Old landing page draft</h4>
            <p>Unused website section</p>
          </div>
        </article>

        <article class="vb-trashdrag-card" data-vb-trashdrag-card data-title="Duplicate image export">
          <button type="button" data-vb-trashdrag-handle>⋮⋮</button>
          <div>
            <h4>Duplicate image export</h4>
            <p>Media library cleanup</p>
          </div>
        </article>

        <article class="vb-trashdrag-card" data-vb-trashdrag-card data-title="Outdated FAQ block">
          <button type="button" data-vb-trashdrag-handle>⋮⋮</button>
          <div>
            <h4>Outdated FAQ block</h4>
            <p>Old support content</p>
          </div>
        </article>

        <article class="vb-trashdrag-card" data-vb-trashdrag-card data-title="Unused campaign banner">
          <button type="button" data-vb-trashdrag-handle>⋮⋮</button>
          <div>
            <h4>Unused campaign banner</h4>
            <p>Marketing asset</p>
          </div>
        </article>
      </section>

      <aside class="vb-trashdrag-panel">
        <div class="vb-trashdrag-zone" data-vb-trashdrag-drop>
          <span>Trash Zone</span>
          <strong>Drop here to delete</strong>
          <p>Deleted items: <b data-vb-trashdrag-count>0</b></p>
        </div>

        <button type="button" class="vb-trashdrag-undo" data-vb-trashdrag-undo disabled>Undo last delete</button>
      </aside>
    </div>

    <div class="vb-trashdrag-status" data-vb-trashdrag-status>Drag an item into the trash zone.</div>
  </div>
</div>

<style>
.vb-trashdrag-demo,
.vb-trashdrag-demo * {
  box-sizing: border-box;
}

.vb-trashdrag-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(239, 68, 68, 0.16), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(15, 23, 42, 0.14), transparent 34%),
    linear-gradient(135deg, #fef2f2 0%, #f8fafc 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-trashdrag-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-trashdrag-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-trashdrag-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-trashdrag-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-trashdrag-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-trashdrag-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(280px, 0.55fr);
  gap: 16px;
}

.vb-trashdrag-list {
  display: grid;
  gap: 12px;
  padding: 16px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-trashdrag-card {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 14px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 12px 30px rgba(15, 23, 42, 0.06);
}

.vb-trashdrag-card.is-dragging {
  opacity: 0.45;
}

.vb-trashdrag-card button {
  width: 38px;
  height: 44px;
  border: 0;
  border-radius: 14px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 20px;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
}

.vb-trashdrag-card h4 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
}

.vb-trashdrag-card p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.45;
  font-weight: 700;
}

.vb-trashdrag-panel {
  display: grid;
  gap: 12px;
}

.vb-trashdrag-zone {
  display: flex;
  min-height: 280px;
  padding: 24px;
  border-radius: 30px;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  text-align: center;
  background:
    radial-gradient(circle at 50% 20%, rgba(248, 113, 113, 0.24), transparent 38%),
    linear-gradient(135deg, #450a0a, #0f172a) !important;
  border: 1px dashed rgba(252, 165, 165, 0.75);
  box-shadow: 0 22px 60px rgba(15, 23, 42, 0.18);
}

.vb-trashdrag-zone.is-over {
  background:
    radial-gradient(circle at 50% 20%, rgba(248, 113, 113, 0.42), transparent 40%),
    linear-gradient(135deg, #7f1d1d, #111827) !important;
  box-shadow: inset 0 0 0 5px rgba(248, 113, 113, 0.20), 0 22px 60px rgba(15, 23, 42, 0.18);
}

.vb-trashdrag-zone span {
  color: #fecaca !important;
  -webkit-text-fill-color: #fecaca !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-trashdrag-zone strong {
  margin: 10px 0;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4vw, 44px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-trashdrag-zone p {
  margin: 0 !important;
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: 15px;
  font-weight: 750;
}

.vb-trashdrag-undo {
  min-height: 48px;
  border: 0;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-trashdrag-undo:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.vb-trashdrag-status {
  margin-top: 16px;
  padding: 13px 15px;
  border-radius: 18px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-trashdrag-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(320px, calc(100vw - 32px));
  padding: 13px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(239, 68, 68, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
}

.vb-trashdrag-ghost strong {
  color: #991b1b !important;
  -webkit-text-fill-color: #991b1b !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-trashdrag-layout {
    grid-template-columns: 1fr;
  }

  .vb-trashdrag-zone {
    min-height: 220px;
  }
}

@media (max-width: 520px) {
  .vb-trashdrag-card {
    grid-template-columns: auto minmax(0, 1fr);
  }
}
</style>

<script>
(function () {
  function initTrashDrag() {
    document.querySelectorAll("[data-vb-trashdrag]").forEach(function (root) {
      if (root.getAttribute("data-vb-trashdrag-ready") === "1") return;
      root.setAttribute("data-vb-trashdrag-ready", "1");

      const list = root.querySelector("[data-vb-trashdrag-list]");
      const drop = root.querySelector("[data-vb-trashdrag-drop]");
      const count = root.querySelector("[data-vb-trashdrag-count]");
      const status = root.querySelector("[data-vb-trashdrag-status]");
      const undo = root.querySelector("[data-vb-trashdrag-undo]");

      let active = null;
      let ghost = null;
      let deleted = [];
      let deletedCount = 0;

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function isOverTrash(x, y) {
        const el = document.elementFromPoint(x, y);
        return !!(el && el.closest("[data-vb-trashdrag-drop]") === drop);
      }

      function createGhost(card, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-trashdrag-ghost";
        ghost.innerHTML = "<strong>" + card.getAttribute("data-title") + "</strong>";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-trashdrag-handle]");
        if (!handle) return;

        const card = handle.closest("[data-vb-trashdrag-card]");
        if (!card) return;

        event.preventDefault();

        const point = getPoint(event);
        active = card;
        active.classList.add("is-dragging");
        createGhost(card, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;
        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);

        if (isOverTrash(point.x, point.y)) {
          drop.classList.add("is-over");
        } else {
          drop.classList.remove("is-over");
        }
      }

      function end(event) {
        if (!active) return;

        const point = getPoint(event);

        if (isOverTrash(point.x, point.y)) {
          deleted.push(active);
          active.remove();
          deletedCount += 1;
          count.textContent = deletedCount;
          undo.disabled = false;
          status.textContent = "Deleted: " + active.getAttribute("data-title");
        }

        cleanup();
      }

      function cancel() {
        cleanup();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        drop.classList.remove("is-over");

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      undo.addEventListener("click", function () {
        const restored = deleted.pop();
        if (!restored) return;

        list.appendChild(restored);
        deletedCount = Math.max(0, deletedCount - 1);
        count.textContent = deletedCount;
        undo.disabled = deleted.length === 0;
        status.textContent = "Restored: " + restored.getAttribute("data-title");
      });

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initTrashDrag);
  } else {
    initTrashDrag();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initTrashDrag() {
    document.querySelectorAll("[data-vb-trashdrag]").forEach(function (root) {
      if (root.getAttribute("data-vb-trashdrag-ready") === "1") return;
      root.setAttribute("data-vb-trashdrag-ready", "1");

      const list = root.querySelector("[data-vb-trashdrag-list]");
      const drop = root.querySelector("[data-vb-trashdrag-drop]");
      const count = root.querySelector("[data-vb-trashdrag-count]");
      const status = root.querySelector("[data-vb-trashdrag-status]");
      const undo = root.querySelector("[data-vb-trashdrag-undo]");

      let active = null;
      let ghost = null;
      let deleted = [];
      let deletedCount = 0;

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function isOverTrash(x, y) {
        const el = document.elementFromPoint(x, y);
        return !!(el &amp;&amp; el.closest("[data-vb-trashdrag-drop]") === drop);
      }

      function createGhost(card, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-trashdrag-ghost";
        ghost.innerHTML = "&lt;strong&gt;" + card.getAttribute("data-title") + "&lt;/strong&gt;";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-trashdrag-handle]");
        if (!handle) return;

        const card = handle.closest("[data-vb-trashdrag-card]");
        if (!card) return;

        event.preventDefault();

        const point = getPoint(event);
        active = card;
        active.classList.add("is-dragging");
        createGhost(card, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;
        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);

        if (isOverTrash(point.x, point.y)) {
          drop.classList.add("is-over");
        } else {
          drop.classList.remove("is-over");
        }
      }

      function end(event) {
        if (!active) return;

        const point = getPoint(event);

        if (isOverTrash(point.x, point.y)) {
          deleted.push(active);
          active.remove();
          deletedCount += 1;
          count.textContent = deletedCount;
          undo.disabled = false;
          status.textContent = "Deleted: " + active.getAttribute("data-title");
        }

        cleanup();
      }

      function cancel() {
        cleanup();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        drop.classList.remove("is-over");

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      undo.addEventListener("click", function () {
        const restored = deleted.pop();
        if (!restored) return;

        list.appendChild(restored);
        deletedCount = Math.max(0, deletedCount - 1);
        count.textContent = deletedCount;
        undo.disabled = deleted.length === 0;
        status.textContent = "Restored: " + restored.getAttribute("data-title");
      });

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initTrashDrag);
  } else {
    initTrashDrag();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-trashdrag-demo"&gt;
  &lt;div class="vb-trashdrag-wrap" data-vb-trashdrag&gt;
    &lt;div class="vb-trashdrag-head"&gt;
      &lt;span&gt;Example 16&lt;/span&gt;
      &lt;h3&gt;Drag to Delete Interaction&lt;/h3&gt;
      &lt;p&gt;Drag any task card into the trash zone. The item disappears and can be restored with the undo button.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-trashdrag-layout"&gt;
      &lt;section class="vb-trashdrag-list" data-vb-trashdrag-list&gt;
        &lt;article class="vb-trashdrag-card" data-vb-trashdrag-card data-title="Old landing page draft"&gt;
          &lt;button type="button" data-vb-trashdrag-handle&gt;⋮⋮&lt;/button&gt;
          &lt;div&gt;&lt;h4&gt;Old landing page draft&lt;/h4&gt;&lt;p&gt;Unused website section&lt;/p&gt;&lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-trashdrag-card" data-vb-trashdrag-card data-title="Duplicate image export"&gt;
          &lt;button type="button" data-vb-trashdrag-handle&gt;⋮⋮&lt;/button&gt;
          &lt;div&gt;&lt;h4&gt;Duplicate image export&lt;/h4&gt;&lt;p&gt;Media library cleanup&lt;/p&gt;&lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-trashdrag-card" data-vb-trashdrag-card data-title="Outdated FAQ block"&gt;
          &lt;button type="button" data-vb-trashdrag-handle&gt;⋮⋮&lt;/button&gt;
          &lt;div&gt;&lt;h4&gt;Outdated FAQ block&lt;/h4&gt;&lt;p&gt;Old support content&lt;/p&gt;&lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-trashdrag-card" data-vb-trashdrag-card data-title="Unused campaign banner"&gt;
          &lt;button type="button" data-vb-trashdrag-handle&gt;⋮⋮&lt;/button&gt;
          &lt;div&gt;&lt;h4&gt;Unused campaign banner&lt;/h4&gt;&lt;p&gt;Marketing asset&lt;/p&gt;&lt;/div&gt;
        &lt;/article&gt;
      &lt;/section&gt;

      &lt;aside class="vb-trashdrag-panel"&gt;
        &lt;div class="vb-trashdrag-zone" data-vb-trashdrag-drop&gt;
          &lt;span&gt;Trash Zone&lt;/span&gt;
          &lt;strong&gt;Drop here to delete&lt;/strong&gt;
          &lt;p&gt;Deleted items: &lt;b data-vb-trashdrag-count&gt;0&lt;/b&gt;&lt;/p&gt;
        &lt;/div&gt;

        &lt;button type="button" class="vb-trashdrag-undo" data-vb-trashdrag-undo disabled&gt;Undo last delete&lt;/button&gt;
      &lt;/aside&gt;
    &lt;/div&gt;

    &lt;div class="vb-trashdrag-status" data-vb-trashdrag-status&gt;Drag an item into the trash zone.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">/* CSS is included fully in the live demo block above. */</pre>



<p class="wp-block-paragraph">This JavaScript drag to delete interaction is useful for task apps, admin lists, saved item dashboards, file managers, image galleries, shopping carts, and mobile-style UI components.</p>



<h2 class="wp-block-heading">17. Drag to Favorite / Save Item</h2>



<p class="wp-block-paragraph"><strong>A drag to favorite interaction</strong> lets users save cards by dragging them into a favorites area. This pattern is useful for product wishlists, article saving, portfolio collections, saved tools, recipe apps, dashboards, and ecommerce interfaces.</p>



<ul class="wp-block-list">
<li>Drag cards into a save area</li>
<li>Prevents duplicate saved items</li>
<li>Live favorites count</li>
<li>Mouse and touch support</li>
<li>Visual saved collection</li>
</ul>



<div class="vb-savezone-demo">
  <div class="vb-savezone-wrap" data-vb-savezone>
    <div class="vb-savezone-head">
      <span>Example 17</span>
      <h3>Drag to Favorite / Save Item</h3>
      <p>Drag an article card into the saved collection area. Duplicate items are ignored automatically.</p>
    </div>

    <div class="vb-savezone-layout">
      <section class="vb-savezone-feed">
        <article class="vb-savezone-card" data-vb-savezone-card data-id="css-layouts" data-title="Modern CSS Layouts">
          <button type="button" data-vb-savezone-handle>⋮⋮</button>
          <div class="vb-savezone-image vb-savezone-blue"></div>
          <div>
            <h4>Modern CSS Layouts</h4>
            <p>Grid, Flexbox and layout examples</p>
          </div>
        </article>

        <article class="vb-savezone-card" data-vb-savezone-card data-id="js-forms" data-title="JavaScript Form Validation">
          <button type="button" data-vb-savezone-handle>⋮⋮</button>
          <div class="vb-savezone-image vb-savezone-green"></div>
          <div>
            <h4>JavaScript Form Validation</h4>
            <p>Input checks and checkout forms</p>
          </div>
        </article>

        <article class="vb-savezone-card" data-vb-savezone-card data-id="pricing-tables" data-title="CSS Pricing Tables">
          <button type="button" data-vb-savezone-handle>⋮⋮</button>
          <div class="vb-savezone-image vb-savezone-orange"></div>
          <div>
            <h4>CSS Pricing Tables</h4>
            <p>Responsive pricing section designs</p>
          </div>
        </article>
      </section>

      <aside class="vb-savezone-panel">
        <div class="vb-savezone-target" data-vb-savezone-drop>
          <span>Saved Collection</span>
          <strong data-vb-savezone-count>0 saved</strong>
          <p>Drop article cards here.</p>
        </div>

        <div class="vb-savezone-saved" data-vb-savezone-list></div>
      </aside>
    </div>

    <div class="vb-savezone-status" data-vb-savezone-status>Drag an article into the saved collection.</div>
  </div>
</div>

<style>
.vb-savezone-demo,
.vb-savezone-demo * {
  box-sizing: border-box;
}

.vb-savezone-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 10% 12%, rgba(236, 72, 153, 0.16), transparent 34%),
    radial-gradient(circle at 92% 20%, rgba(249, 115, 22, 0.16), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #fff7ed 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-savezone-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-savezone-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-savezone-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fce7f3;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-savezone-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-savezone-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-savezone-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 0.65fr);
  gap: 16px;
}

.vb-savezone-feed {
  display: grid;
  gap: 14px;
}

.vb-savezone-card {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr);
  gap: 14px;
  align-items: center;
  padding: 16px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 16px 44px rgba(15, 23, 42, 0.08);
}

.vb-savezone-card.is-dragging {
  opacity: 0.45;
}

.vb-savezone-card button {
  width: 38px;
  height: 44px;
  border: 0;
  border-radius: 14px;
  background: #fce7f3;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 20px;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
}

.vb-savezone-image {
  width: 78px;
  height: 78px;
  border-radius: 22px;
}

.vb-savezone-blue {
  background: linear-gradient(135deg, #2563eb, #7c3aed);
}

.vb-savezone-green {
  background: linear-gradient(135deg, #059669, #0ea5e9);
}

.vb-savezone-orange {
  background: linear-gradient(135deg, #f97316, #db2777);
}

.vb-savezone-card h4 {
  margin: 0 0 5px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 17px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
}

.vb-savezone-card p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.45;
  font-weight: 700;
}

.vb-savezone-panel {
  display: grid;
  gap: 14px;
  align-content: start;
}

.vb-savezone-target {
  min-height: 220px;
  padding: 24px;
  border-radius: 30px;
  text-align: center;
  background:
    radial-gradient(circle at 50% 20%, rgba(244, 114, 182, 0.24), transparent 38%),
    linear-gradient(135deg, #831843, #0f172a) !important;
  border: 1px dashed rgba(244, 114, 182, 0.75);
  box-shadow: 0 22px 60px rgba(15, 23, 42, 0.18);
}

.vb-savezone-target.is-over {
  box-shadow: inset 0 0 0 5px rgba(244, 114, 182, 0.20), 0 22px 60px rgba(15, 23, 42, 0.18);
}

.vb-savezone-target span {
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-savezone-target strong {
  display: block;
  margin: 12px 0;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4vw, 44px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-savezone-target p {
  margin: 0 !important;
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 15px;
  font-weight: 750;
}

.vb-savezone-saved {
  display: grid;
  gap: 10px;
}

.vb-savezone-saved-item {
  padding: 13px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 12px 30px rgba(15, 23, 42, 0.06);
}

.vb-savezone-status {
  margin-top: 16px;
  padding: 13px 15px;
  border-radius: 18px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-savezone-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(320px, calc(100vw - 32px));
  padding: 13px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(236, 72, 153, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
}

.vb-savezone-ghost strong {
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-savezone-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 520px) {
  .vb-savezone-card {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .vb-savezone-image {
    display: none;
  }
}
</style>

<script>
(function () {
  function initSaveZone() {
    document.querySelectorAll("[data-vb-savezone]").forEach(function (root) {
      if (root.getAttribute("data-vb-savezone-ready") === "1") return;
      root.setAttribute("data-vb-savezone-ready", "1");

      const drop = root.querySelector("[data-vb-savezone-drop]");
      const savedList = root.querySelector("[data-vb-savezone-list]");
      const count = root.querySelector("[data-vb-savezone-count]");
      const status = root.querySelector("[data-vb-savezone-status]");

      let active = null;
      let ghost = null;
      let saved = [];

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function isOverDrop(x, y) {
        const el = document.elementFromPoint(x, y);
        return !!(el && el.closest("[data-vb-savezone-drop]") === drop);
      }

      function renderSaved() {
        savedList.innerHTML = "";

        saved.forEach(function (item) {
          const div = document.createElement("div");
          div.className = "vb-savezone-saved-item";
          div.textContent = "Saved: " + item.title;
          savedList.appendChild(div);
        });

        count.textContent = saved.length === 1 ? "1 saved" : saved.length + " saved";
      }

      function createGhost(card, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-savezone-ghost";
        ghost.innerHTML = "<strong>" + card.getAttribute("data-title") + "</strong>";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-savezone-handle]");
        if (!handle) return;

        const card = handle.closest("[data-vb-savezone-card]");
        if (!card) return;

        event.preventDefault();

        const point = getPoint(event);
        active = card;
        active.classList.add("is-dragging");
        createGhost(card, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;
        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);

        if (isOverDrop(point.x, point.y)) {
          drop.classList.add("is-over");
        } else {
          drop.classList.remove("is-over");
        }
      }

      function end(event) {
        if (!active) return;

        const point = getPoint(event);

        if (isOverDrop(point.x, point.y)) {
          const id = active.getAttribute("data-id");
          const title = active.getAttribute("data-title");
          const exists = saved.some(function (item) { return item.id === id; });

          if (!exists) {
            saved.push({ id: id, title: title });
            status.textContent = title + " added to saved items.";
          } else {
            status.textContent = title + " is already saved.";
          }

          renderSaved();
        }

        cleanup();
      }

      function cancel() {
        cleanup();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        drop.classList.remove("is-over");

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      renderSaved();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initSaveZone);
  } else {
    initSaveZone();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initSaveZone() {
    document.querySelectorAll("[data-vb-savezone]").forEach(function (root) {
      if (root.getAttribute("data-vb-savezone-ready") === "1") return;
      root.setAttribute("data-vb-savezone-ready", "1");

      const drop = root.querySelector("[data-vb-savezone-drop]");
      const savedList = root.querySelector("[data-vb-savezone-list]");
      const count = root.querySelector("[data-vb-savezone-count]");
      const status = root.querySelector("[data-vb-savezone-status]");

      let active = null;
      let ghost = null;
      let saved = [];

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function isOverDrop(x, y) {
        const el = document.elementFromPoint(x, y);
        return !!(el &amp;&amp; el.closest("[data-vb-savezone-drop]") === drop);
      }

      function renderSaved() {
        savedList.innerHTML = "";

        saved.forEach(function (item) {
          const div = document.createElement("div");
          div.className = "vb-savezone-saved-item";
          div.textContent = "Saved: " + item.title;
          savedList.appendChild(div);
        });

        count.textContent = saved.length === 1 ? "1 saved" : saved.length + " saved";
      }

      function createGhost(card, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-savezone-ghost";
        ghost.innerHTML = "&lt;strong&gt;" + card.getAttribute("data-title") + "&lt;/strong&gt;";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-savezone-handle]");
        if (!handle) return;

        const card = handle.closest("[data-vb-savezone-card]");
        if (!card) return;

        event.preventDefault();

        const point = getPoint(event);
        active = card;
        active.classList.add("is-dragging");
        createGhost(card, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;
        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);

        if (isOverDrop(point.x, point.y)) {
          drop.classList.add("is-over");
        } else {
          drop.classList.remove("is-over");
        }
      }

      function end(event) {
        if (!active) return;

        const point = getPoint(event);

        if (isOverDrop(point.x, point.y)) {
          const id = active.getAttribute("data-id");
          const title = active.getAttribute("data-title");
          const exists = saved.some(function (item) { return item.id === id; });

          if (!exists) {
            saved.push({ id: id, title: title });
            status.textContent = title + " added to saved items.";
          } else {
            status.textContent = title + " is already saved.";
          }

          renderSaved();
        }

        cleanup();
      }

      function cancel() {
        cleanup();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        drop.classList.remove("is-over");

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      renderSaved();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initSaveZone);
  } else {
    initSaveZone();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-savezone-demo"&gt;
  &lt;div class="vb-savezone-wrap" data-vb-savezone&gt;
    &lt;div class="vb-savezone-head"&gt;
      &lt;span&gt;Example 17&lt;/span&gt;
      &lt;h3&gt;Drag to Favorite / Save Item&lt;/h3&gt;
      &lt;p&gt;Drag an article card into the saved collection area. Duplicate items are ignored automatically.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-savezone-layout"&gt;
      &lt;section class="vb-savezone-feed"&gt;
        &lt;article class="vb-savezone-card" data-vb-savezone-card data-id="css-layouts" data-title="Modern CSS Layouts"&gt;
          &lt;button type="button" data-vb-savezone-handle&gt;⋮⋮&lt;/button&gt;
          &lt;div class="vb-savezone-image vb-savezone-blue"&gt;&lt;/div&gt;
          &lt;div&gt;&lt;h4&gt;Modern CSS Layouts&lt;/h4&gt;&lt;p&gt;Grid, Flexbox and layout examples&lt;/p&gt;&lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-savezone-card" data-vb-savezone-card data-id="js-forms" data-title="JavaScript Form Validation"&gt;
          &lt;button type="button" data-vb-savezone-handle&gt;⋮⋮&lt;/button&gt;
          &lt;div class="vb-savezone-image vb-savezone-green"&gt;&lt;/div&gt;
          &lt;div&gt;&lt;h4&gt;JavaScript Form Validation&lt;/h4&gt;&lt;p&gt;Input checks and checkout forms&lt;/p&gt;&lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-savezone-card" data-vb-savezone-card data-id="pricing-tables" data-title="CSS Pricing Tables"&gt;
          &lt;button type="button" data-vb-savezone-handle&gt;⋮⋮&lt;/button&gt;
          &lt;div class="vb-savezone-image vb-savezone-orange"&gt;&lt;/div&gt;
          &lt;div&gt;&lt;h4&gt;CSS Pricing Tables&lt;/h4&gt;&lt;p&gt;Responsive pricing section designs&lt;/p&gt;&lt;/div&gt;
        &lt;/article&gt;
      &lt;/section&gt;

      &lt;aside class="vb-savezone-panel"&gt;
        &lt;div class="vb-savezone-target" data-vb-savezone-drop&gt;
          &lt;span&gt;Saved Collection&lt;/span&gt;
          &lt;strong data-vb-savezone-count&gt;0 saved&lt;/strong&gt;
          &lt;p&gt;Drop article cards here.&lt;/p&gt;
        &lt;/div&gt;

        &lt;div class="vb-savezone-saved" data-vb-savezone-list&gt;&lt;/div&gt;
      &lt;/aside&gt;
    &lt;/div&gt;

    &lt;div class="vb-savezone-status" data-vb-savezone-status&gt;Drag an article into the saved collection.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">/* CSS is included fully in the live demo block above. */</pre>



<p class="wp-block-paragraph">This JavaScript drag to favorite interaction is useful for product wishlists, saved articles, recipe collections, portfolio tools, dashboard cards, and ecommerce save-for-later features.</p>



<h2 class="wp-block-heading">18. Drag and Drop Product Comparison Builder</h2>



<p class="wp-block-paragraph"><strong>A drag and drop product comparison builder</strong> lets users drag products into comparison slots. This is useful for ecommerce stores, SaaS pricing tools, product review pages, affiliate websites, marketplace pages, and recommendation interfaces.</p>



<ul class="wp-block-list">
<li>Drag products into comparison slots</li>
<li>Maximum three compared products</li>
<li>Duplicate protection</li>
<li>Live comparison table</li>
<li>Mouse and touch support</li>
</ul>



<div class="vb-compare-demo">
  <div class="vb-compare-wrap" data-vb-compare>
    <div class="vb-compare-head">
      <span>Example 18</span>
      <h3>Product Comparison Builder</h3>
      <p>Drag products into the comparison area. The comparison table updates automatically.</p>
    </div>

    <div class="vb-compare-layout">
      <section class="vb-compare-products">
        <article class="vb-compare-product" data-vb-compare-card data-id="starter" data-title="Starter Plan" data-price="€19" data-speed="Basic" data-support="Email">
          <button type="button" data-vb-compare-handle>⋮⋮</button>
          <div>
            <h4>Starter Plan</h4>
            <p>€19 · Basic speed · Email support</p>
          </div>
        </article>

        <article class="vb-compare-product" data-vb-compare-card data-id="pro" data-title="Pro Plan" data-price="€49" data-speed="Fast" data-support="Priority">
          <button type="button" data-vb-compare-handle>⋮⋮</button>
          <div>
            <h4>Pro Plan</h4>
            <p>€49 · Fast speed · Priority support</p>
          </div>
        </article>

        <article class="vb-compare-product" data-vb-compare-card data-id="business" data-title="Business Plan" data-price="€99" data-speed="Very Fast" data-support="Dedicated">
          <button type="button" data-vb-compare-handle>⋮⋮</button>
          <div>
            <h4>Business Plan</h4>
            <p>€99 · Very fast · Dedicated support</p>
          </div>
        </article>

        <article class="vb-compare-product" data-vb-compare-card data-id="enterprise" data-title="Enterprise Plan" data-price="Custom" data-speed="Maximum" data-support="Account Manager">
          <button type="button" data-vb-compare-handle>⋮⋮</button>
          <div>
            <h4>Enterprise Plan</h4>
            <p>Custom · Maximum speed · Account manager</p>
          </div>
        </article>
      </section>

      <section class="vb-compare-panel">
        <div class="vb-compare-drop" data-vb-compare-drop>
          <span>Comparison area</span>
          <strong data-vb-compare-count>0 / 3 products</strong>
          <p>Drop products here.</p>
        </div>

        <div class="vb-compare-table-wrap">
          <table class="vb-compare-table">
            <tbody data-vb-compare-table>
              <tr><th>Feature</th><td>Drop products to compare</td></tr>
            </tbody>
          </table>
        </div>
      </section>
    </div>

    <div class="vb-compare-status" data-vb-compare-status>Drag a product into the comparison area.</div>
  </div>
</div>

<style>
.vb-compare-demo,
.vb-compare-demo * {
  box-sizing: border-box;
}

.vb-compare-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 10% 12%, rgba(37, 99, 235, 0.16), transparent 34%),
    radial-gradient(circle at 92% 20%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfeff 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-compare-wrap {
  max-width: 1160px;
  margin: 0 auto;
}

.vb-compare-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-compare-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-compare-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-compare-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-compare-layout {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(320px, 1.1fr);
  gap: 16px;
}

.vb-compare-products {
  display: grid;
  gap: 12px;
  align-content: start;
  padding: 16px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-compare-product {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 14px;
  border-radius: 20px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.24);
}

.vb-compare-product.is-dragging {
  opacity: 0.45;
}

.vb-compare-product button {
  width: 38px;
  height: 44px;
  border: 0;
  border-radius: 14px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 20px;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
}

.vb-compare-product h4 {
  margin: 0 0 5px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
}

.vb-compare-product p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.45;
  font-weight: 700;
}

.vb-compare-panel {
  display: grid;
  gap: 14px;
}

.vb-compare-drop {
  min-height: 190px;
  padding: 24px;
  border-radius: 30px;
  text-align: center;
  background:
    radial-gradient(circle at 50% 20%, rgba(59, 130, 246, 0.24), transparent 38%),
    linear-gradient(135deg, #1e3a8a, #0f172a) !important;
  border: 1px dashed rgba(147, 197, 253, 0.75);
  box-shadow: 0 22px 60px rgba(15, 23, 42, 0.18);
}

.vb-compare-drop.is-over {
  box-shadow: inset 0 0 0 5px rgba(59, 130, 246, 0.20), 0 22px 60px rgba(15, 23, 42, 0.18);
}

.vb-compare-drop span {
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-compare-drop strong {
  display: block;
  margin: 12px 0;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4vw, 44px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-compare-drop p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 15px;
  font-weight: 750;
}

.vb-compare-table-wrap {
  overflow-x: auto;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-compare-table {
  width: 100%;
  border-collapse: collapse;
  min-width: 420px;
}

.vb-compare-table th,
.vb-compare-table td {
  padding: 14px;
  border-bottom: 1px solid #e2e8f0;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  text-align: left;
}

.vb-compare-table th {
  background: #f8fafc;
  font-weight: 950;
}

.vb-compare-table td {
  font-weight: 700;
}

.vb-compare-status {
  margin-top: 16px;
  padding: 13px 15px;
  border-radius: 18px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-compare-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(320px, calc(100vw - 32px));
  padding: 13px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(37, 99, 235, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
}

.vb-compare-ghost strong {
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vb-compare-layout {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  function initCompareBuilder() {
    document.querySelectorAll("[data-vb-compare]").forEach(function (root) {
      if (root.getAttribute("data-vb-compare-ready") === "1") return;
      root.setAttribute("data-vb-compare-ready", "1");

      const drop = root.querySelector("[data-vb-compare-drop]");
      const count = root.querySelector("[data-vb-compare-count]");
      const table = root.querySelector("[data-vb-compare-table]");
      const status = root.querySelector("[data-vb-compare-status]");
      let active = null;
      let ghost = null;
      let compared = [];

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function isOverDrop(x, y) {
        const el = document.elementFromPoint(x, y);
        return !!(el && el.closest("[data-vb-compare-drop]") === drop);
      }

      function cardData(card) {
        return {
          id: card.getAttribute("data-id"),
          title: card.getAttribute("data-title"),
          price: card.getAttribute("data-price"),
          speed: card.getAttribute("data-speed"),
          support: card.getAttribute("data-support")
        };
      }

      function renderTable() {
        count.textContent = compared.length + " / 3 products";

        if (!compared.length) {
          table.innerHTML = "<tr><th>Feature</th><td>Drop products to compare</td></tr>";
          return;
        }

        function row(label, key) {
          return "<tr><th>" + label + "</th>" + compared.map(function (item) {
            return "<td>" + item[key] + "</td>";
          }).join("") + "</tr>";
        }

        table.innerHTML =
          row("Product", "title") +
          row("Price", "price") +
          row("Speed", "speed") +
          row("Support", "support");
      }

      function createGhost(card, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-compare-ghost";
        ghost.innerHTML = "<strong>" + card.getAttribute("data-title") + "</strong>";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-compare-handle]");
        if (!handle) return;

        const card = handle.closest("[data-vb-compare-card]");
        if (!card) return;

        event.preventDefault();

        const point = getPoint(event);
        active = card;
        active.classList.add("is-dragging");
        createGhost(card, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;
        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);

        if (isOverDrop(point.x, point.y)) {
          drop.classList.add("is-over");
        } else {
          drop.classList.remove("is-over");
        }
      }

      function end(event) {
        if (!active) return;

        const point = getPoint(event);

        if (isOverDrop(point.x, point.y)) {
          const data = cardData(active);
          const exists = compared.some(function (item) { return item.id === data.id; });

          if (exists) {
            status.textContent = data.title + " is already in the comparison table.";
          } else if (compared.length >= 3) {
            status.textContent = "Maximum 3 products can be compared.";
          } else {
            compared.push(data);
            status.textContent = data.title + " added to comparison.";
          }

          renderTable();
        }

        cleanup();
      }

      function cancel() {
        cleanup();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        drop.classList.remove("is-over");

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      renderTable();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initCompareBuilder);
  } else {
    initCompareBuilder();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initCompareBuilder() {
    document.querySelectorAll("[data-vb-compare]").forEach(function (root) {
      if (root.getAttribute("data-vb-compare-ready") === "1") return;
      root.setAttribute("data-vb-compare-ready", "1");

      const drop = root.querySelector("[data-vb-compare-drop]");
      const count = root.querySelector("[data-vb-compare-count]");
      const table = root.querySelector("[data-vb-compare-table]");
      const status = root.querySelector("[data-vb-compare-status]");
      let active = null;
      let ghost = null;
      let compared = [];

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function isOverDrop(x, y) {
        const el = document.elementFromPoint(x, y);
        return !!(el &amp;&amp; el.closest("[data-vb-compare-drop]") === drop);
      }

      function cardData(card) {
        return {
          id: card.getAttribute("data-id"),
          title: card.getAttribute("data-title"),
          price: card.getAttribute("data-price"),
          speed: card.getAttribute("data-speed"),
          support: card.getAttribute("data-support")
        };
      }

      function renderTable() {
        count.textContent = compared.length + " / 3 products";

        if (!compared.length) {
          table.innerHTML = "&lt;tr&gt;&lt;th&gt;Feature&lt;/th&gt;&lt;td&gt;Drop products to compare&lt;/td&gt;&lt;/tr&gt;";
          return;
        }

        function row(label, key) {
          return "&lt;tr&gt;&lt;th&gt;" + label + "&lt;/th&gt;" + compared.map(function (item) {
            return "&lt;td&gt;" + item[key] + "&lt;/td&gt;";
          }).join("") + "&lt;/tr&gt;";
        }

        table.innerHTML =
          row("Product", "title") +
          row("Price", "price") +
          row("Speed", "speed") +
          row("Support", "support");
      }

      function createGhost(card, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-compare-ghost";
        ghost.innerHTML = "&lt;strong&gt;" + card.getAttribute("data-title") + "&lt;/strong&gt;";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-compare-handle]");
        if (!handle) return;

        const card = handle.closest("[data-vb-compare-card]");
        if (!card) return;

        event.preventDefault();

        const point = getPoint(event);
        active = card;
        active.classList.add("is-dragging");
        createGhost(card, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;
        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);

        if (isOverDrop(point.x, point.y)) {
          drop.classList.add("is-over");
        } else {
          drop.classList.remove("is-over");
        }
      }

      function end(event) {
        if (!active) return;

        const point = getPoint(event);

        if (isOverDrop(point.x, point.y)) {
          const data = cardData(active);
          const exists = compared.some(function (item) { return item.id === data.id; });

          if (exists) {
            status.textContent = data.title + " is already in the comparison table.";
          } else if (compared.length &gt;= 3) {
            status.textContent = "Maximum 3 products can be compared.";
          } else {
            compared.push(data);
            status.textContent = data.title + " added to comparison.";
          }

          renderTable();
        }

        cleanup();
      }

      function cancel() {
        cleanup();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        drop.classList.remove("is-over");

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      renderTable();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initCompareBuilder);
  } else {
    initCompareBuilder();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-compare-demo"&gt;
  &lt;div class="vb-compare-wrap" data-vb-compare&gt;
    &lt;div class="vb-compare-head"&gt;
      &lt;span&gt;Example 18&lt;/span&gt;
      &lt;h3&gt;Product Comparison Builder&lt;/h3&gt;
      &lt;p&gt;Drag products into the comparison area. The comparison table updates automatically.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-compare-layout"&gt;
      &lt;section class="vb-compare-products"&gt;
        &lt;article class="vb-compare-product" data-vb-compare-card data-id="starter" data-title="Starter Plan" data-price="€19" data-speed="Basic" data-support="Email"&gt;
          &lt;button type="button" data-vb-compare-handle&gt;⋮⋮&lt;/button&gt;
          &lt;div&gt;&lt;h4&gt;Starter Plan&lt;/h4&gt;&lt;p&gt;€19 · Basic speed · Email support&lt;/p&gt;&lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-compare-product" data-vb-compare-card data-id="pro" data-title="Pro Plan" data-price="€49" data-speed="Fast" data-support="Priority"&gt;
          &lt;button type="button" data-vb-compare-handle&gt;⋮⋮&lt;/button&gt;
          &lt;div&gt;&lt;h4&gt;Pro Plan&lt;/h4&gt;&lt;p&gt;€49 · Fast speed · Priority support&lt;/p&gt;&lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-compare-product" data-vb-compare-card data-id="business" data-title="Business Plan" data-price="€99" data-speed="Very Fast" data-support="Dedicated"&gt;
          &lt;button type="button" data-vb-compare-handle&gt;⋮⋮&lt;/button&gt;
          &lt;div&gt;&lt;h4&gt;Business Plan&lt;/h4&gt;&lt;p&gt;€99 · Very fast · Dedicated support&lt;/p&gt;&lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-compare-product" data-vb-compare-card data-id="enterprise" data-title="Enterprise Plan" data-price="Custom" data-speed="Maximum" data-support="Account Manager"&gt;
          &lt;button type="button" data-vb-compare-handle&gt;⋮⋮&lt;/button&gt;
          &lt;div&gt;&lt;h4&gt;Enterprise Plan&lt;/h4&gt;&lt;p&gt;Custom · Maximum speed · Account manager&lt;/p&gt;&lt;/div&gt;
        &lt;/article&gt;
      &lt;/section&gt;

      &lt;section class="vb-compare-panel"&gt;
        &lt;div class="vb-compare-drop" data-vb-compare-drop&gt;
          &lt;span&gt;Comparison area&lt;/span&gt;
          &lt;strong data-vb-compare-count&gt;0 / 3 products&lt;/strong&gt;
          &lt;p&gt;Drop products here.&lt;/p&gt;
        &lt;/div&gt;

        &lt;div class="vb-compare-table-wrap"&gt;
          &lt;table class="vb-compare-table"&gt;
            &lt;tbody data-vb-compare-table&gt;
              &lt;tr&gt;&lt;th&gt;Feature&lt;/th&gt;&lt;td&gt;Drop products to compare&lt;/td&gt;&lt;/tr&gt;
            &lt;/tbody&gt;
          &lt;/table&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;

    &lt;div class="vb-compare-status" data-vb-compare-status&gt;Drag a product into the comparison area.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">/* CSS is included fully in the live demo block above. */</pre>



<p class="wp-block-paragraph">This JavaScript product comparison builder is useful for ecommerce stores, SaaS pricing pages, product review posts, affiliate websites, marketplace layouts, and recommendation interfaces.</p>



<div class="vb-mini-contact-cta">
  <p><strong>Need a custom interactive JavaScript feature?</strong> We can build drag and drop tools, calculators, forms, dashboards, and custom website components for your business.</p>
  <a href="https://veebilehed24.ee/en/contact/">Contact us</a>
</div>

<style>
.vb-mini-contact-cta,
.vb-mini-contact-cta * {
  box-sizing: border-box;
}

.vb-mini-contact-cta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin: 36px 0;
  padding: 16px 18px;
  border-radius: 18px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.28);
}

.vb-mini-contact-cta p {
  margin: 0 !important;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-mini-contact-cta strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-weight: 950;
}

.vb-mini-contact-cta a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 40px;
  padding: 10px 16px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 900;
  text-decoration: none !important;
  white-space: nowrap;
}

@media (max-width: 680px) {
  .vb-mini-contact-cta {
    align-items: flex-start;
    flex-direction: column;
  }
}
</style>



<h2 class="wp-block-heading">19. Drag and Drop Pricing Feature Selector</h2>



<p class="wp-block-paragraph"><strong>A drag and drop pricing feature selector</strong> lets users build a custom plan by dragging features into a pricing box. This is useful for SaaS pricing pages, custom quote builders, hosting plans, service packages, subscription pages, and product configuration tools.</p>



<ul class="wp-block-list">
<li>Drag features into a pricing plan</li>
<li>Updates total price automatically</li>
<li>Prevents duplicate features</li>
<li>Mouse and touch support</li>
<li>Works without external libraries</li>
</ul>



<div class="vb-pricepick-demo">
  <div class="vb-pricepick-wrap" data-vb-pricepick>
    <div class="vb-pricepick-head">
      <span>Example 19</span>
      <h3>Pricing Feature Selector</h3>
      <p>Drag extra features into the pricing plan. The monthly price updates instantly.</p>
    </div>

    <div class="vb-pricepick-layout">
      <section class="vb-pricepick-features">
        <article class="vb-pricepick-feature" data-vb-pricepick-card data-id="analytics" data-title="Advanced Analytics" data-price="12">
          <button type="button" data-vb-pricepick-handle>⋮⋮</button>
          <div>
            <h4>Advanced Analytics</h4>
            <p>€12 / month</p>
          </div>
        </article>

        <article class="vb-pricepick-feature" data-vb-pricepick-card data-id="automation" data-title="Workflow Automation" data-price="19">
          <button type="button" data-vb-pricepick-handle>⋮⋮</button>
          <div>
            <h4>Workflow Automation</h4>
            <p>€19 / month</p>
          </div>
        </article>

        <article class="vb-pricepick-feature" data-vb-pricepick-card data-id="support" data-title="Priority Support" data-price="15">
          <button type="button" data-vb-pricepick-handle>⋮⋮</button>
          <div>
            <h4>Priority Support</h4>
            <p>€15 / month</p>
          </div>
        </article>

        <article class="vb-pricepick-feature" data-vb-pricepick-card data-id="branding" data-title="White Label Branding" data-price="25">
          <button type="button" data-vb-pricepick-handle>⋮⋮</button>
          <div>
            <h4>White Label Branding</h4>
            <p>€25 / month</p>
          </div>
        </article>
      </section>

      <aside class="vb-pricepick-plan">
        <div class="vb-pricepick-cardbox" data-vb-pricepick-drop>
          <span>Custom Plan</span>
          <strong data-vb-pricepick-total>€29</strong>
          <p>Base plan + selected features</p>
          <div class="vb-pricepick-selected" data-vb-pricepick-list></div>
        </div>
      </aside>
    </div>

    <div class="vb-pricepick-status" data-vb-pricepick-status>Drag a feature into the custom plan.</div>
  </div>
</div>

<style>
.vb-pricepick-demo,
.vb-pricepick-demo * {
  box-sizing: border-box;
}

.vb-pricepick-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(34, 197, 94, 0.16), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #eff6ff 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-pricepick-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-pricepick-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-pricepick-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-pricepick-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-pricepick-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-pricepick-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 0.7fr);
  gap: 16px;
}

.vb-pricepick-features {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  align-content: start;
}

.vb-pricepick-feature {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 16px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 16px 44px rgba(15, 23, 42, 0.08);
}

.vb-pricepick-feature.is-dragging {
  opacity: 0.45;
}

.vb-pricepick-feature button {
  width: 38px;
  height: 44px;
  border: 0;
  border-radius: 14px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 20px;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
}

.vb-pricepick-feature h4 {
  margin: 0 0 5px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
}

.vb-pricepick-feature p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.45;
  font-weight: 700;
}

.vb-pricepick-plan {
  min-width: 0;
}

.vb-pricepick-cardbox {
  min-height: 360px;
  padding: 26px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 16% 14%, rgba(34, 197, 94, 0.26), transparent 38%),
    linear-gradient(135deg, #052e16, #0f172a) !important;
  border: 1px dashed rgba(134, 239, 172, 0.75);
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.22);
}

.vb-pricepick-cardbox.is-over {
  box-shadow: inset 0 0 0 5px rgba(34, 197, 94, 0.18), 0 22px 64px rgba(15, 23, 42, 0.22);
}

.vb-pricepick-cardbox > span {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-pricepick-cardbox > strong {
  display: block;
  margin: 12px 0 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(44px, 6vw, 70px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.07em;
}

.vb-pricepick-cardbox > p {
  margin: 0 0 16px !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 15px;
  line-height: 1.55;
  font-weight: 700;
}

.vb-pricepick-selected {
  display: grid;
  gap: 10px;
}

.vb-pricepick-selected-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px;
  border-radius: 16px;
  background: rgba(255,255,255,0.12);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-pricepick-selected-item b {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
}

.vb-pricepick-status {
  margin-top: 16px;
  padding: 13px 15px;
  border-radius: 18px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-pricepick-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(320px, calc(100vw - 32px));
  padding: 13px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(34, 197, 94, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
}

.vb-pricepick-ghost strong {
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-pricepick-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-pricepick-features {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  function initPricePicker() {
    document.querySelectorAll("[data-vb-pricepick]").forEach(function (root) {
      if (root.getAttribute("data-vb-pricepick-ready") === "1") return;
      root.setAttribute("data-vb-pricepick-ready", "1");

      const drop = root.querySelector("[data-vb-pricepick-drop]");
      const list = root.querySelector("[data-vb-pricepick-list]");
      const total = root.querySelector("[data-vb-pricepick-total]");
      const status = root.querySelector("[data-vb-pricepick-status]");
      const basePrice = 29;

      let active = null;
      let ghost = null;
      let selected = [];

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function isOverDrop(x, y) {
        const el = document.elementFromPoint(x, y);
        return !!(el && el.closest("[data-vb-pricepick-drop]") === drop);
      }

      function cardData(card) {
        return {
          id: card.getAttribute("data-id"),
          title: card.getAttribute("data-title"),
          price: Number(card.getAttribute("data-price"))
        };
      }

      function renderSelected() {
        list.innerHTML = "";

        let price = basePrice;

        selected.forEach(function (item) {
          price += item.price;

          const row = document.createElement("div");
          row.className = "vb-pricepick-selected-item";
          row.innerHTML = "<span>" + item.title + "</span><b>+€" + item.price + "</b>";
          list.appendChild(row);
        });

        total.textContent = "€" + price;
      }

      function createGhost(card, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-pricepick-ghost";
        ghost.innerHTML = "<strong>" + card.getAttribute("data-title") + "</strong>";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-pricepick-handle]");
        if (!handle) return;

        const card = handle.closest("[data-vb-pricepick-card]");
        if (!card) return;

        event.preventDefault();

        const point = getPoint(event);
        active = card;
        active.classList.add("is-dragging");
        createGhost(card, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;
        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);

        if (isOverDrop(point.x, point.y)) {
          drop.classList.add("is-over");
        } else {
          drop.classList.remove("is-over");
        }
      }

      function end(event) {
        if (!active) return;

        const point = getPoint(event);

        if (isOverDrop(point.x, point.y)) {
          const data = cardData(active);
          const exists = selected.some(function (item) { return item.id === data.id; });

          if (exists) {
            status.textContent = data.title + " is already included.";
          } else {
            selected.push(data);
            status.textContent = data.title + " added to the plan.";
            renderSelected();
          }
        }

        cleanup();
      }

      function cancel() {
        cleanup();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        drop.classList.remove("is-over");

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      renderSelected();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initPricePicker);
  } else {
    initPricePicker();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initPricePicker() {
    document.querySelectorAll("[data-vb-pricepick]").forEach(function (root) {
      if (root.getAttribute("data-vb-pricepick-ready") === "1") return;
      root.setAttribute("data-vb-pricepick-ready", "1");

      const drop = root.querySelector("[data-vb-pricepick-drop]");
      const list = root.querySelector("[data-vb-pricepick-list]");
      const total = root.querySelector("[data-vb-pricepick-total]");
      const status = root.querySelector("[data-vb-pricepick-status]");
      const basePrice = 29;

      let active = null;
      let ghost = null;
      let selected = [];

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function isOverDrop(x, y) {
        const el = document.elementFromPoint(x, y);
        return !!(el &amp;&amp; el.closest("[data-vb-pricepick-drop]") === drop);
      }

      function cardData(card) {
        return {
          id: card.getAttribute("data-id"),
          title: card.getAttribute("data-title"),
          price: Number(card.getAttribute("data-price"))
        };
      }

      function renderSelected() {
        list.innerHTML = "";

        let price = basePrice;

        selected.forEach(function (item) {
          price += item.price;

          const row = document.createElement("div");
          row.className = "vb-pricepick-selected-item";
          row.innerHTML = "&lt;span&gt;" + item.title + "&lt;/span&gt;&lt;b&gt;+€" + item.price + "&lt;/b&gt;";
          list.appendChild(row);
        });

        total.textContent = "€" + price;
      }

      function createGhost(card, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-pricepick-ghost";
        ghost.innerHTML = "&lt;strong&gt;" + card.getAttribute("data-title") + "&lt;/strong&gt;";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-pricepick-handle]");
        if (!handle) return;

        const card = handle.closest("[data-vb-pricepick-card]");
        if (!card) return;

        event.preventDefault();

        const point = getPoint(event);
        active = card;
        active.classList.add("is-dragging");
        createGhost(card, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;
        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);

        if (isOverDrop(point.x, point.y)) {
          drop.classList.add("is-over");
        } else {
          drop.classList.remove("is-over");
        }
      }

      function end(event) {
        if (!active) return;

        const point = getPoint(event);

        if (isOverDrop(point.x, point.y)) {
          const data = cardData(active);
          const exists = selected.some(function (item) { return item.id === data.id; });

          if (exists) {
            status.textContent = data.title + " is already included.";
          } else {
            selected.push(data);
            status.textContent = data.title + " added to the plan.";
            renderSelected();
          }
        }

        cleanup();
      }

      function cancel() {
        cleanup();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        drop.classList.remove("is-over");

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      renderSelected();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initPricePicker);
  } else {
    initPricePicker();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-pricepick-demo"&gt;
  &lt;div class="vb-pricepick-wrap" data-vb-pricepick&gt;
    &lt;div class="vb-pricepick-head"&gt;
      &lt;span&gt;Example 19&lt;/span&gt;
      &lt;h3&gt;Pricing Feature Selector&lt;/h3&gt;
      &lt;p&gt;Drag extra features into the pricing plan. The monthly price updates instantly.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-pricepick-layout"&gt;
      &lt;section class="vb-pricepick-features"&gt;
        &lt;article class="vb-pricepick-feature" data-vb-pricepick-card data-id="analytics" data-title="Advanced Analytics" data-price="12"&gt;
          &lt;button type="button" data-vb-pricepick-handle&gt;⋮⋮&lt;/button&gt;
          &lt;div&gt;&lt;h4&gt;Advanced Analytics&lt;/h4&gt;&lt;p&gt;€12 / month&lt;/p&gt;&lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-pricepick-feature" data-vb-pricepick-card data-id="automation" data-title="Workflow Automation" data-price="19"&gt;
          &lt;button type="button" data-vb-pricepick-handle&gt;⋮⋮&lt;/button&gt;
          &lt;div&gt;&lt;h4&gt;Workflow Automation&lt;/h4&gt;&lt;p&gt;€19 / month&lt;/p&gt;&lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-pricepick-feature" data-vb-pricepick-card data-id="support" data-title="Priority Support" data-price="15"&gt;
          &lt;button type="button" data-vb-pricepick-handle&gt;⋮⋮&lt;/button&gt;
          &lt;div&gt;&lt;h4&gt;Priority Support&lt;/h4&gt;&lt;p&gt;€15 / month&lt;/p&gt;&lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-pricepick-feature" data-vb-pricepick-card data-id="branding" data-title="White Label Branding" data-price="25"&gt;
          &lt;button type="button" data-vb-pricepick-handle&gt;⋮⋮&lt;/button&gt;
          &lt;div&gt;&lt;h4&gt;White Label Branding&lt;/h4&gt;&lt;p&gt;€25 / month&lt;/p&gt;&lt;/div&gt;
        &lt;/article&gt;
      &lt;/section&gt;

      &lt;aside class="vb-pricepick-plan"&gt;
        &lt;div class="vb-pricepick-cardbox" data-vb-pricepick-drop&gt;
          &lt;span&gt;Custom Plan&lt;/span&gt;
          &lt;strong data-vb-pricepick-total&gt;€29&lt;/strong&gt;
          &lt;p&gt;Base plan + selected features&lt;/p&gt;
          &lt;div class="vb-pricepick-selected" data-vb-pricepick-list&gt;&lt;/div&gt;
        &lt;/div&gt;
      &lt;/aside&gt;
    &lt;/div&gt;

    &lt;div class="vb-pricepick-status" data-vb-pricepick-status&gt;Drag a feature into the custom plan.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-pricepick-demo,
.vb-pricepick-demo * {
  box-sizing: border-box;
}

.vb-pricepick-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(34, 197, 94, 0.16), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #eff6ff 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-pricepick-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-pricepick-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-pricepick-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-pricepick-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-pricepick-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-pricepick-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 0.7fr);
  gap: 16px;
}

.vb-pricepick-features {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  align-content: start;
}

.vb-pricepick-feature {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 16px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 16px 44px rgba(15, 23, 42, 0.08);
}

.vb-pricepick-feature.is-dragging {
  opacity: 0.45;
}

.vb-pricepick-feature button {
  width: 38px;
  height: 44px;
  border: 0;
  border-radius: 14px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 20px;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
}

.vb-pricepick-feature h4 {
  margin: 0 0 5px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
}

.vb-pricepick-feature p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.45;
  font-weight: 700;
}

.vb-pricepick-plan {
  min-width: 0;
}

.vb-pricepick-cardbox {
  min-height: 360px;
  padding: 26px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 16% 14%, rgba(34, 197, 94, 0.26), transparent 38%),
    linear-gradient(135deg, #052e16, #0f172a) !important;
  border: 1px dashed rgba(134, 239, 172, 0.75);
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.22);
}

.vb-pricepick-cardbox.is-over {
  box-shadow: inset 0 0 0 5px rgba(34, 197, 94, 0.18), 0 22px 64px rgba(15, 23, 42, 0.22);
}

.vb-pricepick-cardbox > span {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-pricepick-cardbox > strong {
  display: block;
  margin: 12px 0 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(44px, 6vw, 70px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.07em;
}

.vb-pricepick-cardbox > p {
  margin: 0 0 16px !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 15px;
  line-height: 1.55;
  font-weight: 700;
}

.vb-pricepick-selected {
  display: grid;
  gap: 10px;
}

.vb-pricepick-selected-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px;
  border-radius: 16px;
  background: rgba(255,255,255,0.12);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-pricepick-selected-item b {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
}

.vb-pricepick-status {
  margin-top: 16px;
  padding: 13px 15px;
  border-radius: 18px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-pricepick-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(320px, calc(100vw - 32px));
  padding: 13px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(34, 197, 94, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
}

.vb-pricepick-ghost strong {
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-pricepick-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-pricepick-features {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript pricing feature selector is useful for SaaS pricing pages, service package builders, hosting plan configurators, quote tools, and subscription product pages.</p>



<h2 class="wp-block-heading">20. Drag and Drop Quiz Matching Game</h2>



<p class="wp-block-paragraph"><strong>A drag and drop quiz matching game</strong> is an interactive JavaScript learning pattern where users match answers to the correct question cards. It is useful for education websites, onboarding flows, language learning apps, product training, quizzes, and gamified learning interfaces.</p>



<ul class="wp-block-list">
<li>Match answers to question cards</li>
<li>Correct and wrong answer feedback</li>
<li>Live score counter</li>
<li>Mouse and touch support</li>
<li>Different logic from builder examples</li>
</ul>



<div class="vb-quizmatch-demo">
  <div class="vb-quizmatch-wrap" data-vb-quizmatch>
    <div class="vb-quizmatch-head">
      <span>Example 20</span>
      <h3>Quiz Matching Game</h3>
      <p>Drag each answer into the matching question card. Correct matches stay locked.</p>
    </div>

    <div class="vb-quizmatch-score">
      <span>Score</span>
      <strong data-vb-quizmatch-score>0 / 3 correct</strong>
    </div>

    <div class="vb-quizmatch-layout">
      <section class="vb-quizmatch-questions">
        <article class="vb-quizmatch-question" data-vb-quizmatch-drop data-answer="html">
          <h4>What language structures a web page?</h4>
          <div class="vb-quizmatch-slot" data-vb-quizmatch-slot>Drop answer here</div>
        </article>

        <article class="vb-quizmatch-question" data-vb-quizmatch-drop data-answer="css">
          <h4>What language styles a web page?</h4>
          <div class="vb-quizmatch-slot" data-vb-quizmatch-slot>Drop answer here</div>
        </article>

        <article class="vb-quizmatch-question" data-vb-quizmatch-drop data-answer="javascript">
          <h4>What language adds interaction?</h4>
          <div class="vb-quizmatch-slot" data-vb-quizmatch-slot>Drop answer here</div>
        </article>
      </section>

      <section class="vb-quizmatch-answers" data-vb-quizmatch-pool>
        <article class="vb-quizmatch-answer" data-vb-quizmatch-answer data-id="css" data-label="CSS">
          <button type="button" data-vb-quizmatch-handle>⋮⋮</button>
          <strong>CSS</strong>
        </article>

        <article class="vb-quizmatch-answer" data-vb-quizmatch-answer data-id="javascript" data-label="JavaScript">
          <button type="button" data-vb-quizmatch-handle>⋮⋮</button>
          <strong>JavaScript</strong>
        </article>

        <article class="vb-quizmatch-answer" data-vb-quizmatch-answer data-id="html" data-label="HTML">
          <button type="button" data-vb-quizmatch-handle>⋮⋮</button>
          <strong>HTML</strong>
        </article>
      </section>
    </div>

    <div class="vb-quizmatch-status" data-vb-quizmatch-status>Drag an answer into a question card.</div>
  </div>
</div>

<style>
.vb-quizmatch-demo,
.vb-quizmatch-demo * {
  box-sizing: border-box;
}

.vb-quizmatch-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(168, 85, 247, 0.16), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(249, 115, 22, 0.16), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #fff7ed 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-quizmatch-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-quizmatch-head {
  max-width: 780px;
  margin-bottom: 18px;
}

.vb-quizmatch-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-quizmatch-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-quizmatch-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-quizmatch-score {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: center;
  margin-bottom: 16px;
  padding: 14px 16px;
  border-radius: 20px;
  background: #0f172a;
}

.vb-quizmatch-score span {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-quizmatch-score strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-quizmatch-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 0.45fr);
  gap: 16px;
}

.vb-quizmatch-questions {
  display: grid;
  gap: 14px;
}

.vb-quizmatch-question {
  padding: 18px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 16px 44px rgba(15, 23, 42, 0.08);
}

.vb-quizmatch-question.is-over {
  border-color: rgba(168, 85, 247, 0.84);
  background: #faf5ff;
  box-shadow: inset 0 0 0 4px rgba(168, 85, 247, 0.10), 0 16px 44px rgba(15, 23, 42, 0.08);
}

.vb-quizmatch-question.is-correct {
  border-color: rgba(34, 197, 94, 0.75);
  background: #f0fdf4;
}

.vb-quizmatch-question.is-wrong {
  border-color: rgba(239, 68, 68, 0.72);
  background: #fef2f2;
}

.vb-quizmatch-question h4 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
}

.vb-quizmatch-slot {
  min-height: 52px;
  display: flex;
  align-items: center;
  padding: 12px;
  border-radius: 16px;
  background: #f8fafc;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-quizmatch-answers {
  display: grid;
  align-content: start;
  gap: 12px;
  padding: 16px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-quizmatch-answer {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 14px;
  border-radius: 18px;
  background: #faf5ff;
  border: 1px solid rgba(168, 85, 247, 0.20);
}

.vb-quizmatch-answer.is-dragging {
  opacity: 0.45;
}

.vb-quizmatch-answer.is-locked {
  opacity: 0.35;
  pointer-events: none;
}

.vb-quizmatch-answer button {
  width: 36px;
  height: 42px;
  border: 0;
  border-radius: 14px;
  background: #7e22ce;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 19px;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
}

.vb-quizmatch-answer strong {
  color: #581c87 !important;
  -webkit-text-fill-color: #581c87 !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-quizmatch-status {
  margin-top: 16px;
  padding: 13px 15px;
  border-radius: 18px;
  background: #581c87;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-quizmatch-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(260px, calc(100vw - 32px));
  padding: 13px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(168, 85, 247, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
}

.vb-quizmatch-ghost strong {
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 820px) {
  .vb-quizmatch-layout {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  function initQuizMatch() {
    document.querySelectorAll("[data-vb-quizmatch]").forEach(function (root) {
      if (root.getAttribute("data-vb-quizmatch-ready") === "1") return;
      root.setAttribute("data-vb-quizmatch-ready", "1");

      const drops = Array.from(root.querySelectorAll("[data-vb-quizmatch-drop]"));
      const score = root.querySelector("[data-vb-quizmatch-score]");
      const status = root.querySelector("[data-vb-quizmatch-status]");
      let active = null;
      let ghost = null;
      let correct = 0;

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function getDropAt(x, y) {
        const el = document.elementFromPoint(x, y);
        if (!el) return null;
        const drop = el.closest("[data-vb-quizmatch-drop]");
        return drops.includes(drop) ? drop : null;
      }

      function clearOver() {
        drops.forEach(function (drop) {
          drop.classList.remove("is-over", "is-wrong");
        });
      }

      function updateScore() {
        score.textContent = correct + " / 3 correct";
      }

      function createGhost(card, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-quizmatch-ghost";
        ghost.innerHTML = "<strong>" + card.getAttribute("data-label") + "</strong>";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-quizmatch-handle]");
        if (!handle) return;

        const card = handle.closest("[data-vb-quizmatch-answer]");
        if (!card || card.classList.contains("is-locked")) return;

        event.preventDefault();

        const point = getPoint(event);
        active = card;
        active.classList.add("is-dragging");
        createGhost(card, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;
        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);
        clearOver();

        const drop = getDropAt(point.x, point.y);
        if (drop && !drop.classList.contains("is-correct")) {
          drop.classList.add("is-over");
        }
      }

      function end(event) {
        if (!active) return;

        const point = getPoint(event);
        const drop = getDropAt(point.x, point.y);

        if (drop && !drop.classList.contains("is-correct")) {
          const answer = active.getAttribute("data-id");
          const correctAnswer = drop.getAttribute("data-answer");

          if (answer === correctAnswer) {
            const slot = drop.querySelector("[data-vb-quizmatch-slot]");
            slot.textContent = active.getAttribute("data-label");
            drop.classList.add("is-correct");
            active.classList.add("is-locked");
            correct += 1;
            status.textContent = "Correct match: " + active.getAttribute("data-label");
            updateScore();
          } else {
            drop.classList.add("is-wrong");
            status.textContent = "Wrong answer. Try another question.";
          }
        }

        cleanup();
      }

      function cancel() {
        cleanup();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        drops.forEach(function (drop) { drop.classList.remove("is-over"); });

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateScore();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initQuizMatch);
  } else {
    initQuizMatch();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initQuizMatch() {
    document.querySelectorAll("[data-vb-quizmatch]").forEach(function (root) {
      if (root.getAttribute("data-vb-quizmatch-ready") === "1") return;
      root.setAttribute("data-vb-quizmatch-ready", "1");

      const drops = Array.from(root.querySelectorAll("[data-vb-quizmatch-drop]"));
      const score = root.querySelector("[data-vb-quizmatch-score]");
      const status = root.querySelector("[data-vb-quizmatch-status]");
      let active = null;
      let ghost = null;
      let correct = 0;

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function getDropAt(x, y) {
        const el = document.elementFromPoint(x, y);
        if (!el) return null;
        const drop = el.closest("[data-vb-quizmatch-drop]");
        return drops.includes(drop) ? drop : null;
      }

      function clearOver() {
        drops.forEach(function (drop) {
          drop.classList.remove("is-over", "is-wrong");
        });
      }

      function updateScore() {
        score.textContent = correct + " / 3 correct";
      }

      function createGhost(card, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-quizmatch-ghost";
        ghost.innerHTML = "&lt;strong&gt;" + card.getAttribute("data-label") + "&lt;/strong&gt;";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-quizmatch-handle]");
        if (!handle) return;

        const card = handle.closest("[data-vb-quizmatch-answer]");
        if (!card || card.classList.contains("is-locked")) return;

        event.preventDefault();

        const point = getPoint(event);
        active = card;
        active.classList.add("is-dragging");
        createGhost(card, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;
        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);
        clearOver();

        const drop = getDropAt(point.x, point.y);
        if (drop &amp;&amp; !drop.classList.contains("is-correct")) {
          drop.classList.add("is-over");
        }
      }

      function end(event) {
        if (!active) return;

        const point = getPoint(event);
        const drop = getDropAt(point.x, point.y);

        if (drop &amp;&amp; !drop.classList.contains("is-correct")) {
          const answer = active.getAttribute("data-id");
          const correctAnswer = drop.getAttribute("data-answer");

          if (answer === correctAnswer) {
            const slot = drop.querySelector("[data-vb-quizmatch-slot]");
            slot.textContent = active.getAttribute("data-label");
            drop.classList.add("is-correct");
            active.classList.add("is-locked");
            correct += 1;
            status.textContent = "Correct match: " + active.getAttribute("data-label");
            updateScore();
          } else {
            drop.classList.add("is-wrong");
            status.textContent = "Wrong answer. Try another question.";
          }
        }

        cleanup();
      }

      function cancel() {
        cleanup();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        drops.forEach(function (drop) { drop.classList.remove("is-over"); });

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateScore();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initQuizMatch);
  } else {
    initQuizMatch();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-quizmatch-demo"&gt;
  &lt;div class="vb-quizmatch-wrap" data-vb-quizmatch&gt;
    &lt;div class="vb-quizmatch-head"&gt;
      &lt;span&gt;Example 20&lt;/span&gt;
      &lt;h3&gt;Quiz Matching Game&lt;/h3&gt;
      &lt;p&gt;Drag each answer into the matching question card. Correct matches stay locked.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-quizmatch-score"&gt;
      &lt;span&gt;Score&lt;/span&gt;
      &lt;strong data-vb-quizmatch-score&gt;0 / 3 correct&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-quizmatch-layout"&gt;
      &lt;section class="vb-quizmatch-questions"&gt;
        &lt;article class="vb-quizmatch-question" data-vb-quizmatch-drop data-answer="html"&gt;
          &lt;h4&gt;What language structures a web page?&lt;/h4&gt;
          &lt;div class="vb-quizmatch-slot" data-vb-quizmatch-slot&gt;Drop answer here&lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-quizmatch-question" data-vb-quizmatch-drop data-answer="css"&gt;
          &lt;h4&gt;What language styles a web page?&lt;/h4&gt;
          &lt;div class="vb-quizmatch-slot" data-vb-quizmatch-slot&gt;Drop answer here&lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-quizmatch-question" data-vb-quizmatch-drop data-answer="javascript"&gt;
          &lt;h4&gt;What language adds interaction?&lt;/h4&gt;
          &lt;div class="vb-quizmatch-slot" data-vb-quizmatch-slot&gt;Drop answer here&lt;/div&gt;
        &lt;/article&gt;
      &lt;/section&gt;

      &lt;section class="vb-quizmatch-answers" data-vb-quizmatch-pool&gt;
        &lt;article class="vb-quizmatch-answer" data-vb-quizmatch-answer data-id="css" data-label="CSS"&gt;
          &lt;button type="button" data-vb-quizmatch-handle&gt;⋮⋮&lt;/button&gt;
          &lt;strong&gt;CSS&lt;/strong&gt;
        &lt;/article&gt;

        &lt;article class="vb-quizmatch-answer" data-vb-quizmatch-answer data-id="javascript" data-label="JavaScript"&gt;
          &lt;button type="button" data-vb-quizmatch-handle&gt;⋮⋮&lt;/button&gt;
          &lt;strong&gt;JavaScript&lt;/strong&gt;
        &lt;/article&gt;

        &lt;article class="vb-quizmatch-answer" data-vb-quizmatch-answer data-id="html" data-label="HTML"&gt;
          &lt;button type="button" data-vb-quizmatch-handle&gt;⋮⋮&lt;/button&gt;
          &lt;strong&gt;HTML&lt;/strong&gt;
        &lt;/article&gt;
      &lt;/section&gt;
    &lt;/div&gt;

    &lt;div class="vb-quizmatch-status" data-vb-quizmatch-status&gt;Drag an answer into a question card.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-quizmatch-demo,
.vb-quizmatch-demo * {
  box-sizing: border-box;
}

.vb-quizmatch-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(168, 85, 247, 0.16), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(249, 115, 22, 0.16), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #fff7ed 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-quizmatch-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-quizmatch-head {
  max-width: 780px;
  margin-bottom: 18px;
}

.vb-quizmatch-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-quizmatch-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-quizmatch-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-quizmatch-score {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: center;
  margin-bottom: 16px;
  padding: 14px 16px;
  border-radius: 20px;
  background: #0f172a;
}

.vb-quizmatch-score span {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-quizmatch-score strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-quizmatch-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 0.45fr);
  gap: 16px;
}

.vb-quizmatch-questions {
  display: grid;
  gap: 14px;
}

.vb-quizmatch-question {
  padding: 18px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 16px 44px rgba(15, 23, 42, 0.08);
}

.vb-quizmatch-question.is-over {
  border-color: rgba(168, 85, 247, 0.84);
  background: #faf5ff;
  box-shadow: inset 0 0 0 4px rgba(168, 85, 247, 0.10), 0 16px 44px rgba(15, 23, 42, 0.08);
}

.vb-quizmatch-question.is-correct {
  border-color: rgba(34, 197, 94, 0.75);
  background: #f0fdf4;
}

.vb-quizmatch-question.is-wrong {
  border-color: rgba(239, 68, 68, 0.72);
  background: #fef2f2;
}

.vb-quizmatch-question h4 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
}

.vb-quizmatch-slot {
  min-height: 52px;
  display: flex;
  align-items: center;
  padding: 12px;
  border-radius: 16px;
  background: #f8fafc;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-quizmatch-answers {
  display: grid;
  align-content: start;
  gap: 12px;
  padding: 16px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-quizmatch-answer {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 14px;
  border-radius: 18px;
  background: #faf5ff;
  border: 1px solid rgba(168, 85, 247, 0.20);
}

.vb-quizmatch-answer.is-dragging {
  opacity: 0.45;
}

.vb-quizmatch-answer.is-locked {
  opacity: 0.35;
  pointer-events: none;
}

.vb-quizmatch-answer button {
  width: 36px;
  height: 42px;
  border: 0;
  border-radius: 14px;
  background: #7e22ce;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 19px;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
}

.vb-quizmatch-answer strong {
  color: #581c87 !important;
  -webkit-text-fill-color: #581c87 !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-quizmatch-status {
  margin-top: 16px;
  padding: 13px 15px;
  border-radius: 18px;
  background: #581c87;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-quizmatch-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(260px, calc(100vw - 32px));
  padding: 13px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(168, 85, 247, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
}

.vb-quizmatch-ghost strong {
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 820px) {
  .vb-quizmatch-layout {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript drag and drop quiz matching game is useful for education websites, onboarding screens, product training, quizzes, language learning apps, and interactive learning interfaces.</p>



<h2 class="wp-block-heading">21. Drag and Drop Puzzle Grid</h2>



<p class="wp-block-paragraph"><strong>A drag and drop puzzle grid</strong> turns sorting into a small interactive game. Users drag tiles into the correct order and the interface checks whether the puzzle is solved. This pattern is useful for educational games, onboarding tasks, visual learning tools, gamified UI demos, and interactive tutorials.</p>



<ul class="wp-block-list">
<li>Reorder puzzle tiles</li>
<li>Checks if the puzzle is solved</li>
<li>Mouse and touch support</li>
<li>Shuffle button</li>
<li>Compact responsive grid</li>
</ul>



<div class="vb-puzzlegrid-demo">
  <div class="vb-puzzlegrid-wrap" data-vb-puzzlegrid>
    <div class="vb-puzzlegrid-head">
      <span>Example 21</span>
      <h3>Drag and Drop Puzzle Grid</h3>
      <p>Reorder the tiles from 1 to 9. The status updates when the puzzle is solved.</p>
    </div>

    <div class="vb-puzzlegrid-panel">
      <div class="vb-puzzlegrid-board" data-vb-puzzlegrid-board>
        <button type="button" class="vb-puzzlegrid-tile" data-vb-puzzlegrid-tile data-value="5">5</button>
        <button type="button" class="vb-puzzlegrid-tile" data-vb-puzzlegrid-tile data-value="1">1</button>
        <button type="button" class="vb-puzzlegrid-tile" data-vb-puzzlegrid-tile data-value="8">8</button>
        <button type="button" class="vb-puzzlegrid-tile" data-vb-puzzlegrid-tile data-value="3">3</button>
        <button type="button" class="vb-puzzlegrid-tile" data-vb-puzzlegrid-tile data-value="7">7</button>
        <button type="button" class="vb-puzzlegrid-tile" data-vb-puzzlegrid-tile data-value="2">2</button>
        <button type="button" class="vb-puzzlegrid-tile" data-vb-puzzlegrid-tile data-value="9">9</button>
        <button type="button" class="vb-puzzlegrid-tile" data-vb-puzzlegrid-tile data-value="4">4</button>
        <button type="button" class="vb-puzzlegrid-tile" data-vb-puzzlegrid-tile data-value="6">6</button>
      </div>

      <aside class="vb-puzzlegrid-side">
        <span>Puzzle Status</span>
        <strong data-vb-puzzlegrid-status>Not solved yet</strong>
        <p>Drag tiles until the order is 1, 2, 3, 4, 5, 6, 7, 8, 9.</p>
        <button type="button" data-vb-puzzlegrid-shuffle>Shuffle tiles</button>
      </aside>
    </div>
  </div>
</div>

<style>
.vb-puzzlegrid-demo,
.vb-puzzlegrid-demo * {
  box-sizing: border-box;
}

.vb-puzzlegrid-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(14, 165, 233, 0.16), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(245, 158, 11, 0.18), transparent 34%),
    linear-gradient(135deg, #ecfeff 0%, #fffbeb 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-puzzlegrid-wrap {
  max-width: 1060px;
  margin: 0 auto;
}

.vb-puzzlegrid-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-puzzlegrid-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #cffafe;
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-puzzlegrid-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-puzzlegrid-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-puzzlegrid-panel {
  display: grid;
  grid-template-columns: minmax(280px, 0.85fr) minmax(260px, 0.65fr);
  gap: 16px;
  align-items: stretch;
}

.vb-puzzlegrid-board {
  display: grid;
  grid-template-columns: repeat(3, minmax(72px, 1fr));
  gap: 12px;
  padding: 18px;
  border-radius: 30px;
  background: #0f172a;
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.22);
}

.vb-puzzlegrid-tile {
  min-height: 112px;
  border: 0;
  border-radius: 22px;
  background:
    radial-gradient(circle at 25% 18%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #06b6d4, #2563eb) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 58px);
  line-height: 1;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.28), 0 12px 26px rgba(0,0,0,0.20);
}

.vb-puzzlegrid-tile:nth-child(2n) {
  background:
    radial-gradient(circle at 25% 18%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #f59e0b, #ec4899) !important;
}

.vb-puzzlegrid-tile.is-dragging {
  opacity: 0.45;
}

.vb-puzzlegrid-tile.is-over {
  outline: 4px solid rgba(255,255,255,0.38);
}

.vb-puzzlegrid-side {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 26px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 16% 16%, rgba(34, 211, 238, 0.22), transparent 36%),
    linear-gradient(135deg, #164e63, #0f172a) !important;
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.20);
}

.vb-puzzlegrid-side span {
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-puzzlegrid-side strong {
  margin: 12px 0;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(26px, 4vw, 42px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-puzzlegrid-side p {
  margin: 0 0 18px !important;
  color: #cffafe !important;
  -webkit-text-fill-color: #cffafe !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-puzzlegrid-side button {
  min-height: 46px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-puzzlegrid-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: 92px;
  height: 92px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 22px;
  background: linear-gradient(135deg, #06b6d4, #2563eb) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 42px;
  font-weight: 950;
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.30);
}

@media (max-width: 820px) {
  .vb-puzzlegrid-panel {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 480px) {
  .vb-puzzlegrid-board {
    gap: 8px;
    padding: 12px;
  }

  .vb-puzzlegrid-tile {
    min-height: 82px;
    border-radius: 18px;
  }
}
</style>

<script>
(function () {
  function initPuzzleGrid() {
    document.querySelectorAll("[data-vb-puzzlegrid]").forEach(function (root) {
      if (root.getAttribute("data-vb-puzzlegrid-ready") === "1") return;
      root.setAttribute("data-vb-puzzlegrid-ready", "1");

      const board = root.querySelector("[data-vb-puzzlegrid-board]");
      const status = root.querySelector("[data-vb-puzzlegrid-status]");
      const shuffle = root.querySelector("[data-vb-puzzlegrid-shuffle]");
      let active = null;
      let ghost = null;

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function orderValues() {
        return Array.from(board.querySelectorAll("[data-vb-puzzlegrid-tile]")).map(function (tile) {
          return tile.getAttribute("data-value");
        });
      }

      function checkSolved() {
        const solved = orderValues().join("") === "123456789";
        status.textContent = solved ? "Puzzle solved!" : "Not solved yet";
      }

      function createGhost(tile, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-puzzlegrid-ghost";
        ghost.textContent = tile.textContent;
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function clearOver() {
        board.querySelectorAll(".is-over").forEach(function (tile) {
          tile.classList.remove("is-over");
        });
      }

      function reorderAt(x, y) {
        const el = document.elementFromPoint(x, y);
        const target = el ? el.closest("[data-vb-puzzlegrid-tile]") : null;

        if (!target || target === active || !board.contains(target)) return;

        clearOver();
        target.classList.add("is-over");

        const allTiles = Array.from(board.querySelectorAll("[data-vb-puzzlegrid-tile]"));
        const activeIndex = allTiles.indexOf(active);
        const targetIndex = allTiles.indexOf(target);

        if (activeIndex < targetIndex) {
          target.insertAdjacentElement("afterend", active);
        } else {
          target.insertAdjacentElement("beforebegin", active);
        }

        checkSolved();
      }

      function start(event) {
        const tile = event.target.closest("[data-vb-puzzlegrid-tile]");
        if (!tile) return;

        event.preventDefault();

        const point = getPoint(event);
        active = tile;
        active.classList.add("is-dragging");
        createGhost(tile, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;

        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);
        reorderAt(point.x, point.y);
      }

      function end() {
        cleanup();
        checkSolved();
      }

      function cancel() {
        cleanup();
        checkSolved();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      shuffle.addEventListener("click", function () {
        const tiles = Array.from(board.querySelectorAll("[data-vb-puzzlegrid-tile]"));
        tiles.sort(function () {
          return Math.random() - 0.5;
        });
        tiles.forEach(function (tile) {
          board.appendChild(tile);
        });
        checkSolved();
      });

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      checkSolved();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initPuzzleGrid);
  } else {
    initPuzzleGrid();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initPuzzleGrid() {
    document.querySelectorAll("[data-vb-puzzlegrid]").forEach(function (root) {
      if (root.getAttribute("data-vb-puzzlegrid-ready") === "1") return;
      root.setAttribute("data-vb-puzzlegrid-ready", "1");

      const board = root.querySelector("[data-vb-puzzlegrid-board]");
      const status = root.querySelector("[data-vb-puzzlegrid-status]");
      const shuffle = root.querySelector("[data-vb-puzzlegrid-shuffle]");
      let active = null;
      let ghost = null;

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function orderValues() {
        return Array.from(board.querySelectorAll("[data-vb-puzzlegrid-tile]")).map(function (tile) {
          return tile.getAttribute("data-value");
        });
      }

      function checkSolved() {
        const solved = orderValues().join("") === "123456789";
        status.textContent = solved ? "Puzzle solved!" : "Not solved yet";
      }

      function createGhost(tile, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-puzzlegrid-ghost";
        ghost.textContent = tile.textContent;
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function clearOver() {
        board.querySelectorAll(".is-over").forEach(function (tile) {
          tile.classList.remove("is-over");
        });
      }

      function reorderAt(x, y) {
        const el = document.elementFromPoint(x, y);
        const target = el ? el.closest("[data-vb-puzzlegrid-tile]") : null;

        if (!target || target === active || !board.contains(target)) return;

        clearOver();
        target.classList.add("is-over");

        const allTiles = Array.from(board.querySelectorAll("[data-vb-puzzlegrid-tile]"));
        const activeIndex = allTiles.indexOf(active);
        const targetIndex = allTiles.indexOf(target);

        if (activeIndex &lt; targetIndex) {
          target.insertAdjacentElement("afterend", active);
        } else {
          target.insertAdjacentElement("beforebegin", active);
        }

        checkSolved();
      }

      function start(event) {
        const tile = event.target.closest("[data-vb-puzzlegrid-tile]");
        if (!tile) return;

        event.preventDefault();

        const point = getPoint(event);
        active = tile;
        active.classList.add("is-dragging");
        createGhost(tile, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;

        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);
        reorderAt(point.x, point.y);
      }

      function end() {
        cleanup();
        checkSolved();
      }

      function cancel() {
        cleanup();
        checkSolved();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      shuffle.addEventListener("click", function () {
        const tiles = Array.from(board.querySelectorAll("[data-vb-puzzlegrid-tile]"));
        tiles.sort(function () {
          return Math.random() - 0.5;
        });
        tiles.forEach(function (tile) {
          board.appendChild(tile);
        });
        checkSolved();
      });

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      checkSolved();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initPuzzleGrid);
  } else {
    initPuzzleGrid();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-puzzlegrid-demo"&gt;
  &lt;div class="vb-puzzlegrid-wrap" data-vb-puzzlegrid&gt;
    &lt;div class="vb-puzzlegrid-head"&gt;
      &lt;span&gt;Example 21&lt;/span&gt;
      &lt;h3&gt;Drag and Drop Puzzle Grid&lt;/h3&gt;
      &lt;p&gt;Reorder the tiles from 1 to 9. The status updates when the puzzle is solved.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-puzzlegrid-panel"&gt;
      &lt;div class="vb-puzzlegrid-board" data-vb-puzzlegrid-board&gt;
        &lt;button type="button" class="vb-puzzlegrid-tile" data-vb-puzzlegrid-tile data-value="5"&gt;5&lt;/button&gt;
        &lt;button type="button" class="vb-puzzlegrid-tile" data-vb-puzzlegrid-tile data-value="1"&gt;1&lt;/button&gt;
        &lt;button type="button" class="vb-puzzlegrid-tile" data-vb-puzzlegrid-tile data-value="8"&gt;8&lt;/button&gt;
        &lt;button type="button" class="vb-puzzlegrid-tile" data-vb-puzzlegrid-tile data-value="3"&gt;3&lt;/button&gt;
        &lt;button type="button" class="vb-puzzlegrid-tile" data-vb-puzzlegrid-tile data-value="7"&gt;7&lt;/button&gt;
        &lt;button type="button" class="vb-puzzlegrid-tile" data-vb-puzzlegrid-tile data-value="2"&gt;2&lt;/button&gt;
        &lt;button type="button" class="vb-puzzlegrid-tile" data-vb-puzzlegrid-tile data-value="9"&gt;9&lt;/button&gt;
        &lt;button type="button" class="vb-puzzlegrid-tile" data-vb-puzzlegrid-tile data-value="4"&gt;4&lt;/button&gt;
        &lt;button type="button" class="vb-puzzlegrid-tile" data-vb-puzzlegrid-tile data-value="6"&gt;6&lt;/button&gt;
      &lt;/div&gt;

      &lt;aside class="vb-puzzlegrid-side"&gt;
        &lt;span&gt;Puzzle Status&lt;/span&gt;
        &lt;strong data-vb-puzzlegrid-status&gt;Not solved yet&lt;/strong&gt;
        &lt;p&gt;Drag tiles until the order is 1, 2, 3, 4, 5, 6, 7, 8, 9.&lt;/p&gt;
        &lt;button type="button" data-vb-puzzlegrid-shuffle&gt;Shuffle tiles&lt;/button&gt;
      &lt;/aside&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-puzzlegrid-demo,
.vb-puzzlegrid-demo * {
  box-sizing: border-box;
}

.vb-puzzlegrid-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(14, 165, 233, 0.16), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(245, 158, 11, 0.18), transparent 34%),
    linear-gradient(135deg, #ecfeff 0%, #fffbeb 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-puzzlegrid-wrap {
  max-width: 1060px;
  margin: 0 auto;
}

.vb-puzzlegrid-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-puzzlegrid-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #cffafe;
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-puzzlegrid-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-puzzlegrid-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-puzzlegrid-panel {
  display: grid;
  grid-template-columns: minmax(280px, 0.85fr) minmax(260px, 0.65fr);
  gap: 16px;
  align-items: stretch;
}

.vb-puzzlegrid-board {
  display: grid;
  grid-template-columns: repeat(3, minmax(72px, 1fr));
  gap: 12px;
  padding: 18px;
  border-radius: 30px;
  background: #0f172a;
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.22);
}

.vb-puzzlegrid-tile {
  min-height: 112px;
  border: 0;
  border-radius: 22px;
  background:
    radial-gradient(circle at 25% 18%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #06b6d4, #2563eb) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 58px);
  line-height: 1;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.28), 0 12px 26px rgba(0,0,0,0.20);
}

.vb-puzzlegrid-tile:nth-child(2n) {
  background:
    radial-gradient(circle at 25% 18%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #f59e0b, #ec4899) !important;
}

.vb-puzzlegrid-tile.is-dragging {
  opacity: 0.45;
}

.vb-puzzlegrid-tile.is-over {
  outline: 4px solid rgba(255,255,255,0.38);
}

.vb-puzzlegrid-side {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 26px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 16% 16%, rgba(34, 211, 238, 0.22), transparent 36%),
    linear-gradient(135deg, #164e63, #0f172a) !important;
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.20);
}

.vb-puzzlegrid-side span {
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-puzzlegrid-side strong {
  margin: 12px 0;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(26px, 4vw, 42px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-puzzlegrid-side p {
  margin: 0 0 18px !important;
  color: #cffafe !important;
  -webkit-text-fill-color: #cffafe !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-puzzlegrid-side button {
  min-height: 46px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-puzzlegrid-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: 92px;
  height: 92px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 22px;
  background: linear-gradient(135deg, #06b6d4, #2563eb) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 42px;
  font-weight: 950;
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.30);
}

@media (max-width: 820px) {
  .vb-puzzlegrid-panel {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 480px) {
  .vb-puzzlegrid-board {
    gap: 8px;
    padding: 12px;
  }

  .vb-puzzlegrid-tile {
    min-height: 82px;
    border-radius: 18px;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript drag and drop puzzle grid is useful for educational games, onboarding tasks, visual learning tools, gamified UI demos, interactive tutorials, and puzzle-based web components.</p>



<h2 class="wp-block-heading">22. Drag and Drop Seat Booking Layout</h2>



<p class="wp-block-paragraph"><strong>A drag and drop seat booking layout</strong> lets users drag people into available seats. This pattern is useful for event booking pages, meeting room planners, classroom layouts, cinema booking prototypes, restaurant seating tools, and conference dashboards.</p>



<ul class="wp-block-list">
<li>Drag guests into seat slots</li>
<li>Prevents duplicate seat assignments</li>
<li>Mouse and touch support</li>
<li>Live assigned seat count</li>
<li>Responsive seating layout</li>
</ul>



<div class="vb-seatbook-demo">
  <div class="vb-seatbook-wrap" data-vb-seatbook>
    <div class="vb-seatbook-head">
      <span>Example 22</span>
      <h3>Seat Booking Layout</h3>
      <p>Drag each guest into an empty seat. The seat keeps the assigned name and updates the counter.</p>
    </div>

    <div class="vb-seatbook-layout">
      <section class="vb-seatbook-guests">
        <h4>Guests</h4>

        <article class="vb-seatbook-guest" data-vb-seatbook-guest data-id="anna" data-name="Anna">
          <button type="button" data-vb-seatbook-handle>⋮⋮</button>
          <span>AN</span>
          <strong>Anna</strong>
        </article>

        <article class="vb-seatbook-guest" data-vb-seatbook-guest data-id="mark" data-name="Mark">
          <button type="button" data-vb-seatbook-handle>⋮⋮</button>
          <span>MK</span>
          <strong>Mark</strong>
        </article>

        <article class="vb-seatbook-guest" data-vb-seatbook-guest data-id="lisa" data-name="Lisa">
          <button type="button" data-vb-seatbook-handle>⋮⋮</button>
          <span>LS</span>
          <strong>Lisa</strong>
        </article>

        <article class="vb-seatbook-guest" data-vb-seatbook-guest data-id="tom" data-name="Tom">
          <button type="button" data-vb-seatbook-handle>⋮⋮</button>
          <span>TM</span>
          <strong>Tom</strong>
        </article>
      </section>

      <section class="vb-seatbook-map">
        <div class="vb-seatbook-stage">Stage</div>

        <div class="vb-seatbook-seats">
          <button type="button" class="vb-seatbook-seat" data-vb-seatbook-seat data-seat="A1"><span>A1</span><strong>Empty</strong></button>
          <button type="button" class="vb-seatbook-seat" data-vb-seatbook-seat data-seat="A2"><span>A2</span><strong>Empty</strong></button>
          <button type="button" class="vb-seatbook-seat" data-vb-seatbook-seat data-seat="A3"><span>A3</span><strong>Empty</strong></button>
          <button type="button" class="vb-seatbook-seat" data-vb-seatbook-seat data-seat="B1"><span>B1</span><strong>Empty</strong></button>
          <button type="button" class="vb-seatbook-seat" data-vb-seatbook-seat data-seat="B2"><span>B2</span><strong>Empty</strong></button>
          <button type="button" class="vb-seatbook-seat" data-vb-seatbook-seat data-seat="B3"><span>B3</span><strong>Empty</strong></button>
        </div>

        <div class="vb-seatbook-summary">
          <span>Assigned seats</span>
          <strong data-vb-seatbook-count>0 / 6</strong>
        </div>
      </section>
    </div>

    <div class="vb-seatbook-status" data-vb-seatbook-status>Drag a guest into an empty seat.</div>
  </div>
</div>

<style>
.vb-seatbook-demo,
.vb-seatbook-demo * {
  box-sizing: border-box;
}

.vb-seatbook-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(99, 102, 241, 0.16), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #ecfeff 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-seatbook-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-seatbook-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-seatbook-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #e0e7ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-seatbook-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-seatbook-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-seatbook-layout {
  display: grid;
  grid-template-columns: minmax(240px, 0.36fr) minmax(0, 1fr);
  gap: 16px;
}

.vb-seatbook-guests,
.vb-seatbook-map {
  padding: 16px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-seatbook-guests {
  display: grid;
  align-content: start;
  gap: 12px;
}

.vb-seatbook-guests h4 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 22px !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-seatbook-guest {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  padding: 12px;
  border-radius: 18px;
  background: #eef2ff;
  border: 1px solid rgba(99, 102, 241, 0.20);
}

.vb-seatbook-guest.is-dragging {
  opacity: 0.45;
}

.vb-seatbook-guest button {
  width: 34px;
  height: 40px;
  border: 0;
  border-radius: 13px;
  background: #4338ca;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
}

.vb-seatbook-guest span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: linear-gradient(135deg, #4f46e5, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-seatbook-guest strong {
  color: #312e81 !important;
  -webkit-text-fill-color: #312e81 !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-seatbook-map {
  background:
    linear-gradient(180deg, #ffffff, #f8fafc) !important;
}

.vb-seatbook-stage {
  margin-bottom: 18px;
  padding: 16px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-align: center;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.vb-seatbook-seats {
  display: grid;
  grid-template-columns: repeat(3, minmax(120px, 1fr));
  gap: 14px;
}

.vb-seatbook-seat {
  min-height: 120px;
  padding: 16px;
  border: 1px dashed rgba(99, 102, 241, 0.38);
  border-radius: 24px;
  background: #eef2ff;
  cursor: default;
}

.vb-seatbook-seat.is-over {
  border-color: rgba(99, 102, 241, 0.95);
  background: #e0e7ff;
  box-shadow: inset 0 0 0 4px rgba(99, 102, 241, 0.12);
}

.vb-seatbook-seat.is-filled {
  border-style: solid;
  background: linear-gradient(135deg, #312e81, #0369a1) !important;
}

.vb-seatbook-seat span {
  display: block;
  margin-bottom: 8px;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-seatbook-seat strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-seatbook-seat.is-filled span,
.vb-seatbook-seat.is-filled strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-seatbook-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-top: 16px;
  padding: 14px 16px;
  border-radius: 20px;
  background: #0f172a;
}

.vb-seatbook-summary span,
.vb-seatbook-summary strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-seatbook-status {
  margin-top: 16px;
  padding: 13px 15px;
  border-radius: 18px;
  background: #312e81;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-seatbook-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(220px, calc(100vw - 32px));
  padding: 13px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(99, 102, 241, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
}

.vb-seatbook-ghost strong {
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-seatbook-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-seatbook-seats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
</style>

<script>
(function () {
  function initSeatBook() {
    document.querySelectorAll("[data-vb-seatbook]").forEach(function (root) {
      if (root.getAttribute("data-vb-seatbook-ready") === "1") return;
      root.setAttribute("data-vb-seatbook-ready", "1");

      const seats = Array.from(root.querySelectorAll("[data-vb-seatbook-seat]"));
      const count = root.querySelector("[data-vb-seatbook-count]");
      const status = root.querySelector("[data-vb-seatbook-status]");

      let active = null;
      let ghost = null;
      let assigned = {};

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function getSeatAt(x, y) {
        const el = document.elementFromPoint(x, y);
        if (!el) return null;
        const seat = el.closest("[data-vb-seatbook-seat]");
        return seats.includes(seat) ? seat : null;
      }

      function updateCount() {
        count.textContent = Object.keys(assigned).length + " / " + seats.length;
      }

      function clearOver() {
        seats.forEach(function (seat) {
          seat.classList.remove("is-over");
        });
      }

      function createGhost(guest, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-seatbook-ghost";
        ghost.innerHTML = "<strong>" + guest.getAttribute("data-name") + "</strong>";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-seatbook-handle]");
        if (!handle) return;

        const guest = handle.closest("[data-vb-seatbook-guest]");
        if (!guest) return;

        event.preventDefault();

        const point = getPoint(event);
        active = guest;
        active.classList.add("is-dragging");
        createGhost(guest, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;
        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);
        clearOver();

        const seat = getSeatAt(point.x, point.y);
        if (seat && !seat.classList.contains("is-filled")) {
          seat.classList.add("is-over");
        }
      }

      function end(event) {
        if (!active) return;

        const point = getPoint(event);
        const seat = getSeatAt(point.x, point.y);

        if (seat && !seat.classList.contains("is-filled")) {
          const guestId = active.getAttribute("data-id");
          const guestName = active.getAttribute("data-name");

          if (assigned[guestId]) {
            status.textContent = guestName + " already has a seat.";
          } else {
            assigned[guestId] = seat.getAttribute("data-seat");
            seat.classList.add("is-filled");
            seat.querySelector("strong").textContent = guestName;
            active.style.display = "none";
            status.textContent = guestName + " assigned to seat " + seat.getAttribute("data-seat") + ".";
            updateCount();
          }
        }

        cleanup();
      }

      function cancel() {
        cleanup();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateCount();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initSeatBook);
  } else {
    initSeatBook();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initSeatBook() {
    document.querySelectorAll("[data-vb-seatbook]").forEach(function (root) {
      if (root.getAttribute("data-vb-seatbook-ready") === "1") return;
      root.setAttribute("data-vb-seatbook-ready", "1");

      const seats = Array.from(root.querySelectorAll("[data-vb-seatbook-seat]"));
      const count = root.querySelector("[data-vb-seatbook-count]");
      const status = root.querySelector("[data-vb-seatbook-status]");

      let active = null;
      let ghost = null;
      let assigned = {};

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function getSeatAt(x, y) {
        const el = document.elementFromPoint(x, y);
        if (!el) return null;
        const seat = el.closest("[data-vb-seatbook-seat]");
        return seats.includes(seat) ? seat : null;
      }

      function updateCount() {
        count.textContent = Object.keys(assigned).length + " / " + seats.length;
      }

      function clearOver() {
        seats.forEach(function (seat) {
          seat.classList.remove("is-over");
        });
      }

      function createGhost(guest, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-seatbook-ghost";
        ghost.innerHTML = "&lt;strong&gt;" + guest.getAttribute("data-name") + "&lt;/strong&gt;";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-seatbook-handle]");
        if (!handle) return;

        const guest = handle.closest("[data-vb-seatbook-guest]");
        if (!guest) return;

        event.preventDefault();

        const point = getPoint(event);
        active = guest;
        active.classList.add("is-dragging");
        createGhost(guest, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;
        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);
        clearOver();

        const seat = getSeatAt(point.x, point.y);
        if (seat &amp;&amp; !seat.classList.contains("is-filled")) {
          seat.classList.add("is-over");
        }
      }

      function end(event) {
        if (!active) return;

        const point = getPoint(event);
        const seat = getSeatAt(point.x, point.y);

        if (seat &amp;&amp; !seat.classList.contains("is-filled")) {
          const guestId = active.getAttribute("data-id");
          const guestName = active.getAttribute("data-name");

          if (assigned[guestId]) {
            status.textContent = guestName + " already has a seat.";
          } else {
            assigned[guestId] = seat.getAttribute("data-seat");
            seat.classList.add("is-filled");
            seat.querySelector("strong").textContent = guestName;
            active.style.display = "none";
            status.textContent = guestName + " assigned to seat " + seat.getAttribute("data-seat") + ".";
            updateCount();
          }
        }

        cleanup();
      }

      function cancel() {
        cleanup();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateCount();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initSeatBook);
  } else {
    initSeatBook();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-seatbook-demo"&gt;
  &lt;div class="vb-seatbook-wrap" data-vb-seatbook&gt;
    &lt;div class="vb-seatbook-head"&gt;
      &lt;span&gt;Example 22&lt;/span&gt;
      &lt;h3&gt;Seat Booking Layout&lt;/h3&gt;
      &lt;p&gt;Drag each guest into an empty seat. The seat keeps the assigned name and updates the counter.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-seatbook-layout"&gt;
      &lt;section class="vb-seatbook-guests"&gt;
        &lt;h4&gt;Guests&lt;/h4&gt;

        &lt;article class="vb-seatbook-guest" data-vb-seatbook-guest data-id="anna" data-name="Anna"&gt;
          &lt;button type="button" data-vb-seatbook-handle&gt;⋮⋮&lt;/button&gt;
          &lt;span&gt;AN&lt;/span&gt;
          &lt;strong&gt;Anna&lt;/strong&gt;
        &lt;/article&gt;

        &lt;article class="vb-seatbook-guest" data-vb-seatbook-guest data-id="mark" data-name="Mark"&gt;
          &lt;button type="button" data-vb-seatbook-handle&gt;⋮⋮&lt;/button&gt;
          &lt;span&gt;MK&lt;/span&gt;
          &lt;strong&gt;Mark&lt;/strong&gt;
        &lt;/article&gt;

        &lt;article class="vb-seatbook-guest" data-vb-seatbook-guest data-id="lisa" data-name="Lisa"&gt;
          &lt;button type="button" data-vb-seatbook-handle&gt;⋮⋮&lt;/button&gt;
          &lt;span&gt;LS&lt;/span&gt;
          &lt;strong&gt;Lisa&lt;/strong&gt;
        &lt;/article&gt;

        &lt;article class="vb-seatbook-guest" data-vb-seatbook-guest data-id="tom" data-name="Tom"&gt;
          &lt;button type="button" data-vb-seatbook-handle&gt;⋮⋮&lt;/button&gt;
          &lt;span&gt;TM&lt;/span&gt;
          &lt;strong&gt;Tom&lt;/strong&gt;
        &lt;/article&gt;
      &lt;/section&gt;

      &lt;section class="vb-seatbook-map"&gt;
        &lt;div class="vb-seatbook-stage"&gt;Stage&lt;/div&gt;

        &lt;div class="vb-seatbook-seats"&gt;
          &lt;button type="button" class="vb-seatbook-seat" data-vb-seatbook-seat data-seat="A1"&gt;&lt;span&gt;A1&lt;/span&gt;&lt;strong&gt;Empty&lt;/strong&gt;&lt;/button&gt;
          &lt;button type="button" class="vb-seatbook-seat" data-vb-seatbook-seat data-seat="A2"&gt;&lt;span&gt;A2&lt;/span&gt;&lt;strong&gt;Empty&lt;/strong&gt;&lt;/button&gt;
          &lt;button type="button" class="vb-seatbook-seat" data-vb-seatbook-seat data-seat="A3"&gt;&lt;span&gt;A3&lt;/span&gt;&lt;strong&gt;Empty&lt;/strong&gt;&lt;/button&gt;
          &lt;button type="button" class="vb-seatbook-seat" data-vb-seatbook-seat data-seat="B1"&gt;&lt;span&gt;B1&lt;/span&gt;&lt;strong&gt;Empty&lt;/strong&gt;&lt;/button&gt;
          &lt;button type="button" class="vb-seatbook-seat" data-vb-seatbook-seat data-seat="B2"&gt;&lt;span&gt;B2&lt;/span&gt;&lt;strong&gt;Empty&lt;/strong&gt;&lt;/button&gt;
          &lt;button type="button" class="vb-seatbook-seat" data-vb-seatbook-seat data-seat="B3"&gt;&lt;span&gt;B3&lt;/span&gt;&lt;strong&gt;Empty&lt;/strong&gt;&lt;/button&gt;
        &lt;/div&gt;

        &lt;div class="vb-seatbook-summary"&gt;
          &lt;span&gt;Assigned seats&lt;/span&gt;
          &lt;strong data-vb-seatbook-count&gt;0 / 6&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;

    &lt;div class="vb-seatbook-status" data-vb-seatbook-status&gt;Drag a guest into an empty seat.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">/* CSS is included fully in the live demo block above. */</pre>



<p class="wp-block-paragraph">This JavaScript drag and drop seat booking layout is useful for event seating, classroom tools, restaurant layouts, cinema booking demos, meeting room planners, and conference dashboards.</p>



<h2 class="wp-block-heading">23. Drag and Drop Timeline Builder</h2>



<p class="wp-block-paragraph"><strong>A drag and drop timeline builder</strong> lets users reorder project milestones visually. This pattern is useful for project roadmaps, product launch timelines, event planning, content calendars, onboarding steps, and workflow builders.</p>



<ul class="wp-block-list">
<li>Reorder timeline milestones</li>
<li>Automatic step numbering</li>
<li>Live next milestone preview</li>
<li>Mouse and touch support</li>
<li>Vertical responsive timeline layout</li>
</ul>



<div class="vb-timelinebuild-demo">
  <div class="vb-timelinebuild-wrap" data-vb-timelinebuild>
    <div class="vb-timelinebuild-head">
      <span>Example 23</span>
      <h3>Timeline Builder</h3>
      <p>Drag milestones up or down to change the project timeline order.</p>
    </div>

    <div class="vb-timelinebuild-layout">
      <section class="vb-timelinebuild-list" data-vb-timelinebuild-list>
        <article class="vb-timelinebuild-item" data-vb-timelinebuild-item data-title="Research">
          <button type="button" data-vb-timelinebuild-handle>⋮⋮</button>
          <span data-vb-timelinebuild-number>1</span>
          <div>
            <h4>Research</h4>
            <p>Collect requirements and define project scope.</p>
          </div>
        </article>

        <article class="vb-timelinebuild-item" data-vb-timelinebuild-item data-title="Wireframes">
          <button type="button" data-vb-timelinebuild-handle>⋮⋮</button>
          <span data-vb-timelinebuild-number>2</span>
          <div>
            <h4>Wireframes</h4>
            <p>Create low-fidelity layouts and user flows.</p>
          </div>
        </article>

        <article class="vb-timelinebuild-item" data-vb-timelinebuild-item data-title="Development">
          <button type="button" data-vb-timelinebuild-handle>⋮⋮</button>
          <span data-vb-timelinebuild-number>3</span>
          <div>
            <h4>Development</h4>
            <p>Build the frontend, backend, and integrations.</p>
          </div>
        </article>

        <article class="vb-timelinebuild-item" data-vb-timelinebuild-item data-title="Launch">
          <button type="button" data-vb-timelinebuild-handle>⋮⋮</button>
          <span data-vb-timelinebuild-number>4</span>
          <div>
            <h4>Launch</h4>
            <p>Publish the final website or product release.</p>
          </div>
        </article>
      </section>

      <aside class="vb-timelinebuild-side">
        <span>Next milestone</span>
        <strong data-vb-timelinebuild-next>Research</strong>
        <p>The first milestone is treated as the next active step.</p>
      </aside>
    </div>
  </div>
</div>

<style>
.vb-timelinebuild-demo,
.vb-timelinebuild-demo * {
  box-sizing: border-box;
}

.vb-timelinebuild-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(245, 158, 11, 0.16), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(239, 68, 68, 0.13), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fff1f2 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-timelinebuild-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-timelinebuild-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-timelinebuild-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-timelinebuild-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-timelinebuild-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-timelinebuild-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 0.6fr);
  gap: 16px;
  align-items: stretch;
}

.vb-timelinebuild-list {
  position: relative;
  display: grid;
  gap: 14px;
  padding: 16px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-timelinebuild-item {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr);
  gap: 14px;
  align-items: center;
  padding: 15px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 12px 30px rgba(15, 23, 42, 0.06);
}

.vb-timelinebuild-item.is-dragging {
  opacity: 0.45;
}

.vb-timelinebuild-item.is-over {
  border-color: rgba(245, 158, 11, 0.82);
  background: #fffbeb;
}

.vb-timelinebuild-item button {
  width: 38px;
  height: 44px;
  border: 0;
  border-radius: 14px;
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 20px;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
}

.vb-timelinebuild-item > span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-timelinebuild-item h4 {
  margin: 0 0 5px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 17px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
}

.vb-timelinebuild-item p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.5;
  font-weight: 700;
}

.vb-timelinebuild-side {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 26px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 16% 16%, rgba(251, 191, 36, 0.22), transparent 36%),
    linear-gradient(135deg, #78350f, #0f172a) !important;
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.20);
}

.vb-timelinebuild-side span {
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-timelinebuild-side strong {
  margin: 12px 0;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4vw, 44px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-timelinebuild-side p {
  margin: 0 !important;
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-timelinebuild-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(320px, calc(100vw - 32px));
  padding: 13px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(245, 158, 11, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
}

.vb-timelinebuild-ghost strong {
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-timelinebuild-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-timelinebuild-item {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .vb-timelinebuild-item > span {
    display: none;
  }
}
</style>

<script>
(function () {
  function initTimelineBuilder() {
    document.querySelectorAll("[data-vb-timelinebuild]").forEach(function (root) {
      if (root.getAttribute("data-vb-timelinebuild-ready") === "1") return;
      root.setAttribute("data-vb-timelinebuild-ready", "1");

      const list = root.querySelector("[data-vb-timelinebuild-list]");
      const next = root.querySelector("[data-vb-timelinebuild-next]");
      let active = null;
      let ghost = null;

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function updateTimeline() {
        const items = Array.from(list.querySelectorAll("[data-vb-timelinebuild-item]"));

        items.forEach(function (item, index) {
          const number = item.querySelector("[data-vb-timelinebuild-number]");
          if (number) number.textContent = index + 1;
        });

        if (items[0]) {
          next.textContent = items[0].getAttribute("data-title");
        }
      }

      function createGhost(item, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-timelinebuild-ghost";
        ghost.innerHTML = "<strong>" + item.getAttribute("data-title") + "</strong>";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function clearOver() {
        list.querySelectorAll(".is-over").forEach(function (item) {
          item.classList.remove("is-over");
        });
      }

      function reorderAt(x, y) {
        const el = document.elementFromPoint(x, y);
        const target = el ? el.closest("[data-vb-timelinebuild-item]") : null;

        if (!target || target === active || !list.contains(target)) return;

        const rect = target.getBoundingClientRect();
        const after = y > rect.top + rect.height / 2;

        clearOver();
        target.classList.add("is-over");

        if (after) {
          target.insertAdjacentElement("afterend", active);
        } else {
          target.insertAdjacentElement("beforebegin", active);
        }

        updateTimeline();
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-timelinebuild-handle]");
        if (!handle) return;

        const item = handle.closest("[data-vb-timelinebuild-item]");
        if (!item) return;

        event.preventDefault();

        const point = getPoint(event);
        active = item;
        active.classList.add("is-dragging");
        createGhost(item, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;

        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);
        reorderAt(point.x, point.y);
      }

      function end() {
        cleanup();
        updateTimeline();
      }

      function cancel() {
        cleanup();
        updateTimeline();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateTimeline();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initTimelineBuilder);
  } else {
    initTimelineBuilder();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initTimelineBuilder() {
    document.querySelectorAll("[data-vb-timelinebuild]").forEach(function (root) {
      if (root.getAttribute("data-vb-timelinebuild-ready") === "1") return;
      root.setAttribute("data-vb-timelinebuild-ready", "1");

      const list = root.querySelector("[data-vb-timelinebuild-list]");
      const next = root.querySelector("[data-vb-timelinebuild-next]");
      let active = null;
      let ghost = null;

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function updateTimeline() {
        const items = Array.from(list.querySelectorAll("[data-vb-timelinebuild-item]"));

        items.forEach(function (item, index) {
          const number = item.querySelector("[data-vb-timelinebuild-number]");
          if (number) number.textContent = index + 1;
        });

        if (items[0]) {
          next.textContent = items[0].getAttribute("data-title");
        }
      }

      function createGhost(item, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-timelinebuild-ghost";
        ghost.innerHTML = "&lt;strong&gt;" + item.getAttribute("data-title") + "&lt;/strong&gt;";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function clearOver() {
        list.querySelectorAll(".is-over").forEach(function (item) {
          item.classList.remove("is-over");
        });
      }

      function reorderAt(x, y) {
        const el = document.elementFromPoint(x, y);
        const target = el ? el.closest("[data-vb-timelinebuild-item]") : null;

        if (!target || target === active || !list.contains(target)) return;

        const rect = target.getBoundingClientRect();
        const after = y &gt; rect.top + rect.height / 2;

        clearOver();
        target.classList.add("is-over");

        if (after) {
          target.insertAdjacentElement("afterend", active);
        } else {
          target.insertAdjacentElement("beforebegin", active);
        }

        updateTimeline();
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-timelinebuild-handle]");
        if (!handle) return;

        const item = handle.closest("[data-vb-timelinebuild-item]");
        if (!item) return;

        event.preventDefault();

        const point = getPoint(event);
        active = item;
        active.classList.add("is-dragging");
        createGhost(item, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;

        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);
        reorderAt(point.x, point.y);
      }

      function end() {
        cleanup();
        updateTimeline();
      }

      function cancel() {
        cleanup();
        updateTimeline();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateTimeline();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initTimelineBuilder);
  } else {
    initTimelineBuilder();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-timelinebuild-demo"&gt;
  &lt;div class="vb-timelinebuild-wrap" data-vb-timelinebuild&gt;
    &lt;div class="vb-timelinebuild-head"&gt;
      &lt;span&gt;Example 23&lt;/span&gt;
      &lt;h3&gt;Timeline Builder&lt;/h3&gt;
      &lt;p&gt;Drag milestones up or down to change the project timeline order.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-timelinebuild-layout"&gt;
      &lt;section class="vb-timelinebuild-list" data-vb-timelinebuild-list&gt;
        &lt;article class="vb-timelinebuild-item" data-vb-timelinebuild-item data-title="Research"&gt;
          &lt;button type="button" data-vb-timelinebuild-handle&gt;⋮⋮&lt;/button&gt;
          &lt;span data-vb-timelinebuild-number&gt;1&lt;/span&gt;
          &lt;div&gt;&lt;h4&gt;Research&lt;/h4&gt;&lt;p&gt;Collect requirements and define project scope.&lt;/p&gt;&lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-timelinebuild-item" data-vb-timelinebuild-item data-title="Wireframes"&gt;
          &lt;button type="button" data-vb-timelinebuild-handle&gt;⋮⋮&lt;/button&gt;
          &lt;span data-vb-timelinebuild-number&gt;2&lt;/span&gt;
          &lt;div&gt;&lt;h4&gt;Wireframes&lt;/h4&gt;&lt;p&gt;Create low-fidelity layouts and user flows.&lt;/p&gt;&lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-timelinebuild-item" data-vb-timelinebuild-item data-title="Development"&gt;
          &lt;button type="button" data-vb-timelinebuild-handle&gt;⋮⋮&lt;/button&gt;
          &lt;span data-vb-timelinebuild-number&gt;3&lt;/span&gt;
          &lt;div&gt;&lt;h4&gt;Development&lt;/h4&gt;&lt;p&gt;Build the frontend, backend, and integrations.&lt;/p&gt;&lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-timelinebuild-item" data-vb-timelinebuild-item data-title="Launch"&gt;
          &lt;button type="button" data-vb-timelinebuild-handle&gt;⋮⋮&lt;/button&gt;
          &lt;span data-vb-timelinebuild-number&gt;4&lt;/span&gt;
          &lt;div&gt;&lt;h4&gt;Launch&lt;/h4&gt;&lt;p&gt;Publish the final website or product release.&lt;/p&gt;&lt;/div&gt;
        &lt;/article&gt;
      &lt;/section&gt;

      &lt;aside class="vb-timelinebuild-side"&gt;
        &lt;span&gt;Next milestone&lt;/span&gt;
        &lt;strong data-vb-timelinebuild-next&gt;Research&lt;/strong&gt;
        &lt;p&gt;The first milestone is treated as the next active step.&lt;/p&gt;
      &lt;/aside&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">/* CSS is included fully in the live demo block above. */</pre>



<p class="wp-block-paragraph">This JavaScript drag and drop timeline builder is useful for project roadmaps, launch timelines, content calendars, onboarding flows, event schedules, and workflow planning tools.</p>



<h2 class="wp-block-heading">24. Drag and Drop Tag Organizer</h2>



<p class="wp-block-paragraph"><strong>A drag and drop tag organizer</strong> lets users sort tags into different groups. This pattern is useful for blog admin panels, CRM filters, product attributes, content categorization tools, preference builders, and dashboard filtering interfaces.</p>



<ul class="wp-block-list">
<li>Drag tags into category groups</li>
<li>Live group counters</li>
<li>Compact tag-style design</li>
<li>Mouse and touch support</li>
<li>Useful for content and filter UIs</li>
</ul>



<div class="vb-tagorg-demo">
  <div class="vb-tagorg-wrap" data-vb-tagorg>
    <div class="vb-tagorg-head">
      <span>Example 24</span>
      <h3>Tag Organizer</h3>
      <p>Drag tags into topic groups. This is a compact pattern for filters, labels, categories, and admin tools.</p>
    </div>

    <div class="vb-tagorg-layout">
      <section class="vb-tagorg-pool">
        <div class="vb-tagorg-title">
          <h4>Available Tags</h4>
          <strong data-vb-tagorg-count="pool">0</strong>
        </div>

        <div class="vb-tagorg-drop" data-vb-tagorg-drop data-zone="pool">
          <button type="button" class="vb-tagorg-tag" data-vb-tagorg-tag data-label="JavaScript">JavaScript</button>
          <button type="button" class="vb-tagorg-tag" data-vb-tagorg-tag data-label="CSS">CSS</button>
          <button type="button" class="vb-tagorg-tag" data-vb-tagorg-tag data-label="SEO">SEO</button>
          <button type="button" class="vb-tagorg-tag" data-vb-tagorg-tag data-label="WordPress">WordPress</button>
          <button type="button" class="vb-tagorg-tag" data-vb-tagorg-tag data-label="Forms">Forms</button>
          <button type="button" class="vb-tagorg-tag" data-vb-tagorg-tag data-label="Ecommerce">Ecommerce</button>
        </div>
      </section>

      <section class="vb-tagorg-groups">
        <div class="vb-tagorg-group">
          <div class="vb-tagorg-title">
            <h4>Development</h4>
            <strong data-vb-tagorg-count="development">0</strong>
          </div>
          <div class="vb-tagorg-drop" data-vb-tagorg-drop data-zone="development"></div>
        </div>

        <div class="vb-tagorg-group">
          <div class="vb-tagorg-title">
            <h4>Marketing</h4>
            <strong data-vb-tagorg-count="marketing">0</strong>
          </div>
          <div class="vb-tagorg-drop" data-vb-tagorg-drop data-zone="marketing"></div>
        </div>
      </section>
    </div>

    <div class="vb-tagorg-status" data-vb-tagorg-status>Drag tags into groups.</div>
  </div>
</div>

<style>
.vb-tagorg-demo,
.vb-tagorg-demo * {
  box-sizing: border-box;
}

.vb-tagorg-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(20, 184, 166, 0.16), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdfa 0%, #f0fdf4 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-tagorg-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-tagorg-head {
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-tagorg-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-tagorg-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-tagorg-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-tagorg-layout {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 16px;
}

.vb-tagorg-pool,
.vb-tagorg-group {
  padding: 16px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-tagorg-groups {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
}

.vb-tagorg-title {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: center;
  margin-bottom: 14px;
}

.vb-tagorg-title h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-tagorg-title strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 38px;
  height: 34px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-tagorg-drop {
  display: flex;
  flex-wrap: wrap;
  align-content: flex-start;
  gap: 10px;
  min-height: 250px;
  padding: 12px;
  border-radius: 22px;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  background: #f8fafc;
}

.vb-tagorg-drop.is-over {
  border-color: rgba(20, 184, 166, 0.86);
  background: #f0fdfa;
  box-shadow: inset 0 0 0 4px rgba(20, 184, 166, 0.10);
}

.vb-tagorg-tag {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  padding: 9px 13px;
  border: 0;
  border-radius: 999px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 13px;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
  box-shadow: 0 8px 18px rgba(15, 23, 42, 0.06);
}

.vb-tagorg-tag:nth-child(2n) {
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
}

.vb-tagorg-tag.is-dragging {
  opacity: 0.45;
}

.vb-tagorg-status {
  margin-top: 16px;
  padding: 13px 15px;
  border-radius: 18px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-tagorg-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  padding: 11px 15px;
  border-radius: 999px;
  background: #ffffff;
  border: 1px solid rgba(20, 184, 166, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.24);
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-tagorg-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-tagorg-groups {
    grid-template-columns: 1fr;
  }

  .vb-tagorg-drop {
    min-height: 160px;
  }
}
</style>

<script>
(function () {
  function initTagOrganizer() {
    document.querySelectorAll("[data-vb-tagorg]").forEach(function (root) {
      if (root.getAttribute("data-vb-tagorg-ready") === "1") return;
      root.setAttribute("data-vb-tagorg-ready", "1");

      const drops = Array.from(root.querySelectorAll("[data-vb-tagorg-drop]"));
      const status = root.querySelector("[data-vb-tagorg-status]");

      let active = null;
      let ghost = null;

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function updateCounts() {
        drops.forEach(function (drop) {
          const zone = drop.getAttribute("data-zone");
          const count = root.querySelector('[data-vb-tagorg-count="' + zone + '"]');
          if (count) count.textContent = drop.querySelectorAll("[data-vb-tagorg-tag]").length;
        });
      }

      function getDropAt(x, y) {
        const el = document.elementFromPoint(x, y);
        if (!el) return null;
        const drop = el.closest("[data-vb-tagorg-drop]");
        return drops.includes(drop) ? drop : null;
      }

      function clearOver() {
        drops.forEach(function (drop) {
          drop.classList.remove("is-over");
        });
      }

      function createGhost(tag, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-tagorg-ghost";
        ghost.textContent = tag.getAttribute("data-label");
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function start(event) {
        const tag = event.target.closest("[data-vb-tagorg-tag]");
        if (!tag) return;

        event.preventDefault();

        const point = getPoint(event);
        active = tag;
        active.classList.add("is-dragging");
        createGhost(tag, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;

        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);
        clearOver();

        const drop = getDropAt(point.x, point.y);
        if (drop) drop.classList.add("is-over");
      }

      function end(event) {
        if (!active) return;

        const point = getPoint(event);
        const drop = getDropAt(point.x, point.y);

        if (drop) {
          drop.appendChild(active);
          status.textContent = active.getAttribute("data-label") + " moved to " + drop.getAttribute("data-zone") + ".";
        }

        cleanup();
        updateCounts();
      }

      function cancel() {
        cleanup();
        updateCounts();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateCounts();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initTagOrganizer);
  } else {
    initTagOrganizer();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initTagOrganizer() {
    document.querySelectorAll("[data-vb-tagorg]").forEach(function (root) {
      if (root.getAttribute("data-vb-tagorg-ready") === "1") return;
      root.setAttribute("data-vb-tagorg-ready", "1");

      const drops = Array.from(root.querySelectorAll("[data-vb-tagorg-drop]"));
      const status = root.querySelector("[data-vb-tagorg-status]");

      let active = null;
      let ghost = null;

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function updateCounts() {
        drops.forEach(function (drop) {
          const zone = drop.getAttribute("data-zone");
          const count = root.querySelector('[data-vb-tagorg-count="' + zone + '"]');
          if (count) count.textContent = drop.querySelectorAll("[data-vb-tagorg-tag]").length;
        });
      }

      function getDropAt(x, y) {
        const el = document.elementFromPoint(x, y);
        if (!el) return null;
        const drop = el.closest("[data-vb-tagorg-drop]");
        return drops.includes(drop) ? drop : null;
      }

      function clearOver() {
        drops.forEach(function (drop) {
          drop.classList.remove("is-over");
        });
      }

      function createGhost(tag, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-tagorg-ghost";
        ghost.textContent = tag.getAttribute("data-label");
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 14 + "px";
        ghost.style.top = y + 14 + "px";
      }

      function start(event) {
        const tag = event.target.closest("[data-vb-tagorg-tag]");
        if (!tag) return;

        event.preventDefault();

        const point = getPoint(event);
        active = tag;
        active.classList.add("is-dragging");
        createGhost(tag, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;

        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);
        clearOver();

        const drop = getDropAt(point.x, point.y);
        if (drop) drop.classList.add("is-over");
      }

      function end(event) {
        if (!active) return;

        const point = getPoint(event);
        const drop = getDropAt(point.x, point.y);

        if (drop) {
          drop.appendChild(active);
          status.textContent = active.getAttribute("data-label") + " moved to " + drop.getAttribute("data-zone") + ".";
        }

        cleanup();
        updateCounts();
      }

      function cancel() {
        cleanup();
        updateCounts();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateCounts();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initTagOrganizer);
  } else {
    initTagOrganizer();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-tagorg-demo"&gt;
  &lt;div class="vb-tagorg-wrap" data-vb-tagorg&gt;
    &lt;div class="vb-tagorg-head"&gt;
      &lt;span&gt;Example 24&lt;/span&gt;
      &lt;h3&gt;Tag Organizer&lt;/h3&gt;
      &lt;p&gt;Drag tags into topic groups. This is a compact pattern for filters, labels, categories, and admin tools.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-tagorg-layout"&gt;
      &lt;section class="vb-tagorg-pool"&gt;
        &lt;div class="vb-tagorg-title"&gt;
          &lt;h4&gt;Available Tags&lt;/h4&gt;
          &lt;strong data-vb-tagorg-count="pool"&gt;0&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-tagorg-drop" data-vb-tagorg-drop data-zone="pool"&gt;
          &lt;button type="button" class="vb-tagorg-tag" data-vb-tagorg-tag data-label="JavaScript"&gt;JavaScript&lt;/button&gt;
          &lt;button type="button" class="vb-tagorg-tag" data-vb-tagorg-tag data-label="CSS"&gt;CSS&lt;/button&gt;
          &lt;button type="button" class="vb-tagorg-tag" data-vb-tagorg-tag data-label="SEO"&gt;SEO&lt;/button&gt;
          &lt;button type="button" class="vb-tagorg-tag" data-vb-tagorg-tag data-label="WordPress"&gt;WordPress&lt;/button&gt;
          &lt;button type="button" class="vb-tagorg-tag" data-vb-tagorg-tag data-label="Forms"&gt;Forms&lt;/button&gt;
          &lt;button type="button" class="vb-tagorg-tag" data-vb-tagorg-tag data-label="Ecommerce"&gt;Ecommerce&lt;/button&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-tagorg-groups"&gt;
        &lt;div class="vb-tagorg-group"&gt;
          &lt;div class="vb-tagorg-title"&gt;
            &lt;h4&gt;Development&lt;/h4&gt;
            &lt;strong data-vb-tagorg-count="development"&gt;0&lt;/strong&gt;
          &lt;/div&gt;
          &lt;div class="vb-tagorg-drop" data-vb-tagorg-drop data-zone="development"&gt;&lt;/div&gt;
        &lt;/div&gt;

        &lt;div class="vb-tagorg-group"&gt;
          &lt;div class="vb-tagorg-title"&gt;
            &lt;h4&gt;Marketing&lt;/h4&gt;
            &lt;strong data-vb-tagorg-count="marketing"&gt;0&lt;/strong&gt;
          &lt;/div&gt;
          &lt;div class="vb-tagorg-drop" data-vb-tagorg-drop data-zone="marketing"&gt;&lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;

    &lt;div class="vb-tagorg-status" data-vb-tagorg-status&gt;Drag tags into groups.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">/* CSS is included fully in the live demo block above. */</pre>



<p class="wp-block-paragraph">This JavaScript drag and drop tag organizer is useful for blog admin panels, CRM filters, product attributes, content categorization tools, preference builders, and dashboard filtering interfaces.</p>



<div class="vb-mini-contact-cta">
  <p><strong>Need a custom interactive JavaScript feature?</strong> We can build drag and drop tools, calculators, forms, dashboards, and custom website components for your business.</p>
  <a href="https://veebilehed24.ee/en/contact/">Contact us</a>
</div>

<style>
.vb-mini-contact-cta,
.vb-mini-contact-cta * {
  box-sizing: border-box;
}

.vb-mini-contact-cta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin: 36px 0;
  padding: 16px 18px;
  border-radius: 18px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.28);
}

.vb-mini-contact-cta p {
  margin: 0 !important;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-mini-contact-cta strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-weight: 950;
}

.vb-mini-contact-cta a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 40px;
  padding: 10px 16px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 900;
  text-decoration: none !important;
  white-space: nowrap;
}

@media (max-width: 680px) {
  .vb-mini-contact-cta {
    align-items: flex-start;
    flex-direction: column;
  }
}
</style>



<h2 class="wp-block-heading">25. Drag and Drop Upload with Progress Simulation</h2>



<p class="wp-block-paragraph"><strong>A drag and drop upload with progress simulation</strong> is useful for file upload interfaces, admin dashboards, media libraries, document portals, profile forms, project tools, and SaaS apps. This demo does not upload files to a real server. It simulates upload progress in the browser so the UI pattern is safe to test inside a blog post.</p>



<ul class="wp-block-list">
<li>Drag files into an upload zone</li>
<li>Simulated progress bars</li>
<li>Multiple file support</li>
<li>Works with click-to-select too</li>
<li>No real server upload</li>
</ul>



<div class="vb-uploadsim-demo">
  <div class="vb-uploadsim-wrap" data-vb-uploadsim>
    <div class="vb-uploadsim-head">
      <span>Example 25</span>
      <h3>Upload with Progress Simulation</h3>
      <p>Drop files into the upload zone or click the button. Progress is simulated in the browser.</p>
    </div>

    <div class="vb-uploadsim-layout">
      <section class="vb-uploadsim-zone" data-vb-uploadsim-zone>
        <input type="file" multiple data-vb-uploadsim-input>
        <div class="vb-uploadsim-icon">↑</div>
        <h4>Drop files here</h4>
        <p>Images, PDFs, documents or project files</p>
        <button type="button" data-vb-uploadsim-browse>Choose files</button>
      </section>

      <section class="vb-uploadsim-panel">
        <div class="vb-uploadsim-panel-head">
          <div>
            <span>Upload Queue</span>
            <h4>Files</h4>
          </div>
          <strong data-vb-uploadsim-count>0 files</strong>
        </div>

        <div class="vb-uploadsim-list" data-vb-uploadsim-list>
          <p data-vb-uploadsim-empty>No files added yet.</p>
        </div>
      </section>
    </div>

    <div class="vb-uploadsim-status" data-vb-uploadsim-status>Drag files into the upload zone.</div>
  </div>
</div>

<style>
.vb-uploadsim-demo,
.vb-uploadsim-demo * {
  box-sizing: border-box;
}

.vb-uploadsim-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(59, 130, 246, 0.16), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(16, 185, 129, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-uploadsim-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-uploadsim-head {
  max-width: 800px;
  margin-bottom: 22px;
}

.vb-uploadsim-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-uploadsim-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-uploadsim-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-uploadsim-layout {
  display: grid;
  grid-template-columns: minmax(280px, 0.72fr) minmax(0, 1fr);
  gap: 16px;
}

.vb-uploadsim-zone {
  position: relative;
  min-height: 380px;
  padding: 28px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 50% 20%, rgba(96, 165, 250, 0.28), transparent 38%),
    linear-gradient(135deg, #1e3a8a, #064e3b) !important;
  border: 2px dashed rgba(191, 219, 254, 0.72);
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.22);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  overflow: hidden;
}

.vb-uploadsim-zone.is-over {
  border-color: #ffffff;
  box-shadow: inset 0 0 0 6px rgba(255,255,255,0.16), 0 22px 64px rgba(15, 23, 42, 0.22);
}

.vb-uploadsim-zone input {
  display: none;
}

.vb-uploadsim-icon {
  width: 82px;
  height: 82px;
  margin-bottom: 18px;
  border-radius: 28px;
  background: rgba(255,255,255,0.16);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 46px;
  font-weight: 950;
}

.vb-uploadsim-zone h4 {
  margin: 0 0 8px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4vw, 44px) !important;
  line-height: 1.05 !important;
  font-weight: 950 !important;
  letter-spacing: -0.05em;
}

.vb-uploadsim-zone p {
  margin: 0 0 18px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 15px;
  font-weight: 700;
}

.vb-uploadsim-zone button {
  min-height: 44px;
  padding: 10px 18px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-uploadsim-panel {
  min-width: 0;
  padding: 16px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-uploadsim-panel-head {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  align-items: center;
  margin-bottom: 14px;
}

.vb-uploadsim-panel-head span {
  display: block;
  margin-bottom: 5px;
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-uploadsim-panel-head h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 24px !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-uploadsim-panel-head strong {
  display: inline-flex;
  min-width: 84px;
  justify-content: center;
  padding: 9px 12px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-uploadsim-list {
  display: grid;
  gap: 12px;
  max-height: 430px;
  overflow: auto;
  padding-right: 4px;
}

.vb-uploadsim-list > p {
  margin: 0 !important;
  padding: 18px;
  border-radius: 18px;
  background: #f8fafc;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 750;
  text-align: center;
}

.vb-uploadsim-file {
  padding: 14px;
  border-radius: 20px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.24);
}

.vb-uploadsim-file-top {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}

.vb-uploadsim-file strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 950;
  word-break: break-word;
}

.vb-uploadsim-file span {
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 12px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-uploadsim-bar {
  height: 10px;
  overflow: hidden;
  border-radius: 999px;
  background: #e2e8f0;
}

.vb-uploadsim-fill {
  width: 0%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #2563eb, #10b981);
  transition: width 0.18s ease;
}

.vb-uploadsim-status {
  margin-top: 16px;
  padding: 13px 15px;
  border-radius: 18px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

@media (max-width: 860px) {
  .vb-uploadsim-layout {
    grid-template-columns: 1fr;
  }

  .vb-uploadsim-zone {
    min-height: 300px;
  }
}
</style>

<script>
(function () {
  function initUploadSim() {
    document.querySelectorAll("[data-vb-uploadsim]").forEach(function (root) {
      if (root.getAttribute("data-vb-uploadsim-ready") === "1") return;
      root.setAttribute("data-vb-uploadsim-ready", "1");

      const zone = root.querySelector("[data-vb-uploadsim-zone]");
      const input = root.querySelector("[data-vb-uploadsim-input]");
      const browse = root.querySelector("[data-vb-uploadsim-browse]");
      const list = root.querySelector("[data-vb-uploadsim-list]");
      const empty = root.querySelector("[data-vb-uploadsim-empty]");
      const count = root.querySelector("[data-vb-uploadsim-count]");
      const status = root.querySelector("[data-vb-uploadsim-status]");

      let totalFiles = 0;

      function prettySize(bytes) {
        if (bytes < 1024) return bytes + " B";
        if (bytes < 1024 * 1024) return Math.round(bytes / 1024) + " KB";
        return (bytes / 1024 / 1024).toFixed(1) + " MB";
      }

      function updateCount() {
        count.textContent = totalFiles === 1 ? "1 file" : totalFiles + " files";
        if (empty) empty.style.display = totalFiles ? "none" : "block";
      }

      function addFile(file) {
        totalFiles += 1;
        updateCount();

        const item = document.createElement("article");
        item.className = "vb-uploadsim-file";

        item.innerHTML =
          '<div class="vb-uploadsim-file-top">' +
          '<strong>' + file.name + '</strong>' +
          '<span>0%</span>' +
          '</div>' +
          '<div class="vb-uploadsim-bar"><div class="vb-uploadsim-fill"></div></div>';

        list.appendChild(item);

        const label = item.querySelector("span");
        const fill = item.querySelector(".vb-uploadsim-fill");
        let progress = 0;

        status.textContent = "Simulating upload: " + file.name + " (" + prettySize(file.size) + ")";

        const timer = setInterval(function () {
          progress += Math.floor(Math.random() * 18) + 7;
          if (progress >= 100) {
            progress = 100;
            clearInterval(timer);
          }

          label.textContent = progress + "%";
          fill.style.width = progress + "%";

          if (progress === 100) {
            label.textContent = "Done";
            status.textContent = "Upload simulation complete.";
          }
        }, 240);
      }

      function addFiles(files) {
        Array.from(files).forEach(addFile);
      }

      browse.addEventListener("click", function () {
        input.click();
      });

      input.addEventListener("change", function () {
        addFiles(input.files);
        input.value = "";
      });

      zone.addEventListener("dragover", function (event) {
        event.preventDefault();
        zone.classList.add("is-over");
      });

      zone.addEventListener("dragleave", function () {
        zone.classList.remove("is-over");
      });

      zone.addEventListener("drop", function (event) {
        event.preventDefault();
        zone.classList.remove("is-over");
        addFiles(event.dataTransfer.files);
      });

      updateCount();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initUploadSim);
  } else {
    initUploadSim();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initUploadSim() {
    document.querySelectorAll("[data-vb-uploadsim]").forEach(function (root) {
      if (root.getAttribute("data-vb-uploadsim-ready") === "1") return;
      root.setAttribute("data-vb-uploadsim-ready", "1");

      const zone = root.querySelector("[data-vb-uploadsim-zone]");
      const input = root.querySelector("[data-vb-uploadsim-input]");
      const browse = root.querySelector("[data-vb-uploadsim-browse]");
      const list = root.querySelector("[data-vb-uploadsim-list]");
      const empty = root.querySelector("[data-vb-uploadsim-empty]");
      const count = root.querySelector("[data-vb-uploadsim-count]");
      const status = root.querySelector("[data-vb-uploadsim-status]");

      let totalFiles = 0;

      function prettySize(bytes) {
        if (bytes &lt; 1024) return bytes + " B";
        if (bytes &lt; 1024 * 1024) return Math.round(bytes / 1024) + " KB";
        return (bytes / 1024 / 1024).toFixed(1) + " MB";
      }

      function updateCount() {
        count.textContent = totalFiles === 1 ? "1 file" : totalFiles + " files";
        if (empty) empty.style.display = totalFiles ? "none" : "block";
      }

      function addFile(file) {
        totalFiles += 1;
        updateCount();

        const item = document.createElement("article");
        item.className = "vb-uploadsim-file";

        item.innerHTML =
          '&lt;div class="vb-uploadsim-file-top"&gt;' +
          '&lt;strong&gt;' + file.name + '&lt;/strong&gt;' +
          '&lt;span&gt;0%&lt;/span&gt;' +
          '&lt;/div&gt;' +
          '&lt;div class="vb-uploadsim-bar"&gt;&lt;div class="vb-uploadsim-fill"&gt;&lt;/div&gt;&lt;/div&gt;';

        list.appendChild(item);

        const label = item.querySelector("span");
        const fill = item.querySelector(".vb-uploadsim-fill");
        let progress = 0;

        status.textContent = "Simulating upload: " + file.name + " (" + prettySize(file.size) + ")";

        const timer = setInterval(function () {
          progress += Math.floor(Math.random() * 18) + 7;
          if (progress &gt;= 100) {
            progress = 100;
            clearInterval(timer);
          }

          label.textContent = progress + "%";
          fill.style.width = progress + "%";

          if (progress === 100) {
            label.textContent = "Done";
            status.textContent = "Upload simulation complete.";
          }
        }, 240);
      }

      function addFiles(files) {
        Array.from(files).forEach(addFile);
      }

      browse.addEventListener("click", function () {
        input.click();
      });

      input.addEventListener("change", function () {
        addFiles(input.files);
        input.value = "";
      });

      zone.addEventListener("dragover", function (event) {
        event.preventDefault();
        zone.classList.add("is-over");
      });

      zone.addEventListener("dragleave", function () {
        zone.classList.remove("is-over");
      });

      zone.addEventListener("drop", function (event) {
        event.preventDefault();
        zone.classList.remove("is-over");
        addFiles(event.dataTransfer.files);
      });

      updateCount();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initUploadSim);
  } else {
    initUploadSim();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-uploadsim-demo"&gt;
  &lt;div class="vb-uploadsim-wrap" data-vb-uploadsim&gt;
    &lt;div class="vb-uploadsim-head"&gt;
      &lt;span&gt;Example 25&lt;/span&gt;
      &lt;h3&gt;Upload with Progress Simulation&lt;/h3&gt;
      &lt;p&gt;Drop files into the upload zone or click the button. Progress is simulated in the browser.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-uploadsim-layout"&gt;
      &lt;section class="vb-uploadsim-zone" data-vb-uploadsim-zone&gt;
        &lt;input type="file" multiple data-vb-uploadsim-input&gt;
        &lt;div class="vb-uploadsim-icon"&gt;↑&lt;/div&gt;
        &lt;h4&gt;Drop files here&lt;/h4&gt;
        &lt;p&gt;Images, PDFs, documents or project files&lt;/p&gt;
        &lt;button type="button" data-vb-uploadsim-browse&gt;Choose files&lt;/button&gt;
      &lt;/section&gt;

      &lt;section class="vb-uploadsim-panel"&gt;
        &lt;div class="vb-uploadsim-panel-head"&gt;
          &lt;div&gt;
            &lt;span&gt;Upload Queue&lt;/span&gt;
            &lt;h4&gt;Files&lt;/h4&gt;
          &lt;/div&gt;
          &lt;strong data-vb-uploadsim-count&gt;0 files&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-uploadsim-list" data-vb-uploadsim-list&gt;
          &lt;p data-vb-uploadsim-empty&gt;No files added yet.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;

    &lt;div class="vb-uploadsim-status" data-vb-uploadsim-status&gt;Drag files into the upload zone.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">/* CSS is included fully in the live demo block above. */</pre>



<p class="wp-block-paragraph">This JavaScript drag and drop upload simulation is useful for file upload forms, media dashboards, document portals, admin panels, SaaS apps, and project management tools.</p>



<h2 class="wp-block-heading">26. Drag and Drop Card Stack Swipe UI</h2>



<p class="wp-block-paragraph"><strong>A card stack swipe UI</strong> lets users drag the top card left or right to make a quick decision. This pattern is useful for onboarding screens, product recommendations, candidate review tools, idea voting, content approval interfaces, and mobile-style web apps.</p>



<ul class="wp-block-list">
<li>Drag top card left or right</li>
<li>Accept and reject counters</li>
<li>Card stack animation</li>
<li>Mouse and touch support</li>
<li>Different from list sorting examples</li>
</ul>



<div class="vb-cardstack-demo">
  <div class="vb-cardstack-wrap" data-vb-cardstack>
    <div class="vb-cardstack-head">
      <span>Example 26</span>
      <h3>Card Stack Swipe UI</h3>
      <p>Drag the top card left to reject or right to approve. The next card appears automatically.</p>
    </div>

    <div class="vb-cardstack-layout">
      <section class="vb-cardstack-area">
        <div class="vb-cardstack-deck" data-vb-cardstack-deck>
          <article class="vb-cardstack-card" data-vb-cardstack-card data-title="Website redesign" data-index="0">
            <span>Project Idea</span>
            <h4>Website redesign</h4>
            <p>Refresh the homepage, service pages, and contact flow with a modern visual system.</p>
          </article>

          <article class="vb-cardstack-card" data-vb-cardstack-card data-title="AI chatbot" data-index="1">
            <span>Product Idea</span>
            <h4>AI chatbot</h4>
            <p>Add a custom trained chatbot that answers customer questions and suggests products.</p>
          </article>

          <article class="vb-cardstack-card" data-vb-cardstack-card data-title="SEO content hub" data-index="2">
            <span>Growth Idea</span>
            <h4>SEO content hub</h4>
            <p>Create a large content hub with examples, tutorials, internal links, and lead capture.</p>
          </article>
        </div>

        <div class="vb-cardstack-actions">
          <span>← Reject</span>
          <span>Approve →</span>
        </div>
      </section>

      <aside class="vb-cardstack-score">
        <span>Decision Summary</span>
        <strong><b data-vb-cardstack-approved>0</b> approved</strong>
        <strong><b data-vb-cardstack-rejected>0</b> rejected</strong>
        <p data-vb-cardstack-status>Drag the top card to start.</p>
        <button type="button" data-vb-cardstack-reset>Reset stack</button>
      </aside>
    </div>
  </div>
</div>

<style>
.vb-cardstack-demo,
.vb-cardstack-demo * {
  box-sizing: border-box;
}

.vb-cardstack-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(236, 72, 153, 0.16), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(124, 58, 237, 0.16), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #f5f3ff 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-cardstack-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-cardstack-head {
  max-width: 800px;
  margin-bottom: 22px;
}

.vb-cardstack-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fce7f3;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-cardstack-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-cardstack-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-cardstack-layout {
  display: grid;
  grid-template-columns: minmax(280px, 1fr) minmax(260px, 0.56fr);
  gap: 16px;
  align-items: stretch;
}

.vb-cardstack-area {
  min-height: 480px;
  padding: 18px;
  border-radius: 32px;
  background: #0f172a;
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.22);
  overflow: hidden;
}

.vb-cardstack-deck {
  position: relative;
  height: 390px;
}

.vb-cardstack-card {
  position: absolute;
  inset: 0;
  padding: clamp(22px, 4vw, 42px);
  border-radius: 32px;
  background:
    radial-gradient(circle at 80% 12%, rgba(255,255,255,0.32), transparent 30%),
    linear-gradient(135deg, #be185d, #7c3aed) !important;
  box-shadow: 0 22px 60px rgba(0, 0, 0, 0.24);
  cursor: grab;
  user-select: none;
  touch-action: none;
  transition: transform 0.22s ease, opacity 0.22s ease;
}

.vb-cardstack-card:nth-child(2) {
  transform: translateY(14px) scale(0.96);
  background:
    radial-gradient(circle at 80% 12%, rgba(255,255,255,0.32), transparent 30%),
    linear-gradient(135deg, #2563eb, #7c3aed) !important;
}

.vb-cardstack-card:nth-child(3) {
  transform: translateY(28px) scale(0.92);
  background:
    radial-gradient(circle at 80% 12%, rgba(255,255,255,0.32), transparent 30%),
    linear-gradient(135deg, #0f766e, #2563eb) !important;
}

.vb-cardstack-card.is-dragging {
  transition: none;
}

.vb-cardstack-card span {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.18);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-cardstack-card h4 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 6vw, 64px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-cardstack-card p {
  max-width: 560px;
  margin: 0 !important;
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 16px;
  line-height: 1.65;
  font-weight: 700;
}

.vb-cardstack-actions {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-top: 18px;
}

.vb-cardstack-actions span {
  flex: 1;
  padding: 13px 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  text-align: center;
}

.vb-cardstack-score {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 26px;
  border-radius: 32px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-cardstack-score > span {
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-cardstack-score strong {
  margin-top: 12px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 24px;
  line-height: 1.1;
  font-weight: 950;
}

.vb-cardstack-score strong b {
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
}

.vb-cardstack-score p {
  margin: 18px 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 700;
}

.vb-cardstack-score button {
  min-height: 46px;
  border: 0;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

@media (max-width: 860px) {
  .vb-cardstack-layout {
    grid-template-columns: 1fr;
  }

  .vb-cardstack-area {
    min-height: 420px;
  }

  .vb-cardstack-deck {
    height: 330px;
  }
}
</style>

<script>
(function () {
  function initCardStack() {
    document.querySelectorAll("[data-vb-cardstack]").forEach(function (root) {
      if (root.getAttribute("data-vb-cardstack-ready") === "1") return;
      root.setAttribute("data-vb-cardstack-ready", "1");

      const deck = root.querySelector("[data-vb-cardstack-deck]");
      const approvedEl = root.querySelector("[data-vb-cardstack-approved]");
      const rejectedEl = root.querySelector("[data-vb-cardstack-rejected]");
      const status = root.querySelector("[data-vb-cardstack-status]");
      const reset = root.querySelector("[data-vb-cardstack-reset]");

      const original = deck.innerHTML;
      let active = null;
      let startX = 0;
      let startY = 0;
      let currentX = 0;
      let currentY = 0;
      let approved = 0;
      let rejected = 0;

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function topCard() {
        return deck.querySelector("[data-vb-cardstack-card]");
      }

      function updateScores() {
        approvedEl.textContent = approved;
        rejectedEl.textContent = rejected;
      }

      function start(event) {
        const card = event.target.closest("[data-vb-cardstack-card]");
        if (!card || card !== topCard()) return;

        event.preventDefault();

        const point = getPoint(event);
        active = card;
        startX = point.x;
        startY = point.y;
        currentX = 0;
        currentY = 0;
        active.classList.add("is-dragging");

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;

        event.preventDefault();

        const point = getPoint(event);
        currentX = point.x - startX;
        currentY = point.y - startY;

        const rotate = currentX / 18;
        active.style.transform = "translate(" + currentX + "px, " + currentY + "px) rotate(" + rotate + "deg)";
      }

      function removeCard(direction) {
        const title = active.getAttribute("data-title");

        if (direction === "right") {
          approved += 1;
          status.textContent = "Approved: " + title;
          active.style.transform = "translate(130%, " + currentY + "px) rotate(18deg)";
        } else {
          rejected += 1;
          status.textContent = "Rejected: " + title;
          active.style.transform = "translate(-130%, " + currentY + "px) rotate(-18deg)";
        }

        active.style.opacity = "0";
        updateScores();

        const removed = active;
        setTimeout(function () {
          removed.remove();
          if (!topCard()) status.textContent = "All cards reviewed. Use reset to start again.";
        }, 230);
      }

      function end() {
        if (!active) return;

        if (currentX > 110) {
          removeCard("right");
        } else if (currentX < -110) {
          removeCard("left");
        } else {
          active.style.transform = "";
        }

        cleanup();
      }

      function cancel() {
        if (active) active.style.transform = "";
        cleanup();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");

        active = null;

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      reset.addEventListener("click", function () {
        deck.innerHTML = original;
        approved = 0;
        rejected = 0;
        updateScores();
        status.textContent = "Drag the top card to start.";
      });

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateScores();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initCardStack);
  } else {
    initCardStack();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initCardStack() {
    document.querySelectorAll("[data-vb-cardstack]").forEach(function (root) {
      if (root.getAttribute("data-vb-cardstack-ready") === "1") return;
      root.setAttribute("data-vb-cardstack-ready", "1");

      const deck = root.querySelector("[data-vb-cardstack-deck]");
      const approvedEl = root.querySelector("[data-vb-cardstack-approved]");
      const rejectedEl = root.querySelector("[data-vb-cardstack-rejected]");
      const status = root.querySelector("[data-vb-cardstack-status]");
      const reset = root.querySelector("[data-vb-cardstack-reset]");

      const original = deck.innerHTML;
      let active = null;
      let startX = 0;
      let startY = 0;
      let currentX = 0;
      let currentY = 0;
      let approved = 0;
      let rejected = 0;

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function topCard() {
        return deck.querySelector("[data-vb-cardstack-card]");
      }

      function updateScores() {
        approvedEl.textContent = approved;
        rejectedEl.textContent = rejected;
      }

      function start(event) {
        const card = event.target.closest("[data-vb-cardstack-card]");
        if (!card || card !== topCard()) return;

        event.preventDefault();

        const point = getPoint(event);
        active = card;
        startX = point.x;
        startY = point.y;
        currentX = 0;
        currentY = 0;
        active.classList.add("is-dragging");

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;

        event.preventDefault();

        const point = getPoint(event);
        currentX = point.x - startX;
        currentY = point.y - startY;

        const rotate = currentX / 18;
        active.style.transform = "translate(" + currentX + "px, " + currentY + "px) rotate(" + rotate + "deg)";
      }

      function removeCard(direction) {
        const title = active.getAttribute("data-title");

        if (direction === "right") {
          approved += 1;
          status.textContent = "Approved: " + title;
          active.style.transform = "translate(130%, " + currentY + "px) rotate(18deg)";
        } else {
          rejected += 1;
          status.textContent = "Rejected: " + title;
          active.style.transform = "translate(-130%, " + currentY + "px) rotate(-18deg)";
        }

        active.style.opacity = "0";
        updateScores();

        const removed = active;
        setTimeout(function () {
          removed.remove();
          if (!topCard()) status.textContent = "All cards reviewed. Use reset to start again.";
        }, 230);
      }

      function end() {
        if (!active) return;

        if (currentX &gt; 110) {
          removeCard("right");
        } else if (currentX &lt; -110) {
          removeCard("left");
        } else {
          active.style.transform = "";
        }

        cleanup();
      }

      function cancel() {
        if (active) active.style.transform = "";
        cleanup();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");

        active = null;

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      reset.addEventListener("click", function () {
        deck.innerHTML = original;
        approved = 0;
        rejected = 0;
        updateScores();
        status.textContent = "Drag the top card to start.";
      });

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateScores();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initCardStack);
  } else {
    initCardStack();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-cardstack-demo"&gt;
  &lt;div class="vb-cardstack-wrap" data-vb-cardstack&gt;
    &lt;div class="vb-cardstack-head"&gt;
      &lt;span&gt;Example 26&lt;/span&gt;
      &lt;h3&gt;Card Stack Swipe UI&lt;/h3&gt;
      &lt;p&gt;Drag the top card left to reject or right to approve. The next card appears automatically.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-cardstack-layout"&gt;
      &lt;section class="vb-cardstack-area"&gt;
        &lt;div class="vb-cardstack-deck" data-vb-cardstack-deck&gt;
          &lt;article class="vb-cardstack-card" data-vb-cardstack-card data-title="Website redesign" data-index="0"&gt;
            &lt;span&gt;Project Idea&lt;/span&gt;
            &lt;h4&gt;Website redesign&lt;/h4&gt;
            &lt;p&gt;Refresh the homepage, service pages, and contact flow with a modern visual system.&lt;/p&gt;
          &lt;/article&gt;

          &lt;article class="vb-cardstack-card" data-vb-cardstack-card data-title="AI chatbot" data-index="1"&gt;
            &lt;span&gt;Product Idea&lt;/span&gt;
            &lt;h4&gt;AI chatbot&lt;/h4&gt;
            &lt;p&gt;Add a custom trained chatbot that answers customer questions and suggests products.&lt;/p&gt;
          &lt;/article&gt;

          &lt;article class="vb-cardstack-card" data-vb-cardstack-card data-title="SEO content hub" data-index="2"&gt;
            &lt;span&gt;Growth Idea&lt;/span&gt;
            &lt;h4&gt;SEO content hub&lt;/h4&gt;
            &lt;p&gt;Create a large content hub with examples, tutorials, internal links, and lead capture.&lt;/p&gt;
          &lt;/article&gt;
        &lt;/div&gt;

        &lt;div class="vb-cardstack-actions"&gt;
          &lt;span&gt;← Reject&lt;/span&gt;
          &lt;span&gt;Approve →&lt;/span&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;aside class="vb-cardstack-score"&gt;
        &lt;span&gt;Decision Summary&lt;/span&gt;
        &lt;strong&gt;&lt;b data-vb-cardstack-approved&gt;0&lt;/b&gt; approved&lt;/strong&gt;
        &lt;strong&gt;&lt;b data-vb-cardstack-rejected&gt;0&lt;/b&gt; rejected&lt;/strong&gt;
        &lt;p data-vb-cardstack-status&gt;Drag the top card to start.&lt;/p&gt;
        &lt;button type="button" data-vb-cardstack-reset&gt;Reset stack&lt;/button&gt;
      &lt;/aside&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">/* CSS is included fully in the live demo block above. */</pre>



<p class="wp-block-paragraph">This JavaScript drag and drop card stack swipe UI is useful for onboarding screens, product recommendation tools, content approval systems, candidate review dashboards, and mobile-style web apps.</p>



<h2 class="wp-block-heading">27. Drag and Drop Map Pin Placement UI</h2>



<p class="wp-block-paragraph"><strong>A drag and drop map pin placement UI</strong> lets users place a marker on a visual map area. This pattern is useful for location forms, delivery zone tools, property dashboards, event map builders, store locator interfaces, and admin map editors.</p>



<ul class="wp-block-list">
<li>Drag a pin around a map area</li>
<li>Stores relative X and Y position</li>
<li>Mouse and touch support</li>
<li>Live coordinate output</li>
<li>No external map library required</li>
</ul>



<div class="vb-mapdrop-demo">
  <div class="vb-mapdrop-wrap" data-vb-mapdrop>
    <div class="vb-mapdrop-head">
      <span>Example 27</span>
      <h3>Map Pin Placement UI</h3>
      <p>Drag the map pin to choose a location. The relative map coordinates update instantly.</p>
    </div>

    <div class="vb-mapdrop-layout">
      <section class="vb-mapdrop-map" data-vb-mapdrop-map>
        <div class="vb-mapdrop-road vb-mapdrop-road-one"></div>
        <div class="vb-mapdrop-road vb-mapdrop-road-two"></div>
        <div class="vb-mapdrop-block vb-mapdrop-block-a"></div>
        <div class="vb-mapdrop-block vb-mapdrop-block-b"></div>
        <div class="vb-mapdrop-block vb-mapdrop-block-c"></div>

        <button type="button" class="vb-mapdrop-pin" data-vb-mapdrop-pin aria-label="Move map pin">
          <span></span>
        </button>
      </section>

      <aside class="vb-mapdrop-panel">
        <span>Selected Position</span>
        <strong data-vb-mapdrop-output>X: 50%, Y: 50%</strong>
        <p>This demo uses relative percentage coordinates, so the pin stays responsive inside the map area.</p>
        <button type="button" data-vb-mapdrop-reset>Reset pin</button>
      </aside>
    </div>
  </div>
</div>

<style>
.vb-mapdrop-demo,
.vb-mapdrop-demo * {
  box-sizing: border-box;
}

.vb-mapdrop-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(34, 197, 94, 0.15), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #ecfeff 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-mapdrop-wrap {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-mapdrop-head {
  max-width: 800px;
  margin-bottom: 22px;
}

.vb-mapdrop-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-mapdrop-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-mapdrop-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-mapdrop-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 0.56fr);
  gap: 16px;
}

.vb-mapdrop-map {
  position: relative;
  min-height: 460px;
  border-radius: 34px;
  overflow: hidden;
  background:
    linear-gradient(90deg, rgba(255,255,255,0.12) 1px, transparent 1px),
    linear-gradient(rgba(255,255,255,0.12) 1px, transparent 1px),
    linear-gradient(135deg, #16a34a, #0e7490) !important;
  background-size: 42px 42px, 42px 42px, auto;
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.20);
  border: 1px solid rgba(255,255,255,0.35);
}

.vb-mapdrop-road {
  position: absolute;
  border-radius: 999px;
  background: rgba(255,255,255,0.62);
  box-shadow: 0 10px 30px rgba(15, 23, 42, 0.12);
}

.vb-mapdrop-road-one {
  width: 120%;
  height: 34px;
  left: -10%;
  top: 44%;
  transform: rotate(-12deg);
}

.vb-mapdrop-road-two {
  width: 34px;
  height: 120%;
  left: 56%;
  top: -10%;
  transform: rotate(18deg);
}

.vb-mapdrop-block {
  position: absolute;
  border-radius: 22px;
  background: rgba(255,255,255,0.22);
  border: 1px solid rgba(255,255,255,0.28);
}

.vb-mapdrop-block-a {
  width: 24%;
  height: 22%;
  left: 10%;
  top: 12%;
}

.vb-mapdrop-block-b {
  width: 28%;
  height: 20%;
  right: 10%;
  top: 18%;
}

.vb-mapdrop-block-c {
  width: 30%;
  height: 22%;
  left: 18%;
  bottom: 12%;
}

.vb-mapdrop-pin {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 54px;
  height: 54px;
  border: 0;
  border-radius: 50% 50% 50% 8px;
  background: #ef4444;
  transform: translate(-50%, -100%) rotate(-45deg);
  cursor: grab;
  touch-action: none;
  box-shadow: 0 18px 34px rgba(127, 29, 29, 0.32);
  z-index: 5;
}

.vb-mapdrop-pin.is-dragging {
  cursor: grabbing;
}

.vb-mapdrop-pin span {
  position: absolute;
  width: 18px;
  height: 18px;
  left: 18px;
  top: 18px;
  border-radius: 999px;
  background: #ffffff;
}

.vb-mapdrop-panel {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 26px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 16% 16%, rgba(34, 197, 94, 0.22), transparent 36%),
    linear-gradient(135deg, #064e3b, #0f172a) !important;
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.20);
}

.vb-mapdrop-panel > span {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-mapdrop-panel strong {
  margin: 12px 0;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(26px, 4vw, 42px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-mapdrop-panel p {
  margin: 0 0 18px !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-mapdrop-panel button {
  min-height: 46px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

@media (max-width: 860px) {
  .vb-mapdrop-layout {
    grid-template-columns: 1fr;
  }

  .vb-mapdrop-map {
    min-height: 360px;
  }
}
</style>

<script>
(function () {
  function initMapDrop() {
    document.querySelectorAll("[data-vb-mapdrop]").forEach(function (root) {
      if (root.getAttribute("data-vb-mapdrop-ready") === "1") return;
      root.setAttribute("data-vb-mapdrop-ready", "1");

      const map = root.querySelector("[data-vb-mapdrop-map]");
      const pin = root.querySelector("[data-vb-mapdrop-pin]");
      const output = root.querySelector("[data-vb-mapdrop-output]");
      const reset = root.querySelector("[data-vb-mapdrop-reset]");

      let active = false;

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function setPinByPercent(xPercent, yPercent) {
        xPercent = Math.max(3, Math.min(97, xPercent));
        yPercent = Math.max(8, Math.min(98, yPercent));

        pin.style.left = xPercent + "%";
        pin.style.top = yPercent + "%";
        output.textContent = "X: " + Math.round(xPercent) + "%, Y: " + Math.round(yPercent) + "%";
      }

      function setPinByPoint(x, y) {
        const rect = map.getBoundingClientRect();
        const xPercent = ((x - rect.left) / rect.width) * 100;
        const yPercent = ((y - rect.top) / rect.height) * 100;
        setPinByPercent(xPercent, yPercent);
      }

      function start(event) {
        if (!event.target.closest("[data-vb-mapdrop-pin]")) return;

        event.preventDefault();
        active = true;
        pin.classList.add("is-dragging");

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", end);
      }

      function move(event) {
        if (!active) return;

        event.preventDefault();

        const point = getPoint(event);
        setPinByPoint(point.x, point.y);
      }

      function end() {
        active = false;
        pin.classList.remove("is-dragging");

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", end);
      }

      reset.addEventListener("click", function () {
        setPinByPercent(50, 50);
      });

      pin.addEventListener("mousedown", start);
      pin.addEventListener("touchstart", start, { passive: false });
      setPinByPercent(50, 50);
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initMapDrop);
  } else {
    initMapDrop();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initMapDrop() {
    document.querySelectorAll("[data-vb-mapdrop]").forEach(function (root) {
      if (root.getAttribute("data-vb-mapdrop-ready") === "1") return;
      root.setAttribute("data-vb-mapdrop-ready", "1");

      const map = root.querySelector("[data-vb-mapdrop-map]");
      const pin = root.querySelector("[data-vb-mapdrop-pin]");
      const output = root.querySelector("[data-vb-mapdrop-output]");
      const reset = root.querySelector("[data-vb-mapdrop-reset]");

      let active = false;

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function setPinByPercent(xPercent, yPercent) {
        xPercent = Math.max(3, Math.min(97, xPercent));
        yPercent = Math.max(8, Math.min(98, yPercent));

        pin.style.left = xPercent + "%";
        pin.style.top = yPercent + "%";
        output.textContent = "X: " + Math.round(xPercent) + "%, Y: " + Math.round(yPercent) + "%";
      }

      function setPinByPoint(x, y) {
        const rect = map.getBoundingClientRect();
        const xPercent = ((x - rect.left) / rect.width) * 100;
        const yPercent = ((y - rect.top) / rect.height) * 100;
        setPinByPercent(xPercent, yPercent);
      }

      function start(event) {
        if (!event.target.closest("[data-vb-mapdrop-pin]")) return;

        event.preventDefault();
        active = true;
        pin.classList.add("is-dragging");

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", end);
      }

      function move(event) {
        if (!active) return;

        event.preventDefault();

        const point = getPoint(event);
        setPinByPoint(point.x, point.y);
      }

      function end() {
        active = false;
        pin.classList.remove("is-dragging");

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", end);
      }

      reset.addEventListener("click", function () {
        setPinByPercent(50, 50);
      });

      pin.addEventListener("mousedown", start);
      pin.addEventListener("touchstart", start, { passive: false });
      setPinByPercent(50, 50);
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initMapDrop);
  } else {
    initMapDrop();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-mapdrop-demo"&gt;
  &lt;div class="vb-mapdrop-wrap" data-vb-mapdrop&gt;
    &lt;div class="vb-mapdrop-head"&gt;
      &lt;span&gt;Example 27&lt;/span&gt;
      &lt;h3&gt;Map Pin Placement UI&lt;/h3&gt;
      &lt;p&gt;Drag the map pin to choose a location. The relative map coordinates update instantly.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-mapdrop-layout"&gt;
      &lt;section class="vb-mapdrop-map" data-vb-mapdrop-map&gt;
        &lt;div class="vb-mapdrop-road vb-mapdrop-road-one"&gt;&lt;/div&gt;
        &lt;div class="vb-mapdrop-road vb-mapdrop-road-two"&gt;&lt;/div&gt;
        &lt;div class="vb-mapdrop-block vb-mapdrop-block-a"&gt;&lt;/div&gt;
        &lt;div class="vb-mapdrop-block vb-mapdrop-block-b"&gt;&lt;/div&gt;
        &lt;div class="vb-mapdrop-block vb-mapdrop-block-c"&gt;&lt;/div&gt;

        &lt;button type="button" class="vb-mapdrop-pin" data-vb-mapdrop-pin aria-label="Move map pin"&gt;
          &lt;span&gt;&lt;/span&gt;
        &lt;/button&gt;
      &lt;/section&gt;

      &lt;aside class="vb-mapdrop-panel"&gt;
        &lt;span&gt;Selected Position&lt;/span&gt;
        &lt;strong data-vb-mapdrop-output&gt;X: 50%, Y: 50%&lt;/strong&gt;
        &lt;p&gt;This demo uses relative percentage coordinates, so the pin stays responsive inside the map area.&lt;/p&gt;
        &lt;button type="button" data-vb-mapdrop-reset&gt;Reset pin&lt;/button&gt;
      &lt;/aside&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">/* CSS is included fully in the live demo block above. */</pre>



<p class="wp-block-paragraph">This JavaScript map pin placement UI is useful for location forms, delivery zone tools, property dashboards, event map builders, store locator interfaces, and admin map editors.</p>



<h2 class="wp-block-heading">28. Mobile-Friendly Touch Drag and Drop List</h2>



<p class="wp-block-paragraph"><strong>A mobile-friendly touch drag and drop list</strong> is useful when users need to reorder tasks, checklist items, priorities, lessons, steps, or content blocks on phones and tablets. This example uses mouse and touch events, a floating drag preview, automatic reordering, and a live order summary.</p>



<ul class="wp-block-list">
<li>Works with mouse and touch</li>
<li>Drag handle for safer mobile interaction</li>
<li>Floating preview while dragging</li>
<li>Live order summary</li>
<li>No external JavaScript library</li>
</ul>



<div class="vb-touchsort-demo">
  <div class="vb-touchsort-wrap" data-vb-touchsort>
    <div class="vb-touchsort-head">
      <span>Example 28</span>
      <h3>Mobile Touch Sort List</h3>
      <p>Drag the handle on each card to reorder the mobile task list.</p>
    </div>

    <div class="vb-touchsort-phone">
      <div class="vb-touchsort-phone-top">
        <span>Today</span>
        <strong>Priority List</strong>
      </div>

      <div class="vb-touchsort-list" data-vb-touchsort-list>
        <article class="vb-touchsort-item" data-vb-touchsort-item data-title="Plan homepage layout">
          <button type="button" data-vb-touchsort-handle aria-label="Drag item">⋮⋮</button>
          <div>
            <h4>Plan homepage layout</h4>
            <p>Define sections and CTA order</p>
          </div>
        </article>

        <article class="vb-touchsort-item" data-vb-touchsort-item data-title="Write service copy">
          <button type="button" data-vb-touchsort-handle aria-label="Drag item">⋮⋮</button>
          <div>
            <h4>Write service copy</h4>
            <p>Create short conversion text</p>
          </div>
        </article>

        <article class="vb-touchsort-item" data-vb-touchsort-item data-title="Design contact form">
          <button type="button" data-vb-touchsort-handle aria-label="Drag item">⋮⋮</button>
          <div>
            <h4>Design contact form</h4>
            <p>Make it fast and simple</p>
          </div>
        </article>

        <article class="vb-touchsort-item" data-vb-touchsort-item data-title="Test mobile view">
          <button type="button" data-vb-touchsort-handle aria-label="Drag item">⋮⋮</button>
          <div>
            <h4>Test mobile view</h4>
            <p>Check spacing and buttons</p>
          </div>
        </article>
      </div>

      <div class="vb-touchsort-output" data-vb-touchsort-output>Plan homepage layout → Write service copy → Design contact form → Test mobile view</div>
    </div>
  </div>
</div>

<style>
.vb-touchsort-demo,
.vb-touchsort-demo * {
  box-sizing: border-box;
}

.vb-touchsort-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(14, 165, 233, 0.16), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #ecfeff 0%, #eef2ff 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-touchsort-wrap {
  max-width: 960px;
  margin: 0 auto;
}

.vb-touchsort-head {
  max-width: 760px;
  margin: 0 auto 24px;
  text-align: center;
}

.vb-touchsort-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #cffafe;
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-touchsort-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-touchsort-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-touchsort-phone {
  max-width: 430px;
  margin: 0 auto;
  padding: 16px;
  border-radius: 36px;
  background: #0f172a;
  box-shadow: 0 26px 80px rgba(15, 23, 42, 0.25);
}

.vb-touchsort-phone-top {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: center;
  padding: 14px 14px 18px;
}

.vb-touchsort-phone-top span {
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-touchsort-phone-top strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-touchsort-list {
  display: grid;
  gap: 10px;
}

.vb-touchsort-item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 13px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(255, 255, 255, 0.16);
  box-shadow: 0 12px 26px rgba(0, 0, 0, 0.18);
}

.vb-touchsort-item.is-dragging {
  opacity: 0.38;
}

.vb-touchsort-item.is-over {
  outline: 3px solid rgba(34, 211, 238, 0.45);
}

.vb-touchsort-item button {
  width: 38px;
  height: 44px;
  border: 0;
  border-radius: 15px;
  background: #cffafe;
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 20px;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
}

.vb-touchsort-item h4 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px !important;
  line-height: 1.22 !important;
  font-weight: 950 !important;
}

.vb-touchsort-item p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.45;
  font-weight: 700;
}

.vb-touchsort-output {
  margin-top: 12px;
  padding: 13px;
  border-radius: 20px;
  background: rgba(255,255,255,0.08);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  line-height: 1.55;
  font-weight: 800;
}

.vb-touchsort-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(340px, calc(100vw - 28px));
  padding: 13px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(14, 165, 233, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.26);
}

.vb-touchsort-ghost strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 520px) {
  .vb-touchsort-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-touchsort-phone {
    border-radius: 28px;
  }
}
</style>

<script>
(function () {
  function initTouchSort() {
    document.querySelectorAll("[data-vb-touchsort]").forEach(function (root) {
      if (root.getAttribute("data-vb-touchsort-ready") === "1") return;
      root.setAttribute("data-vb-touchsort-ready", "1");

      const list = root.querySelector("[data-vb-touchsort-list]");
      const output = root.querySelector("[data-vb-touchsort-output]");
      let active = null;
      let ghost = null;

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function updateOutput() {
        output.textContent = Array.from(list.querySelectorAll("[data-vb-touchsort-item]"))
          .map(function (item) { return item.getAttribute("data-title"); })
          .join(" → ");
      }

      function createGhost(item, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-touchsort-ghost";
        ghost.innerHTML = "<strong>" + item.getAttribute("data-title") + "</strong>";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 12 + "px";
        ghost.style.top = y + 12 + "px";
      }

      function clearOver() {
        list.querySelectorAll(".is-over").forEach(function (item) {
          item.classList.remove("is-over");
        });
      }

      function reorderAt(x, y) {
        const element = document.elementFromPoint(x, y);
        const target = element ? element.closest("[data-vb-touchsort-item]") : null;

        if (!target || target === active || !list.contains(target)) return;

        const rect = target.getBoundingClientRect();
        const after = y > rect.top + rect.height / 2;

        clearOver();
        target.classList.add("is-over");

        if (after) {
          target.insertAdjacentElement("afterend", active);
        } else {
          target.insertAdjacentElement("beforebegin", active);
        }

        updateOutput();
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-touchsort-handle]");
        if (!handle) return;

        const item = handle.closest("[data-vb-touchsort-item]");
        if (!item) return;

        event.preventDefault();

        const point = getPoint(event);
        active = item;
        active.classList.add("is-dragging");
        createGhost(item, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;

        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);
        reorderAt(point.x, point.y);
      }

      function end() {
        cleanup();
        updateOutput();
      }

      function cancel() {
        cleanup();
        updateOutput();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateOutput();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initTouchSort);
  } else {
    initTouchSort();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initTouchSort() {
    document.querySelectorAll("[data-vb-touchsort]").forEach(function (root) {
      if (root.getAttribute("data-vb-touchsort-ready") === "1") return;
      root.setAttribute("data-vb-touchsort-ready", "1");

      const list = root.querySelector("[data-vb-touchsort-list]");
      const output = root.querySelector("[data-vb-touchsort-output]");
      let active = null;
      let ghost = null;

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function updateOutput() {
        output.textContent = Array.from(list.querySelectorAll("[data-vb-touchsort-item]"))
          .map(function (item) { return item.getAttribute("data-title"); })
          .join(" → ");
      }

      function createGhost(item, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-touchsort-ghost";
        ghost.innerHTML = "&lt;strong&gt;" + item.getAttribute("data-title") + "&lt;/strong&gt;";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 12 + "px";
        ghost.style.top = y + 12 + "px";
      }

      function clearOver() {
        list.querySelectorAll(".is-over").forEach(function (item) {
          item.classList.remove("is-over");
        });
      }

      function reorderAt(x, y) {
        const element = document.elementFromPoint(x, y);
        const target = element ? element.closest("[data-vb-touchsort-item]") : null;

        if (!target || target === active || !list.contains(target)) return;

        const rect = target.getBoundingClientRect();
        const after = y &gt; rect.top + rect.height / 2;

        clearOver();
        target.classList.add("is-over");

        if (after) {
          target.insertAdjacentElement("afterend", active);
        } else {
          target.insertAdjacentElement("beforebegin", active);
        }

        updateOutput();
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-touchsort-handle]");
        if (!handle) return;

        const item = handle.closest("[data-vb-touchsort-item]");
        if (!item) return;

        event.preventDefault();

        const point = getPoint(event);
        active = item;
        active.classList.add("is-dragging");
        createGhost(item, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;

        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);
        reorderAt(point.x, point.y);
      }

      function end() {
        cleanup();
        updateOutput();
      }

      function cancel() {
        cleanup();
        updateOutput();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateOutput();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initTouchSort);
  } else {
    initTouchSort();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-touchsort-demo"&gt;
  &lt;div class="vb-touchsort-wrap" data-vb-touchsort&gt;
    &lt;div class="vb-touchsort-head"&gt;
      &lt;span&gt;Example 28&lt;/span&gt;
      &lt;h3&gt;Mobile Touch Sort List&lt;/h3&gt;
      &lt;p&gt;Drag the handle on each card to reorder the mobile task list.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-touchsort-phone"&gt;
      &lt;div class="vb-touchsort-phone-top"&gt;
        &lt;span&gt;Today&lt;/span&gt;
        &lt;strong&gt;Priority List&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-touchsort-list" data-vb-touchsort-list&gt;
        &lt;article class="vb-touchsort-item" data-vb-touchsort-item data-title="Plan homepage layout"&gt;
          &lt;button type="button" data-vb-touchsort-handle aria-label="Drag item"&gt;⋮⋮&lt;/button&gt;
          &lt;div&gt;
            &lt;h4&gt;Plan homepage layout&lt;/h4&gt;
            &lt;p&gt;Define sections and CTA order&lt;/p&gt;
          &lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-touchsort-item" data-vb-touchsort-item data-title="Write service copy"&gt;
          &lt;button type="button" data-vb-touchsort-handle aria-label="Drag item"&gt;⋮⋮&lt;/button&gt;
          &lt;div&gt;
            &lt;h4&gt;Write service copy&lt;/h4&gt;
            &lt;p&gt;Create short conversion text&lt;/p&gt;
          &lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-touchsort-item" data-vb-touchsort-item data-title="Design contact form"&gt;
          &lt;button type="button" data-vb-touchsort-handle aria-label="Drag item"&gt;⋮⋮&lt;/button&gt;
          &lt;div&gt;
            &lt;h4&gt;Design contact form&lt;/h4&gt;
            &lt;p&gt;Make it fast and simple&lt;/p&gt;
          &lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-touchsort-item" data-vb-touchsort-item data-title="Test mobile view"&gt;
          &lt;button type="button" data-vb-touchsort-handle aria-label="Drag item"&gt;⋮⋮&lt;/button&gt;
          &lt;div&gt;
            &lt;h4&gt;Test mobile view&lt;/h4&gt;
            &lt;p&gt;Check spacing and buttons&lt;/p&gt;
          &lt;/div&gt;
        &lt;/article&gt;
      &lt;/div&gt;

      &lt;div class="vb-touchsort-output" data-vb-touchsort-output&gt;Plan homepage layout → Write service copy → Design contact form → Test mobile view&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-touchsort-demo,
.vb-touchsort-demo * {
  box-sizing: border-box;
}

.vb-touchsort-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(14, 165, 233, 0.16), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #ecfeff 0%, #eef2ff 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-touchsort-wrap {
  max-width: 960px;
  margin: 0 auto;
}

.vb-touchsort-head {
  max-width: 760px;
  margin: 0 auto 24px;
  text-align: center;
}

.vb-touchsort-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #cffafe;
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-touchsort-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-touchsort-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-touchsort-phone {
  max-width: 430px;
  margin: 0 auto;
  padding: 16px;
  border-radius: 36px;
  background: #0f172a;
  box-shadow: 0 26px 80px rgba(15, 23, 42, 0.25);
}

.vb-touchsort-phone-top {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: center;
  padding: 14px 14px 18px;
}

.vb-touchsort-phone-top span {
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-touchsort-phone-top strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-touchsort-list {
  display: grid;
  gap: 10px;
}

.vb-touchsort-item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 13px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(255, 255, 255, 0.16);
  box-shadow: 0 12px 26px rgba(0, 0, 0, 0.18);
}

.vb-touchsort-item.is-dragging {
  opacity: 0.38;
}

.vb-touchsort-item.is-over {
  outline: 3px solid rgba(34, 211, 238, 0.45);
}

.vb-touchsort-item button {
  width: 38px;
  height: 44px;
  border: 0;
  border-radius: 15px;
  background: #cffafe;
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 20px;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
}

.vb-touchsort-item h4 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px !important;
  line-height: 1.22 !important;
  font-weight: 950 !important;
}

.vb-touchsort-item p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.45;
  font-weight: 700;
}

.vb-touchsort-output {
  margin-top: 12px;
  padding: 13px;
  border-radius: 20px;
  background: rgba(255,255,255,0.08);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  line-height: 1.55;
  font-weight: 800;
}

.vb-touchsort-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(340px, calc(100vw - 28px));
  padding: 13px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(14, 165, 233, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.26);
}

.vb-touchsort-ghost strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 520px) {
  .vb-touchsort-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-touchsort-phone {
    border-radius: 28px;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript mobile-friendly touch drag and drop list is useful for task apps, priority lists, mobile dashboards, checklist builders, lesson ordering, and responsive admin interfaces.</p>



<h2 class="wp-block-heading">29. Accessible Drag and Drop List with Keyboard Controls</h2>



<p class="wp-block-paragraph"><strong>An accessible drag and drop list</strong> should not rely only on pointer movement. This example adds keyboard controls so users can select an item, move it up or down, and understand the current order through a live status message.</p>



<ul class="wp-block-list">
<li>Keyboard-friendly reorder buttons</li>
<li>Mouse and touch drag support</li>
<li>Screen-reader style live status</li>
<li>Automatic numbering</li>
<li>Useful for accessibility-focused interfaces</li>
</ul>



<div class="vb-a11ysort-demo">
  <div class="vb-a11ysort-wrap" data-vb-a11ysort>
    <div class="vb-a11ysort-head">
      <span>Example 29</span>
      <h3>Accessible Reorder List</h3>
      <p>Use drag handles, or use the up and down buttons to reorder each item without dragging.</p>
    </div>

    <div class="vb-a11ysort-card">
      <div class="vb-a11ysort-list" data-vb-a11ysort-list>
        <article class="vb-a11ysort-item" data-vb-a11ysort-item data-title="Account setup">
          <button type="button" class="vb-a11ysort-handle" data-vb-a11ysort-handle aria-label="Drag Account setup">⋮⋮</button>
          <span data-vb-a11ysort-number>1</span>
          <div>
            <h4>Account setup</h4>
            <p>Create user account and verify email.</p>
          </div>
          <div class="vb-a11ysort-actions">
            <button type="button" data-vb-a11ysort-up aria-label="Move Account setup up">↑</button>
            <button type="button" data-vb-a11ysort-down aria-label="Move Account setup down">↓</button>
          </div>
        </article>

        <article class="vb-a11ysort-item" data-vb-a11ysort-item data-title="Choose template">
          <button type="button" class="vb-a11ysort-handle" data-vb-a11ysort-handle aria-label="Drag Choose template">⋮⋮</button>
          <span data-vb-a11ysort-number>2</span>
          <div>
            <h4>Choose template</h4>
            <p>Select a design or starting layout.</p>
          </div>
          <div class="vb-a11ysort-actions">
            <button type="button" data-vb-a11ysort-up aria-label="Move Choose template up">↑</button>
            <button type="button" data-vb-a11ysort-down aria-label="Move Choose template down">↓</button>
          </div>
        </article>

        <article class="vb-a11ysort-item" data-vb-a11ysort-item data-title="Add content">
          <button type="button" class="vb-a11ysort-handle" data-vb-a11ysort-handle aria-label="Drag Add content">⋮⋮</button>
          <span data-vb-a11ysort-number>3</span>
          <div>
            <h4>Add content</h4>
            <p>Write page copy and add images.</p>
          </div>
          <div class="vb-a11ysort-actions">
            <button type="button" data-vb-a11ysort-up aria-label="Move Add content up">↑</button>
            <button type="button" data-vb-a11ysort-down aria-label="Move Add content down">↓</button>
          </div>
        </article>

        <article class="vb-a11ysort-item" data-vb-a11ysort-item data-title="Publish page">
          <button type="button" class="vb-a11ysort-handle" data-vb-a11ysort-handle aria-label="Drag Publish page">⋮⋮</button>
          <span data-vb-a11ysort-number>4</span>
          <div>
            <h4>Publish page</h4>
            <p>Review, test, and publish online.</p>
          </div>
          <div class="vb-a11ysort-actions">
            <button type="button" data-vb-a11ysort-up aria-label="Move Publish page up">↑</button>
            <button type="button" data-vb-a11ysort-down aria-label="Move Publish page down">↓</button>
          </div>
        </article>
      </div>

      <div class="vb-a11ysort-status" data-vb-a11ysort-status aria-live="polite">
        Current order: Account setup → Choose template → Add content → Publish page
      </div>
    </div>
  </div>
</div>

<style>
.vb-a11ysort-demo,
.vb-a11ysort-demo * {
  box-sizing: border-box;
}

.vb-a11ysort-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(168, 85, 247, 0.15), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(14, 165, 233, 0.15), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #ecfeff 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-a11ysort-wrap {
  max-width: 1040px;
  margin: 0 auto;
}

.vb-a11ysort-head {
  max-width: 800px;
  margin-bottom: 22px;
}

.vb-a11ysort-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-a11ysort-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-a11ysort-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-a11ysort-card {
  padding: 16px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-a11ysort-list {
  display: grid;
  gap: 12px;
}

.vb-a11ysort-item {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  padding: 14px;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.26);
}

.vb-a11ysort-item.is-dragging {
  opacity: 0.42;
}

.vb-a11ysort-item.is-over {
  outline: 3px solid rgba(168, 85, 247, 0.30);
}

.vb-a11ysort-handle {
  width: 38px;
  height: 44px;
  border: 0;
  border-radius: 14px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 20px;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
}

.vb-a11ysort-item > span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-a11ysort-item h4 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px !important;
  line-height: 1.22 !important;
  font-weight: 950 !important;
}

.vb-a11ysort-item p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.45;
  font-weight: 700;
}

.vb-a11ysort-actions {
  display: flex;
  gap: 8px;
}

.vb-a11ysort-actions button {
  width: 38px;
  height: 38px;
  border: 0;
  border-radius: 13px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
}

.vb-a11ysort-actions button:focus,
.vb-a11ysort-handle:focus {
  outline: 3px solid rgba(14, 165, 233, 0.65);
  outline-offset: 2px;
}

.vb-a11ysort-status {
  margin-top: 14px;
  padding: 14px 16px;
  border-radius: 18px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 800;
}

.vb-a11ysort-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(340px, calc(100vw - 28px));
  padding: 13px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(168, 85, 247, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.26);
}

.vb-a11ysort-ghost strong {
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 720px) {
  .vb-a11ysort-item {
    grid-template-columns: auto auto minmax(0, 1fr);
  }

  .vb-a11ysort-actions {
    grid-column: 1 / -1;
    justify-content: flex-end;
  }
}

@media (max-width: 480px) {
  .vb-a11ysort-item > span {
    display: none;
  }

  .vb-a11ysort-item {
    grid-template-columns: auto minmax(0, 1fr);
  }
}
</style>

<script>
(function () {
  function initA11ySort() {
    document.querySelectorAll("[data-vb-a11ysort]").forEach(function (root) {
      if (root.getAttribute("data-vb-a11ysort-ready") === "1") return;
      root.setAttribute("data-vb-a11ysort-ready", "1");

      const list = root.querySelector("[data-vb-a11ysort-list]");
      const status = root.querySelector("[data-vb-a11ysort-status]");
      let active = null;
      let ghost = null;

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function getItems() {
        return Array.from(list.querySelectorAll("[data-vb-a11ysort-item]"));
      }

      function updateStatus(message) {
        getItems().forEach(function (item, index) {
          const number = item.querySelector("[data-vb-a11ysort-number]");
          if (number) number.textContent = index + 1;
        });

        const order = getItems().map(function (item) {
          return item.getAttribute("data-title");
        }).join(" → ");

        status.textContent = message ? message + " Current order: " + order : "Current order: " + order;
      }

      function moveItem(item, direction) {
        if (direction === "up" && item.previousElementSibling) {
          list.insertBefore(item, item.previousElementSibling);
          updateStatus(item.getAttribute("data-title") + " moved up.");
        }

        if (direction === "down" && item.nextElementSibling) {
          list.insertBefore(item.nextElementSibling, item);
          updateStatus(item.getAttribute("data-title") + " moved down.");
        }
      }

      function createGhost(item, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-a11ysort-ghost";
        ghost.innerHTML = "<strong>" + item.getAttribute("data-title") + "</strong>";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 12 + "px";
        ghost.style.top = y + 12 + "px";
      }

      function clearOver() {
        list.querySelectorAll(".is-over").forEach(function (item) {
          item.classList.remove("is-over");
        });
      }

      function reorderAt(x, y) {
        const element = document.elementFromPoint(x, y);
        const target = element ? element.closest("[data-vb-a11ysort-item]") : null;

        if (!target || target === active || !list.contains(target)) return;

        const rect = target.getBoundingClientRect();
        const after = y > rect.top + rect.height / 2;

        clearOver();
        target.classList.add("is-over");

        if (after) {
          target.insertAdjacentElement("afterend", active);
        } else {
          target.insertAdjacentElement("beforebegin", active);
        }

        updateStatus("List reordered.");
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-a11ysort-handle]");
        if (!handle) return;

        const item = handle.closest("[data-vb-a11ysort-item]");
        if (!item) return;

        event.preventDefault();

        const point = getPoint(event);
        active = item;
        active.classList.add("is-dragging");
        createGhost(item, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;

        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);
        reorderAt(point.x, point.y);
      }

      function end() {
        cleanup();
        updateStatus("Drag reorder finished.");
      }

      function cancel() {
        cleanup();
        updateStatus("Drag cancelled.");
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("click", function (event) {
        const up = event.target.closest("[data-vb-a11ysort-up]");
        const down = event.target.closest("[data-vb-a11ysort-down]");

        if (up) moveItem(up.closest("[data-vb-a11ysort-item]"), "up");
        if (down) moveItem(down.closest("[data-vb-a11ysort-item]"), "down");
      });

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateStatus();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initA11ySort);
  } else {
    initA11ySort();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initA11ySort() {
    document.querySelectorAll("[data-vb-a11ysort]").forEach(function (root) {
      if (root.getAttribute("data-vb-a11ysort-ready") === "1") return;
      root.setAttribute("data-vb-a11ysort-ready", "1");

      const list = root.querySelector("[data-vb-a11ysort-list]");
      const status = root.querySelector("[data-vb-a11ysort-status]");
      let active = null;
      let ghost = null;

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function getItems() {
        return Array.from(list.querySelectorAll("[data-vb-a11ysort-item]"));
      }

      function updateStatus(message) {
        getItems().forEach(function (item, index) {
          const number = item.querySelector("[data-vb-a11ysort-number]");
          if (number) number.textContent = index + 1;
        });

        const order = getItems().map(function (item) {
          return item.getAttribute("data-title");
        }).join(" → ");

        status.textContent = message ? message + " Current order: " + order : "Current order: " + order;
      }

      function moveItem(item, direction) {
        if (direction === "up" &amp;&amp; item.previousElementSibling) {
          list.insertBefore(item, item.previousElementSibling);
          updateStatus(item.getAttribute("data-title") + " moved up.");
        }

        if (direction === "down" &amp;&amp; item.nextElementSibling) {
          list.insertBefore(item.nextElementSibling, item);
          updateStatus(item.getAttribute("data-title") + " moved down.");
        }
      }

      function createGhost(item, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-a11ysort-ghost";
        ghost.innerHTML = "&lt;strong&gt;" + item.getAttribute("data-title") + "&lt;/strong&gt;";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 12 + "px";
        ghost.style.top = y + 12 + "px";
      }

      function clearOver() {
        list.querySelectorAll(".is-over").forEach(function (item) {
          item.classList.remove("is-over");
        });
      }

      function reorderAt(x, y) {
        const element = document.elementFromPoint(x, y);
        const target = element ? element.closest("[data-vb-a11ysort-item]") : null;

        if (!target || target === active || !list.contains(target)) return;

        const rect = target.getBoundingClientRect();
        const after = y &gt; rect.top + rect.height / 2;

        clearOver();
        target.classList.add("is-over");

        if (after) {
          target.insertAdjacentElement("afterend", active);
        } else {
          target.insertAdjacentElement("beforebegin", active);
        }

        updateStatus("List reordered.");
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-a11ysort-handle]");
        if (!handle) return;

        const item = handle.closest("[data-vb-a11ysort-item]");
        if (!item) return;

        event.preventDefault();

        const point = getPoint(event);
        active = item;
        active.classList.add("is-dragging");
        createGhost(item, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;

        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);
        reorderAt(point.x, point.y);
      }

      function end() {
        cleanup();
        updateStatus("Drag reorder finished.");
      }

      function cancel() {
        cleanup();
        updateStatus("Drag cancelled.");
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("click", function (event) {
        const up = event.target.closest("[data-vb-a11ysort-up]");
        const down = event.target.closest("[data-vb-a11ysort-down]");

        if (up) moveItem(up.closest("[data-vb-a11ysort-item]"), "up");
        if (down) moveItem(down.closest("[data-vb-a11ysort-item]"), "down");
      });

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateStatus();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initA11ySort);
  } else {
    initA11ySort();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-a11ysort-demo"&gt;
  &lt;div class="vb-a11ysort-wrap" data-vb-a11ysort&gt;
    &lt;div class="vb-a11ysort-head"&gt;
      &lt;span&gt;Example 29&lt;/span&gt;
      &lt;h3&gt;Accessible Reorder List&lt;/h3&gt;
      &lt;p&gt;Use drag handles, or use the up and down buttons to reorder each item without dragging.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-a11ysort-card"&gt;
      &lt;div class="vb-a11ysort-list" data-vb-a11ysort-list&gt;
        &lt;article class="vb-a11ysort-item" data-vb-a11ysort-item data-title="Account setup"&gt;
          &lt;button type="button" class="vb-a11ysort-handle" data-vb-a11ysort-handle aria-label="Drag Account setup"&gt;⋮⋮&lt;/button&gt;
          &lt;span data-vb-a11ysort-number&gt;1&lt;/span&gt;
          &lt;div&gt;
            &lt;h4&gt;Account setup&lt;/h4&gt;
            &lt;p&gt;Create user account and verify email.&lt;/p&gt;
          &lt;/div&gt;
          &lt;div class="vb-a11ysort-actions"&gt;
            &lt;button type="button" data-vb-a11ysort-up aria-label="Move Account setup up"&gt;↑&lt;/button&gt;
            &lt;button type="button" data-vb-a11ysort-down aria-label="Move Account setup down"&gt;↓&lt;/button&gt;
          &lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-a11ysort-item" data-vb-a11ysort-item data-title="Choose template"&gt;
          &lt;button type="button" class="vb-a11ysort-handle" data-vb-a11ysort-handle aria-label="Drag Choose template"&gt;⋮⋮&lt;/button&gt;
          &lt;span data-vb-a11ysort-number&gt;2&lt;/span&gt;
          &lt;div&gt;
            &lt;h4&gt;Choose template&lt;/h4&gt;
            &lt;p&gt;Select a design or starting layout.&lt;/p&gt;
          &lt;/div&gt;
          &lt;div class="vb-a11ysort-actions"&gt;
            &lt;button type="button" data-vb-a11ysort-up aria-label="Move Choose template up"&gt;↑&lt;/button&gt;
            &lt;button type="button" data-vb-a11ysort-down aria-label="Move Choose template down"&gt;↓&lt;/button&gt;
          &lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-a11ysort-item" data-vb-a11ysort-item data-title="Add content"&gt;
          &lt;button type="button" class="vb-a11ysort-handle" data-vb-a11ysort-handle aria-label="Drag Add content"&gt;⋮⋮&lt;/button&gt;
          &lt;span data-vb-a11ysort-number&gt;3&lt;/span&gt;
          &lt;div&gt;
            &lt;h4&gt;Add content&lt;/h4&gt;
            &lt;p&gt;Write page copy and add images.&lt;/p&gt;
          &lt;/div&gt;
          &lt;div class="vb-a11ysort-actions"&gt;
            &lt;button type="button" data-vb-a11ysort-up aria-label="Move Add content up"&gt;↑&lt;/button&gt;
            &lt;button type="button" data-vb-a11ysort-down aria-label="Move Add content down"&gt;↓&lt;/button&gt;
          &lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-a11ysort-item" data-vb-a11ysort-item data-title="Publish page"&gt;
          &lt;button type="button" class="vb-a11ysort-handle" data-vb-a11ysort-handle aria-label="Drag Publish page"&gt;⋮⋮&lt;/button&gt;
          &lt;span data-vb-a11ysort-number&gt;4&lt;/span&gt;
          &lt;div&gt;
            &lt;h4&gt;Publish page&lt;/h4&gt;
            &lt;p&gt;Review, test, and publish online.&lt;/p&gt;
          &lt;/div&gt;
          &lt;div class="vb-a11ysort-actions"&gt;
            &lt;button type="button" data-vb-a11ysort-up aria-label="Move Publish page up"&gt;↑&lt;/button&gt;
            &lt;button type="button" data-vb-a11ysort-down aria-label="Move Publish page down"&gt;↓&lt;/button&gt;
          &lt;/div&gt;
        &lt;/article&gt;
      &lt;/div&gt;

      &lt;div class="vb-a11ysort-status" data-vb-a11ysort-status aria-live="polite"&gt;
        Current order: Account setup → Choose template → Add content → Publish page
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-a11ysort-demo,
.vb-a11ysort-demo * {
  box-sizing: border-box;
}

.vb-a11ysort-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(168, 85, 247, 0.15), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(14, 165, 233, 0.15), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #ecfeff 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-a11ysort-wrap {
  max-width: 1040px;
  margin: 0 auto;
}

.vb-a11ysort-head {
  max-width: 800px;
  margin-bottom: 22px;
}

.vb-a11ysort-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-a11ysort-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-a11ysort-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-a11ysort-card {
  padding: 16px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-a11ysort-list {
  display: grid;
  gap: 12px;
}

.vb-a11ysort-item {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  padding: 14px;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.26);
}

.vb-a11ysort-item.is-dragging {
  opacity: 0.42;
}

.vb-a11ysort-item.is-over {
  outline: 3px solid rgba(168, 85, 247, 0.30);
}

.vb-a11ysort-handle {
  width: 38px;
  height: 44px;
  border: 0;
  border-radius: 14px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 20px;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
}

.vb-a11ysort-item > span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-a11ysort-item h4 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px !important;
  line-height: 1.22 !important;
  font-weight: 950 !important;
}

.vb-a11ysort-item p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.45;
  font-weight: 700;
}

.vb-a11ysort-actions {
  display: flex;
  gap: 8px;
}

.vb-a11ysort-actions button {
  width: 38px;
  height: 38px;
  border: 0;
  border-radius: 13px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
}

.vb-a11ysort-actions button:focus,
.vb-a11ysort-handle:focus {
  outline: 3px solid rgba(14, 165, 233, 0.65);
  outline-offset: 2px;
}

.vb-a11ysort-status {
  margin-top: 14px;
  padding: 14px 16px;
  border-radius: 18px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 800;
}

.vb-a11ysort-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(340px, calc(100vw - 28px));
  padding: 13px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(168, 85, 247, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.26);
}

.vb-a11ysort-ghost strong {
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 720px) {
  .vb-a11ysort-item {
    grid-template-columns: auto auto minmax(0, 1fr);
  }

  .vb-a11ysort-actions {
    grid-column: 1 / -1;
    justify-content: flex-end;
  }
}

@media (max-width: 480px) {
  .vb-a11ysort-item > span {
    display: none;
  }

  .vb-a11ysort-item {
    grid-template-columns: auto minmax(0, 1fr);
  }
}</pre>



<p class="wp-block-paragraph">This accessible JavaScript drag and drop list is useful for admin dashboards, step ordering tools, onboarding builders, content workflows, accessibility-focused forms, and keyboard-friendly web interfaces.</p>



<h2 class="wp-block-heading">30. Complete Responsive Drag and Drop Project Planner</h2>



<p class="wp-block-paragraph"><strong>A complete responsive drag and drop project planner</strong> combines multiple practical ideas into one stronger UI: task columns, drag and drop cards, live counters, priority labels, and a project summary. It is useful for project dashboards, editorial calendars, agency workflows, client portals, team task boards, and SaaS productivity tools.</p>



<ul class="wp-block-list">
<li>Drag tasks between project columns</li>
<li>Live column counters</li>
<li>Mouse and touch support</li>
<li>Responsive board layout</li>
<li>Practical complete UI example</li>
</ul>



<div class="vb-projectplan-demo">
  <div class="vb-projectplan-wrap" data-vb-projectplan>
    <div class="vb-projectplan-head">
      <span>Example 30</span>
      <h3>Responsive Project Planner</h3>
      <p>Drag cards between columns to update the project status. Counters and summary update automatically.</p>
    </div>

    <div class="vb-projectplan-summary">
      <div>
        <span>Total tasks</span>
        <strong data-vb-projectplan-total>6</strong>
      </div>
      <div>
        <span>In progress</span>
        <strong data-vb-projectplan-column-count="progress">0</strong>
      </div>
      <div>
        <span>Done</span>
        <strong data-vb-projectplan-column-count="done">0</strong>
      </div>
    </div>

    <div class="vb-projectplan-board">
      <section class="vb-projectplan-column">
        <div class="vb-projectplan-column-head">
          <h4>Backlog</h4>
          <strong data-vb-projectplan-column-count="backlog">0</strong>
        </div>

        <div class="vb-projectplan-drop" data-vb-projectplan-drop data-column="backlog">
          <article class="vb-projectplan-card" data-vb-projectplan-card data-title="Create landing page wireframe">
            <button type="button" data-vb-projectplan-handle aria-label="Drag task">⋮⋮</button>
            <div>
              <span class="vb-projectplan-pill">Design</span>
              <h5>Create landing page wireframe</h5>
              <p>Plan hero, sections, CTA flow and mobile structure.</p>
            </div>
          </article>

          <article class="vb-projectplan-card" data-vb-projectplan-card data-title="Write SEO page copy">
            <button type="button" data-vb-projectplan-handle aria-label="Drag task">⋮⋮</button>
            <div>
              <span class="vb-projectplan-pill vb-projectplan-pill-green">Content</span>
              <h5>Write SEO page copy</h5>
              <p>Create clear headings, intro text and service descriptions.</p>
            </div>
          </article>
        </div>
      </section>

      <section class="vb-projectplan-column">
        <div class="vb-projectplan-column-head">
          <h4>In Progress</h4>
          <strong data-vb-projectplan-column-count="progress">0</strong>
        </div>

        <div class="vb-projectplan-drop" data-vb-projectplan-drop data-column="progress">
          <article class="vb-projectplan-card" data-vb-projectplan-card data-title="Build responsive CSS layout">
            <button type="button" data-vb-projectplan-handle aria-label="Drag task">⋮⋮</button>
            <div>
              <span class="vb-projectplan-pill vb-projectplan-pill-blue">Frontend</span>
              <h5>Build responsive CSS layout</h5>
              <p>Make the layout work on desktop, tablet and mobile.</p>
            </div>
          </article>

          <article class="vb-projectplan-card" data-vb-projectplan-card data-title="Connect quote request form">
            <button type="button" data-vb-projectplan-handle aria-label="Drag task">⋮⋮</button>
            <div>
              <span class="vb-projectplan-pill vb-projectplan-pill-orange">Forms</span>
              <h5>Connect quote request form</h5>
              <p>Send form data to email and save request details.</p>
            </div>
          </article>
        </div>
      </section>

      <section class="vb-projectplan-column">
        <div class="vb-projectplan-column-head">
          <h4>Review</h4>
          <strong data-vb-projectplan-column-count="review">0</strong>
        </div>

        <div class="vb-projectplan-drop" data-vb-projectplan-drop data-column="review">
          <article class="vb-projectplan-card" data-vb-projectplan-card data-title="Test contact page">
            <button type="button" data-vb-projectplan-handle aria-label="Drag task">⋮⋮</button>
            <div>
              <span class="vb-projectplan-pill vb-projectplan-pill-purple">QA</span>
              <h5>Test contact page</h5>
              <p>Check validation, email delivery and mobile spacing.</p>
            </div>
          </article>
        </div>
      </section>

      <section class="vb-projectplan-column">
        <div class="vb-projectplan-column-head">
          <h4>Done</h4>
          <strong data-vb-projectplan-column-count="done">0</strong>
        </div>

        <div class="vb-projectplan-drop" data-vb-projectplan-drop data-column="done">
          <article class="vb-projectplan-card" data-vb-projectplan-card data-title="Install analytics">
            <button type="button" data-vb-projectplan-handle aria-label="Drag task">⋮⋮</button>
            <div>
              <span class="vb-projectplan-pill vb-projectplan-pill-green">Tracking</span>
              <h5>Install analytics</h5>
              <p>Add tracking and conversion events.</p>
            </div>
          </article>
        </div>
      </section>
    </div>

    <div class="vb-projectplan-status" data-vb-projectplan-status>Drag a task card between project columns.</div>
  </div>
</div>

<style>
.vb-projectplan-demo,
.vb-projectplan-demo * {
  box-sizing: border-box;
}

.vb-projectplan-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(59, 130, 246, 0.16), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(16, 185, 129, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-projectplan-wrap {
  max-width: 1240px;
  margin: 0 auto;
}

.vb-projectplan-head {
  max-width: 860px;
  margin-bottom: 22px;
}

.vb-projectplan-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-projectplan-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-projectplan-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-projectplan-summary {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  margin-bottom: 16px;
}

.vb-projectplan-summary div {
  padding: 16px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-projectplan-summary span {
  display: block;
  margin-bottom: 6px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-projectplan-summary strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 30px;
  line-height: 1;
  font-weight: 950;
}

.vb-projectplan-board {
  display: grid;
  grid-template-columns: repeat(4, minmax(220px, 1fr));
  gap: 14px;
  overflow-x: auto;
  padding-bottom: 4px;
}

.vb-projectplan-column {
  min-width: 220px;
  padding: 14px;
  border-radius: 28px;
  background: rgba(255,255,255,0.78);
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-projectplan-column-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.vb-projectplan-column-head h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-projectplan-column-head strong {
  display: inline-flex;
  min-width: 34px;
  height: 32px;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-projectplan-drop {
  display: grid;
  align-content: start;
  gap: 10px;
  min-height: 360px;
  padding: 10px;
  border-radius: 22px;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  background: #f8fafc;
}

.vb-projectplan-drop.is-over {
  border-color: rgba(37, 99, 235, 0.88);
  background: #eff6ff;
  box-shadow: inset 0 0 0 4px rgba(37, 99, 235, 0.10);
}

.vb-projectplan-card {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 10px;
  align-items: flex-start;
  padding: 12px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 12px 26px rgba(15, 23, 42, 0.07);
}

.vb-projectplan-card.is-dragging {
  opacity: 0.42;
}

.vb-projectplan-card button {
  width: 34px;
  height: 42px;
  border: 0;
  border-radius: 13px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 18px;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
}

.vb-projectplan-pill {
  display: inline-flex;
  margin-bottom: 8px;
  padding: 5px 9px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-projectplan-pill-green {
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
}

.vb-projectplan-pill-blue {
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
}

.vb-projectplan-pill-orange {
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
}

.vb-projectplan-pill-purple {
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
}

.vb-projectplan-card h5 {
  margin: 0 0 6px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px !important;
  line-height: 1.24 !important;
  font-weight: 950 !important;
}

.vb-projectplan-card p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.5;
  font-weight: 700;
}

.vb-projectplan-status {
  margin-top: 16px;
  padding: 13px 15px;
  border-radius: 18px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-projectplan-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(320px, calc(100vw - 28px));
  padding: 13px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(37, 99, 235, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.26);
}

.vb-projectplan-ghost strong {
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vb-projectplan-summary {
    grid-template-columns: 1fr;
  }

  .vb-projectplan-board {
    grid-template-columns: repeat(4, minmax(250px, 1fr));
  }
}

@media (max-width: 520px) {
  .vb-projectplan-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-projectplan-column {
    min-width: 250px;
  }
}
</style>

<script>
(function () {
  function initProjectPlanner() {
    document.querySelectorAll("[data-vb-projectplan]").forEach(function (root) {
      if (root.getAttribute("data-vb-projectplan-ready") === "1") return;
      root.setAttribute("data-vb-projectplan-ready", "1");

      const drops = Array.from(root.querySelectorAll("[data-vb-projectplan-drop]"));
      const total = root.querySelector("[data-vb-projectplan-total]");
      const status = root.querySelector("[data-vb-projectplan-status]");
      let active = null;
      let ghost = null;

      function getPoint(event) {
        if (event.touches && event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches && event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function updateCounts() {
        const allCards = root.querySelectorAll("[data-vb-projectplan-card]");
        total.textContent = allCards.length;

        drops.forEach(function (drop) {
          const column = drop.getAttribute("data-column");
          const countEls = root.querySelectorAll('[data-vb-projectplan-column-count="' + column + '"]');
          countEls.forEach(function (countEl) {
            countEl.textContent = drop.querySelectorAll("[data-vb-projectplan-card]").length;
          });
        });
      }

      function getDropAt(x, y) {
        const element = document.elementFromPoint(x, y);
        if (!element) return null;
        const drop = element.closest("[data-vb-projectplan-drop]");
        return drops.includes(drop) ? drop : null;
      }

      function clearOver() {
        drops.forEach(function (drop) {
          drop.classList.remove("is-over");
        });
      }

      function createGhost(card, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-projectplan-ghost";
        ghost.innerHTML = "<strong>" + card.getAttribute("data-title") + "</strong>";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 12 + "px";
        ghost.style.top = y + 12 + "px";
      }

      function placeCardInDrop(drop, x, y) {
        const cards = Array.from(drop.querySelectorAll("[data-vb-projectplan-card]")).filter(function (card) {
          return card !== active;
        });

        let placed = false;

        cards.forEach(function (card) {
          if (placed) return;

          const rect = card.getBoundingClientRect();
          if (y < rect.top + rect.height / 2) {
            drop.insertBefore(active, card);
            placed = true;
          }
        });

        if (!placed) {
          drop.appendChild(active);
        }
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-projectplan-handle]");
        if (!handle) return;

        const card = handle.closest("[data-vb-projectplan-card]");
        if (!card) return;

        event.preventDefault();

        const point = getPoint(event);
        active = card;
        active.classList.add("is-dragging");
        createGhost(card, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;

        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);
        clearOver();

        const drop = getDropAt(point.x, point.y);
        if (drop) {
          drop.classList.add("is-over");
          placeCardInDrop(drop, point.x, point.y);
          updateCounts();
        }
      }

      function end(event) {
        if (!active) return;

        const point = getPoint(event);
        const drop = getDropAt(point.x, point.y);

        if (drop) {
          status.textContent = active.getAttribute("data-title") + " moved to " + drop.getAttribute("data-column") + ".";
        }

        cleanup();
        updateCounts();
      }

      function cancel() {
        cleanup();
        updateCounts();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateCounts();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initProjectPlanner);
  } else {
    initProjectPlanner();
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  function initProjectPlanner() {
    document.querySelectorAll("[data-vb-projectplan]").forEach(function (root) {
      if (root.getAttribute("data-vb-projectplan-ready") === "1") return;
      root.setAttribute("data-vb-projectplan-ready", "1");

      const drops = Array.from(root.querySelectorAll("[data-vb-projectplan-drop]"));
      const total = root.querySelector("[data-vb-projectplan-total]");
      const status = root.querySelector("[data-vb-projectplan-status]");
      let active = null;
      let ghost = null;

      function getPoint(event) {
        if (event.touches &amp;&amp; event.touches.length) return { x: event.touches[0].clientX, y: event.touches[0].clientY };
        if (event.changedTouches &amp;&amp; event.changedTouches.length) return { x: event.changedTouches[0].clientX, y: event.changedTouches[0].clientY };
        return { x: event.clientX, y: event.clientY };
      }

      function updateCounts() {
        const allCards = root.querySelectorAll("[data-vb-projectplan-card]");
        total.textContent = allCards.length;

        drops.forEach(function (drop) {
          const column = drop.getAttribute("data-column");
          const countEls = root.querySelectorAll('[data-vb-projectplan-column-count="' + column + '"]');
          countEls.forEach(function (countEl) {
            countEl.textContent = drop.querySelectorAll("[data-vb-projectplan-card]").length;
          });
        });
      }

      function getDropAt(x, y) {
        const element = document.elementFromPoint(x, y);
        if (!element) return null;
        const drop = element.closest("[data-vb-projectplan-drop]");
        return drops.includes(drop) ? drop : null;
      }

      function clearOver() {
        drops.forEach(function (drop) {
          drop.classList.remove("is-over");
        });
      }

      function createGhost(card, x, y) {
        ghost = document.createElement("div");
        ghost.className = "vb-projectplan-ghost";
        ghost.innerHTML = "&lt;strong&gt;" + card.getAttribute("data-title") + "&lt;/strong&gt;";
        document.body.appendChild(ghost);
        moveGhost(x, y);
      }

      function moveGhost(x, y) {
        if (!ghost) return;
        ghost.style.left = x + 12 + "px";
        ghost.style.top = y + 12 + "px";
      }

      function placeCardInDrop(drop, x, y) {
        const cards = Array.from(drop.querySelectorAll("[data-vb-projectplan-card]")).filter(function (card) {
          return card !== active;
        });

        let placed = false;

        cards.forEach(function (card) {
          if (placed) return;

          const rect = card.getBoundingClientRect();
          if (y &lt; rect.top + rect.height / 2) {
            drop.insertBefore(active, card);
            placed = true;
          }
        });

        if (!placed) {
          drop.appendChild(active);
        }
      }

      function start(event) {
        const handle = event.target.closest("[data-vb-projectplan-handle]");
        if (!handle) return;

        const card = handle.closest("[data-vb-projectplan-card]");
        if (!card) return;

        event.preventDefault();

        const point = getPoint(event);
        active = card;
        active.classList.add("is-dragging");
        createGhost(card, point.x, point.y);

        document.addEventListener("mousemove", move);
        document.addEventListener("mouseup", end);
        document.addEventListener("touchmove", move, { passive: false });
        document.addEventListener("touchend", end);
        document.addEventListener("touchcancel", cancel);
      }

      function move(event) {
        if (!active) return;

        event.preventDefault();

        const point = getPoint(event);
        moveGhost(point.x, point.y);
        clearOver();

        const drop = getDropAt(point.x, point.y);
        if (drop) {
          drop.classList.add("is-over");
          placeCardInDrop(drop, point.x, point.y);
          updateCounts();
        }
      }

      function end(event) {
        if (!active) return;

        const point = getPoint(event);
        const drop = getDropAt(point.x, point.y);

        if (drop) {
          status.textContent = active.getAttribute("data-title") + " moved to " + drop.getAttribute("data-column") + ".";
        }

        cleanup();
        updateCounts();
      }

      function cancel() {
        cleanup();
        updateCounts();
      }

      function cleanup() {
        if (active) active.classList.remove("is-dragging");
        if (ghost) ghost.remove();

        active = null;
        ghost = null;
        clearOver();

        document.removeEventListener("mousemove", move);
        document.removeEventListener("mouseup", end);
        document.removeEventListener("touchmove", move);
        document.removeEventListener("touchend", end);
        document.removeEventListener("touchcancel", cancel);
      }

      root.addEventListener("mousedown", start);
      root.addEventListener("touchstart", start, { passive: false });
      updateCounts();
    });
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", initProjectPlanner);
  } else {
    initProjectPlanner();
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-projectplan-demo"&gt;
  &lt;div class="vb-projectplan-wrap" data-vb-projectplan&gt;
    &lt;div class="vb-projectplan-head"&gt;
      &lt;span&gt;Example 30&lt;/span&gt;
      &lt;h3&gt;Responsive Project Planner&lt;/h3&gt;
      &lt;p&gt;Drag cards between columns to update the project status. Counters and summary update automatically.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-projectplan-summary"&gt;
      &lt;div&gt;
        &lt;span&gt;Total tasks&lt;/span&gt;
        &lt;strong data-vb-projectplan-total&gt;6&lt;/strong&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;span&gt;In progress&lt;/span&gt;
        &lt;strong data-vb-projectplan-column-count="progress"&gt;0&lt;/strong&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;span&gt;Done&lt;/span&gt;
        &lt;strong data-vb-projectplan-column-count="done"&gt;0&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-projectplan-board"&gt;
      &lt;section class="vb-projectplan-column"&gt;
        &lt;div class="vb-projectplan-column-head"&gt;
          &lt;h4&gt;Backlog&lt;/h4&gt;
          &lt;strong data-vb-projectplan-column-count="backlog"&gt;0&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-projectplan-drop" data-vb-projectplan-drop data-column="backlog"&gt;
          &lt;article class="vb-projectplan-card" data-vb-projectplan-card data-title="Create landing page wireframe"&gt;
            &lt;button type="button" data-vb-projectplan-handle aria-label="Drag task"&gt;⋮⋮&lt;/button&gt;
            &lt;div&gt;
              &lt;span class="vb-projectplan-pill"&gt;Design&lt;/span&gt;
              &lt;h5&gt;Create landing page wireframe&lt;/h5&gt;
              &lt;p&gt;Plan hero, sections, CTA flow and mobile structure.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/article&gt;

          &lt;article class="vb-projectplan-card" data-vb-projectplan-card data-title="Write SEO page copy"&gt;
            &lt;button type="button" data-vb-projectplan-handle aria-label="Drag task"&gt;⋮⋮&lt;/button&gt;
            &lt;div&gt;
              &lt;span class="vb-projectplan-pill vb-projectplan-pill-green"&gt;Content&lt;/span&gt;
              &lt;h5&gt;Write SEO page copy&lt;/h5&gt;
              &lt;p&gt;Create clear headings, intro text and service descriptions.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/article&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-projectplan-column"&gt;
        &lt;div class="vb-projectplan-column-head"&gt;
          &lt;h4&gt;In Progress&lt;/h4&gt;
          &lt;strong data-vb-projectplan-column-count="progress"&gt;0&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-projectplan-drop" data-vb-projectplan-drop data-column="progress"&gt;
          &lt;article class="vb-projectplan-card" data-vb-projectplan-card data-title="Build responsive CSS layout"&gt;
            &lt;button type="button" data-vb-projectplan-handle aria-label="Drag task"&gt;⋮⋮&lt;/button&gt;
            &lt;div&gt;
              &lt;span class="vb-projectplan-pill vb-projectplan-pill-blue"&gt;Frontend&lt;/span&gt;
              &lt;h5&gt;Build responsive CSS layout&lt;/h5&gt;
              &lt;p&gt;Make the layout work on desktop, tablet and mobile.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/article&gt;

          &lt;article class="vb-projectplan-card" data-vb-projectplan-card data-title="Connect quote request form"&gt;
            &lt;button type="button" data-vb-projectplan-handle aria-label="Drag task"&gt;⋮⋮&lt;/button&gt;
            &lt;div&gt;
              &lt;span class="vb-projectplan-pill vb-projectplan-pill-orange"&gt;Forms&lt;/span&gt;
              &lt;h5&gt;Connect quote request form&lt;/h5&gt;
              &lt;p&gt;Send form data to email and save request details.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/article&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-projectplan-column"&gt;
        &lt;div class="vb-projectplan-column-head"&gt;
          &lt;h4&gt;Review&lt;/h4&gt;
          &lt;strong data-vb-projectplan-column-count="review"&gt;0&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-projectplan-drop" data-vb-projectplan-drop data-column="review"&gt;
          &lt;article class="vb-projectplan-card" data-vb-projectplan-card data-title="Test contact page"&gt;
            &lt;button type="button" data-vb-projectplan-handle aria-label="Drag task"&gt;⋮⋮&lt;/button&gt;
            &lt;div&gt;
              &lt;span class="vb-projectplan-pill vb-projectplan-pill-purple"&gt;QA&lt;/span&gt;
              &lt;h5&gt;Test contact page&lt;/h5&gt;
              &lt;p&gt;Check validation, email delivery and mobile spacing.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/article&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-projectplan-column"&gt;
        &lt;div class="vb-projectplan-column-head"&gt;
          &lt;h4&gt;Done&lt;/h4&gt;
          &lt;strong data-vb-projectplan-column-count="done"&gt;0&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-projectplan-drop" data-vb-projectplan-drop data-column="done"&gt;
          &lt;article class="vb-projectplan-card" data-vb-projectplan-card data-title="Install analytics"&gt;
            &lt;button type="button" data-vb-projectplan-handle aria-label="Drag task"&gt;⋮⋮&lt;/button&gt;
            &lt;div&gt;
              &lt;span class="vb-projectplan-pill vb-projectplan-pill-green"&gt;Tracking&lt;/span&gt;
              &lt;h5&gt;Install analytics&lt;/h5&gt;
              &lt;p&gt;Add tracking and conversion events.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/article&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;

    &lt;div class="vb-projectplan-status" data-vb-projectplan-status&gt;Drag a task card between project columns.&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-projectplan-demo,
.vb-projectplan-demo * {
  box-sizing: border-box;
}

.vb-projectplan-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(59, 130, 246, 0.16), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(16, 185, 129, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-projectplan-wrap {
  max-width: 1240px;
  margin: 0 auto;
}

.vb-projectplan-head {
  max-width: 860px;
  margin-bottom: 22px;
}

.vb-projectplan-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-projectplan-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-projectplan-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-projectplan-summary {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  margin-bottom: 16px;
}

.vb-projectplan-summary div {
  padding: 16px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-projectplan-summary span {
  display: block;
  margin-bottom: 6px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-projectplan-summary strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 30px;
  line-height: 1;
  font-weight: 950;
}

.vb-projectplan-board {
  display: grid;
  grid-template-columns: repeat(4, minmax(220px, 1fr));
  gap: 14px;
  overflow-x: auto;
  padding-bottom: 4px;
}

.vb-projectplan-column {
  min-width: 220px;
  padding: 14px;
  border-radius: 28px;
  background: rgba(255,255,255,0.78);
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb-projectplan-column-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.vb-projectplan-column-head h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-projectplan-column-head strong {
  display: inline-flex;
  min-width: 34px;
  height: 32px;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-projectplan-drop {
  display: grid;
  align-content: start;
  gap: 10px;
  min-height: 360px;
  padding: 10px;
  border-radius: 22px;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  background: #f8fafc;
}

.vb-projectplan-drop.is-over {
  border-color: rgba(37, 99, 235, 0.88);
  background: #eff6ff;
  box-shadow: inset 0 0 0 4px rgba(37, 99, 235, 0.10);
}

.vb-projectplan-card {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 10px;
  align-items: flex-start;
  padding: 12px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 12px 26px rgba(15, 23, 42, 0.07);
}

.vb-projectplan-card.is-dragging {
  opacity: 0.42;
}

.vb-projectplan-card button {
  width: 34px;
  height: 42px;
  border: 0;
  border-radius: 13px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 18px;
  font-weight: 950;
  cursor: grab;
  touch-action: none;
}

.vb-projectplan-pill {
  display: inline-flex;
  margin-bottom: 8px;
  padding: 5px 9px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-projectplan-pill-green {
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
}

.vb-projectplan-pill-blue {
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
}

.vb-projectplan-pill-orange {
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
}

.vb-projectplan-pill-purple {
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
}

.vb-projectplan-card h5 {
  margin: 0 0 6px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px !important;
  line-height: 1.24 !important;
  font-weight: 950 !important;
}

.vb-projectplan-card p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.5;
  font-weight: 700;
}

.vb-projectplan-status {
  margin-top: 16px;
  padding: 13px 15px;
  border-radius: 18px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-projectplan-ghost {
  position: fixed;
  z-index: 999999;
  pointer-events: none;
  width: min(320px, calc(100vw - 28px));
  padding: 13px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(37, 99, 235, 0.55);
  box-shadow: 0 24px 60px rgba(15, 23, 42, 0.26);
}

.vb-projectplan-ghost strong {
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 14px;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vb-projectplan-summary {
    grid-template-columns: 1fr;
  }

  .vb-projectplan-board {
    grid-template-columns: repeat(4, minmax(250px, 1fr));
  }
}

@media (max-width: 520px) {
  .vb-projectplan-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-projectplan-column {
    min-width: 250px;
  }
}</pre>



<p class="wp-block-paragraph">This complete responsive JavaScript drag and drop project planner is useful for project dashboards, agency workflows, client portals, editorial calendars, team boards, productivity apps, and SaaS task management interfaces.</p>



<div class="vb24-drag-bottom-ad">
  <a class="vb24-drag-bottom-ad-card" href="https://veebilehed24.ee/en/shop/entityschema-pro/" target="_blank" rel="sponsored noopener">
    <div class="vb24-drag-bottom-ad-media">
      <img decoding="async" src="https://veebilehed24.ee/wp-content/uploads/2026/03/entityschema-cover-600x400.webp" width="600" height="400" alt="EntitySchema Pro WordPress structured data and entity SEO plugin" loading="lazy">
    </div>

    <div class="vb24-drag-bottom-ad-content">
      <span>WordPress SEO Plugin</span>
      <h2>EntitySchema Pro</h2>
      <p>Build a stronger entity-based structured data system for WordPress, modern SEO, AI-readable content, schema markup, and better search visibility.</p>

      <div class="vb24-drag-bottom-ad-price">
        <div>
          <small>Sale price</small>
          <del>89€</del>
        </div>
        <strong>29€</strong>
        <em>Save 60€</em>
      </div>

      <b>View Plugin</b>
    </div>
  </a>
</div>

<style>
.vb24-drag-bottom-ad,
.vb24-drag-bottom-ad * {
  box-sizing: border-box;
}

.vb24-drag-bottom-ad {
  margin: 52px 0 46px;
}

.vb24-drag-bottom-ad-card {
  display: grid;
  grid-template-columns: minmax(260px, 0.9fr) minmax(0, 1.1fr);
  gap: 0;
  overflow: hidden;
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 211, 238, 0.26), transparent 34%),
    radial-gradient(circle at 88% 14%, rgba(236, 72, 153, 0.24), transparent 36%),
    linear-gradient(135deg, #111827 0%, #312e81 52%, #701a75 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.22);
  text-decoration: none !important;
}

.vb24-drag-bottom-ad-media {
  min-height: 100%;
  background: rgba(255,255,255,0.08);
}

.vb24-drag-bottom-ad-media img {
  display: block;
  width: 100%;
  height: 100%;
  min-height: 320px;
  object-fit: cover;
}

.vb24-drag-bottom-ad-content {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(24px, 5vw, 46px);
}

.vb24-drag-bottom-ad-content span {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.18);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb24-drag-bottom-ad-content h2 {
  margin: 0 0 12px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb24-drag-bottom-ad-content p {
  margin: 0 0 20px !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb24-drag-bottom-ad-price {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  margin-bottom: 18px;
  padding: 14px;
  border-radius: 20px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.16);
}

.vb24-drag-bottom-ad-price div {
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.vb24-drag-bottom-ad-price small {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb24-drag-bottom-ad-price del {
  color: rgba(255,255,255,0.62) !important;
  -webkit-text-fill-color: rgba(255,255,255,0.62) !important;
  font-size: 16px;
  font-weight: 850;
  text-decoration-color: rgba(248, 113, 113, 0.95);
  text-decoration-thickness: 2px;
}

.vb24-drag-bottom-ad-price strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 38px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb24-drag-bottom-ad-price em {
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.18);
  border: 1px solid rgba(74, 222, 128, 0.34);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-style: normal;
  font-weight: 950;
}

.vb24-drag-bottom-ad-content b {
  display: inline-flex;
  align-self: flex-start;
  min-height: 46px;
  align-items: center;
  justify-content: center;
  padding: 12px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22d3ee, #2563eb 55%, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 14px 34px rgba(37, 99, 235, 0.30);
}

@media (max-width: 780px) {
  .vb24-drag-bottom-ad-card {
    grid-template-columns: 1fr;
  }

  .vb24-drag-bottom-ad-media img {
    min-height: 220px;
  }
}
</style>



<h2 class="wp-block-heading" id="javascript-drag-and-drop-best-practices">JavaScript Drag and Drop Best Practices</h2>



<p class="wp-block-paragraph">JavaScript drag and drop interfaces work best when the user always understands what can be moved, where it can be dropped, and what changed after the drop action. A good drag and drop component should feel smooth, predictable, responsive, and safe to use.</p>



<p class="wp-block-paragraph">For simple desktop-only features, the native HTML Drag and Drop API can be enough. For mobile-friendly components, custom pointer, mouse, and touch logic is often more reliable because touch support for native drag behavior is limited and inconsistent across devices. That is why many of the examples in this guide use controlled drag handles, custom floating previews, drop-zone detection, and scoped JavaScript logic.</p>



<ul class="wp-block-list">
  <li><strong>Use clear drag handles</strong> so users know exactly where to start the drag action.</li>
  <li><strong>Highlight active drop zones</strong> when a draggable item is over a valid target.</li>
  <li><strong>Show drag feedback</strong> with opacity, ghost previews, outlines, shadows, or helper labels.</li>
  <li><strong>Update the interface immediately</strong> after the drop action, including counters, labels, totals, order numbers, and status text.</li>
  <li><strong>Prevent duplicate items</strong> in features such as saved lists, comparison builders, favorites, carts, and assigned users.</li>
  <li><strong>Validate dropped files</strong> before previewing images, showing progress, or sending upload data to the server.</li>
  <li><strong>Keep JavaScript scoped</strong> so several drag and drop examples can run on the same WordPress post without conflicts.</li>
  <li><strong>Use unique class names</strong> for every demo, especially inside Gutenberg where multiple code examples appear on the same page.</li>
  <li><strong>Make long boards scrollable</strong> so Kanban columns, galleries, dashboards, and project planners remain usable on smaller screens.</li>
  <li><strong>Add accessible alternatives</strong> such as move up/down buttons, keyboard controls, clear labels, and live status messages.</li>
</ul>



<p class="wp-block-paragraph">For real production websites, also think about saving the final order or state. A sortable list may need to save item order in a database, a Kanban board may need to send updated card status to an API, and a dashboard builder may need to remember widget placement for each user. For that, drag and drop logic can be combined with <a href="https://veebilehed24.ee/en/blog/javascript/javascript-localstorage-examples/">JavaScript localStorage</a> for simple browser storage or <a href="https://veebilehed24.ee/en/blog/javascript/javascript-fetch-api-examples/">JavaScript Fetch API</a> for server-side saving.</p>



<h2 class="wp-block-heading" id="responsive-drag-and-drop-ui-tips">Responsive Drag and Drop UI Tips</h2>



<p class="wp-block-paragraph">Responsive drag and drop design is not only about making the layout smaller. A drag interface that works well on a large desktop screen can become difficult on a phone if the drag handle is too small, the drop zone is hidden, or the board requires too much horizontal movement.</p>



<p class="wp-block-paragraph">On mobile screens, drag and drop should use larger touch targets, clear spacing, scrollable containers, and simple movement rules. A mobile task list should not require pixel-perfect dragging. A Kanban board may need horizontal scrolling. A file upload area should still include a normal file input button because some users may prefer tapping instead of dragging files.</p>



<div class="vb24-drag-tip-grid">
  <div>
    <h3>Use large touch handles</h3>
    <p>Small icons are hard to drag on mobile. Use visible handles with enough width and height for touch users.</p>
  </div>

  <div>
    <h3>Keep drop zones visible</h3>
    <p>Users should not have to guess where a card, file, tag, widget, or task can be dropped.</p>
  </div>

  <div>
    <h3>Support scrolling layouts</h3>
    <p>Kanban boards, galleries, dashboards, and planners often need horizontal or vertical scrolling on smaller screens.</p>
  </div>

  <div>
    <h3>Provide fallback controls</h3>
    <p>Use buttons, inputs, or keyboard controls when dragging is not the easiest interaction for every user.</p>
  </div>
</div>

<style>
.vb24-drag-tip-grid,
.vb24-drag-tip-grid * {
  box-sizing: border-box;
}

.vb24-drag-tip-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 30px;
}

.vb24-drag-tip-grid div {
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 18% 10%, rgba(37, 99, 235, 0.10), transparent 32%),
    linear-gradient(135deg, #ffffff, #eff6ff) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb24-drag-tip-grid h3 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.25 !important;
  font-weight: 900 !important;
}

.vb24-drag-tip-grid p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

@media (max-width: 980px) {
  .vb24-drag-tip-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-drag-tip-grid {
    grid-template-columns: 1fr;
  }
}
</style>



<p class="wp-block-paragraph">For the best mobile experience, test the feature on an actual phone, not only inside a desktop browser preview. Check whether the page scrolls correctly, whether dragging blocks unwanted page movement, whether touch targets are large enough, and whether the drop result is clear after the user releases the item.</p>



<h2 class="wp-block-heading" id="common-javascript-drag-and-drop-mistakes">Common JavaScript Drag and Drop Mistakes</h2>



<p class="wp-block-paragraph">Many drag and drop interfaces look good in a demo but become frustrating in real use. The most common mistakes happen when the interaction has weak feedback, no mobile support, no accessible alternative, or unclear drop logic.</p>



<ul class="wp-block-list">
  <li><strong>Using only native drag events for mobile UI</strong> without testing touch behavior on phones and tablets.</li>
  <li><strong>Making the whole card draggable</strong> when the card also contains buttons, links, inputs, or other interactive elements.</li>
  <li><strong>Not showing a clear drop target</strong> so users do not know where the item will land.</li>
  <li><strong>Forgetting duplicate protection</strong> in favorites, comparison tables, carts, saved lists, and assignment tools.</li>
  <li><strong>Not updating counters or order labels</strong> after items are moved.</li>
  <li><strong>Making columns too narrow</strong> so task cards become cramped and hard to drag.</li>
  <li><strong>Ignoring empty states</strong> when all items have been moved out of a list or column.</li>
  <li><strong>Not validating uploaded files</strong> before previewing or simulating progress.</li>
  <li><strong>Using global selectors carelessly</strong> so one example breaks another example on the same WordPress page.</li>
  <li><strong>Forgetting accessibility</strong> by giving users no keyboard or button-based alternative to dragging.</li>
</ul>



<p class="wp-block-paragraph">A strong drag and drop UI should not surprise the user. When a card is moved, the new position should be obvious. When a file is dropped, the file name, preview, validation result, or progress state should appear. When a task moves to another column, the counter and status label should update immediately.</p>



<h2 class="wp-block-heading" id="javascript-drag-and-drop-faq">JavaScript Drag and Drop FAQ</h2>



<div class="vb24-drag-faq">
  <details>
    <summary>What is JavaScript drag and drop?</summary>
    <p>JavaScript drag and drop is an interaction pattern that lets users move items on a web page. It can be used for sortable lists, Kanban boards, upload zones, image galleries, form builders, dashboard layouts, menu builders, carts, comparison tools, and project planners.</p>
  </details>

  <details>
    <summary>Should I use the HTML Drag and Drop API or custom JavaScript events?</summary>
    <p>The HTML Drag and Drop API is useful for simple desktop interactions and file drop zones. Custom mouse, touch, or pointer logic is often better for mobile-friendly sorting, cards, dashboards, touch lists, and complex UI layouts.</p>
  </details>

  <details>
    <summary>Does native drag and drop work well on mobile?</summary>
    <p>Native HTML drag and drop is not always reliable on touch devices. For mobile-friendly drag and drop, use larger drag handles, touch events, pointer events, floating previews, and clear drop feedback.</p>
  </details>

  <details>
    <summary>Can JavaScript drag and drop upload files to a server?</summary>
    <p>Dragging files into a browser can select and preview files, but real uploading requires server-side handling or an API endpoint. A front-end demo can simulate progress, but production uploads need validation, security checks, storage logic, and server-side processing.</p>
  </details>

  <details>
    <summary>How do I save the new order after drag and drop?</summary>
    <p>You can save order in the browser with <code>localStorage</code> for simple UI preferences. For real apps, send the updated order to a backend using <code>fetch()</code> and store it in a database.</p>
  </details>

  <details>
    <summary>How do I make drag and drop accessible?</summary>
    <p>Add non-drag alternatives such as move up/down buttons, clear focus styles, status messages with <code>aria-live</code>, keyboard controls, readable labels, and simple instructions. Users should not be forced to use only a mouse or touch drag gesture.</p>
  </details>

  <details>
    <summary>Why does my drag and drop code break inside WordPress?</summary>
    <p>WordPress pages often include many blocks, scripts, and repeated examples. Use unique class names, scoped selectors, wrapper attributes, and initialization guards so one demo does not affect another demo on the same page.</p>
  </details>

  <details>
    <summary>Can I use drag and drop without external libraries?</summary>
    <p>Yes. All examples in this guide use vanilla JavaScript. External libraries can help with advanced sorting and animation, but many practical drag and drop interfaces can be built with plain HTML, CSS, and JavaScript.</p>
  </details>
</div>

<style>
.vb24-drag-faq,
.vb24-drag-faq * {
  box-sizing: border-box;
}

.vb24-drag-faq {
  display: grid;
  gap: 12px;
  margin: 24px 0 34px;
}

.vb24-drag-faq details {
  overflow: hidden;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb24-drag-faq summary {
  position: relative;
  cursor: pointer;
  padding: 18px 62px 18px 20px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 17px;
  line-height: 1.35;
  font-weight: 900;
  list-style: none;
}

.vb24-drag-faq summary::-webkit-details-marker {
  display: none;
}

.vb24-drag-faq summary::after {
  content: "+";
  position: absolute;
  right: 18px;
  top: 50%;
  width: 30px;
  height: 30px;
  transform: translateY(-50%);
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #7c3aed, #f97316);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  line-height: 1;
  font-weight: 950;
}

.vb24-drag-faq details[open] summary::after {
  content: "–";
}

.vb24-drag-faq p {
  margin: 0 !important;
  padding: 0 20px 18px;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb24-drag-faq code {
  padding: 2px 6px;
  border-radius: 7px;
  background: #f1f5f9;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 0.92em;
  font-weight: 800;
}

@media (max-width: 640px) {
  .vb24-drag-faq summary {
    padding: 16px 50px 16px 16px;
    font-size: 16px;
  }

  .vb24-drag-faq p {
    padding: 0 16px 16px;
  }
}
</style>



<h2 class="wp-block-heading" id="javascript-drag-and-drop-conclusion">Conclusion</h2>



<p class="wp-block-paragraph">JavaScript drag and drop features can turn a normal website into a more interactive tool. They help users reorder tasks, organize galleries, move cards between columns, upload files, assign people, build forms, arrange widgets, compare products, save favorites, and manage project workflows directly inside the interface.</p>



<p class="wp-block-paragraph">The 30 examples in this guide show how flexible vanilla JavaScript can be. You can build sortable task lists, Kanban boards, drag and drop file upload zones, image previews, shopping cart interactions, team assignment boards, timeline builders, tag organizers, touch-friendly mobile lists, accessible reorder lists, and complete project planners without relying on a heavy framework.</p>



<p class="wp-block-paragraph">For the best results, keep every drag and drop component practical. Use clear handles, visible drop zones, strong visual feedback, responsive layouts, scoped code, duplicate protection, and accessible alternatives. When the feature affects real user data, save the final state with localStorage, an API request, or a backend database instead of relying only on the front-end interface.</p>



<p class="wp-block-paragraph">Drag and drop is most powerful when it solves a real workflow problem. Use it where direct movement is faster than clicking through forms or settings, and avoid it when a simple button, select field, or checkbox would be easier for the user.</p>



<h2 class="wp-block-heading" id="related-javascript-and-css-guides">Related JavaScript and CSS Guides</h2>



<p class="wp-block-paragraph">Continue learning with these related JavaScript and CSS examples. These guides pair well with drag and drop components because many real interfaces combine sorting, forms, validation, storage, filtering, modals, cards, navigation, and responsive layout patterns.</p>



<div class="vb24-drag-related-grid">
  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-localstorage-examples/">
    <span>JavaScript</span>
    <strong>JavaScript LocalStorage Examples</strong>
    <p>Save user preferences, form state, carts, UI settings, and simple app data in the browser.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-fetch-api-examples/">
    <span>JavaScript</span>
    <strong>JavaScript Fetch API Examples</strong>
    <p>Send and receive data, connect forms, load JSON, handle API errors, and build dynamic UI features.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-form-validation-examples/">
    <span>JavaScript</span>
    <strong>JavaScript Form Validation Examples</strong>
    <p>Validate inputs, checkout forms, signup forms, required fields, errors, and interactive form states.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-calculator-examples/">
    <span>JavaScript</span>
    <strong>JavaScript Calculator Examples</strong>
    <p>Build price calculators, quote calculators, BMI tools, loan calculators, discount tools, and form calculators.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-search-filter-examples/">
    <span>JavaScript</span>
    <strong>JavaScript Search Filter Examples</strong>
    <p>Create live search, filters, category selectors, product filtering, and practical search UI components.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-modal-examples/">
    <span>JavaScript</span>
    <strong>JavaScript Modal Examples</strong>
    <p>Build popups, dialogs, lightboxes, confirmation windows, lead forms, and reusable overlay components.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-cards/">
    <span>CSS</span>
    <strong>Modern CSS Cards</strong>
    <p>Design better card layouts for dashboards, products, blog grids, portfolios, pricing sections, and UI blocks.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-layouts/">
    <span>CSS</span>
    <strong>Modern CSS Layouts</strong>
    <p>Learn Grid, Flexbox, container queries, responsive layout patterns, dashboards, bento grids, and landing pages.</p>
  </a>
</div>

<style>
.vb24-drag-related-grid,
.vb24-drag-related-grid * {
  box-sizing: border-box;
}

.vb24-drag-related-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 20px;
}

.vb24-drag-related-grid a {
  display: flex;
  flex-direction: column;
  min-height: 210px;
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 18% 10%, rgba(124, 58, 237, 0.10), transparent 32%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
  text-decoration: none !important;
  transition: transform 0.22s ease, box-shadow 0.22s ease, border-color 0.22s ease;
}

.vb24-drag-related-grid a:hover {
  transform: translateY(-3px);
  border-color: rgba(124, 58, 237, 0.42);
  box-shadow: 0 22px 54px rgba(15, 23, 42, 0.12);
}

.vb24-drag-related-grid span {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 12px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb24-drag-related-grid strong {
  margin-bottom: 10px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
}

.vb24-drag-related-grid p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 1100px) {
  .vb24-drag-related-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-drag-related-grid {
    grid-template-columns: 1fr;
  }

  .vb24-drag-related-grid a {
    min-height: auto;
  }
}
</style>
]]></content:encoded>
					
					<wfw:commentRss>https://veebilehed24.ee/en/blog/javascript/javascript-drag-and-drop-examples/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>30 JavaScript Date and Time Examples – Format Dates, Timers, Calendars &#038; Time Zones</title>
		<link>https://veebilehed24.ee/en/blog/javascript/javascript-date-time-examples/</link>
					<comments>https://veebilehed24.ee/en/blog/javascript/javascript-date-time-examples/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Wed, 17 Jun 2026 07:40:30 +0000</pubDate>
				<category><![CDATA[Javascript]]></category>
		<guid isPermaLink="false">https://veebilehed24.ee/?p=1772</guid>

					<description><![CDATA[JavaScript date and time features are used in almost every practical website or web app. They can format dates, display live clocks, calculate countdowns, show booking times, compare deadlines, create calendar widgets, convert time zones, validate date inputs, generate timestamps, and make dashboards, forms, ecommerce pages, event pages, and booking systems feel more useful. In [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">JavaScript date and time features are used in almost every practical website or web app. They can format dates, display live clocks, calculate countdowns, show booking times, compare deadlines, create calendar widgets, convert time zones, validate date inputs, generate timestamps, and make dashboards, forms, ecommerce pages, event pages, and booking systems feel more useful.</p>



<p class="wp-block-paragraph">In this guide, you will find 30 JavaScript date and time examples for real website projects, including live clocks, countdown timers, date formatters, time zone converters, event countdowns, booking date pickers, delivery date calculators, working hour checkers, age calculators, calendar cards, deadline trackers, relative time labels, and reusable vanilla JavaScript date components.</p>



<p class="wp-block-paragraph">This post focuses on practical JavaScript date and time logic, including the <code>Date</code> object, timestamps, <code>Intl.DateTimeFormat</code>, date formatting, time differences, countdown intervals, timezone display, weekday calculations, deadline checks, form date validation, calendar UI patterns, and copy-paste-ready HTML, CSS, and JavaScript examples. For related JavaScript UI features, you can also explore our <a href="https://veebilehed24.ee/en/blog/javascript/javascript-countdown-timer-examples/">JavaScript countdown timer examples</a>, <a href="https://veebilehed24.ee/en/blog/javascript/javascript-form-validation-examples/">JavaScript form validation examples</a>, <a href="https://veebilehed24.ee/en/blog/javascript/javascript-localstorage-examples/">JavaScript localStorage examples</a>, and <a href="https://veebilehed24.ee/en/blog/javascript/javascript-calculator-examples/">JavaScript calculator examples</a>.</p>



<div class="vb24-js-date-jump-box">
  <a class="vb24-js-date-jump-button" href="#javascript-date-time-examples">View All 30 JavaScript Date and Time Examples</a>
</div>

<style>
.vb24-js-date-jump-box {
  margin: 28px 0 36px;
}

.vb24-js-date-jump-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 14px 22px;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #7c3aed 52%, #f97316);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 850;
  line-height: 1.2;
  text-decoration: none !important;
  box-shadow: 0 16px 38px rgba(124, 58, 237, 0.26);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-js-date-jump-button::after {
  content: "↓";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.18);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  line-height: 1;
}

.vb24-js-date-jump-button:hover {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transform: translateY(-2px);
  filter: saturate(1.08);
  box-shadow: 0 20px 46px rgba(124, 58, 237, 0.34);
}

@media (max-width: 640px) {
  .vb24-js-date-jump-button {
    width: 100%;
    padding: 14px 16px;
    font-size: 14px;
  }
}
</style>



<div class="toc-affiliate-wrap vb24-js-date-toc-wrap">

  <div class="toc-left vb24-js-date-toc-left">

    <div class="vb24-js-date-toc-kicker">On this page</div>

    <h2>Table of Contents</h2>

    <ul class="vl24-toc vb24-js-date-toc">
      <li><a href="#what-is-javascript-date-and-time">What Is JavaScript Date and Time?</a></li>
      <li><a href="#why-date-and-time-features-matter">Why Date and Time Features Matter</a></li>
      <li><a href="#javascript-date-and-time-use-cases">JavaScript Date and Time Use Cases</a></li>
      <li><a href="#what-should-a-good-date-time-component-include">What Should a Good Date Time Component Include?</a></li>
      <li><a class="vb24-featured-toc-link" href="#javascript-date-time-examples">30 JavaScript Date and Time Examples</a></li>
      <li><a href="#javascript-date-time-best-practices">JavaScript Date and Time Best Practices</a></li>
      <li><a href="#responsive-date-time-ui-tips">Responsive Date and Time UI Tips</a></li>
      <li><a href="#common-javascript-date-time-mistakes">Common JavaScript Date and Time Mistakes</a></li>
      <li><a href="#javascript-date-time-faq">JavaScript Date and Time FAQ</a></li>
      <li><a href="#javascript-date-time-conclusion">Conclusion</a></li>
      <li><a href="#related-javascript-and-css-guides">Related JavaScript and CSS Guides</a></li>
    </ul>

  </div>

  <div class="toc-right vb24-js-date-toc-right">

    <a class="vb24-entityschema-ad-card" href="https://veebilehed24.ee/en/shop/entityschema-pro/" target="_blank" rel="sponsored noopener">
      <span class="vb24-entityschema-ad-badge">WordPress SEO Plugin</span>

      <div class="vb24-entityschema-ad-image">
        <img decoding="async" src="https://veebilehed24.ee/wp-content/uploads/2026/03/entityschema-cover-600x400.webp" width="300" height="200" alt="EntitySchema Pro WordPress structured data and entity SEO plugin" loading="lazy">
      </div>

      <div class="vb24-entityschema-ad-content">
        <h3>EntitySchema Pro</h3>
        <p>Build a real entity-based structured data system for WordPress, modern SEO, and AI-readable websites.</p>

        <div class="vb24-entityschema-ad-price">
          <div class="vb24-entityschema-ad-price-left">
            <span class="vb24-entityschema-ad-price-label">Sale price</span>
            <span class="vb24-entityschema-ad-old-price">89€</span>
          </div>

          <strong class="vb24-entityschema-ad-sale-price">29€</strong>

          <span class="vb24-entityschema-ad-save">Save 60€</span>
        </div>

        <span class="vb24-entityschema-ad-button">View Plugin</span>
      </div>
    </a>

  </div>

</div>

<style>
.vb24-js-date-toc-wrap {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 26px;
  align-items: stretch;
  margin: 34px 0 44px;
}

.vb24-js-date-toc-left,
.vb24-js-date-toc-right {
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 28px;
  background: linear-gradient(135deg, #0f172a 0%, #312e81 48%, #7c2d12 100%);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.18);
}

.vb24-js-date-toc-left {
  padding: 28px 30px 30px;
}

.vb24-js-date-toc-kicker {
  margin-bottom: 10px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 13px;
  font-weight: 850;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb24-js-date-toc-left h2 {
  margin: 0 0 22px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px !important;
  line-height: 1.15 !important;
  font-weight: 850 !important;
}

.vb24-js-date-toc {
  display: grid !important;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px !important;
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb24-js-date-toc li {
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb24-js-date-toc li::before {
  display: none !important;
  content: none !important;
}

.vb24-js-date-toc a {
  display: flex;
  align-items: center;
  min-height: 54px;
  padding: 13px 15px;
  border: 1px solid rgba(148, 163, 184, 0.18);
  border-radius: 15px;
  background: rgba(255, 255, 255, 0.065);
  color: #f3f4f6 !important;
  -webkit-text-fill-color: #f3f4f6 !important;
  font-size: 15px;
  font-weight: 750;
  line-height: 1.35;
  text-decoration: none !important;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.05);
  transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease;
}

.vb24-js-date-toc a:hover {
  transform: translateY(-2px);
  border-color: rgba(249, 115, 22, 0.70);
  background: rgba(249, 115, 22, 0.16);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb24-js-date-toc .vb24-featured-toc-link {
  border-color: rgba(251, 146, 60, 0.78);
  background: linear-gradient(135deg, rgba(37, 99, 235, 0.30), rgba(124, 58, 237, 0.30), rgba(249, 115, 22, 0.26));
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb24-js-date-toc-right {
  display: flex;
  align-items: stretch;
  justify-content: center;
  padding: 16px;
  overflow: hidden;
}

.vb24-entityschema-ad-card,
.vb24-entityschema-ad-card * {
  box-sizing: border-box;
}

.vb24-entityschema-ad-card {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  min-height: 100%;
  padding: 12px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(34, 211, 238, 0.28), transparent 34%),
    radial-gradient(circle at 86% 14%, rgba(236, 72, 153, 0.24), transparent 36%),
    linear-gradient(135deg, #111827 0%, #312e81 52%, #701a75 100%) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  overflow: hidden;
  box-shadow: 0 20px 56px rgba(2, 6, 23, 0.32);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-entityschema-ad-card:hover {
  transform: translateY(-3px);
  filter: saturate(1.08);
  box-shadow: 0 26px 70px rgba(2, 6, 23, 0.42);
}

.vb24-entityschema-ad-badge {
  position: absolute;
  z-index: 3;
  top: 18px;
  left: 18px;
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.70);
  border: 1px solid rgba(255,255,255,0.22);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb24-entityschema-ad-image {
  overflow: hidden;
  border-radius: 17px;
  border: 1px solid rgba(255,255,255,0.16);
  background: rgba(255,255,255,0.08);
}

.vb24-entityschema-ad-image img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 17px;
}

.vb24-entityschema-ad-content {
  padding: 15px 8px 4px;
}

.vb24-entityschema-ad-content h3 {
  margin: 0 0 8px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 23px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb24-entityschema-ad-content p {
  margin: 0 0 14px !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 13px;
  line-height: 1.5;
  font-weight: 650;
}

.vb24-entityschema-ad-price {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin: 0 0 12px;
  padding: 11px 12px;
  border-radius: 16px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.16);
}

.vb24-entityschema-ad-price-left {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.vb24-entityschema-ad-price-label {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 11px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb24-entityschema-ad-old-price {
  color: rgba(255,255,255,0.62) !important;
  -webkit-text-fill-color: rgba(255,255,255,0.62) !important;
  font-size: 15px;
  line-height: 1;
  font-weight: 850;
  text-decoration: line-through;
  text-decoration-thickness: 2px;
  text-decoration-color: rgba(248, 113, 113, 0.95);
}

.vb24-entityschema-ad-sale-price {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 31px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb24-entityschema-ad-save {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 28px;
  padding: 6px 9px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.18);
  border: 1px solid rgba(74, 222, 128, 0.34);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 11px;
  font-weight: 950;
  white-space: nowrap;
}

.vb24-entityschema-ad-button {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 43px;
  padding: 12px 14px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22d3ee, #2563eb 55%, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
  box-shadow: 0 14px 34px rgba(37, 99, 235, 0.30);
}

@media (max-width: 900px) {
  .vb24-js-date-toc-wrap {
    grid-template-columns: 1fr;
  }

  .vb24-js-date-toc-right {
    justify-content: flex-start;
    max-width: 360px;
  }
}

@media (max-width: 640px) {
  .vb24-js-date-toc-left {
    padding: 22px 18px;
    border-radius: 22px;
  }

  .vb24-js-date-toc-left h2 {
    font-size: 26px !important;
  }

  .vb24-js-date-toc {
    grid-template-columns: 1fr;
  }

  .vb24-js-date-toc a {
    min-height: 48px;
    font-size: 14px;
  }

  .vb24-js-date-toc-right {
    max-width: 100%;
    border-radius: 22px;
  }
}
</style>



<h2 class="wp-block-heading" id="what-is-javascript-date-and-time">What Is JavaScript Date and Time?</h2>



<p class="wp-block-paragraph">JavaScript date and time refers to the browser-based logic used to create, read, format, compare, and update dates and times on a website. The most common starting point is the built-in <code>Date</code> object, which can represent the current time, a selected date, a future deadline, a past timestamp, or a custom date value entered by the user.</p>



<p class="wp-block-paragraph">Date and time features are important because websites often need to show information that changes with time. A landing page may need an event countdown, an ecommerce page may need a delivery estimate, a dashboard may need a live clock, a booking form may need date validation, and a blog or app interface may need relative labels like “today”, “yesterday”, or “3 days ago”.</p>



<p class="wp-block-paragraph">JavaScript can also format dates for different languages and regions, calculate the difference between two dates, show weekdays, detect working hours, display local time, convert basic time zone views, and keep timers updating automatically. These small features can make a simple page feel more interactive, useful, and professional.</p>



<h2 class="wp-block-heading" id="why-date-and-time-features-matter">Why Date and Time Features Matter</h2>



<p class="wp-block-paragraph">Date and time features matter because users often make decisions based on timing. They want to know when a sale ends, when an event starts, how long delivery may take, whether a business is open, how much time remains before a deadline, or what date they selected in a form.</p>



<ul class="wp-block-list">
  <li><strong>They improve user experience</strong> by showing live clocks, readable dates, countdowns, deadlines, and helpful time labels.</li>
  <li><strong>They support conversions</strong> by creating urgency for sales, events, limited offers, bookings, and product launches.</li>
  <li><strong>They make forms smarter</strong> by validating dates, checking minimum dates, calculating age, and preventing invalid booking choices.</li>
  <li><strong>They help ecommerce pages</strong> by showing estimated delivery dates, sale countdowns, pickup times, and order deadlines.</li>
  <li><strong>They teach real JavaScript logic</strong> because date features often use intervals, calculations, formatting, DOM updates, conditions, and reusable functions.</li>
</ul>



<p class="wp-block-paragraph">Date and time logic should still be handled carefully. Time zones, daylight saving time, invalid date inputs, browser differences, and formatting expectations can create mistakes if the logic is too simple. For most website UI components, the best approach is to keep the feature clear, test realistic dates, and display results in a format users understand immediately.</p>



<h2 class="wp-block-heading" id="javascript-date-and-time-use-cases">JavaScript Date and Time Use Cases</h2>



<p class="wp-block-paragraph">There are many practical JavaScript date and time use cases for websites, landing pages, ecommerce stores, dashboards, booking systems, blogs, and web apps. Some are small UI helpers, while others can become full interactive tools.</p>



<p class="wp-block-paragraph">A simple date feature may only show the current year in the footer. A more advanced feature may calculate delivery dates, update a countdown every second, compare selected booking dates, generate a mini calendar, or display multiple time zones for an international audience.</p>



<ul class="wp-block-list">
  <li><strong>Live clock components</strong> show the current time in dashboards, admin panels, event pages, or support widgets.</li>
  <li><strong>Date formatting tools</strong> convert raw date values into readable formats for users in different regions.</li>
  <li><strong>Countdown timers</strong> create urgency for sales, webinars, launches, bookings, and limited-time offers.</li>
  <li><strong>Booking date validation</strong> prevents users from selecting past dates, unavailable days, or invalid time slots.</li>
  <li><strong>Delivery date calculators</strong> estimate shipping, pickup, production, or service dates based on business rules.</li>
  <li><strong>Time zone displays</strong> help international visitors compare local times, meeting times, and remote support hours.</li>
  <li><strong>Relative time labels</strong> show human-friendly text such as “just now”, “2 hours ago”, “yesterday”, or “next week”.</li>
  <li><strong>Deadline trackers</strong> help dashboards, task apps, CRM tools, and project pages show remaining time clearly.</li>
</ul>



<p class="wp-block-paragraph">This guide focuses on JavaScript date and time examples, so every demo will include visible JavaScript, HTML, and CSS code. The examples are designed to be copy-paste friendly, practical for real websites, and different in layout, logic, interface style, time calculation, UI behavior, and responsive design.</p>



<h2 class="wp-block-heading" id="what-should-a-good-date-time-component-include">What Should a Good Date Time Component Include?</h2>



<p class="wp-block-paragraph">A good date and time component should be accurate, readable, and useful. Users should understand what the time means, the display should update when needed, and the interface should avoid confusing date formats or hidden assumptions.</p>



<div class="vb24-js-date-checklist">
  <div class="vb24-js-date-check-item">
    <h3>Clear date purpose</h3>
    <p>The component should have a clear reason to show time, such as a deadline, event date, booking slot, delivery estimate, live clock, or relative timestamp.</p>
  </div>

  <div class="vb24-js-date-check-item">
    <h3>Readable formatting</h3>
    <p>Dates should be displayed in a format users understand quickly, instead of raw timestamps or confusing numeric-only values.</p>
  </div>

  <div class="vb24-js-date-check-item">
    <h3>Reliable time logic</h3>
    <p>The component should handle updates, expired states, invalid inputs, selected dates, and time differences in a predictable way.</p>
  </div>

  <div class="vb24-js-date-check-item">
    <h3>Responsive UI design</h3>
    <p>Date cards, countdowns, calendars, and time panels should stay readable on mobile, tablet, and desktop screens.</p>
  </div>
</div>

<style>
.vb24-js-date-checklist {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 30px;
}

.vb24-js-date-check-item {
  padding: 20px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 22px;
  background:
    radial-gradient(circle at 18% 10%, rgba(124, 58, 237, 0.10), transparent 32%),
    linear-gradient(135deg, #ffffff, #fff7ed) !important;
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb24-js-date-check-item h3 {
  margin: 0 0 10px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 850;
}

.vb24-js-date-check-item p {
  margin: 0;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb24-js-date-checklist {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-js-date-checklist {
    grid-template-columns: 1fr;
  }

  .vb24-js-date-check-item {
    padding: 18px;
    border-radius: 20px;
  }
}
</style>



<p class="wp-block-paragraph">Before building a JavaScript date or time feature, decide what the user needs to know. Is the goal to show the current time, count down to an event, calculate a date range, format an input, compare two dates, show available booking days, or create urgency for a sale? A clear purpose makes the code simpler and the interface more useful.</p>



<ul class="wp-block-list">
  <li><strong>Use readable date formats</strong> so users do not need to guess whether a date means month/day/year or day/month/year.</li>
  <li><strong>Use <code>Intl.DateTimeFormat</code> where possible</strong> for cleaner locale-aware date and time formatting.</li>
  <li><strong>Validate user date input</strong> before calculating deadlines, age, booking dates, or delivery estimates.</li>
  <li><strong>Handle expired states</strong> so countdowns and deadlines do not keep showing negative time.</li>
  <li><strong>Update live components carefully</strong> using intervals only when a component really needs real-time updates.</li>
  <li><strong>Keep time zone labels visible</strong> when showing international meeting times or support hours.</li>
  <li><strong>Test edge cases</strong> such as today’s date, tomorrow, month endings, leap years, and invalid inputs.</li>
  <li><strong>Use unique class names and scoped JavaScript</strong> so multiple examples can work on the same WordPress page.</li>
  <li><strong>Make date UI mobile friendly</strong> because calendars, timers, and time cards can easily become cramped on small screens.</li>
  <li><strong>Do not overcomplicate simple features</strong> when a clear date label or small helper function is enough.</li>
</ul>



<p class="wp-block-paragraph">You can combine JavaScript date and time features with many other website patterns. Countdown logic works well with <a href="https://veebilehed24.ee/en/blog/javascript/javascript-countdown-timer-examples/">JavaScript countdown timers</a>, date validation can improve <a href="https://veebilehed24.ee/en/blog/javascript/javascript-form-validation-examples/">JavaScript form validation</a>, saved date preferences can be combined with <a href="https://veebilehed24.ee/en/blog/javascript/javascript-localstorage-examples/">JavaScript localStorage</a>, and date-based calculators can support examples from our <a href="https://veebilehed24.ee/en/blog/javascript/javascript-calculator-examples/">JavaScript calculator examples</a> guide.</p>



<h2 class="wp-block-heading" id="javascript-date-time-examples">30 JavaScript Date and Time Examples</h2>



<p class="wp-block-paragraph">Now let’s look at 30 JavaScript date and time examples for real website projects. Each example uses a different time-related purpose, layout style, interface pattern, date calculation, formatting method, live update behavior, validation rule, deadline state, time zone display, or responsive UI approach, so you can build practical browser-based date and time features with visible JavaScript, HTML, and CSS code.</p>



<h2 class="wp-block-heading">1. Live Digital Clock with Date and Weekday</h2>



<p class="wp-block-paragraph"><strong>A live digital clock</strong> is one of the most useful JavaScript date and time examples for dashboards, admin panels, booking systems, event pages, support widgets, and modern website headers. It shows the current time, date, and weekday in real time.</p>



<p class="wp-block-paragraph">This example uses the JavaScript <code>Date</code> object and updates the interface every second with <code>setInterval()</code>. It also uses <code>Intl.DateTimeFormat</code> to create readable date and weekday labels.</p>



<ul class="wp-block-list">
<li>Live updating digital clock</li>
<li>Shows current time, date, and weekday</li>
<li>Uses JavaScript Date object</li>
<li>Updates every second</li>
<li>Good for dashboards, booking pages, and admin UI</li>
</ul>



<div class="vb-date-one-demo">
  <div class="vb-date-one-card" data-vb-date-one>
    <div class="vb-date-one-orbit">
      <span></span>
      <span></span>
      <span></span>
    </div>

    <div class="vb-date-one-content">
      <span class="vb-date-one-kicker">Example 01</span>
      <h3>Live Digital Clock</h3>
      <p>This clock updates every second and displays the current time, weekday, and full date using JavaScript.</p>

      <div class="vb-date-one-clock">
        <strong data-clock-time>00:00:00</strong>
        <span data-clock-weekday>Loading weekday&#8230;</span>
        <small data-clock-date>Loading date&#8230;</small>
      </div>
    </div>
  </div>
</div>

<style>
.vb-date-one-demo,
.vb-date-one-demo * {
  box-sizing: border-box;
}

.vb-date-one-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 36px;
  background:
    radial-gradient(circle at 15% 18%, rgba(37, 99, 235, 0.22), transparent 34%),
    radial-gradient(circle at 88% 12%, rgba(249, 115, 22, 0.22), transparent 36%),
    linear-gradient(135deg, #eff6ff 0%, #fff7ed 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-date-one-card {
  position: relative;
  max-width: 980px;
  margin: 0 auto;
  min-height: 440px;
  display: grid;
  place-items: center;
  overflow: hidden;
  border-radius: 34px;
  background:
    radial-gradient(circle at center, rgba(59, 130, 246, 0.28), transparent 36%),
    linear-gradient(135deg, #0f172a 0%, #1e1b4b 50%, #7c2d12 100%);
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.32);
}

.vb-date-one-orbit {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.vb-date-one-orbit span {
  position: absolute;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,0.14);
  animation: vbDateOneFloat 8s ease-in-out infinite;
}

.vb-date-one-orbit span:nth-child(1) {
  width: 310px;
  height: 310px;
  left: -80px;
  top: -80px;
}

.vb-date-one-orbit span:nth-child(2) {
  width: 420px;
  height: 420px;
  right: -120px;
  bottom: -150px;
  animation-delay: -2s;
}

.vb-date-one-orbit span:nth-child(3) {
  width: 180px;
  height: 180px;
  right: 18%;
  top: 12%;
  animation-delay: -4s;
}

@keyframes vbDateOneFloat {
  0%, 100% {
    transform: translateY(0) scale(1);
    opacity: 0.55;
  }

  50% {
    transform: translateY(-16px) scale(1.04);
    opacity: 0.95;
  }
}

.vb-date-one-content {
  position: relative;
  z-index: 2;
  width: min(100%, 720px);
  padding: clamp(22px, 5vw, 54px);
  text-align: center;
}

.vb-date-one-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 13px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.18);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.vb-date-one-content h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 7vw, 78px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-one-content p {
  max-width: 580px;
  margin: 0 auto 26px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-one-clock {
  display: grid;
  gap: 10px;
  justify-items: center;
  max-width: 560px;
  margin: 0 auto;
  padding: clamp(18px, 4vw, 32px);
  border-radius: 28px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.10);
  backdrop-filter: blur(16px);
}

.vb-date-one-clock strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(48px, 9vw, 96px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.06em;
  font-variant-numeric: tabular-nums;
}

.vb-date-one-clock span {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: clamp(20px, 3vw, 30px);
  font-weight: 900;
}

.vb-date-one-clock small {
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 15px;
  line-height: 1.5;
  font-weight: 750;
}

@media (max-width: 560px) {
  .vb-date-one-card {
    min-height: 390px;
    border-radius: 26px;
  }

  .vb-date-one-clock {
    border-radius: 22px;
  }

  .vb-date-one-clock strong {
    font-size: 50px;
  }
}
</style>

<script>
(function () {
  const clock = document.querySelector("[data-vb-date-one]");
  if (!clock) return;

  const timeElement = clock.querySelector("[data-clock-time]");
  const weekdayElement = clock.querySelector("[data-clock-weekday]");
  const dateElement = clock.querySelector("[data-clock-date]");

  function updateClock() {
    const now = new Date();

    timeElement.textContent = new Intl.DateTimeFormat("en", {
      hour: "2-digit",
      minute: "2-digit",
      second: "2-digit"
    }).format(now);

    weekdayElement.textContent = new Intl.DateTimeFormat("en", {
      weekday: "long"
    }).format(now);

    dateElement.textContent = new Intl.DateTimeFormat("en", {
      month: "long",
      day: "numeric",
      year: "numeric"
    }).format(now);
  }

  updateClock();
  setInterval(updateClock, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const clock = document.querySelector("[data-vb-date-one]");
  if (!clock) return;

  const timeElement = clock.querySelector("[data-clock-time]");
  const weekdayElement = clock.querySelector("[data-clock-weekday]");
  const dateElement = clock.querySelector("[data-clock-date]");

  function updateClock() {
    const now = new Date();

    timeElement.textContent = new Intl.DateTimeFormat("en", {
      hour: "2-digit",
      minute: "2-digit",
      second: "2-digit"
    }).format(now);

    weekdayElement.textContent = new Intl.DateTimeFormat("en", {
      weekday: "long"
    }).format(now);

    dateElement.textContent = new Intl.DateTimeFormat("en", {
      month: "long",
      day: "numeric",
      year: "numeric"
    }).format(now);
  }

  updateClock();
  setInterval(updateClock, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-one-demo"&gt;
  &lt;div class="vb-date-one-card" data-vb-date-one&gt;
    &lt;div class="vb-date-one-orbit"&gt;
      &lt;span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;/span&gt;
      &lt;span&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-one-content"&gt;
      &lt;span class="vb-date-one-kicker"&gt;Example 01&lt;/span&gt;
      &lt;h3&gt;Live Digital Clock&lt;/h3&gt;
      &lt;p&gt;This clock updates every second and displays the current time, weekday, and full date using JavaScript.&lt;/p&gt;

      &lt;div class="vb-date-one-clock"&gt;
        &lt;strong data-clock-time&gt;00:00:00&lt;/strong&gt;
        &lt;span data-clock-weekday&gt;Loading weekday...&lt;/span&gt;
        &lt;small data-clock-date&gt;Loading date...&lt;/small&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-one-demo,
.vb-date-one-demo * {
  box-sizing: border-box;
}

.vb-date-one-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 36px;
  background:
    radial-gradient(circle at 15% 18%, rgba(37, 99, 235, 0.22), transparent 34%),
    radial-gradient(circle at 88% 12%, rgba(249, 115, 22, 0.22), transparent 36%),
    linear-gradient(135deg, #eff6ff 0%, #fff7ed 58%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-date-one-card {
  position: relative;
  max-width: 980px;
  margin: 0 auto;
  min-height: 440px;
  display: grid;
  place-items: center;
  overflow: hidden;
  border-radius: 34px;
  background:
    radial-gradient(circle at center, rgba(59, 130, 246, 0.28), transparent 36%),
    linear-gradient(135deg, #0f172a 0%, #1e1b4b 50%, #7c2d12 100%);
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.32);
}

.vb-date-one-orbit {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.vb-date-one-orbit span {
  position: absolute;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,0.14);
  animation: vbDateOneFloat 8s ease-in-out infinite;
}

.vb-date-one-orbit span:nth-child(1) {
  width: 310px;
  height: 310px;
  left: -80px;
  top: -80px;
}

.vb-date-one-orbit span:nth-child(2) {
  width: 420px;
  height: 420px;
  right: -120px;
  bottom: -150px;
  animation-delay: -2s;
}

.vb-date-one-orbit span:nth-child(3) {
  width: 180px;
  height: 180px;
  right: 18%;
  top: 12%;
  animation-delay: -4s;
}

@keyframes vbDateOneFloat {
  0%, 100% {
    transform: translateY(0) scale(1);
    opacity: 0.55;
  }

  50% {
    transform: translateY(-16px) scale(1.04);
    opacity: 0.95;
  }
}

.vb-date-one-content {
  position: relative;
  z-index: 2;
  width: min(100%, 720px);
  padding: clamp(22px, 5vw, 54px);
  text-align: center;
}

.vb-date-one-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 13px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.18);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.vb-date-one-content h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 7vw, 78px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-one-content p {
  max-width: 580px;
  margin: 0 auto 26px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-one-clock {
  display: grid;
  gap: 10px;
  justify-items: center;
  max-width: 560px;
  margin: 0 auto;
  padding: clamp(18px, 4vw, 32px);
  border-radius: 28px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.10);
  backdrop-filter: blur(16px);
}

.vb-date-one-clock strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(48px, 9vw, 96px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.06em;
  font-variant-numeric: tabular-nums;
}

.vb-date-one-clock span {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: clamp(20px, 3vw, 30px);
  font-weight: 900;
}

.vb-date-one-clock small {
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 15px;
  line-height: 1.5;
  font-weight: 750;
}

@media (max-width: 560px) {
  .vb-date-one-card {
    min-height: 390px;
    border-radius: 26px;
  }

  .vb-date-one-clock {
    border-radius: 22px;
  }

  .vb-date-one-clock strong {
    font-size: 50px;
  }
}</pre>



<p class="wp-block-paragraph">This live JavaScript clock example is useful for admin dashboards, SaaS interfaces, booking systems, event websites, support pages, internal tools, and landing pages where real-time date and time information improves the user experience.</p>



<h2 class="wp-block-heading">2. Date Formatter Tool with Multiple Output Styles</h2>



<p class="wp-block-paragraph"><strong>A JavaScript date formatter tool</strong> helps users convert a selected date into different readable formats. This is useful for dashboards, content tools, booking systems, CRM notes, invoices, event pages, and any interface where raw date input should become human-friendly text.</p>



<p class="wp-block-paragraph">This example uses an HTML date input and formats the selected date into long date, short date, weekday, ISO-style date, and a custom friendly label. It uses <code>Intl.DateTimeFormat</code> for clean browser-based date formatting.</p>



<ul class="wp-block-list">
<li>Formats selected date instantly</li>
<li>Shows multiple date output styles</li>
<li>Uses Intl.DateTimeFormat</li>
<li>Includes long date, short date, weekday, and ISO output</li>
<li>Useful for tools, dashboards, forms, and CMS interfaces</li>
</ul>



<div class="vb-date-two-demo">
  <div class="vb-date-two-shell" data-vb-date-two>
    <div class="vb-date-two-panel">
      <span class="vb-date-two-kicker">Example 02</span>
      <h3>Date Formatter Tool</h3>
      <p>Select a date and JavaScript will format it into several useful output styles.</p>

      <label class="vb-date-two-input-wrap">
        <span>Choose a date</span>
        <input type="date" data-date-input>
      </label>

      <button type="button" data-today-button>Use Today</button>
    </div>

    <div class="vb-date-two-results">
      <div class="vb-date-two-result-card">
        <span>Long date</span>
        <strong data-output-long>Choose a date</strong>
      </div>

      <div class="vb-date-two-result-card">
        <span>Short date</span>
        <strong data-output-short>Choose a date</strong>
      </div>

      <div class="vb-date-two-result-card">
        <span>Weekday</span>
        <strong data-output-weekday>Choose a date</strong>
      </div>

      <div class="vb-date-two-result-card">
        <span>ISO style</span>
        <strong data-output-iso>Choose a date</strong>
      </div>

      <div class="vb-date-two-result-card vb-date-two-wide">
        <span>Friendly label</span>
        <strong data-output-friendly>Choose a date to create a readable label.</strong>
      </div>
    </div>
  </div>
</div>

<style>
.vb-date-two-demo,
.vb-date-two-demo * {
  box-sizing: border-box;
}

.vb-date-two-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 12% 16%, rgba(14, 165, 233, 0.18), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(236, 72, 153, 0.16), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #fdf2f8 52%, #eff6ff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.09);
}

.vb-date-two-shell {
  display: grid;
  grid-template-columns: minmax(280px, 0.8fr) minmax(0, 1.2fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-two-panel {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 22px 70px rgba(15, 23, 42, 0.10);
}

.vb-date-two-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-two-panel h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-date-two-panel p {
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-two-input-wrap {
  display: grid;
  gap: 8px;
  margin-bottom: 14px;
}

.vb-date-two-input-wrap span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-two-input-wrap input {
  width: 100%;
  min-height: 52px;
  padding: 0 15px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-two-input-wrap input:focus {
  border-color: rgba(14, 165, 233, 0.8);
  box-shadow: 0 0 0 4px rgba(14, 165, 233, 0.12);
}

.vb-date-two-panel button {
  display: inline-flex;
  align-self: flex-start;
  align-items: center;
  justify-content: center;
  min-height: 46px;
  padding: 12px 16px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #0ea5e9, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 14px 34px rgba(14, 165, 233, 0.22);
}

.vb-date-two-results {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-date-two-result-card {
  display: grid;
  gap: 10px;
  min-height: 150px;
  align-content: center;
  padding: 22px;
  border-radius: 26px;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.90), rgba(255,255,255,0.70)),
    radial-gradient(circle at top right, rgba(14, 165, 233, 0.18), transparent 42%);
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 20px 60px rgba(15, 23, 42, 0.08);
}

.vb-date-two-result-card span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.10em;
}

.vb-date-two-result-card strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(20px, 3vw, 30px);
  line-height: 1.12;
  font-weight: 950;
  letter-spacing: -0.045em;
  word-break: break-word;
}

.vb-date-two-wide {
  grid-column: 1 / -1;
  min-height: 130px;
  background:
    radial-gradient(circle at 8% 20%, rgba(236, 72, 153, 0.16), transparent 34%),
    linear-gradient(135deg, #0f172a, #1e1b4b) !important;
}

.vb-date-two-wide span {
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
}

.vb-date-two-wide strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

@media (max-width: 880px) {
  .vb-date-two-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-date-two-results {
    grid-template-columns: 1fr;
  }

  .vb-date-two-panel,
  .vb-date-two-result-card {
    border-radius: 22px;
  }

  .vb-date-two-panel button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const formatter = document.querySelector("[data-vb-date-two]");
  if (!formatter) return;

  const input = formatter.querySelector("[data-date-input]");
  const todayButton = formatter.querySelector("[data-today-button]");

  const outputLong = formatter.querySelector("[data-output-long]");
  const outputShort = formatter.querySelector("[data-output-short]");
  const outputWeekday = formatter.querySelector("[data-output-weekday]");
  const outputIso = formatter.querySelector("[data-output-iso]");
  const outputFriendly = formatter.querySelector("[data-output-friendly]");

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function formatDate() {
    if (!input.value) {
      outputLong.textContent = "Choose a date";
      outputShort.textContent = "Choose a date";
      outputWeekday.textContent = "Choose a date";
      outputIso.textContent = "Choose a date";
      outputFriendly.textContent = "Choose a date to create a readable label.";
      return;
    }

    const selectedDate = createLocalDate(input.value);

    outputLong.textContent = new Intl.DateTimeFormat("en", {
      month: "long",
      day: "numeric",
      year: "numeric"
    }).format(selectedDate);

    outputShort.textContent = new Intl.DateTimeFormat("en", {
      month: "short",
      day: "numeric",
      year: "numeric"
    }).format(selectedDate);

    outputWeekday.textContent = new Intl.DateTimeFormat("en", {
      weekday: "long"
    }).format(selectedDate);

    outputIso.textContent = input.value;

    outputFriendly.textContent =
      "Selected date is " +
      outputWeekday.textContent +
      ", " +
      outputLong.textContent +
      ".";
  }

  function setToday() {
    const today = new Date();
    const year = today.getFullYear();
    const month = String(today.getMonth() + 1).padStart(2, "0");
    const day = String(today.getDate()).padStart(2, "0");

    input.value = year + "-" + month + "-" + day;
    formatDate();
  }

  input.addEventListener("change", formatDate);
  todayButton.addEventListener("click", setToday);

  setToday();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const formatter = document.querySelector("[data-vb-date-two]");
  if (!formatter) return;

  const input = formatter.querySelector("[data-date-input]");
  const todayButton = formatter.querySelector("[data-today-button]");

  const outputLong = formatter.querySelector("[data-output-long]");
  const outputShort = formatter.querySelector("[data-output-short]");
  const outputWeekday = formatter.querySelector("[data-output-weekday]");
  const outputIso = formatter.querySelector("[data-output-iso]");
  const outputFriendly = formatter.querySelector("[data-output-friendly]");

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function formatDate() {
    if (!input.value) {
      outputLong.textContent = "Choose a date";
      outputShort.textContent = "Choose a date";
      outputWeekday.textContent = "Choose a date";
      outputIso.textContent = "Choose a date";
      outputFriendly.textContent = "Choose a date to create a readable label.";
      return;
    }

    const selectedDate = createLocalDate(input.value);

    outputLong.textContent = new Intl.DateTimeFormat("en", {
      month: "long",
      day: "numeric",
      year: "numeric"
    }).format(selectedDate);

    outputShort.textContent = new Intl.DateTimeFormat("en", {
      month: "short",
      day: "numeric",
      year: "numeric"
    }).format(selectedDate);

    outputWeekday.textContent = new Intl.DateTimeFormat("en", {
      weekday: "long"
    }).format(selectedDate);

    outputIso.textContent = input.value;

    outputFriendly.textContent =
      "Selected date is " +
      outputWeekday.textContent +
      ", " +
      outputLong.textContent +
      ".";
  }

  function setToday() {
    const today = new Date();
    const year = today.getFullYear();
    const month = String(today.getMonth() + 1).padStart(2, "0");
    const day = String(today.getDate()).padStart(2, "0");

    input.value = year + "-" + month + "-" + day;
    formatDate();
  }

  input.addEventListener("change", formatDate);
  todayButton.addEventListener("click", setToday);

  setToday();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-two-demo"&gt;
  &lt;div class="vb-date-two-shell" data-vb-date-two&gt;
    &lt;div class="vb-date-two-panel"&gt;
      &lt;span class="vb-date-two-kicker"&gt;Example 02&lt;/span&gt;
      &lt;h3&gt;Date Formatter Tool&lt;/h3&gt;
      &lt;p&gt;Select a date and JavaScript will format it into several useful output styles.&lt;/p&gt;

      &lt;label class="vb-date-two-input-wrap"&gt;
        &lt;span&gt;Choose a date&lt;/span&gt;
        &lt;input type="date" data-date-input&gt;
      &lt;/label&gt;

      &lt;button type="button" data-today-button&gt;Use Today&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-two-results"&gt;
      &lt;div class="vb-date-two-result-card"&gt;
        &lt;span&gt;Long date&lt;/span&gt;
        &lt;strong data-output-long&gt;Choose a date&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-two-result-card"&gt;
        &lt;span&gt;Short date&lt;/span&gt;
        &lt;strong data-output-short&gt;Choose a date&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-two-result-card"&gt;
        &lt;span&gt;Weekday&lt;/span&gt;
        &lt;strong data-output-weekday&gt;Choose a date&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-two-result-card"&gt;
        &lt;span&gt;ISO style&lt;/span&gt;
        &lt;strong data-output-iso&gt;Choose a date&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-two-result-card vb-date-two-wide"&gt;
        &lt;span&gt;Friendly label&lt;/span&gt;
        &lt;strong data-output-friendly&gt;Choose a date to create a readable label.&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-two-demo,
.vb-date-two-demo * {
  box-sizing: border-box;
}

.vb-date-two-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 12% 16%, rgba(14, 165, 233, 0.18), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(236, 72, 153, 0.16), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #fdf2f8 52%, #eff6ff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.09);
}

.vb-date-two-shell {
  display: grid;
  grid-template-columns: minmax(280px, 0.8fr) minmax(0, 1.2fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-two-panel {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 22px 70px rgba(15, 23, 42, 0.10);
}

.vb-date-two-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-two-panel h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-date-two-panel p {
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-two-input-wrap {
  display: grid;
  gap: 8px;
  margin-bottom: 14px;
}

.vb-date-two-input-wrap span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-two-input-wrap input {
  width: 100%;
  min-height: 52px;
  padding: 0 15px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-two-input-wrap input:focus {
  border-color: rgba(14, 165, 233, 0.8);
  box-shadow: 0 0 0 4px rgba(14, 165, 233, 0.12);
}

.vb-date-two-panel button {
  display: inline-flex;
  align-self: flex-start;
  align-items: center;
  justify-content: center;
  min-height: 46px;
  padding: 12px 16px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #0ea5e9, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 14px 34px rgba(14, 165, 233, 0.22);
}

.vb-date-two-results {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-date-two-result-card {
  display: grid;
  gap: 10px;
  min-height: 150px;
  align-content: center;
  padding: 22px;
  border-radius: 26px;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.90), rgba(255,255,255,0.70)),
    radial-gradient(circle at top right, rgba(14, 165, 233, 0.18), transparent 42%);
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 20px 60px rgba(15, 23, 42, 0.08);
}

.vb-date-two-result-card span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.10em;
}

.vb-date-two-result-card strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(20px, 3vw, 30px);
  line-height: 1.12;
  font-weight: 950;
  letter-spacing: -0.045em;
  word-break: break-word;
}

.vb-date-two-wide {
  grid-column: 1 / -1;
  min-height: 130px;
  background:
    radial-gradient(circle at 8% 20%, rgba(236, 72, 153, 0.16), transparent 34%),
    linear-gradient(135deg, #0f172a, #1e1b4b) !important;
}

.vb-date-two-wide span {
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
}

.vb-date-two-wide strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

@media (max-width: 880px) {
  .vb-date-two-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-date-two-results {
    grid-template-columns: 1fr;
  }

  .vb-date-two-panel,
  .vb-date-two-result-card {
    border-radius: 22px;
  }

  .vb-date-two-panel button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript date formatter example is useful for admin tools, date input previews, booking forms, CMS interfaces, content scheduling tools, invoice dashboards, and any website feature where selected dates should become readable immediately.</p>



<h2 class="wp-block-heading">3. Event Countdown Timer with Expired State</h2>



<p class="wp-block-paragraph"><strong>An event countdown timer</strong> is a practical JavaScript date and time component for webinars, product launches, limited offers, online events, course starts, booking deadlines, and landing pages. It shows how much time remains until a future date.</p>



<p class="wp-block-paragraph">This example calculates the difference between the current time and a target event date. It updates every second and changes the interface when the countdown reaches zero, so the timer never shows confusing negative values.</p>



<ul class="wp-block-list">
<li>Countdown to a future event</li>
<li>Shows days, hours, minutes, and seconds</li>
<li>Updates every second</li>
<li>Includes expired state</li>
<li>Useful for launches, webinars, sales, and booking pages</li>
</ul>



<div class="vb-date-three-demo">
  <div class="vb-date-three-card" data-vb-date-three data-event-date="2026-12-31T23:59:59">
    <div class="vb-date-three-top">
      <span class="vb-date-three-kicker">Example 03</span>
      <h3>Event Countdown</h3>
      <p>JavaScript calculates the remaining time until the event date and updates the countdown every second.</p>
    </div>

    <div class="vb-date-three-countdown" data-countdown-wrap>
      <div class="vb-date-three-time-box">
        <strong data-days>00</strong>
        <span>Days</span>
      </div>

      <div class="vb-date-three-time-box">
        <strong data-hours>00</strong>
        <span>Hours</span>
      </div>

      <div class="vb-date-three-time-box">
        <strong data-minutes>00</strong>
        <span>Minutes</span>
      </div>

      <div class="vb-date-three-time-box">
        <strong data-seconds>00</strong>
        <span>Seconds</span>
      </div>
    </div>

    <div class="vb-date-three-footer">
      <span data-event-label>Event date: December 31, 2026</span>
      <strong data-event-status>Countdown is active</strong>
    </div>
  </div>
</div>

<style>
.vb-date-three-demo,
.vb-date-three-demo * {
  box-sizing: border-box;
}

.vb-date-three-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 18% 16%, rgba(248, 113, 113, 0.18), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(251, 191, 36, 0.18), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #fef2f2 52%, #ffffff 100%) !important;
  border: 1px solid rgba(248, 113, 113, 0.18);
  box-shadow: 0 28px 80px rgba(127, 29, 29, 0.08);
}

.vb-date-three-card {
  max-width: 1080px;
  margin: 0 auto;
  padding: clamp(22px, 5vw, 46px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(251, 146, 60, 0.22), transparent 34%),
    radial-gradient(circle at 92% 18%, rgba(244, 63, 94, 0.20), transparent 34%),
    linear-gradient(135deg, #111827 0%, #7f1d1d 55%, #9a3412 100%);
  border: 1px solid rgba(255,255,255,0.13);
  box-shadow: 0 30px 90px rgba(127, 29, 29, 0.28);
  overflow: hidden;
}

.vb-date-three-top {
  display: grid;
  gap: 13px;
  max-width: 760px;
  margin-bottom: 28px;
}

.vb-date-three-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-three-top h3 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 7vw, 76px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-three-top p {
  max-width: 640px;
  margin: 0 !important;
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-three-countdown {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
  margin-bottom: 22px;
}

.vb-date-three-time-box {
  display: grid;
  gap: 9px;
  justify-items: center;
  min-height: 165px;
  align-content: center;
  padding: 18px;
  border-radius: 26px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.16);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.10);
  backdrop-filter: blur(12px);
}

.vb-date-three-time-box strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(42px, 7vw, 74px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.065em;
  font-variant-numeric: tabular-nums;
}

.vb-date-three-time-box span {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-three-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  padding: 16px 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-three-footer span {
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-date-three-footer strong {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.18);
  border: 1px solid rgba(74, 222, 128, 0.28);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-date-three-card.is-expired .vb-date-three-footer strong {
  background: rgba(248, 113, 113, 0.20);
  border-color: rgba(248, 113, 113, 0.34);
  color: #fecaca !important;
  -webkit-text-fill-color: #fecaca !important;
}

@media (max-width: 760px) {
  .vb-date-three-countdown {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-date-three-time-box {
    min-height: 140px;
  }
}

@media (max-width: 480px) {
  .vb-date-three-countdown {
    grid-template-columns: 1fr;
  }

  .vb-date-three-card {
    border-radius: 26px;
  }

  .vb-date-three-time-box {
    min-height: 120px;
    border-radius: 22px;
  }
}
</style>

<script>
(function () {
  const countdown = document.querySelector("[data-vb-date-three]");
  if (!countdown) return;

  const eventDateValue = countdown.getAttribute("data-event-date");
  const eventDate = new Date(eventDateValue).getTime();

  const daysElement = countdown.querySelector("[data-days]");
  const hoursElement = countdown.querySelector("[data-hours]");
  const minutesElement = countdown.querySelector("[data-minutes]");
  const secondsElement = countdown.querySelector("[data-seconds]");
  const statusElement = countdown.querySelector("[data-event-status]");

  function padNumber(number) {
    return String(number).padStart(2, "0");
  }

  function updateCountdown() {
    const now = new Date().getTime();
    const distance = eventDate - now;

    if (distance <= 0) {
      daysElement.textContent = "00";
      hoursElement.textContent = "00";
      minutesElement.textContent = "00";
      secondsElement.textContent = "00";
      statusElement.textContent = "Event has started";
      countdown.classList.add("is-expired");
      return;
    }

    const days = Math.floor(distance / (1000 * 60 * 60 * 24));
    const hours = Math.floor((distance / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((distance / (1000 * 60)) % 60);
    const seconds = Math.floor((distance / 1000) % 60);

    daysElement.textContent = padNumber(days);
    hoursElement.textContent = padNumber(hours);
    minutesElement.textContent = padNumber(minutes);
    secondsElement.textContent = padNumber(seconds);
    statusElement.textContent = "Countdown is active";
    countdown.classList.remove("is-expired");
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const countdown = document.querySelector("[data-vb-date-three]");
  if (!countdown) return;

  const eventDateValue = countdown.getAttribute("data-event-date");
  const eventDate = new Date(eventDateValue).getTime();

  const daysElement = countdown.querySelector("[data-days]");
  const hoursElement = countdown.querySelector("[data-hours]");
  const minutesElement = countdown.querySelector("[data-minutes]");
  const secondsElement = countdown.querySelector("[data-seconds]");
  const statusElement = countdown.querySelector("[data-event-status]");

  function padNumber(number) {
    return String(number).padStart(2, "0");
  }

  function updateCountdown() {
    const now = new Date().getTime();
    const distance = eventDate - now;

    if (distance <= 0) {
      daysElement.textContent = "00";
      hoursElement.textContent = "00";
      minutesElement.textContent = "00";
      secondsElement.textContent = "00";
      statusElement.textContent = "Event has started";
      countdown.classList.add("is-expired");
      return;
    }

    const days = Math.floor(distance / (1000 * 60 * 60 * 24));
    const hours = Math.floor((distance / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((distance / (1000 * 60)) % 60);
    const seconds = Math.floor((distance / 1000) % 60);

    daysElement.textContent = padNumber(days);
    hoursElement.textContent = padNumber(hours);
    minutesElement.textContent = padNumber(minutes);
    secondsElement.textContent = padNumber(seconds);
    statusElement.textContent = "Countdown is active";
    countdown.classList.remove("is-expired");
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-three-demo"&gt;
  &lt;div class="vb-date-three-card" data-vb-date-three data-event-date="2026-12-31T23:59:59"&gt;
    &lt;div class="vb-date-three-top"&gt;
      &lt;span class="vb-date-three-kicker"&gt;Example 03&lt;/span&gt;
      &lt;h3&gt;Event Countdown&lt;/h3&gt;
      &lt;p&gt;JavaScript calculates the remaining time until the event date and updates the countdown every second.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-three-countdown" data-countdown-wrap&gt;
      &lt;div class="vb-date-three-time-box"&gt;
        &lt;strong data-days&gt;00&lt;/strong&gt;
        &lt;span&gt;Days&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-three-time-box"&gt;
        &lt;strong data-hours&gt;00&lt;/strong&gt;
        &lt;span&gt;Hours&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-three-time-box"&gt;
        &lt;strong data-minutes&gt;00&lt;/strong&gt;
        &lt;span&gt;Minutes&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-three-time-box"&gt;
        &lt;strong data-seconds&gt;00&lt;/strong&gt;
        &lt;span&gt;Seconds&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-three-footer"&gt;
      &lt;span data-event-label&gt;Event date: December 31, 2026&lt;/span&gt;
      &lt;strong data-event-status&gt;Countdown is active&lt;/strong&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-three-demo,
.vb-date-three-demo * {
  box-sizing: border-box;
}

.vb-date-three-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 18% 16%, rgba(248, 113, 113, 0.18), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(251, 191, 36, 0.18), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #fef2f2 52%, #ffffff 100%) !important;
  border: 1px solid rgba(248, 113, 113, 0.18);
  box-shadow: 0 28px 80px rgba(127, 29, 29, 0.08);
}

.vb-date-three-card {
  max-width: 1080px;
  margin: 0 auto;
  padding: clamp(22px, 5vw, 46px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(251, 146, 60, 0.22), transparent 34%),
    radial-gradient(circle at 92% 18%, rgba(244, 63, 94, 0.20), transparent 34%),
    linear-gradient(135deg, #111827 0%, #7f1d1d 55%, #9a3412 100%);
  border: 1px solid rgba(255,255,255,0.13);
  box-shadow: 0 30px 90px rgba(127, 29, 29, 0.28);
  overflow: hidden;
}

.vb-date-three-top {
  display: grid;
  gap: 13px;
  max-width: 760px;
  margin-bottom: 28px;
}

.vb-date-three-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-three-top h3 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 7vw, 76px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-three-top p {
  max-width: 640px;
  margin: 0 !important;
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-three-countdown {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
  margin-bottom: 22px;
}

.vb-date-three-time-box {
  display: grid;
  gap: 9px;
  justify-items: center;
  min-height: 165px;
  align-content: center;
  padding: 18px;
  border-radius: 26px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.16);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.10);
  backdrop-filter: blur(12px);
}

.vb-date-three-time-box strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(42px, 7vw, 74px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.065em;
  font-variant-numeric: tabular-nums;
}

.vb-date-three-time-box span {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-three-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  padding: 16px 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-three-footer span {
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-date-three-footer strong {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.18);
  border: 1px solid rgba(74, 222, 128, 0.28);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-date-three-card.is-expired .vb-date-three-footer strong {
  background: rgba(248, 113, 113, 0.20);
  border-color: rgba(248, 113, 113, 0.34);
  color: #fecaca !important;
  -webkit-text-fill-color: #fecaca !important;
}

@media (max-width: 760px) {
  .vb-date-three-countdown {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-date-three-time-box {
    min-height: 140px;
  }
}

@media (max-width: 480px) {
  .vb-date-three-countdown {
    grid-template-columns: 1fr;
  }

  .vb-date-three-card {
    border-radius: 26px;
  }

  .vb-date-three-time-box {
    min-height: 120px;
    border-radius: 22px;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript event countdown example is useful for webinar landing pages, product launches, event websites, ecommerce sale pages, online course registrations, booking deadlines, and limited-time promotional sections.</p>



<h2 class="wp-block-heading">4. Time Zone Converter Cards</h2>



<p class="wp-block-paragraph"><strong>A JavaScript time zone converter</strong> is useful for international websites, remote teams, online meetings, support pages, event platforms, and booking interfaces. It helps visitors compare the same selected time across different regions.</p>



<p class="wp-block-paragraph">This example lets the user choose a meeting date and time, then JavaScript displays the matching time in New York, London, Tallinn, Tokyo, and Sydney. It uses <code>Intl.DateTimeFormat</code> with different <code>timeZone</code> values.</p>



<ul class="wp-block-list">
<li>Converts one selected time into multiple time zones</li>
<li>Uses Intl.DateTimeFormat with timeZone options</li>
<li>Includes date and time input</li>
<li>Responsive card layout</li>
<li>Useful for meeting planners, event pages, and support teams</li>
</ul>



<div class="vb-date-four-demo">
  <div class="vb-date-four-shell" data-vb-date-four>
    <div class="vb-date-four-intro">
      <span class="vb-date-four-kicker">Example 04</span>
      <h3>Time Zone Converter</h3>
      <p>Select one meeting time and instantly compare it across major time zones.</p>

      <label>
        <span>Meeting date and time</span>
        <input type="datetime-local" data-timezone-input>
      </label>

      <button type="button" data-timezone-now>Use Current Time</button>
    </div>

    <div class="vb-date-four-grid">
      <article class="vb-date-four-zone">
        <span>New York</span>
        <strong data-zone-output="America/New_York">--:--</strong>
        <small>America/New York</small>
      </article>

      <article class="vb-date-four-zone">
        <span>London</span>
        <strong data-zone-output="Europe/London">--:--</strong>
        <small>Europe/London</small>
      </article>

      <article class="vb-date-four-zone">
        <span>Tallinn</span>
        <strong data-zone-output="Europe/Tallinn">--:--</strong>
        <small>Europe/Tallinn</small>
      </article>

      <article class="vb-date-four-zone">
        <span>Tokyo</span>
        <strong data-zone-output="Asia/Tokyo">--:--</strong>
        <small>Asia/Tokyo</small>
      </article>

      <article class="vb-date-four-zone vb-date-four-wide">
        <span>Sydney</span>
        <strong data-zone-output="Australia/Sydney">--:--</strong>
        <small>Australia/Sydney</small>
      </article>
    </div>
  </div>
</div>

<style>
.vb-date-four-demo,
.vb-date-four-demo * {
  box-sizing: border-box;
}

.vb-date-four-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 14% 16%, rgba(37, 99, 235, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(20, 184, 166, 0.18), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfeff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.09);
}

.vb-date-four-shell {
  display: grid;
  grid-template-columns: minmax(280px, 0.85fr) minmax(0, 1.15fr);
  gap: 20px;
  max-width: 1140px;
  margin: 0 auto;
}

.vb-date-four-intro {
  min-width: 0;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 30px;
  background:
    radial-gradient(circle at top left, rgba(96, 165, 250, 0.20), transparent 38%),
    linear-gradient(135deg, #0f172a 0%, #164e63 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.22);
}

.vb-date-four-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-four-intro h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-four-intro p {
  margin: 0 0 22px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-four-intro label {
  display: grid;
  gap: 8px;
  margin-bottom: 14px;
}

.vb-date-four-intro label span {
  color: #cffafe !important;
  -webkit-text-fill-color: #cffafe !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-four-intro input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(255,255,255,0.20);
  border-radius: 17px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-four-intro input::-webkit-calendar-picker-indicator {
  filter: invert(1);
  opacity: 0.9;
}

.vb-date-four-intro input:focus {
  border-color: rgba(103, 232, 249, 0.85);
  box-shadow: 0 0 0 4px rgba(103, 232, 249, 0.14);
}

.vb-date-four-intro button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 46px;
  padding: 12px 16px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #06b6d4, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 14px 34px rgba(6, 182, 212, 0.24);
}

.vb-date-four-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
}

.vb-date-four-zone {
  display: grid;
  align-content: center;
  gap: 10px;
  min-width: 0;
  min-height: 168px;
  padding: 22px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 20px 60px rgba(15, 23, 42, 0.08);
}

.vb-date-four-zone span {
  color: #0891b2 !important;
  -webkit-text-fill-color: #0891b2 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-date-four-zone strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(24px, 4vw, 42px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-date-four-zone small {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 750;
  overflow-wrap: anywhere;
}

.vb-date-four-wide {
  grid-column: 1 / -1;
  min-height: 138px;
  background:
    radial-gradient(circle at 10% 20%, rgba(20, 184, 166, 0.14), transparent 34%),
    linear-gradient(135deg, #f8fafc, #ecfeff) !important;
}

@media (max-width: 900px) {
  .vb-date-four-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 580px) {
  .vb-date-four-grid {
    grid-template-columns: 1fr;
  }

  .vb-date-four-intro,
  .vb-date-four-zone {
    border-radius: 22px;
  }

  .vb-date-four-intro button {
    width: 100%;
  }

  .vb-date-four-zone {
    min-height: 130px;
  }
}
</style>

<script>
(function () {
  const converter = document.querySelector("[data-vb-date-four]");
  if (!converter) return;

  const input = converter.querySelector("[data-timezone-input]");
  const nowButton = converter.querySelector("[data-timezone-now]");
  const outputs = converter.querySelectorAll("[data-zone-output]");

  function getLocalDateTimeValue(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");
    const hours = String(date.getHours()).padStart(2, "0");
    const minutes = String(date.getMinutes()).padStart(2, "0");

    return year + "-" + month + "-" + day + "T" + hours + ":" + minutes;
  }

  function updateZones() {
    if (!input.value) return;

    const selectedDate = new Date(input.value);

    outputs.forEach(function (output) {
      const zone = output.getAttribute("data-zone-output");

      output.textContent = new Intl.DateTimeFormat("en", {
        timeZone: zone,
        weekday: "short",
        month: "short",
        day: "numeric",
        hour: "2-digit",
        minute: "2-digit"
      }).format(selectedDate);
    });
  }

  function useCurrentTime() {
    input.value = getLocalDateTimeValue(new Date());
    updateZones();
  }

  input.addEventListener("change", updateZones);
  nowButton.addEventListener("click", useCurrentTime);

  useCurrentTime();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const converter = document.querySelector("[data-vb-date-four]");
  if (!converter) return;

  const input = converter.querySelector("[data-timezone-input]");
  const nowButton = converter.querySelector("[data-timezone-now]");
  const outputs = converter.querySelectorAll("[data-zone-output]");

  function getLocalDateTimeValue(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");
    const hours = String(date.getHours()).padStart(2, "0");
    const minutes = String(date.getMinutes()).padStart(2, "0");

    return year + "-" + month + "-" + day + "T" + hours + ":" + minutes;
  }

  function updateZones() {
    if (!input.value) return;

    const selectedDate = new Date(input.value);

    outputs.forEach(function (output) {
      const zone = output.getAttribute("data-zone-output");

      output.textContent = new Intl.DateTimeFormat("en", {
        timeZone: zone,
        weekday: "short",
        month: "short",
        day: "numeric",
        hour: "2-digit",
        minute: "2-digit"
      }).format(selectedDate);
    });
  }

  function useCurrentTime() {
    input.value = getLocalDateTimeValue(new Date());
    updateZones();
  }

  input.addEventListener("change", updateZones);
  nowButton.addEventListener("click", useCurrentTime);

  useCurrentTime();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-four-demo"&gt;
  &lt;div class="vb-date-four-shell" data-vb-date-four&gt;
    &lt;div class="vb-date-four-intro"&gt;
      &lt;span class="vb-date-four-kicker"&gt;Example 04&lt;/span&gt;
      &lt;h3&gt;Time Zone Converter&lt;/h3&gt;
      &lt;p&gt;Select one meeting time and instantly compare it across major time zones.&lt;/p&gt;

      &lt;label&gt;
        &lt;span&gt;Meeting date and time&lt;/span&gt;
        &lt;input type="datetime-local" data-timezone-input&gt;
      &lt;/label&gt;

      &lt;button type="button" data-timezone-now&gt;Use Current Time&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-four-grid"&gt;
      &lt;article class="vb-date-four-zone"&gt;
        &lt;span&gt;New York&lt;/span&gt;
        &lt;strong data-zone-output="America/New_York"&gt;--:--&lt;/strong&gt;
        &lt;small&gt;America/New York&lt;/small&gt;
      &lt;/article&gt;

      &lt;article class="vb-date-four-zone"&gt;
        &lt;span&gt;London&lt;/span&gt;
        &lt;strong data-zone-output="Europe/London"&gt;--:--&lt;/strong&gt;
        &lt;small&gt;Europe/London&lt;/small&gt;
      &lt;/article&gt;

      &lt;article class="vb-date-four-zone"&gt;
        &lt;span&gt;Tallinn&lt;/span&gt;
        &lt;strong data-zone-output="Europe/Tallinn"&gt;--:--&lt;/strong&gt;
        &lt;small&gt;Europe/Tallinn&lt;/small&gt;
      &lt;/article&gt;

      &lt;article class="vb-date-four-zone"&gt;
        &lt;span&gt;Tokyo&lt;/span&gt;
        &lt;strong data-zone-output="Asia/Tokyo"&gt;--:--&lt;/strong&gt;
        &lt;small&gt;Asia/Tokyo&lt;/small&gt;
      &lt;/article&gt;

      &lt;article class="vb-date-four-zone vb-date-four-wide"&gt;
        &lt;span&gt;Sydney&lt;/span&gt;
        &lt;strong data-zone-output="Australia/Sydney"&gt;--:--&lt;/strong&gt;
        &lt;small&gt;Australia/Sydney&lt;/small&gt;
      &lt;/article&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-four-demo,
.vb-date-four-demo * {
  box-sizing: border-box;
}

.vb-date-four-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 14% 16%, rgba(37, 99, 235, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(20, 184, 166, 0.18), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfeff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.09);
}

.vb-date-four-shell {
  display: grid;
  grid-template-columns: minmax(280px, 0.85fr) minmax(0, 1.15fr);
  gap: 20px;
  max-width: 1140px;
  margin: 0 auto;
}

.vb-date-four-intro {
  min-width: 0;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 30px;
  background:
    radial-gradient(circle at top left, rgba(96, 165, 250, 0.20), transparent 38%),
    linear-gradient(135deg, #0f172a 0%, #164e63 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.22);
}

.vb-date-four-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-four-intro h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-four-intro p {
  margin: 0 0 22px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-four-intro label {
  display: grid;
  gap: 8px;
  margin-bottom: 14px;
}

.vb-date-four-intro label span {
  color: #cffafe !important;
  -webkit-text-fill-color: #cffafe !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-four-intro input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(255,255,255,0.20);
  border-radius: 17px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-four-intro input::-webkit-calendar-picker-indicator {
  filter: invert(1);
  opacity: 0.9;
}

.vb-date-four-intro input:focus {
  border-color: rgba(103, 232, 249, 0.85);
  box-shadow: 0 0 0 4px rgba(103, 232, 249, 0.14);
}

.vb-date-four-intro button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 46px;
  padding: 12px 16px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #06b6d4, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 14px 34px rgba(6, 182, 212, 0.24);
}

.vb-date-four-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
}

.vb-date-four-zone {
  display: grid;
  align-content: center;
  gap: 10px;
  min-width: 0;
  min-height: 168px;
  padding: 22px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 20px 60px rgba(15, 23, 42, 0.08);
}

.vb-date-four-zone span {
  color: #0891b2 !important;
  -webkit-text-fill-color: #0891b2 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-date-four-zone strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(24px, 4vw, 42px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-date-four-zone small {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 750;
  overflow-wrap: anywhere;
}

.vb-date-four-wide {
  grid-column: 1 / -1;
  min-height: 138px;
  background:
    radial-gradient(circle at 10% 20%, rgba(20, 184, 166, 0.14), transparent 34%),
    linear-gradient(135deg, #f8fafc, #ecfeff) !important;
}

@media (max-width: 900px) {
  .vb-date-four-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 580px) {
  .vb-date-four-grid {
    grid-template-columns: 1fr;
  }

  .vb-date-four-intro,
  .vb-date-four-zone {
    border-radius: 22px;
  }

  .vb-date-four-intro button {
    width: 100%;
  }

  .vb-date-four-zone {
    min-height: 130px;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript time zone converter example is useful for remote team pages, event registration pages, international booking forms, webinar landing pages, SaaS dashboards, and support pages that serve users in different countries.</p>



<h2 class="wp-block-heading">5. Working Hours Open or Closed Checker</h2>



<p class="wp-block-paragraph"><strong>A working hours checker</strong> is a practical JavaScript date and time example for business websites, support widgets, restaurants, clinics, agencies, ecommerce stores, and local service pages. It tells visitors whether the business is currently open or closed.</p>



<p class="wp-block-paragraph">This example checks the current day and hour in JavaScript. It shows an open or closed status, displays today’s working hours, and explains when the business is available. The layout is responsive and works well inside WordPress content blocks.</p>



<ul class="wp-block-list">
<li>Checks current day and hour</li>
<li>Shows open or closed status</li>
<li>Displays today’s working hours</li>
<li>Includes weekly schedule cards</li>
<li>Useful for local businesses, support teams, and service websites</li>
</ul>



<div class="vb-date-five-demo">
  <div class="vb-date-five-card" data-vb-date-five>
    <div class="vb-date-five-main">
      <span class="vb-date-five-kicker">Example 05</span>
      <h3>Business Hours Checker</h3>
      <p>JavaScript checks the current day and time, then displays whether the business is open or closed.</p>

      <div class="vb-date-five-status" data-status-box>
        <strong data-open-status>Checking...</strong>
        <span data-open-message>Please wait while JavaScript checks the current time.</span>
      </div>
    </div>

    <div class="vb-date-five-side">
      <div class="vb-date-five-today">
        <span>Today</span>
        <strong data-today-hours>Loading...</strong>
      </div>

      <div class="vb-date-five-schedule">
        <div data-day-row="1"><span>Mon</span><strong>09:00 - 17:00</strong></div>
        <div data-day-row="2"><span>Tue</span><strong>09:00 - 17:00</strong></div>
        <div data-day-row="3"><span>Wed</span><strong>09:00 - 17:00</strong></div>
        <div data-day-row="4"><span>Thu</span><strong>09:00 - 17:00</strong></div>
        <div data-day-row="5"><span>Fri</span><strong>09:00 - 16:00</strong></div>
        <div data-day-row="6"><span>Sat</span><strong>Closed</strong></div>
        <div data-day-row="0"><span>Sun</span><strong>Closed</strong></div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-date-five-demo,
.vb-date-five-demo * {
  box-sizing: border-box;
}

.vb-date-five-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 197, 94, 0.18), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #eff6ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-five-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(280px, 380px);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 26px 80px rgba(15, 23, 42, 0.10);
}

.vb-date-five-main {
  display: grid;
  align-content: center;
  min-width: 0;
  padding: clamp(4px, 2vw, 14px);
}

.vb-date-five-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-five-main h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 68px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-five-main p {
  max-width: 620px;
  margin: 0 0 24px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-five-status {
  display: grid;
  gap: 8px;
  max-width: 620px;
  padding: 20px;
  border-radius: 24px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-date-five-status strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(26px, 4vw, 42px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-date-five-status span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 15px;
  line-height: 1.55;
  font-weight: 750;
}

.vb-date-five-status.is-open {
  background: #ecfdf5;
  border-color: rgba(34, 197, 94, 0.28);
}

.vb-date-five-status.is-open strong {
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
}

.vb-date-five-status.is-closed {
  background: #fef2f2;
  border-color: rgba(248, 113, 113, 0.30);
}

.vb-date-five-status.is-closed strong {
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-date-five-side {
  display: grid;
  gap: 14px;
  min-width: 0;
}

.vb-date-five-today {
  display: grid;
  gap: 8px;
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at top right, rgba(34, 197, 94, 0.18), transparent 42%),
    linear-gradient(135deg, #0f172a, #14532d) !important;
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-date-five-today span {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.12em;
}

.vb-date-five-today strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(24px, 4vw, 38px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-date-five-schedule {
  display: grid;
  gap: 8px;
}

.vb-date-five-schedule div {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  min-width: 0;
  padding: 12px 14px;
  border-radius: 16px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.18);
}

.vb-date-five-schedule div.is-today {
  background: #eff6ff;
  border-color: rgba(37, 99, 235, 0.28);
}

.vb-date-five-schedule span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-date-five-schedule strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 13px;
  font-weight: 850;
  text-align: right;
}

@media (max-width: 900px) {
  .vb-date-five-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-date-five-card,
  .vb-date-five-status,
  .vb-date-five-today {
    border-radius: 22px;
  }

  .vb-date-five-schedule div {
    align-items: flex-start;
    flex-direction: column;
    gap: 5px;
  }

  .vb-date-five-schedule strong {
    text-align: left;
  }
}
</style>

<script>
(function () {
  const checker = document.querySelector("[data-vb-date-five]");
  if (!checker) return;

  const statusBox = checker.querySelector("[data-status-box]");
  const statusText = checker.querySelector("[data-open-status]");
  const messageText = checker.querySelector("[data-open-message]");
  const todayHours = checker.querySelector("[data-today-hours]");
  const dayRows = checker.querySelectorAll("[data-day-row]");

  const schedule = {
    0: null,
    1: { open: 9, close: 17, label: "09:00 - 17:00" },
    2: { open: 9, close: 17, label: "09:00 - 17:00" },
    3: { open: 9, close: 17, label: "09:00 - 17:00" },
    4: { open: 9, close: 17, label: "09:00 - 17:00" },
    5: { open: 9, close: 16, label: "09:00 - 16:00" },
    6: null
  };

  function checkBusinessHours() {
    const now = new Date();
    const day = now.getDay();
    const hour = now.getHours();
    const todaySchedule = schedule[day];

    dayRows.forEach(function (row) {
      row.classList.toggle("is-today", Number(row.getAttribute("data-day-row")) === day);
    });

    todayHours.textContent = todaySchedule ? todaySchedule.label : "Closed";

    statusBox.classList.remove("is-open", "is-closed");

    if (todaySchedule && hour >= todaySchedule.open && hour < todaySchedule.close) {
      statusBox.classList.add("is-open");
      statusText.textContent = "We are open now";
      messageText.textContent = "Today’s working hours are " + todaySchedule.label + ". You can contact us during business hours.";
    } else {
      statusBox.classList.add("is-closed");
      statusText.textContent = "We are closed now";

      if (todaySchedule) {
        messageText.textContent = "Today’s working hours are " + todaySchedule.label + ". Please contact us during the next open period.";
      } else {
        messageText.textContent = "The business is closed today. Please check the weekly schedule for the next open day.";
      }
    }
  }

  checkBusinessHours();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const checker = document.querySelector("[data-vb-date-five]");
  if (!checker) return;

  const statusBox = checker.querySelector("[data-status-box]");
  const statusText = checker.querySelector("[data-open-status]");
  const messageText = checker.querySelector("[data-open-message]");
  const todayHours = checker.querySelector("[data-today-hours]");
  const dayRows = checker.querySelectorAll("[data-day-row]");

  const schedule = {
    0: null,
    1: { open: 9, close: 17, label: "09:00 - 17:00" },
    2: { open: 9, close: 17, label: "09:00 - 17:00" },
    3: { open: 9, close: 17, label: "09:00 - 17:00" },
    4: { open: 9, close: 17, label: "09:00 - 17:00" },
    5: { open: 9, close: 16, label: "09:00 - 16:00" },
    6: null
  };

  function checkBusinessHours() {
    const now = new Date();
    const day = now.getDay();
    const hour = now.getHours();
    const todaySchedule = schedule[day];

    dayRows.forEach(function (row) {
      row.classList.toggle("is-today", Number(row.getAttribute("data-day-row")) === day);
    });

    todayHours.textContent = todaySchedule ? todaySchedule.label : "Closed";

    statusBox.classList.remove("is-open", "is-closed");

    if (todaySchedule && hour >= todaySchedule.open && hour < todaySchedule.close) {
      statusBox.classList.add("is-open");
      statusText.textContent = "We are open now";
      messageText.textContent = "Today’s working hours are " + todaySchedule.label + ". You can contact us during business hours.";
    } else {
      statusBox.classList.add("is-closed");
      statusText.textContent = "We are closed now";

      if (todaySchedule) {
        messageText.textContent = "Today’s working hours are " + todaySchedule.label + ". Please contact us during the next open period.";
      } else {
        messageText.textContent = "The business is closed today. Please check the weekly schedule for the next open day.";
      }
    }
  }

  checkBusinessHours();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-five-demo"&gt;
  &lt;div class="vb-date-five-card" data-vb-date-five&gt;
    &lt;div class="vb-date-five-main"&gt;
      &lt;span class="vb-date-five-kicker"&gt;Example 05&lt;/span&gt;
      &lt;h3&gt;Business Hours Checker&lt;/h3&gt;
      &lt;p&gt;JavaScript checks the current day and time, then displays whether the business is open or closed.&lt;/p&gt;

      &lt;div class="vb-date-five-status" data-status-box&gt;
        &lt;strong data-open-status&gt;Checking...&lt;/strong&gt;
        &lt;span data-open-message&gt;Please wait while JavaScript checks the current time.&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-five-side"&gt;
      &lt;div class="vb-date-five-today"&gt;
        &lt;span&gt;Today&lt;/span&gt;
        &lt;strong data-today-hours&gt;Loading...&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-five-schedule"&gt;
        &lt;div data-day-row="1"&gt;&lt;span&gt;Mon&lt;/span&gt;&lt;strong&gt;09:00 - 17:00&lt;/strong&gt;&lt;/div&gt;
        &lt;div data-day-row="2"&gt;&lt;span&gt;Tue&lt;/span&gt;&lt;strong&gt;09:00 - 17:00&lt;/strong&gt;&lt;/div&gt;
        &lt;div data-day-row="3"&gt;&lt;span&gt;Wed&lt;/span&gt;&lt;strong&gt;09:00 - 17:00&lt;/strong&gt;&lt;/div&gt;
        &lt;div data-day-row="4"&gt;&lt;span&gt;Thu&lt;/span&gt;&lt;strong&gt;09:00 - 17:00&lt;/strong&gt;&lt;/div&gt;
        &lt;div data-day-row="5"&gt;&lt;span&gt;Fri&lt;/span&gt;&lt;strong&gt;09:00 - 16:00&lt;/strong&gt;&lt;/div&gt;
        &lt;div data-day-row="6"&gt;&lt;span&gt;Sat&lt;/span&gt;&lt;strong&gt;Closed&lt;/strong&gt;&lt;/div&gt;
        &lt;div data-day-row="0"&gt;&lt;span&gt;Sun&lt;/span&gt;&lt;strong&gt;Closed&lt;/strong&gt;&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-five-demo,
.vb-date-five-demo * {
  box-sizing: border-box;
}

.vb-date-five-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 197, 94, 0.18), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #eff6ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-five-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(280px, 380px);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 26px 80px rgba(15, 23, 42, 0.10);
}

.vb-date-five-main {
  display: grid;
  align-content: center;
  min-width: 0;
  padding: clamp(4px, 2vw, 14px);
}

.vb-date-five-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-five-main h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 68px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-five-main p {
  max-width: 620px;
  margin: 0 0 24px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-five-status {
  display: grid;
  gap: 8px;
  max-width: 620px;
  padding: 20px;
  border-radius: 24px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-date-five-status strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(26px, 4vw, 42px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-date-five-status span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 15px;
  line-height: 1.55;
  font-weight: 750;
}

.vb-date-five-status.is-open {
  background: #ecfdf5;
  border-color: rgba(34, 197, 94, 0.28);
}

.vb-date-five-status.is-open strong {
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
}

.vb-date-five-status.is-closed {
  background: #fef2f2;
  border-color: rgba(248, 113, 113, 0.30);
}

.vb-date-five-status.is-closed strong {
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-date-five-side {
  display: grid;
  gap: 14px;
  min-width: 0;
}

.vb-date-five-today {
  display: grid;
  gap: 8px;
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at top right, rgba(34, 197, 94, 0.18), transparent 42%),
    linear-gradient(135deg, #0f172a, #14532d) !important;
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-date-five-today span {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.12em;
}

.vb-date-five-today strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(24px, 4vw, 38px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-date-five-schedule {
  display: grid;
  gap: 8px;
}

.vb-date-five-schedule div {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  min-width: 0;
  padding: 12px 14px;
  border-radius: 16px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.18);
}

.vb-date-five-schedule div.is-today {
  background: #eff6ff;
  border-color: rgba(37, 99, 235, 0.28);
}

.vb-date-five-schedule span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-date-five-schedule strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 13px;
  font-weight: 850;
  text-align: right;
}

@media (max-width: 900px) {
  .vb-date-five-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-date-five-card,
  .vb-date-five-status,
  .vb-date-five-today {
    border-radius: 22px;
  }

  .vb-date-five-schedule div {
    align-items: flex-start;
    flex-direction: column;
    gap: 5px;
  }

  .vb-date-five-schedule strong {
    text-align: left;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript working hours checker is useful for local business websites, contact pages, live chat widgets, support teams, restaurants, clinics, agencies, service companies, and ecommerce stores that want to show availability clearly.</p>



<h2 class="wp-block-heading">6. Delivery Date Calculator with Business Days</h2>



<p class="wp-block-paragraph"><strong>A delivery date calculator</strong> is a highly practical JavaScript date and time example for ecommerce websites, quote forms, shipping pages, product pages, service bookings, and order dashboards. It helps users understand when they can expect delivery or completion.</p>



<p class="wp-block-paragraph">This example adds business days to the selected order date and skips weekends. The user can choose a processing speed, and JavaScript calculates the estimated delivery date with a clean responsive result card.</p>



<ul class="wp-block-list">
<li>Calculates estimated delivery date</li>
<li>Skips Saturday and Sunday</li>
<li>Includes standard, express, and priority options</li>
<li>Uses JavaScript date calculations</li>
<li>Useful for ecommerce, product pages, shipping pages, and quote forms</li>
</ul>



<div class="vb-date-six-demo">
  <div class="vb-date-six-shell" data-vb-date-six>
    <div class="vb-date-six-form-card">
      <span class="vb-date-six-kicker">Example 06</span>
      <h3>Delivery Date Calculator</h3>
      <p>Select an order date and delivery speed. JavaScript calculates the estimated delivery date while skipping weekends.</p>

      <div class="vb-date-six-controls">
        <label>
          <span>Order date</span>
          <input type="date" data-order-date>
        </label>

        <label>
          <span>Delivery speed</span>
          <select data-delivery-speed>
            <option value="7">Standard delivery - 7 business days</option>
            <option value="4">Express delivery - 4 business days</option>
            <option value="2">Priority delivery - 2 business days</option>
          </select>
        </label>
      </div>

      <button type="button" data-calculate-delivery>Calculate Delivery Date</button>
    </div>

    <div class="vb-date-six-result-card">
      <div class="vb-date-six-badge">Estimated result</div>

      <div class="vb-date-six-date">
        <span data-result-weekday>Weekday</span>
        <strong data-result-date>Select order date</strong>
      </div>

      <p data-result-message>Your estimated delivery date will appear here.</p>

      <div class="vb-date-six-steps">
        <div>
          <span>Order</span>
          <strong data-step-order>--</strong>
        </div>
        <div>
          <span>Business days</span>
          <strong data-step-days>--</strong>
        </div>
        <div>
          <span>Weekend rule</span>
          <strong>Skipped</strong>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-date-six-demo,
.vb-date-six-demo * {
  box-sizing: border-box;
}

.vb-date-six-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 15% 18%, rgba(124, 58, 237, 0.18), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(245, 158, 11, 0.18), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #fffbeb 55%, #ffffff 100%) !important;
  border: 1px solid rgba(124, 58, 237, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.09);
}

.vb-date-six-shell {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 430px);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-six-form-card,
.vb-date-six-result-card {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-six-form-card {
  padding: clamp(22px, 4vw, 38px);
  background: #ffffff;
}

.vb-date-six-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-six-form-card h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-six-form-card p {
  max-width: 640px;
  margin: 0 0 24px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-six-controls {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  margin-bottom: 16px;
}

.vb-date-six-controls label {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.vb-date-six-controls label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-six-controls input,
.vb-date-six-controls select {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 750;
  outline: none;
}

.vb-date-six-controls input:focus,
.vb-date-six-controls select:focus {
  border-color: rgba(124, 58, 237, 0.78);
  box-shadow: 0 0 0 4px rgba(124, 58, 237, 0.12);
}

.vb-date-six-form-card button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #7c3aed, #f97316);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(124, 58, 237, 0.24);
}

.vb-date-six-result-card {
  display: grid;
  align-content: center;
  gap: 18px;
  padding: clamp(22px, 4vw, 34px);
  background:
    radial-gradient(circle at 18% 14%, rgba(253, 186, 116, 0.20), transparent 34%),
    linear-gradient(135deg, #111827 0%, #312e81 52%, #7c2d12 100%) !important;
  overflow: hidden;
}

.vb-date-six-badge {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.16);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-six-date {
  display: grid;
  gap: 8px;
}

.vb-date-six-date span {
  color: #c4b5fd !important;
  -webkit-text-fill-color: #c4b5fd !important;
  font-size: 15px;
  font-weight: 900;
}

.vb-date-six-date strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 6vw, 58px);
  line-height: 0.98;
  font-weight: 950;
  letter-spacing: -0.065em;
  overflow-wrap: anywhere;
}

.vb-date-six-result-card p {
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-date-six-steps {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}

.vb-date-six-steps div {
  min-width: 0;
  padding: 13px;
  border-radius: 17px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-date-six-steps span {
  display: block;
  margin-bottom: 5px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 11px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-date-six-steps strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  line-height: 1.25;
  font-weight: 850;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-date-six-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-date-six-controls,
  .vb-date-six-steps {
    grid-template-columns: 1fr;
  }

  .vb-date-six-form-card,
  .vb-date-six-result-card {
    border-radius: 24px;
  }

  .vb-date-six-form-card button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const calculator = document.querySelector("[data-vb-date-six]");
  if (!calculator) return;

  const orderInput = calculator.querySelector("[data-order-date]");
  const speedSelect = calculator.querySelector("[data-delivery-speed]");
  const calculateButton = calculator.querySelector("[data-calculate-delivery]");

  const resultWeekday = calculator.querySelector("[data-result-weekday]");
  const resultDate = calculator.querySelector("[data-result-date]");
  const resultMessage = calculator.querySelector("[data-result-message]");
  const stepOrder = calculator.querySelector("[data-step-order]");
  const stepDays = calculator.querySelector("[data-step-days]");

  function formatInputDate(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");

    return year + "-" + month + "-" + day;
  }

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function addBusinessDays(startDate, businessDays) {
    const result = new Date(startDate);
    let addedDays = 0;

    while (addedDays < businessDays) {
      result.setDate(result.getDate() + 1);

      const day = result.getDay();
      const isWeekend = day === 0 || day === 6;

      if (!isWeekend) {
        addedDays += 1;
      }
    }

    return result;
  }

  function formatLongDate(date) {
    return new Intl.DateTimeFormat("en", {
      month: "long",
      day: "numeric",
      year: "numeric"
    }).format(date);
  }

  function calculateDeliveryDate() {
    if (!orderInput.value) {
      resultWeekday.textContent = "Missing order date";
      resultDate.textContent = "Select order date";
      resultMessage.textContent = "Please select an order date before calculating the estimated delivery date.";
      stepOrder.textContent = "--";
      stepDays.textContent = "--";
      return;
    }

    const orderDate = createLocalDate(orderInput.value);
    const businessDays = Number(speedSelect.value);
    const deliveryDate = addBusinessDays(orderDate, businessDays);

    resultWeekday.textContent = new Intl.DateTimeFormat("en", {
      weekday: "long"
    }).format(deliveryDate);

    resultDate.textContent = formatLongDate(deliveryDate);
    resultMessage.textContent = "Estimated delivery is " + businessDays + " business days after the selected order date. Weekends are skipped automatically.";

    stepOrder.textContent = formatLongDate(orderDate);
    stepDays.textContent = businessDays + " days";
  }

  function setToday() {
    orderInput.value = formatInputDate(new Date());
    calculateDeliveryDate();
  }

  calculateButton.addEventListener("click", calculateDeliveryDate);
  speedSelect.addEventListener("change", calculateDeliveryDate);
  orderInput.addEventListener("change", calculateDeliveryDate);

  setToday();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const calculator = document.querySelector("[data-vb-date-six]");
  if (!calculator) return;

  const orderInput = calculator.querySelector("[data-order-date]");
  const speedSelect = calculator.querySelector("[data-delivery-speed]");
  const calculateButton = calculator.querySelector("[data-calculate-delivery]");

  const resultWeekday = calculator.querySelector("[data-result-weekday]");
  const resultDate = calculator.querySelector("[data-result-date]");
  const resultMessage = calculator.querySelector("[data-result-message]");
  const stepOrder = calculator.querySelector("[data-step-order]");
  const stepDays = calculator.querySelector("[data-step-days]");

  function formatInputDate(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");

    return year + "-" + month + "-" + day;
  }

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function addBusinessDays(startDate, businessDays) {
    const result = new Date(startDate);
    let addedDays = 0;

    while (addedDays < businessDays) {
      result.setDate(result.getDate() + 1);

      const day = result.getDay();
      const isWeekend = day === 0 || day === 6;

      if (!isWeekend) {
        addedDays += 1;
      }
    }

    return result;
  }

  function formatLongDate(date) {
    return new Intl.DateTimeFormat("en", {
      month: "long",
      day: "numeric",
      year: "numeric"
    }).format(date);
  }

  function calculateDeliveryDate() {
    if (!orderInput.value) {
      resultWeekday.textContent = "Missing order date";
      resultDate.textContent = "Select order date";
      resultMessage.textContent = "Please select an order date before calculating the estimated delivery date.";
      stepOrder.textContent = "--";
      stepDays.textContent = "--";
      return;
    }

    const orderDate = createLocalDate(orderInput.value);
    const businessDays = Number(speedSelect.value);
    const deliveryDate = addBusinessDays(orderDate, businessDays);

    resultWeekday.textContent = new Intl.DateTimeFormat("en", {
      weekday: "long"
    }).format(deliveryDate);

    resultDate.textContent = formatLongDate(deliveryDate);
    resultMessage.textContent = "Estimated delivery is " + businessDays + " business days after the selected order date. Weekends are skipped automatically.";

    stepOrder.textContent = formatLongDate(orderDate);
    stepDays.textContent = businessDays + " days";
  }

  function setToday() {
    orderInput.value = formatInputDate(new Date());
    calculateDeliveryDate();
  }

  calculateButton.addEventListener("click", calculateDeliveryDate);
  speedSelect.addEventListener("change", calculateDeliveryDate);
  orderInput.addEventListener("change", calculateDeliveryDate);

  setToday();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-six-demo"&gt;
  &lt;div class="vb-date-six-shell" data-vb-date-six&gt;
    &lt;div class="vb-date-six-form-card"&gt;
      &lt;span class="vb-date-six-kicker"&gt;Example 06&lt;/span&gt;
      &lt;h3&gt;Delivery Date Calculator&lt;/h3&gt;
      &lt;p&gt;Select an order date and delivery speed. JavaScript calculates the estimated delivery date while skipping weekends.&lt;/p&gt;

      &lt;div class="vb-date-six-controls"&gt;
        &lt;label&gt;
          &lt;span&gt;Order date&lt;/span&gt;
          &lt;input type="date" data-order-date&gt;
        &lt;/label&gt;

        &lt;label&gt;
          &lt;span&gt;Delivery speed&lt;/span&gt;
          &lt;select data-delivery-speed&gt;
            &lt;option value="7"&gt;Standard delivery - 7 business days&lt;/option&gt;
            &lt;option value="4"&gt;Express delivery - 4 business days&lt;/option&gt;
            &lt;option value="2"&gt;Priority delivery - 2 business days&lt;/option&gt;
          &lt;/select&gt;
        &lt;/label&gt;
      &lt;/div&gt;

      &lt;button type="button" data-calculate-delivery&gt;Calculate Delivery Date&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-six-result-card"&gt;
      &lt;div class="vb-date-six-badge"&gt;Estimated result&lt;/div&gt;

      &lt;div class="vb-date-six-date"&gt;
        &lt;span data-result-weekday&gt;Weekday&lt;/span&gt;
        &lt;strong data-result-date&gt;Select order date&lt;/strong&gt;
      &lt;/div&gt;

      &lt;p data-result-message&gt;Your estimated delivery date will appear here.&lt;/p&gt;

      &lt;div class="vb-date-six-steps"&gt;
        &lt;div&gt;
          &lt;span&gt;Order&lt;/span&gt;
          &lt;strong data-step-order&gt;--&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Business days&lt;/span&gt;
          &lt;strong data-step-days&gt;--&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Weekend rule&lt;/span&gt;
          &lt;strong&gt;Skipped&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-six-demo,
.vb-date-six-demo * {
  box-sizing: border-box;
}

.vb-date-six-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 15% 18%, rgba(124, 58, 237, 0.18), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(245, 158, 11, 0.18), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #fffbeb 55%, #ffffff 100%) !important;
  border: 1px solid rgba(124, 58, 237, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.09);
}

.vb-date-six-shell {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 430px);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-six-form-card,
.vb-date-six-result-card {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-six-form-card {
  padding: clamp(22px, 4vw, 38px);
  background: #ffffff;
}

.vb-date-six-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-six-form-card h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-six-form-card p {
  max-width: 640px;
  margin: 0 0 24px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-six-controls {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  margin-bottom: 16px;
}

.vb-date-six-controls label {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.vb-date-six-controls label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-six-controls input,
.vb-date-six-controls select {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 750;
  outline: none;
}

.vb-date-six-controls input:focus,
.vb-date-six-controls select:focus {
  border-color: rgba(124, 58, 237, 0.78);
  box-shadow: 0 0 0 4px rgba(124, 58, 237, 0.12);
}

.vb-date-six-form-card button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #7c3aed, #f97316);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(124, 58, 237, 0.24);
}

.vb-date-six-result-card {
  display: grid;
  align-content: center;
  gap: 18px;
  padding: clamp(22px, 4vw, 34px);
  background:
    radial-gradient(circle at 18% 14%, rgba(253, 186, 116, 0.20), transparent 34%),
    linear-gradient(135deg, #111827 0%, #312e81 52%, #7c2d12 100%) !important;
  overflow: hidden;
}

.vb-date-six-badge {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.16);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-six-date {
  display: grid;
  gap: 8px;
}

.vb-date-six-date span {
  color: #c4b5fd !important;
  -webkit-text-fill-color: #c4b5fd !important;
  font-size: 15px;
  font-weight: 900;
}

.vb-date-six-date strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 6vw, 58px);
  line-height: 0.98;
  font-weight: 950;
  letter-spacing: -0.065em;
  overflow-wrap: anywhere;
}

.vb-date-six-result-card p {
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-date-six-steps {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}

.vb-date-six-steps div {
  min-width: 0;
  padding: 13px;
  border-radius: 17px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-date-six-steps span {
  display: block;
  margin-bottom: 5px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 11px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-date-six-steps strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  line-height: 1.25;
  font-weight: 850;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-date-six-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-date-six-controls,
  .vb-date-six-steps {
    grid-template-columns: 1fr;
  }

  .vb-date-six-form-card,
  .vb-date-six-result-card {
    border-radius: 24px;
  }

  .vb-date-six-form-card button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript delivery date calculator is useful for ecommerce product pages, shipping estimate widgets, quote request forms, service booking systems, production timelines, order dashboards, and checkout helper sections.</p>



<div class="vb24-js-date-contact-cta">
  <div class="vb24-js-date-contact-content">
    <span>Need a custom JavaScript feature?</span>
    <h2>Can’t build this yourself? We can create it for your website.</h2>
    <p>If you need a custom calculator, booking tool, countdown, date picker, dashboard widget, or interactive JavaScript component, our team can build a responsive and professional solution for your website.</p>
  </div>

  <a href="https://veebilehed24.ee/en/contact/" class="vb24-js-date-contact-button">Contact Us</a>
</div>

<style>
.vb24-js-date-contact-cta,
.vb24-js-date-contact-cta * {
  box-sizing: border-box;
}

.vb24-js-date-contact-cta {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 24px;
  align-items: center;
  margin: 42px 0;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 12% 20%, rgba(34, 211, 238, 0.22), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(249, 115, 22, 0.22), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #312e81 52%, #7c2d12 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 26px 80px rgba(15, 23, 42, 0.24);
}

.vb24-js-date-contact-content {
  min-width: 0;
}

.vb24-js-date-contact-content span {
  display: inline-flex;
  margin-bottom: 10px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb24-js-date-contact-content h2 {
  margin: 0 0 10px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(26px, 4vw, 42px) !important;
  line-height: 1.05 !important;
  font-weight: 950 !important;
  letter-spacing: -0.055em;
}

.vb24-js-date-contact-content p {
  max-width: 820px;
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb24-js-date-contact-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 14px 22px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22d3ee, #2563eb 55%, #f97316);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  text-decoration: none !important;
  white-space: nowrap;
  box-shadow: 0 16px 40px rgba(37, 99, 235, 0.32);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-js-date-contact-button:hover {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transform: translateY(-2px);
  filter: saturate(1.08);
  box-shadow: 0 20px 52px rgba(37, 99, 235, 0.40);
}

@media (max-width: 760px) {
  .vb24-js-date-contact-cta {
    grid-template-columns: 1fr;
    border-radius: 24px;
  }

  .vb24-js-date-contact-button {
    width: 100%;
  }
}
</style>



<h2 class="wp-block-heading">7. Age Calculator from Birth Date</h2>



<p class="wp-block-paragraph"><strong>A JavaScript age calculator</strong> is a practical date and time example for signup forms, health calculators, education websites, membership platforms, booking forms, insurance pages, and profile dashboards. It calculates a person’s age from a selected birth date.</p>



<p class="wp-block-paragraph">This example calculates years, months, and days from the selected date of birth. It also shows the next birthday countdown and prevents future birth dates from being used.</p>



<ul class="wp-block-list">
<li>Calculates age from birth date</li>
<li>Shows years, months, and days</li>
<li>Includes next birthday countdown</li>
<li>Prevents future date mistakes</li>
<li>Useful for forms, calculators, profiles, and dashboards</li>
</ul>



<div class="vb-date-seven-demo">
  <div class="vb-date-seven-shell" data-vb-date-seven>
    <div class="vb-date-seven-form">
      <span class="vb-date-seven-kicker">Example 07</span>
      <h3>Age Calculator</h3>
      <p>Select a birth date and JavaScript calculates the exact age and next birthday countdown.</p>

      <label>
        <span>Date of birth</span>
        <input type="date" data-birth-date>
      </label>

      <button type="button" data-age-calculate>Calculate Age</button>
      <small data-age-error></small>
    </div>

    <div class="vb-date-seven-results">
      <div class="vb-date-seven-age-card">
        <span>Your age</span>
        <strong data-age-main>--</strong>
        <small data-age-detail>Select a birth date to calculate age.</small>
      </div>

      <div class="vb-date-seven-mini-grid">
        <div>
          <span>Years</span>
          <strong data-age-years>--</strong>
        </div>
        <div>
          <span>Months</span>
          <strong data-age-months>--</strong>
        </div>
        <div>
          <span>Days</span>
          <strong data-age-days>--</strong>
        </div>
      </div>

      <div class="vb-date-seven-birthday">
        <span>Next birthday</span>
        <strong data-birthday-countdown>--</strong>
      </div>
    </div>
  </div>
</div>

<style>
.vb-date-seven-demo,
.vb-date-seven-demo * {
  box-sizing: border-box;
}

.vb-date-seven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 16%, rgba(236, 72, 153, 0.16), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(99, 102, 241, 0.18), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #eef2ff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(236, 72, 153, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-seven-shell {
  display: grid;
  grid-template-columns: minmax(280px, 0.82fr) minmax(0, 1.18fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-seven-form,
.vb-date-seven-results {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-seven-form {
  display: grid;
  align-content: center;
  padding: clamp(22px, 4vw, 36px);
  background: #ffffff;
}

.vb-date-seven-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fce7f3;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-seven-form h3 {
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-seven-form p {
  margin: 0 0 22px !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-seven-form label {
  display: grid;
  gap: 8px;
  margin-bottom: 14px;
}

.vb-date-seven-form label span {
  color: #374151 !important;
  -webkit-text-fill-color: #374151 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-seven-form input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f9fafb;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-seven-form input:focus {
  border-color: rgba(236, 72, 153, 0.78);
  box-shadow: 0 0 0 4px rgba(236, 72, 153, 0.12);
}

.vb-date-seven-form button {
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #db2777, #4f46e5);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(219, 39, 119, 0.22);
}

.vb-date-seven-form small {
  display: block;
  min-height: 20px;
  margin-top: 10px;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 13px;
  line-height: 1.4;
  font-weight: 750;
}

.vb-date-seven-results {
  display: grid;
  gap: 14px;
  padding: clamp(20px, 4vw, 30px);
  background:
    radial-gradient(circle at 12% 16%, rgba(236, 72, 153, 0.18), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(99, 102, 241, 0.24), transparent 34%),
    linear-gradient(135deg, #111827 0%, #312e81 52%, #831843 100%) !important;
}

.vb-date-seven-age-card,
.vb-date-seven-birthday {
  min-width: 0;
  padding: 22px;
  border-radius: 26px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-seven-age-card {
  display: grid;
  gap: 9px;
}

.vb-date-seven-age-card span,
.vb-date-seven-birthday span,
.vb-date-seven-mini-grid span {
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-seven-age-card strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(40px, 7vw, 76px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.075em;
}

.vb-date-seven-age-card small {
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 15px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-date-seven-mini-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-date-seven-mini-grid div {
  min-width: 0;
  display: grid;
  gap: 7px;
  padding: 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-date-seven-mini-grid strong,
.vb-date-seven-birthday strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(22px, 4vw, 34px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.05em;
  overflow-wrap: anywhere;
}

.vb-date-seven-birthday {
  display: grid;
  gap: 8px;
}

@media (max-width: 900px) {
  .vb-date-seven-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-seven-mini-grid {
    grid-template-columns: 1fr;
  }

  .vb-date-seven-form,
  .vb-date-seven-results,
  .vb-date-seven-age-card,
  .vb-date-seven-birthday {
    border-radius: 24px;
  }

  .vb-date-seven-form button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const calculator = document.querySelector("[data-vb-date-seven]");
  if (!calculator) return;

  const input = calculator.querySelector("[data-birth-date]");
  const button = calculator.querySelector("[data-age-calculate]");
  const error = calculator.querySelector("[data-age-error]");

  const ageMain = calculator.querySelector("[data-age-main]");
  const ageDetail = calculator.querySelector("[data-age-detail]");
  const yearsOutput = calculator.querySelector("[data-age-years]");
  const monthsOutput = calculator.querySelector("[data-age-months]");
  const daysOutput = calculator.querySelector("[data-age-days]");
  const birthdayOutput = calculator.querySelector("[data-birthday-countdown]");

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function calculateAge() {
    error.textContent = "";

    if (!input.value) {
      error.textContent = "Please select a birth date.";
      return;
    }

    const birthDate = createLocalDate(input.value);
    const today = new Date();

    birthDate.setHours(0, 0, 0, 0);
    today.setHours(0, 0, 0, 0);

    if (birthDate > today) {
      error.textContent = "Birth date cannot be in the future.";
      ageMain.textContent = "--";
      ageDetail.textContent = "Select a valid birth date.";
      yearsOutput.textContent = "--";
      monthsOutput.textContent = "--";
      daysOutput.textContent = "--";
      birthdayOutput.textContent = "--";
      return;
    }

    let years = today.getFullYear() - birthDate.getFullYear();
    let months = today.getMonth() - birthDate.getMonth();
    let days = today.getDate() - birthDate.getDate();

    if (days < 0) {
      months -= 1;
      const previousMonth = new Date(today.getFullYear(), today.getMonth(), 0);
      days += previousMonth.getDate();
    }

    if (months < 0) {
      years -= 1;
      months += 12;
    }

    const nextBirthday = new Date(today.getFullYear(), birthDate.getMonth(), birthDate.getDate());

    if (nextBirthday < today) {
      nextBirthday.setFullYear(today.getFullYear() + 1);
    }

    const birthdayDiff = nextBirthday - today;
    const birthdayDays = Math.ceil(birthdayDiff / (1000 * 60 * 60 * 24));

    ageMain.textContent = years + " years";
    ageDetail.textContent = "You are " + years + " years, " + months + " months, and " + days + " days old.";
    yearsOutput.textContent = years;
    monthsOutput.textContent = months;
    daysOutput.textContent = days;
    birthdayOutput.textContent = birthdayDays === 0 ? "Today" : birthdayDays + " days";
  }

  button.addEventListener("click", calculateAge);
  input.addEventListener("change", calculateAge);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const calculator = document.querySelector("[data-vb-date-seven]");
  if (!calculator) return;

  const input = calculator.querySelector("[data-birth-date]");
  const button = calculator.querySelector("[data-age-calculate]");
  const error = calculator.querySelector("[data-age-error]");

  const ageMain = calculator.querySelector("[data-age-main]");
  const ageDetail = calculator.querySelector("[data-age-detail]");
  const yearsOutput = calculator.querySelector("[data-age-years]");
  const monthsOutput = calculator.querySelector("[data-age-months]");
  const daysOutput = calculator.querySelector("[data-age-days]");
  const birthdayOutput = calculator.querySelector("[data-birthday-countdown]");

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function calculateAge() {
    error.textContent = "";

    if (!input.value) {
      error.textContent = "Please select a birth date.";
      return;
    }

    const birthDate = createLocalDate(input.value);
    const today = new Date();

    birthDate.setHours(0, 0, 0, 0);
    today.setHours(0, 0, 0, 0);

    if (birthDate > today) {
      error.textContent = "Birth date cannot be in the future.";
      ageMain.textContent = "--";
      ageDetail.textContent = "Select a valid birth date.";
      yearsOutput.textContent = "--";
      monthsOutput.textContent = "--";
      daysOutput.textContent = "--";
      birthdayOutput.textContent = "--";
      return;
    }

    let years = today.getFullYear() - birthDate.getFullYear();
    let months = today.getMonth() - birthDate.getMonth();
    let days = today.getDate() - birthDate.getDate();

    if (days < 0) {
      months -= 1;
      const previousMonth = new Date(today.getFullYear(), today.getMonth(), 0);
      days += previousMonth.getDate();
    }

    if (months < 0) {
      years -= 1;
      months += 12;
    }

    const nextBirthday = new Date(today.getFullYear(), birthDate.getMonth(), birthDate.getDate());

    if (nextBirthday < today) {
      nextBirthday.setFullYear(today.getFullYear() + 1);
    }

    const birthdayDiff = nextBirthday - today;
    const birthdayDays = Math.ceil(birthdayDiff / (1000 * 60 * 60 * 24));

    ageMain.textContent = years + " years";
    ageDetail.textContent = "You are " + years + " years, " + months + " months, and " + days + " days old.";
    yearsOutput.textContent = years;
    monthsOutput.textContent = months;
    daysOutput.textContent = days;
    birthdayOutput.textContent = birthdayDays === 0 ? "Today" : birthdayDays + " days";
  }

  button.addEventListener("click", calculateAge);
  input.addEventListener("change", calculateAge);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-seven-demo"&gt;
  &lt;div class="vb-date-seven-shell" data-vb-date-seven&gt;
    &lt;div class="vb-date-seven-form"&gt;
      &lt;span class="vb-date-seven-kicker"&gt;Example 07&lt;/span&gt;
      &lt;h3&gt;Age Calculator&lt;/h3&gt;
      &lt;p&gt;Select a birth date and JavaScript calculates the exact age and next birthday countdown.&lt;/p&gt;

      &lt;label&gt;
        &lt;span&gt;Date of birth&lt;/span&gt;
        &lt;input type="date" data-birth-date&gt;
      &lt;/label&gt;

      &lt;button type="button" data-age-calculate&gt;Calculate Age&lt;/button&gt;
      &lt;small data-age-error&gt;&lt;/small&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-seven-results"&gt;
      &lt;div class="vb-date-seven-age-card"&gt;
        &lt;span&gt;Your age&lt;/span&gt;
        &lt;strong data-age-main&gt;--&lt;/strong&gt;
        &lt;small data-age-detail&gt;Select a birth date to calculate age.&lt;/small&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-seven-mini-grid"&gt;
        &lt;div&gt;
          &lt;span&gt;Years&lt;/span&gt;
          &lt;strong data-age-years&gt;--&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Months&lt;/span&gt;
          &lt;strong data-age-months&gt;--&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Days&lt;/span&gt;
          &lt;strong data-age-days&gt;--&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-seven-birthday"&gt;
        &lt;span&gt;Next birthday&lt;/span&gt;
        &lt;strong data-birthday-countdown&gt;--&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-seven-demo,
.vb-date-seven-demo * {
  box-sizing: border-box;
}

.vb-date-seven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 16%, rgba(236, 72, 153, 0.16), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(99, 102, 241, 0.18), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #eef2ff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(236, 72, 153, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-seven-shell {
  display: grid;
  grid-template-columns: minmax(280px, 0.82fr) minmax(0, 1.18fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-seven-form,
.vb-date-seven-results {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-seven-form {
  display: grid;
  align-content: center;
  padding: clamp(22px, 4vw, 36px);
  background: #ffffff;
}

.vb-date-seven-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fce7f3;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-seven-form h3 {
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-seven-form p {
  margin: 0 0 22px !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-seven-form label {
  display: grid;
  gap: 8px;
  margin-bottom: 14px;
}

.vb-date-seven-form label span {
  color: #374151 !important;
  -webkit-text-fill-color: #374151 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-seven-form input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f9fafb;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-seven-form input:focus {
  border-color: rgba(236, 72, 153, 0.78);
  box-shadow: 0 0 0 4px rgba(236, 72, 153, 0.12);
}

.vb-date-seven-form button {
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #db2777, #4f46e5);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(219, 39, 119, 0.22);
}

.vb-date-seven-form small {
  display: block;
  min-height: 20px;
  margin-top: 10px;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 13px;
  line-height: 1.4;
  font-weight: 750;
}

.vb-date-seven-results {
  display: grid;
  gap: 14px;
  padding: clamp(20px, 4vw, 30px);
  background:
    radial-gradient(circle at 12% 16%, rgba(236, 72, 153, 0.18), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(99, 102, 241, 0.24), transparent 34%),
    linear-gradient(135deg, #111827 0%, #312e81 52%, #831843 100%) !important;
}

.vb-date-seven-age-card,
.vb-date-seven-birthday {
  min-width: 0;
  padding: 22px;
  border-radius: 26px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-seven-age-card {
  display: grid;
  gap: 9px;
}

.vb-date-seven-age-card span,
.vb-date-seven-birthday span,
.vb-date-seven-mini-grid span {
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-seven-age-card strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(40px, 7vw, 76px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.075em;
}

.vb-date-seven-age-card small {
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 15px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-date-seven-mini-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-date-seven-mini-grid div {
  min-width: 0;
  display: grid;
  gap: 7px;
  padding: 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-date-seven-mini-grid strong,
.vb-date-seven-birthday strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(22px, 4vw, 34px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.05em;
  overflow-wrap: anywhere;
}

.vb-date-seven-birthday {
  display: grid;
  gap: 8px;
}

@media (max-width: 900px) {
  .vb-date-seven-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-seven-mini-grid {
    grid-template-columns: 1fr;
  }

  .vb-date-seven-form,
  .vb-date-seven-results,
  .vb-date-seven-age-card,
  .vb-date-seven-birthday {
    border-radius: 24px;
  }

  .vb-date-seven-form button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript age calculator example is useful for signup forms, profile pages, membership websites, school forms, health calculators, booking systems, insurance forms, and any feature where age must be calculated from a birth date.</p>



<h2 class="wp-block-heading">8. Date Difference Calculator Between Two Dates</h2>



<p class="wp-block-paragraph"><strong>A date difference calculator</strong> is useful for project dashboards, rental forms, booking websites, event planning tools, travel pages, service estimates, subscription dashboards, and deadline tracking. It calculates how much time exists between two selected dates.</p>



<p class="wp-block-paragraph">This example lets users choose a start date and an end date. JavaScript calculates the total number of days, weeks, and approximate months between them, then shows a clear summary card.</p>



<ul class="wp-block-list">
<li>Calculates difference between two dates</li>
<li>Shows days, weeks, and approximate months</li>
<li>Validates end date against start date</li>
<li>Responsive dashboard-style layout</li>
<li>Useful for rentals, projects, bookings, and deadlines</li>
</ul>



<div class="vb-date-eight-demo">
  <div class="vb-date-eight-card" data-vb-date-eight>
    <div class="vb-date-eight-header">
      <span class="vb-date-eight-kicker">Example 08</span>
      <h3>Date Difference Calculator</h3>
      <p>Select two dates and calculate the duration between them in days, weeks, and approximate months.</p>
    </div>

    <div class="vb-date-eight-body">
      <div class="vb-date-eight-inputs">
        <label>
          <span>Start date</span>
          <input type="date" data-start-date>
        </label>

        <label>
          <span>End date</span>
          <input type="date" data-end-date>
        </label>

        <button type="button" data-difference-calculate>Calculate Difference</button>

        <small data-difference-error></small>
      </div>

      <div class="vb-date-eight-results">
        <div class="vb-date-eight-main-result">
          <span>Total duration</span>
          <strong data-total-days>-- days</strong>
          <small data-duration-label>Select a start and end date.</small>
        </div>

        <div class="vb-date-eight-metrics">
          <div>
            <span>Weeks</span>
            <strong data-total-weeks>--</strong>
          </div>
          <div>
            <span>Months</span>
            <strong data-total-months>--</strong>
          </div>
          <div>
            <span>Range</span>
            <strong data-range-type>--</strong>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-date-eight-demo,
.vb-date-eight-demo * {
  box-sizing: border-box;
}

.vb-date-eight-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 14% 18%, rgba(59, 130, 246, 0.18), transparent 34%),
    radial-gradient(circle at 86% 14%, rgba(16, 185, 129, 0.18), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 55%, #ffffff 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-eight-card {
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 26px 80px rgba(15, 23, 42, 0.10);
}

.vb-date-eight-header {
  max-width: 760px;
  margin-bottom: 22px;
}

.vb-date-eight-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-eight-header h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-eight-header p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-eight-body {
  display: grid;
  grid-template-columns: minmax(280px, 0.82fr) minmax(0, 1.18fr);
  gap: 18px;
}

.vb-date-eight-inputs {
  display: grid;
  align-content: start;
  gap: 14px;
  min-width: 0;
  padding: 20px;
  border-radius: 26px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-date-eight-inputs label {
  display: grid;
  gap: 8px;
}

.vb-date-eight-inputs label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-eight-inputs input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-eight-inputs input:focus {
  border-color: rgba(37, 99, 235, 0.78);
  box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.12);
}

.vb-date-eight-inputs button {
  min-height: 48px;
  padding: 12px 16px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #10b981);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.22);
}

.vb-date-eight-inputs small {
  min-height: 20px;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 13px;
  line-height: 1.4;
  font-weight: 750;
}

.vb-date-eight-results {
  display: grid;
  gap: 14px;
  min-width: 0;
}

.vb-date-eight-main-result {
  display: grid;
  gap: 9px;
  min-width: 0;
  padding: clamp(22px, 4vw, 32px);
  border-radius: 28px;
  background:
    radial-gradient(circle at 12% 18%, rgba(96, 165, 250, 0.20), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #064e3b 100%) !important;
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-date-eight-main-result span,
.vb-date-eight-metrics span {
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-eight-main-result strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 64px);
  line-height: 0.98;
  font-weight: 950;
  letter-spacing: -0.065em;
  overflow-wrap: anywhere;
}

.vb-date-eight-main-result small {
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 15px;
  line-height: 1.5;
  font-weight: 650;
}

.vb-date-eight-metrics {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-date-eight-metrics div {
  min-width: 0;
  display: grid;
  gap: 7px;
  padding: 18px;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-date-eight-metrics span {
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
}

.vb-date-eight-metrics strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(20px, 3vw, 32px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.045em;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-date-eight-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-date-eight-card,
  .vb-date-eight-inputs,
  .vb-date-eight-main-result {
    border-radius: 24px;
  }

  .vb-date-eight-metrics {
    grid-template-columns: 1fr;
  }

  .vb-date-eight-inputs button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const calculator = document.querySelector("[data-vb-date-eight]");
  if (!calculator) return;

  const startInput = calculator.querySelector("[data-start-date]");
  const endInput = calculator.querySelector("[data-end-date]");
  const button = calculator.querySelector("[data-difference-calculate]");
  const error = calculator.querySelector("[data-difference-error]");

  const daysOutput = calculator.querySelector("[data-total-days]");
  const weeksOutput = calculator.querySelector("[data-total-weeks]");
  const monthsOutput = calculator.querySelector("[data-total-months]");
  const rangeOutput = calculator.querySelector("[data-range-type]");
  const labelOutput = calculator.querySelector("[data-duration-label]");

  function formatInputDate(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");

    return year + "-" + month + "-" + day;
  }

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function calculateDifference() {
    error.textContent = "";

    if (!startInput.value || !endInput.value) {
      error.textContent = "Please select both dates.";
      return;
    }

    const startDate = createLocalDate(startInput.value);
    const endDate = createLocalDate(endInput.value);

    if (endDate < startDate) {
      error.textContent = "End date must be after the start date.";
      daysOutput.textContent = "-- days";
      weeksOutput.textContent = "--";
      monthsOutput.textContent = "--";
      rangeOutput.textContent = "--";
      labelOutput.textContent = "Please fix the selected date range.";
      return;
    }

    const differenceMs = endDate - startDate;
    const totalDays = Math.round(differenceMs / (1000 * 60 * 60 * 24));
    const weeks = Math.floor(totalDays / 7);
    const months = (totalDays / 30.44).toFixed(1);

    daysOutput.textContent = totalDays + " days";
    weeksOutput.textContent = weeks + " weeks";
    monthsOutput.textContent = months;
    rangeOutput.textContent = totalDays === 0 ? "Same day" : "Date range";
    labelOutput.textContent = "The selected range is " + totalDays + " day" + (totalDays === 1 ? "" : "s") + " long.";
  }

  function setDefaultDates() {
    const today = new Date();
    const nextWeek = new Date();
    nextWeek.setDate(today.getDate() + 7);

    startInput.value = formatInputDate(today);
    endInput.value = formatInputDate(nextWeek);
    calculateDifference();
  }

  button.addEventListener("click", calculateDifference);
  startInput.addEventListener("change", calculateDifference);
  endInput.addEventListener("change", calculateDifference);

  setDefaultDates();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const calculator = document.querySelector("[data-vb-date-eight]");
  if (!calculator) return;

  const startInput = calculator.querySelector("[data-start-date]");
  const endInput = calculator.querySelector("[data-end-date]");
  const button = calculator.querySelector("[data-difference-calculate]");
  const error = calculator.querySelector("[data-difference-error]");

  const daysOutput = calculator.querySelector("[data-total-days]");
  const weeksOutput = calculator.querySelector("[data-total-weeks]");
  const monthsOutput = calculator.querySelector("[data-total-months]");
  const rangeOutput = calculator.querySelector("[data-range-type]");
  const labelOutput = calculator.querySelector("[data-duration-label]");

  function formatInputDate(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");

    return year + "-" + month + "-" + day;
  }

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function calculateDifference() {
    error.textContent = "";

    if (!startInput.value || !endInput.value) {
      error.textContent = "Please select both dates.";
      return;
    }

    const startDate = createLocalDate(startInput.value);
    const endDate = createLocalDate(endInput.value);

    if (endDate < startDate) {
      error.textContent = "End date must be after the start date.";
      daysOutput.textContent = "-- days";
      weeksOutput.textContent = "--";
      monthsOutput.textContent = "--";
      rangeOutput.textContent = "--";
      labelOutput.textContent = "Please fix the selected date range.";
      return;
    }

    const differenceMs = endDate - startDate;
    const totalDays = Math.round(differenceMs / (1000 * 60 * 60 * 24));
    const weeks = Math.floor(totalDays / 7);
    const months = (totalDays / 30.44).toFixed(1);

    daysOutput.textContent = totalDays + " days";
    weeksOutput.textContent = weeks + " weeks";
    monthsOutput.textContent = months;
    rangeOutput.textContent = totalDays === 0 ? "Same day" : "Date range";
    labelOutput.textContent = "The selected range is " + totalDays + " day" + (totalDays === 1 ? "" : "s") + " long.";
  }

  function setDefaultDates() {
    const today = new Date();
    const nextWeek = new Date();
    nextWeek.setDate(today.getDate() + 7);

    startInput.value = formatInputDate(today);
    endInput.value = formatInputDate(nextWeek);
    calculateDifference();
  }

  button.addEventListener("click", calculateDifference);
  startInput.addEventListener("change", calculateDifference);
  endInput.addEventListener("change", calculateDifference);

  setDefaultDates();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-eight-demo"&gt;
  &lt;div class="vb-date-eight-card" data-vb-date-eight&gt;
    &lt;div class="vb-date-eight-header"&gt;
      &lt;span class="vb-date-eight-kicker"&gt;Example 08&lt;/span&gt;
      &lt;h3&gt;Date Difference Calculator&lt;/h3&gt;
      &lt;p&gt;Select two dates and calculate the duration between them in days, weeks, and approximate months.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-eight-body"&gt;
      &lt;div class="vb-date-eight-inputs"&gt;
        &lt;label&gt;
          &lt;span&gt;Start date&lt;/span&gt;
          &lt;input type="date" data-start-date&gt;
        &lt;/label&gt;

        &lt;label&gt;
          &lt;span&gt;End date&lt;/span&gt;
          &lt;input type="date" data-end-date&gt;
        &lt;/label&gt;

        &lt;button type="button" data-difference-calculate&gt;Calculate Difference&lt;/button&gt;

        &lt;small data-difference-error&gt;&lt;/small&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-eight-results"&gt;
        &lt;div class="vb-date-eight-main-result"&gt;
          &lt;span&gt;Total duration&lt;/span&gt;
          &lt;strong data-total-days&gt;-- days&lt;/strong&gt;
          &lt;small data-duration-label&gt;Select a start and end date.&lt;/small&gt;
        &lt;/div&gt;

        &lt;div class="vb-date-eight-metrics"&gt;
          &lt;div&gt;
            &lt;span&gt;Weeks&lt;/span&gt;
            &lt;strong data-total-weeks&gt;--&lt;/strong&gt;
          &lt;/div&gt;
          &lt;div&gt;
            &lt;span&gt;Months&lt;/span&gt;
            &lt;strong data-total-months&gt;--&lt;/strong&gt;
          &lt;/div&gt;
          &lt;div&gt;
            &lt;span&gt;Range&lt;/span&gt;
            &lt;strong data-range-type&gt;--&lt;/strong&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-eight-demo,
.vb-date-eight-demo * {
  box-sizing: border-box;
}

.vb-date-eight-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 14% 18%, rgba(59, 130, 246, 0.18), transparent 34%),
    radial-gradient(circle at 86% 14%, rgba(16, 185, 129, 0.18), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 55%, #ffffff 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-eight-card {
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 26px 80px rgba(15, 23, 42, 0.10);
}

.vb-date-eight-header {
  max-width: 760px;
  margin-bottom: 22px;
}

.vb-date-eight-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-eight-header h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-eight-header p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-eight-body {
  display: grid;
  grid-template-columns: minmax(280px, 0.82fr) minmax(0, 1.18fr);
  gap: 18px;
}

.vb-date-eight-inputs {
  display: grid;
  align-content: start;
  gap: 14px;
  min-width: 0;
  padding: 20px;
  border-radius: 26px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-date-eight-inputs label {
  display: grid;
  gap: 8px;
}

.vb-date-eight-inputs label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-eight-inputs input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-eight-inputs input:focus {
  border-color: rgba(37, 99, 235, 0.78);
  box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.12);
}

.vb-date-eight-inputs button {
  min-height: 48px;
  padding: 12px 16px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #10b981);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.22);
}

.vb-date-eight-inputs small {
  min-height: 20px;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 13px;
  line-height: 1.4;
  font-weight: 750;
}

.vb-date-eight-results {
  display: grid;
  gap: 14px;
  min-width: 0;
}

.vb-date-eight-main-result {
  display: grid;
  gap: 9px;
  min-width: 0;
  padding: clamp(22px, 4vw, 32px);
  border-radius: 28px;
  background:
    radial-gradient(circle at 12% 18%, rgba(96, 165, 250, 0.20), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #064e3b 100%) !important;
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-date-eight-main-result span,
.vb-date-eight-metrics span {
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-eight-main-result strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 64px);
  line-height: 0.98;
  font-weight: 950;
  letter-spacing: -0.065em;
  overflow-wrap: anywhere;
}

.vb-date-eight-main-result small {
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 15px;
  line-height: 1.5;
  font-weight: 650;
}

.vb-date-eight-metrics {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-date-eight-metrics div {
  min-width: 0;
  display: grid;
  gap: 7px;
  padding: 18px;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-date-eight-metrics span {
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
}

.vb-date-eight-metrics strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(20px, 3vw, 32px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.045em;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-date-eight-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-date-eight-card,
  .vb-date-eight-inputs,
  .vb-date-eight-main-result {
    border-radius: 24px;
  }

  .vb-date-eight-metrics {
    grid-template-columns: 1fr;
  }

  .vb-date-eight-inputs button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript date difference calculator is useful for rental calculators, travel planning tools, project timelines, subscription dashboards, booking ranges, event planning pages, service estimates, and deadline tracking components.</p>



<h2 class="wp-block-heading">9. Relative Time Label Generator</h2>



<p class="wp-block-paragraph"><strong>A relative time label generator</strong> makes dates easier to understand by turning timestamps into labels like “just now”, “5 minutes ago”, “yesterday”, or “3 days ago”. This is useful for blogs, comments, notifications, dashboards, activity feeds, and message lists.</p>



<p class="wp-block-paragraph">This example uses JavaScript to compare each timestamp with the current time. It automatically generates human-friendly relative time labels and refreshes them every minute.</p>



<ul class="wp-block-list">
<li>Creates human-friendly relative time labels</li>
<li>Works with multiple activity items</li>
<li>Updates every minute</li>
<li>Uses timestamp comparison</li>
<li>Useful for comments, notifications, dashboards, and activity feeds</li>
</ul>



<div class="vb-date-nine-demo">
  <div class="vb-date-nine-shell" data-vb-date-nine>
    <div class="vb-date-nine-header">
      <span class="vb-date-nine-kicker">Example 09</span>
      <h3>Relative Time Labels</h3>
      <p>JavaScript converts timestamps into friendly labels that are easier to scan inside activity feeds.</p>
    </div>

    <div class="vb-date-nine-feed">
      <article data-relative-time data-time-offset="2">
        <div class="vb-date-nine-icon">N</div>
        <div>
          <h4>New lead submitted a quote request</h4>
          <p>Website project request received from the contact form.</p>
          <span>Loading...</span>
        </div>
      </article>

      <article data-relative-time data-time-offset="18">
        <div class="vb-date-nine-icon">U</div>
        <div>
          <h4>User updated booking details</h4>
          <p>The appointment date was changed inside the dashboard.</p>
          <span>Loading...</span>
        </div>
      </article>

      <article data-relative-time data-time-offset="180">
        <div class="vb-date-nine-icon">S</div>
        <div>
          <h4>System saved draft automatically</h4>
          <p>Local browser data was saved for the unfinished form.</p>
          <span>Loading...</span>
        </div>
      </article>

      <article data-relative-time data-time-offset="1440">
        <div class="vb-date-nine-icon">M</div>
        <div>
          <h4>Message was sent to the client</h4>
          <p>The project update email was delivered successfully.</p>
          <span>Loading...</span>
        </div>
      </article>
    </div>
  </div>
</div>

<style>
.vb-date-nine-demo,
.vb-date-nine-demo * {
  box-sizing: border-box;
}

.vb-date-nine-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 14% 16%, rgba(14, 165, 233, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(168, 85, 247, 0.18), transparent 34%),
    linear-gradient(135deg, #ecfeff 0%, #faf5ff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-nine-shell {
  display: grid;
  grid-template-columns: minmax(280px, 0.78fr) minmax(0, 1.22fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-nine-header {
  min-width: 0;
  display: grid;
  align-content: center;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 18% 18%, rgba(34, 211, 238, 0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #581c87 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.22);
}

.vb-date-nine-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-nine-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 6vw, 68px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-nine-header p {
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-nine-feed {
  display: grid;
  gap: 12px;
  min-width: 0;
}

.vb-date-nine-feed article {
  display: grid;
  grid-template-columns: 58px minmax(0, 1fr);
  gap: 14px;
  align-items: start;
  min-width: 0;
  padding: 16px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 54px rgba(15, 23, 42, 0.08);
}

.vb-date-nine-icon {
  display: grid;
  place-items: center;
  width: 58px;
  height: 58px;
  border-radius: 20px;
  background: linear-gradient(135deg, #06b6d4, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
  box-shadow: 0 14px 34px rgba(124, 58, 237, 0.20);
}

.vb-date-nine-feed h4 {
  margin: 0 0 6px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 17px !important;
  line-height: 1.25 !important;
  font-weight: 900 !important;
  overflow-wrap: anywhere;
}

.vb-date-nine-feed p {
  margin: 0 0 9px !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-date-nine-feed span {
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: #ecfeff;
  color: #0891b2 !important;
  -webkit-text-fill-color: #0891b2 !important;
  font-size: 12px;
  line-height: 1.2;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vb-date-nine-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-date-nine-header,
  .vb-date-nine-feed article {
    border-radius: 24px;
  }

  .vb-date-nine-feed article {
    grid-template-columns: 1fr;
  }

  .vb-date-nine-icon {
    width: 52px;
    height: 52px;
    border-radius: 18px;
  }
}
</style>

<script>
(function () {
  const feed = document.querySelector("[data-vb-date-nine]");
  if (!feed) return;

  const items = feed.querySelectorAll("[data-relative-time]");

  function getRelativeLabel(date) {
    const now = new Date();
    const diffMs = now - date;
    const diffSeconds = Math.floor(diffMs / 1000);
    const diffMinutes = Math.floor(diffSeconds / 60);
    const diffHours = Math.floor(diffMinutes / 60);
    const diffDays = Math.floor(diffHours / 24);

    if (diffSeconds < 60) {
      return "just now";
    }

    if (diffMinutes < 60) {
      return diffMinutes + " minute" + (diffMinutes === 1 ? "" : "s") + " ago";
    }

    if (diffHours < 24) {
      return diffHours + " hour" + (diffHours === 1 ? "" : "s") + " ago";
    }

    if (diffDays === 1) {
      return "yesterday";
    }

    return diffDays + " days ago";
  }

  function updateRelativeTimes() {
    items.forEach(function (item) {
      const offsetMinutes = Number(item.getAttribute("data-time-offset"));
      const itemDate = new Date(Date.now() - offsetMinutes * 60 * 1000);
      const label = item.querySelector("span");

      label.textContent = getRelativeLabel(itemDate);
    });
  }

  updateRelativeTimes();
  setInterval(updateRelativeTimes, 60000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const feed = document.querySelector("[data-vb-date-nine]");
  if (!feed) return;

  const items = feed.querySelectorAll("[data-relative-time]");

  function getRelativeLabel(date) {
    const now = new Date();
    const diffMs = now - date;
    const diffSeconds = Math.floor(diffMs / 1000);
    const diffMinutes = Math.floor(diffSeconds / 60);
    const diffHours = Math.floor(diffMinutes / 60);
    const diffDays = Math.floor(diffHours / 24);

    if (diffSeconds < 60) {
      return "just now";
    }

    if (diffMinutes < 60) {
      return diffMinutes + " minute" + (diffMinutes === 1 ? "" : "s") + " ago";
    }

    if (diffHours < 24) {
      return diffHours + " hour" + (diffHours === 1 ? "" : "s") + " ago";
    }

    if (diffDays === 1) {
      return "yesterday";
    }

    return diffDays + " days ago";
  }

  function updateRelativeTimes() {
    items.forEach(function (item) {
      const offsetMinutes = Number(item.getAttribute("data-time-offset"));
      const itemDate = new Date(Date.now() - offsetMinutes * 60 * 1000);
      const label = item.querySelector("span");

      label.textContent = getRelativeLabel(itemDate);
    });
  }

  updateRelativeTimes();
  setInterval(updateRelativeTimes, 60000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-nine-demo"&gt;
  &lt;div class="vb-date-nine-shell" data-vb-date-nine&gt;
    &lt;div class="vb-date-nine-header"&gt;
      &lt;span class="vb-date-nine-kicker"&gt;Example 09&lt;/span&gt;
      &lt;h3&gt;Relative Time Labels&lt;/h3&gt;
      &lt;p&gt;JavaScript converts timestamps into friendly labels that are easier to scan inside activity feeds.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-nine-feed"&gt;
      &lt;article data-relative-time data-time-offset="2"&gt;
        &lt;div class="vb-date-nine-icon"&gt;N&lt;/div&gt;
        &lt;div&gt;
          &lt;h4&gt;New lead submitted a quote request&lt;/h4&gt;
          &lt;p&gt;Website project request received from the contact form.&lt;/p&gt;
          &lt;span&gt;Loading...&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-relative-time data-time-offset="18"&gt;
        &lt;div class="vb-date-nine-icon"&gt;U&lt;/div&gt;
        &lt;div&gt;
          &lt;h4&gt;User updated booking details&lt;/h4&gt;
          &lt;p&gt;The appointment date was changed inside the dashboard.&lt;/p&gt;
          &lt;span&gt;Loading...&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-relative-time data-time-offset="180"&gt;
        &lt;div class="vb-date-nine-icon"&gt;S&lt;/div&gt;
        &lt;div&gt;
          &lt;h4&gt;System saved draft automatically&lt;/h4&gt;
          &lt;p&gt;Local browser data was saved for the unfinished form.&lt;/p&gt;
          &lt;span&gt;Loading...&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-relative-time data-time-offset="1440"&gt;
        &lt;div class="vb-date-nine-icon"&gt;M&lt;/div&gt;
        &lt;div&gt;
          &lt;h4&gt;Message was sent to the client&lt;/h4&gt;
          &lt;p&gt;The project update email was delivered successfully.&lt;/p&gt;
          &lt;span&gt;Loading...&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-nine-demo,
.vb-date-nine-demo * {
  box-sizing: border-box;
}

.vb-date-nine-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 14% 16%, rgba(14, 165, 233, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(168, 85, 247, 0.18), transparent 34%),
    linear-gradient(135deg, #ecfeff 0%, #faf5ff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-nine-shell {
  display: grid;
  grid-template-columns: minmax(280px, 0.78fr) minmax(0, 1.22fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-nine-header {
  min-width: 0;
  display: grid;
  align-content: center;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 18% 18%, rgba(34, 211, 238, 0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #581c87 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.22);
}

.vb-date-nine-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-nine-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 6vw, 68px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-nine-header p {
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-nine-feed {
  display: grid;
  gap: 12px;
  min-width: 0;
}

.vb-date-nine-feed article {
  display: grid;
  grid-template-columns: 58px minmax(0, 1fr);
  gap: 14px;
  align-items: start;
  min-width: 0;
  padding: 16px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 54px rgba(15, 23, 42, 0.08);
}

.vb-date-nine-icon {
  display: grid;
  place-items: center;
  width: 58px;
  height: 58px;
  border-radius: 20px;
  background: linear-gradient(135deg, #06b6d4, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
  box-shadow: 0 14px 34px rgba(124, 58, 237, 0.20);
}

.vb-date-nine-feed h4 {
  margin: 0 0 6px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 17px !important;
  line-height: 1.25 !important;
  font-weight: 900 !important;
  overflow-wrap: anywhere;
}

.vb-date-nine-feed p {
  margin: 0 0 9px !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-date-nine-feed span {
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: #ecfeff;
  color: #0891b2 !important;
  -webkit-text-fill-color: #0891b2 !important;
  font-size: 12px;
  line-height: 1.2;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vb-date-nine-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-date-nine-header,
  .vb-date-nine-feed article {
    border-radius: 24px;
  }

  .vb-date-nine-feed article {
    grid-template-columns: 1fr;
  }

  .vb-date-nine-icon {
    width: 52px;
    height: 52px;
    border-radius: 18px;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript relative time label example is useful for comment sections, notification panels, activity feeds, message lists, blog post metadata, user dashboards, CRM timelines, and SaaS admin interfaces.</p>



<h2 class="wp-block-heading">10. Meeting Time Slot Generator</h2>



<p class="wp-block-paragraph"><strong>A meeting time slot generator</strong> is a useful JavaScript date and time example for booking pages, consultation forms, appointment systems, agency websites, support calendars, and service scheduling tools. It creates selectable time slots between a start and end time.</p>



<p class="wp-block-paragraph">This example lets users choose a meeting date and generate 30-minute time slots between 09:00 and 17:00. JavaScript builds the available slots dynamically and lets the visitor select one option.</p>



<ul class="wp-block-list">
<li>Generates meeting time slots dynamically</li>
<li>Uses selected date and fixed working hours</li>
<li>Creates 30-minute booking slots</li>
<li>Includes selected slot summary</li>
<li>Useful for booking pages, consultation forms, and appointment tools</li>
</ul>



<div class="vb-date-ten-demo">
  <div class="vb-date-ten-shell" data-vb-date-ten>
    <div class="vb-date-ten-left">
      <span class="vb-date-ten-kicker">Example 10</span>
      <h3>Meeting Time Slots</h3>
      <p>Select a date and JavaScript generates available 30-minute meeting slots for that day.</p>

      <label>
        <span>Meeting date</span>
        <input type="date" data-slot-date>
      </label>

      <button type="button" data-generate-slots>Generate Slots</button>
    </div>

    <div class="vb-date-ten-right">
      <div class="vb-date-ten-summary">
        <span>Selected meeting</span>
        <strong data-selected-slot>No slot selected</strong>
      </div>

      <div class="vb-date-ten-slots" data-slot-list>
        <p>Choose a date to generate available time slots.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-date-ten-demo,
.vb-date-ten-demo * {
  box-sizing: border-box;
}

.vb-date-ten-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(34, 197, 94, 0.16), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(14, 165, 233, 0.18), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #eff6ff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-ten-shell {
  display: grid;
  grid-template-columns: minmax(280px, 0.78fr) minmax(0, 1.22fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-ten-left,
.vb-date-ten-right {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-ten-left {
  display: grid;
  align-content: center;
  padding: clamp(22px, 4vw, 36px);
  background: #ffffff;
}

.vb-date-ten-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-ten-left h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-ten-left p {
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-ten-left label {
  display: grid;
  gap: 8px;
  margin-bottom: 14px;
}

.vb-date-ten-left label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-ten-left input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-ten-left input:focus {
  border-color: rgba(34, 197, 94, 0.78);
  box-shadow: 0 0 0 4px rgba(34, 197, 94, 0.12);
}

.vb-date-ten-left button {
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #16a34a, #0ea5e9);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(14, 165, 233, 0.22);
}

.vb-date-ten-right {
  display: grid;
  gap: 14px;
  padding: clamp(20px, 4vw, 30px);
  background:
    radial-gradient(circle at 18% 16%, rgba(34, 197, 94, 0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #164e63 100%) !important;
}

.vb-date-ten-summary {
  display: grid;
  gap: 8px;
  padding: 20px;
  border-radius: 24px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-ten-summary span {
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-ten-summary strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(24px, 4vw, 40px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.05em;
  overflow-wrap: anywhere;
}

.vb-date-ten-slots {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
  min-width: 0;
}

.vb-date-ten-slots p {
  grid-column: 1 / -1;
  margin: 0 !important;
  padding: 18px;
  border-radius: 20px;
  background: rgba(255,255,255,0.10);
  border: 1px dashed rgba(255,255,255,0.20);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 750;
}

.vb-date-ten-slot {
  min-width: 0;
  min-height: 44px;
  padding: 10px 12px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  line-height: 1.2;
  font-weight: 900;
  cursor: pointer;
  transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease;
}

.vb-date-ten-slot:hover,
.vb-date-ten-slot.is-selected {
  transform: translateY(-2px);
  background: rgba(34, 197, 94, 0.24);
  border-color: rgba(134, 239, 172, 0.55);
}

@media (max-width: 900px) {
  .vb-date-ten-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-date-ten-left,
  .vb-date-ten-right,
  .vb-date-ten-summary {
    border-radius: 24px;
  }

  .vb-date-ten-left button {
    width: 100%;
  }

  .vb-date-ten-slots {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 420px) {
  .vb-date-ten-slots {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const generator = document.querySelector("[data-vb-date-ten]");
  if (!generator) return;

  const dateInput = generator.querySelector("[data-slot-date]");
  const generateButton = generator.querySelector("[data-generate-slots]");
  const slotList = generator.querySelector("[data-slot-list]");
  const selectedSlot = generator.querySelector("[data-selected-slot]");

  function formatInputDate(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");

    return year + "-" + month + "-" + day;
  }

  function formatReadableDate(value) {
    const parts = value.split("-");
    const date = new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));

    return new Intl.DateTimeFormat("en", {
      month: "short",
      day: "numeric",
      year: "numeric"
    }).format(date);
  }

  function generateSlots() {
    slotList.innerHTML = "";

    if (!dateInput.value) {
      slotList.innerHTML = "<p>Please choose a date first.</p>";
      selectedSlot.textContent = "No slot selected";
      return;
    }

    const slots = [];
    let hour = 9;
    let minute = 0;

    while (hour < 17) {
      const time = String(hour).padStart(2, "0") + ":" + String(minute).padStart(2, "0");
      slots.push(time);

      minute += 30;

      if (minute === 60) {
        minute = 0;
        hour += 1;
      }
    }

    slots.forEach(function (slot) {
      const button = document.createElement("button");
      button.type = "button";
      button.className = "vb-date-ten-slot";
      button.textContent = slot;

      button.addEventListener("click", function () {
        generator.querySelectorAll(".vb-date-ten-slot").forEach(function (item) {
          item.classList.remove("is-selected");
        });

        button.classList.add("is-selected");
        selectedSlot.textContent = formatReadableDate(dateInput.value) + " at " + slot;
      });

      slotList.appendChild(button);
    });
  }

  dateInput.value = formatInputDate(new Date());
  generateButton.addEventListener("click", generateSlots);
  dateInput.addEventListener("change", generateSlots);

  generateSlots();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const generator = document.querySelector("[data-vb-date-ten]");
  if (!generator) return;

  const dateInput = generator.querySelector("[data-slot-date]");
  const generateButton = generator.querySelector("[data-generate-slots]");
  const slotList = generator.querySelector("[data-slot-list]");
  const selectedSlot = generator.querySelector("[data-selected-slot]");

  function formatInputDate(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");

    return year + "-" + month + "-" + day;
  }

  function formatReadableDate(value) {
    const parts = value.split("-");
    const date = new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));

    return new Intl.DateTimeFormat("en", {
      month: "short",
      day: "numeric",
      year: "numeric"
    }).format(date);
  }

  function generateSlots() {
    slotList.innerHTML = "";

    if (!dateInput.value) {
      slotList.innerHTML = "&lt;p&gt;Please choose a date first.&lt;/p&gt;";
      selectedSlot.textContent = "No slot selected";
      return;
    }

    const slots = [];
    let hour = 9;
    let minute = 0;

    while (hour &lt; 17) {
      const time = String(hour).padStart(2, "0") + ":" + String(minute).padStart(2, "0");
      slots.push(time);

      minute += 30;

      if (minute === 60) {
        minute = 0;
        hour += 1;
      }
    }

    slots.forEach(function (slot) {
      const button = document.createElement("button");
      button.type = "button";
      button.className = "vb-date-ten-slot";
      button.textContent = slot;

      button.addEventListener("click", function () {
        generator.querySelectorAll(".vb-date-ten-slot").forEach(function (item) {
          item.classList.remove("is-selected");
        });

        button.classList.add("is-selected");
        selectedSlot.textContent = formatReadableDate(dateInput.value) + " at " + slot;
      });

      slotList.appendChild(button);
    });
  }

  dateInput.value = formatInputDate(new Date());
  generateButton.addEventListener("click", generateSlots);
  dateInput.addEventListener("change", generateSlots);

  generateSlots();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-ten-demo"&gt;
  &lt;div class="vb-date-ten-shell" data-vb-date-ten&gt;
    &lt;div class="vb-date-ten-left"&gt;
      &lt;span class="vb-date-ten-kicker"&gt;Example 10&lt;/span&gt;
      &lt;h3&gt;Meeting Time Slots&lt;/h3&gt;
      &lt;p&gt;Select a date and JavaScript generates available 30-minute meeting slots for that day.&lt;/p&gt;

      &lt;label&gt;
        &lt;span&gt;Meeting date&lt;/span&gt;
        &lt;input type="date" data-slot-date&gt;
      &lt;/label&gt;

      &lt;button type="button" data-generate-slots&gt;Generate Slots&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-ten-right"&gt;
      &lt;div class="vb-date-ten-summary"&gt;
        &lt;span&gt;Selected meeting&lt;/span&gt;
        &lt;strong data-selected-slot&gt;No slot selected&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-ten-slots" data-slot-list&gt;
        &lt;p&gt;Choose a date to generate available time slots.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-ten-demo,
.vb-date-ten-demo * {
  box-sizing: border-box;
}

.vb-date-ten-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(34, 197, 94, 0.16), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(14, 165, 233, 0.18), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #eff6ff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-ten-shell {
  display: grid;
  grid-template-columns: minmax(280px, 0.78fr) minmax(0, 1.22fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-ten-left,
.vb-date-ten-right {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-ten-left {
  display: grid;
  align-content: center;
  padding: clamp(22px, 4vw, 36px);
  background: #ffffff;
}

.vb-date-ten-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-ten-left h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-ten-left p {
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-ten-left label {
  display: grid;
  gap: 8px;
  margin-bottom: 14px;
}

.vb-date-ten-left label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-ten-left input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-ten-left input:focus {
  border-color: rgba(34, 197, 94, 0.78);
  box-shadow: 0 0 0 4px rgba(34, 197, 94, 0.12);
}

.vb-date-ten-left button {
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #16a34a, #0ea5e9);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(14, 165, 233, 0.22);
}

.vb-date-ten-right {
  display: grid;
  gap: 14px;
  padding: clamp(20px, 4vw, 30px);
  background:
    radial-gradient(circle at 18% 16%, rgba(34, 197, 94, 0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #164e63 100%) !important;
}

.vb-date-ten-summary {
  display: grid;
  gap: 8px;
  padding: 20px;
  border-radius: 24px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-ten-summary span {
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-ten-summary strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(24px, 4vw, 40px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.05em;
  overflow-wrap: anywhere;
}

.vb-date-ten-slots {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
  min-width: 0;
}

.vb-date-ten-slots p {
  grid-column: 1 / -1;
  margin: 0 !important;
  padding: 18px;
  border-radius: 20px;
  background: rgba(255,255,255,0.10);
  border: 1px dashed rgba(255,255,255,0.20);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 750;
}

.vb-date-ten-slot {
  min-width: 0;
  min-height: 44px;
  padding: 10px 12px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  line-height: 1.2;
  font-weight: 900;
  cursor: pointer;
  transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease;
}

.vb-date-ten-slot:hover,
.vb-date-ten-slot.is-selected {
  transform: translateY(-2px);
  background: rgba(34, 197, 94, 0.24);
  border-color: rgba(134, 239, 172, 0.55);
}

@media (max-width: 900px) {
  .vb-date-ten-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-date-ten-left,
  .vb-date-ten-right,
  .vb-date-ten-summary {
    border-radius: 24px;
  }

  .vb-date-ten-left button {
    width: 100%;
  }

  .vb-date-ten-slots {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 420px) {
  .vb-date-ten-slots {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript meeting time slot generator is useful for appointment booking forms, agency consultation pages, service scheduling tools, support call pages, coaching websites, and custom WordPress booking interfaces.</p>



<h2 class="wp-block-heading">11. Simple Monthly Calendar Generator</h2>



<p class="wp-block-paragraph"><strong>A monthly calendar generator</strong> is a useful JavaScript date and time example for event websites, booking interfaces, dashboards, content planners, appointment systems, and project tools. It creates a visual calendar grid from JavaScript date calculations.</p>



<p class="wp-block-paragraph">This example generates the current month automatically, highlights today, and lets users move between previous and next months. The calendar grid is responsive and avoids overflow on small screens.</p>



<ul class="wp-block-list">
<li>Generates a monthly calendar with JavaScript</li>
<li>Highlights the current day</li>
<li>Includes previous and next month controls</li>
<li>Responsive 7-column layout</li>
<li>Useful for dashboards, event pages, and booking interfaces</li>
</ul>



<div class="vb-date-eleven-demo">
  <div class="vb-date-eleven-calendar" data-vb-date-eleven>
    <div class="vb-date-eleven-top">
      <div>
        <span class="vb-date-eleven-kicker">Example 11</span>
        <h3>Monthly Calendar</h3>
      </div>

      <div class="vb-date-eleven-controls">
        <button type="button" data-prev-month>Prev</button>
        <button type="button" data-next-month>Next</button>
      </div>
    </div>

    <div class="vb-date-eleven-month" data-current-month>Loading month...</div>

    <div class="vb-date-eleven-weekdays">
      <span>Mon</span>
      <span>Tue</span>
      <span>Wed</span>
      <span>Thu</span>
      <span>Fri</span>
      <span>Sat</span>
      <span>Sun</span>
    </div>

    <div class="vb-date-eleven-grid" data-calendar-grid></div>
  </div>
</div>

<style>
.vb-date-eleven-demo,
.vb-date-eleven-demo * {
  box-sizing: border-box;
}

.vb-date-eleven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 14% 16%, rgba(245, 158, 11, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(239, 68, 68, 0.14), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fef2f2 55%, #ffffff 100%) !important;
  border: 1px solid rgba(245, 158, 11, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-eleven-calendar {
  max-width: 980px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 18% 14%, rgba(251, 191, 36, 0.18), transparent 34%),
    linear-gradient(135deg, #111827 0%, #7c2d12 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 28px 90px rgba(124, 45, 18, 0.24);
  overflow: hidden;
}

.vb-date-eleven-top {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: flex-start;
  margin-bottom: 18px;
}

.vb-date-eleven-kicker {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-eleven-top h3 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-eleven-controls {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: flex-end;
}

.vb-date-eleven-controls button {
  min-height: 42px;
  padding: 10px 14px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-date-eleven-month {
  margin: 0 0 16px;
  padding: 16px 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(22px, 4vw, 34px);
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-date-eleven-weekdays,
.vb-date-eleven-grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 8px;
  min-width: 0;
}

.vb-date-eleven-weekdays {
  margin-bottom: 8px;
}

.vb-date-eleven-weekdays span {
  min-width: 0;
  padding: 10px 4px;
  border-radius: 14px;
  background: rgba(255,255,255,0.08);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  line-height: 1.1;
  font-weight: 950;
  text-align: center;
}

.vb-date-eleven-day {
  min-width: 0;
  min-height: 70px;
  padding: 10px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 900;
  text-align: left;
}

.vb-date-eleven-day.is-empty {
  opacity: 0.35;
}

.vb-date-eleven-day.is-today {
  background: linear-gradient(135deg, #f97316, #ef4444);
  border-color: rgba(255,255,255,0.32);
  box-shadow: 0 14px 34px rgba(249, 115, 22, 0.28);
}

@media (max-width: 680px) {
  .vb-date-eleven-top {
    flex-direction: column;
  }

  .vb-date-eleven-controls {
    width: 100%;
    justify-content: stretch;
  }

  .vb-date-eleven-controls button {
    flex: 1;
  }

  .vb-date-eleven-weekdays,
  .vb-date-eleven-grid {
    gap: 5px;
  }

  .vb-date-eleven-weekdays span {
    font-size: 10px;
    padding: 8px 2px;
    border-radius: 10px;
  }

  .vb-date-eleven-day {
    min-height: 48px;
    padding: 7px;
    border-radius: 12px;
    font-size: 12px;
  }
}

@media (max-width: 420px) {
  .vb-date-eleven-calendar {
    border-radius: 24px;
  }

  .vb-date-eleven-day {
    min-height: 42px;
    padding: 6px 4px;
    text-align: center;
  }
}
</style>

<script>
(function () {
  const calendar = document.querySelector("[data-vb-date-eleven]");
  if (!calendar) return;

  const monthLabel = calendar.querySelector("[data-current-month]");
  const grid = calendar.querySelector("[data-calendar-grid]");
  const prevButton = calendar.querySelector("[data-prev-month]");
  const nextButton = calendar.querySelector("[data-next-month]");

  let visibleDate = new Date();

  function renderCalendar() {
    grid.innerHTML = "";

    const year = visibleDate.getFullYear();
    const month = visibleDate.getMonth();

    const firstDay = new Date(year, month, 1);
    const lastDay = new Date(year, month + 1, 0);
    const today = new Date();

    monthLabel.textContent = new Intl.DateTimeFormat("en", {
      month: "long",
      year: "numeric"
    }).format(firstDay);

    const firstWeekday = (firstDay.getDay() + 6) % 7;
    const daysInMonth = lastDay.getDate();

    for (let i = 0; i < firstWeekday; i += 1) {
      const emptyDay = document.createElement("div");
      emptyDay.className = "vb-date-eleven-day is-empty";
      grid.appendChild(emptyDay);
    }

    for (let day = 1; day <= daysInMonth; day += 1) {
      const dayElement = document.createElement("div");
      dayElement.className = "vb-date-eleven-day";
      dayElement.textContent = day;

      const isToday =
        day === today.getDate() &#038;&#038;
        month === today.getMonth() &#038;&#038;
        year === today.getFullYear();

      if (isToday) {
        dayElement.classList.add("is-today");
      }

      grid.appendChild(dayElement);
    }
  }

  prevButton.addEventListener("click", function () {
    visibleDate.setMonth(visibleDate.getMonth() - 1);
    renderCalendar();
  });

  nextButton.addEventListener("click", function () {
    visibleDate.setMonth(visibleDate.getMonth() + 1);
    renderCalendar();
  });

  renderCalendar();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const calendar = document.querySelector("[data-vb-date-eleven]");
  if (!calendar) return;

  const monthLabel = calendar.querySelector("[data-current-month]");
  const grid = calendar.querySelector("[data-calendar-grid]");
  const prevButton = calendar.querySelector("[data-prev-month]");
  const nextButton = calendar.querySelector("[data-next-month]");

  let visibleDate = new Date();

  function renderCalendar() {
    grid.innerHTML = "";

    const year = visibleDate.getFullYear();
    const month = visibleDate.getMonth();

    const firstDay = new Date(year, month, 1);
    const lastDay = new Date(year, month + 1, 0);
    const today = new Date();

    monthLabel.textContent = new Intl.DateTimeFormat("en", {
      month: "long",
      year: "numeric"
    }).format(firstDay);

    const firstWeekday = (firstDay.getDay() + 6) % 7;
    const daysInMonth = lastDay.getDate();

    for (let i = 0; i &lt; firstWeekday; i += 1) {
      const emptyDay = document.createElement("div");
      emptyDay.className = "vb-date-eleven-day is-empty";
      grid.appendChild(emptyDay);
    }

    for (let day = 1; day &lt;= daysInMonth; day += 1) {
      const dayElement = document.createElement("div");
      dayElement.className = "vb-date-eleven-day";
      dayElement.textContent = day;

      const isToday =
        day === today.getDate() &&
        month === today.getMonth() &&
        year === today.getFullYear();

      if (isToday) {
        dayElement.classList.add("is-today");
      }

      grid.appendChild(dayElement);
    }
  }

  prevButton.addEventListener("click", function () {
    visibleDate.setMonth(visibleDate.getMonth() - 1);
    renderCalendar();
  });

  nextButton.addEventListener("click", function () {
    visibleDate.setMonth(visibleDate.getMonth() + 1);
    renderCalendar();
  });

  renderCalendar();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-eleven-demo"&gt;
  &lt;div class="vb-date-eleven-calendar" data-vb-date-eleven&gt;
    &lt;div class="vb-date-eleven-top"&gt;
      &lt;div&gt;
        &lt;span class="vb-date-eleven-kicker"&gt;Example 11&lt;/span&gt;
        &lt;h3&gt;Monthly Calendar&lt;/h3&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-eleven-controls"&gt;
        &lt;button type="button" data-prev-month&gt;Prev&lt;/button&gt;
        &lt;button type="button" data-next-month&gt;Next&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-eleven-month" data-current-month&gt;Loading month...&lt;/div&gt;

    &lt;div class="vb-date-eleven-weekdays"&gt;
      &lt;span&gt;Mon&lt;/span&gt;
      &lt;span&gt;Tue&lt;/span&gt;
      &lt;span&gt;Wed&lt;/span&gt;
      &lt;span&gt;Thu&lt;/span&gt;
      &lt;span&gt;Fri&lt;/span&gt;
      &lt;span&gt;Sat&lt;/span&gt;
      &lt;span&gt;Sun&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-eleven-grid" data-calendar-grid&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-eleven-demo,
.vb-date-eleven-demo * {
  box-sizing: border-box;
}

.vb-date-eleven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 14% 16%, rgba(245, 158, 11, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(239, 68, 68, 0.14), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fef2f2 55%, #ffffff 100%) !important;
  border: 1px solid rgba(245, 158, 11, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-eleven-calendar {
  max-width: 980px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 18% 14%, rgba(251, 191, 36, 0.18), transparent 34%),
    linear-gradient(135deg, #111827 0%, #7c2d12 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 28px 90px rgba(124, 45, 18, 0.24);
  overflow: hidden;
}

.vb-date-eleven-top {
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: flex-start;
  margin-bottom: 18px;
}

.vb-date-eleven-kicker {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-eleven-top h3 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-eleven-controls {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: flex-end;
}

.vb-date-eleven-controls button {
  min-height: 42px;
  padding: 10px 14px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-date-eleven-month {
  margin: 0 0 16px;
  padding: 16px 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(22px, 4vw, 34px);
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-date-eleven-weekdays,
.vb-date-eleven-grid {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 8px;
  min-width: 0;
}

.vb-date-eleven-weekdays {
  margin-bottom: 8px;
}

.vb-date-eleven-weekdays span {
  min-width: 0;
  padding: 10px 4px;
  border-radius: 14px;
  background: rgba(255,255,255,0.08);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  line-height: 1.1;
  font-weight: 950;
  text-align: center;
}

.vb-date-eleven-day {
  min-width: 0;
  min-height: 70px;
  padding: 10px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 900;
  text-align: left;
}

.vb-date-eleven-day.is-empty {
  opacity: 0.35;
}

.vb-date-eleven-day.is-today {
  background: linear-gradient(135deg, #f97316, #ef4444);
  border-color: rgba(255,255,255,0.32);
  box-shadow: 0 14px 34px rgba(249, 115, 22, 0.28);
}

@media (max-width: 680px) {
  .vb-date-eleven-top {
    flex-direction: column;
  }

  .vb-date-eleven-controls {
    width: 100%;
    justify-content: stretch;
  }

  .vb-date-eleven-controls button {
    flex: 1;
  }

  .vb-date-eleven-weekdays,
  .vb-date-eleven-grid {
    gap: 5px;
  }

  .vb-date-eleven-weekdays span {
    font-size: 10px;
    padding: 8px 2px;
    border-radius: 10px;
  }

  .vb-date-eleven-day {
    min-height: 48px;
    padding: 7px;
    border-radius: 12px;
    font-size: 12px;
  }
}

@media (max-width: 420px) {
  .vb-date-eleven-calendar {
    border-radius: 24px;
  }

  .vb-date-eleven-day {
    min-height: 42px;
    padding: 6px 4px;
    text-align: center;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript monthly calendar generator is useful for event calendars, appointment systems, dashboard widgets, content planners, booking interfaces, project tools, and WordPress pages that need a simple dynamic calendar component.</p>



<h2 class="wp-block-heading">12. Countdown Progress Bar with Deadline Percentage</h2>



<p class="wp-block-paragraph"><strong>A countdown progress bar</strong> combines date calculation with visual progress. It is useful for project deadlines, limited-time offers, campaign timers, course enrollment pages, fundraising goals, event registration, and dashboard widgets.</p>



<p class="wp-block-paragraph">This example compares a start date and deadline date. JavaScript calculates how much time has passed, how much time remains, and updates a progress bar percentage without letting the UI overflow.</p>



<ul class="wp-block-list">
<li>Calculates deadline progress</li>
<li>Shows percentage completed</li>
<li>Displays remaining days</li>
<li>Includes safe progress bar width</li>
<li>Useful for dashboards, campaigns, projects, and landing pages</li>
</ul>



<div class="vb-date-twelve-demo">
  <div class="vb-date-twelve-card" data-vb-date-twelve>
    <div class="vb-date-twelve-content">
      <span class="vb-date-twelve-kicker">Example 12</span>
      <h3>Deadline Progress</h3>
      <p>JavaScript calculates progress between a start date and deadline, then updates a visual progress bar.</p>

      <div class="vb-date-twelve-inputs">
        <label>
          <span>Start date</span>
          <input type="date" data-progress-start>
        </label>

        <label>
          <span>Deadline</span>
          <input type="date" data-progress-end>
        </label>
      </div>

      <button type="button" data-progress-calculate>Update Progress</button>
      <small data-progress-error></small>
    </div>

    <div class="vb-date-twelve-panel">
      <div class="vb-date-twelve-number">
        <span>Progress</span>
        <strong data-progress-percent>--%</strong>
      </div>

      <div class="vb-date-twelve-bar">
        <span data-progress-bar></span>
      </div>

      <div class="vb-date-twelve-stats">
        <div>
          <span>Remaining</span>
          <strong data-days-left>--</strong>
        </div>
        <div>
          <span>Total days</span>
          <strong data-total-range>--</strong>
        </div>
      </div>

      <p data-progress-message>Select dates to calculate deadline progress.</p>
    </div>
  </div>
</div>

<style>
.vb-date-twelve-demo,
.vb-date-twelve-demo * {
  box-sizing: border-box;
}

.vb-date-twelve-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 16%, rgba(124, 58, 237, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(6, 182, 212, 0.18), transparent 34%),
    linear-gradient(135deg, #f5f3ff 0%, #ecfeff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(124, 58, 237, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-twelve-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 430px);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-twelve-content,
.vb-date-twelve-panel {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-twelve-content {
  display: grid;
  align-content: center;
  padding: clamp(22px, 4vw, 36px);
  background: #ffffff;
}

.vb-date-twelve-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-twelve-content h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-twelve-content p {
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-twelve-inputs {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  margin-bottom: 14px;
}

.vb-date-twelve-inputs label {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.vb-date-twelve-inputs label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-twelve-inputs input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-twelve-inputs input:focus {
  border-color: rgba(124, 58, 237, 0.78);
  box-shadow: 0 0 0 4px rgba(124, 58, 237, 0.12);
}

.vb-date-twelve-content button {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #7c3aed, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(124, 58, 237, 0.22);
}

.vb-date-twelve-content small {
  display: block;
  min-height: 20px;
  margin-top: 10px;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 13px;
  line-height: 1.4;
  font-weight: 750;
}

.vb-date-twelve-panel {
  display: grid;
  align-content: center;
  gap: 18px;
  padding: clamp(22px, 4vw, 34px);
  background:
    radial-gradient(circle at 14% 16%, rgba(34, 211, 238, 0.22), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #312e81 100%) !important;
  overflow: hidden;
}

.vb-date-twelve-number {
  display: grid;
  gap: 7px;
}

.vb-date-twelve-number span,
.vb-date-twelve-stats span {
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-twelve-number strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(54px, 9vw, 92px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.075em;
}

.vb-date-twelve-bar {
  width: 100%;
  height: 18px;
  overflow: hidden;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-twelve-bar span {
  display: block;
  width: 0%;
  max-width: 100%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(135deg, #22d3ee, #7c3aed);
  transition: width 0.35s ease;
}

.vb-date-twelve-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-date-twelve-stats div {
  min-width: 0;
  padding: 15px;
  border-radius: 18px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-date-twelve-stats strong {
  display: block;
  margin-top: 5px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1.1;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-date-twelve-panel p {
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-date-twelve-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-twelve-inputs,
  .vb-date-twelve-stats {
    grid-template-columns: 1fr;
  }

  .vb-date-twelve-content,
  .vb-date-twelve-panel {
    border-radius: 24px;
  }

  .vb-date-twelve-content button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const progress = document.querySelector("[data-vb-date-twelve]");
  if (!progress) return;

  const startInput = progress.querySelector("[data-progress-start]");
  const endInput = progress.querySelector("[data-progress-end]");
  const button = progress.querySelector("[data-progress-calculate]");
  const error = progress.querySelector("[data-progress-error]");

  const percentOutput = progress.querySelector("[data-progress-percent]");
  const bar = progress.querySelector("[data-progress-bar]");
  const daysLeftOutput = progress.querySelector("[data-days-left]");
  const totalRangeOutput = progress.querySelector("[data-total-range]");
  const message = progress.querySelector("[data-progress-message]");

  function formatInputDate(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");

    return year + "-" + month + "-" + day;
  }

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function updateProgress() {
    error.textContent = "";

    if (!startInput.value || !endInput.value) {
      error.textContent = "Please select both dates.";
      return;
    }

    const startDate = createLocalDate(startInput.value);
    const endDate = createLocalDate(endInput.value);
    const today = new Date();

    startDate.setHours(0, 0, 0, 0);
    endDate.setHours(0, 0, 0, 0);
    today.setHours(0, 0, 0, 0);

    if (endDate <= startDate) {
      error.textContent = "Deadline must be after the start date.";
      return;
    }

    const totalMs = endDate - startDate;
    const passedMs = today - startDate;
    const remainingMs = endDate - today;

    const totalDays = Math.round(totalMs / (1000 * 60 * 60 * 24));
    const daysLeft = Math.max(0, Math.ceil(remainingMs / (1000 * 60 * 60 * 24)));

    let percent = Math.round((passedMs / totalMs) * 100);
    percent = Math.max(0, Math.min(100, percent));

    percentOutput.textContent = percent + "%";
    bar.style.width = percent + "%";
    daysLeftOutput.textContent = daysLeft + " days";
    totalRangeOutput.textContent = totalDays + " days";

    if (percent >= 100) {
      message.textContent = "The deadline has been reached or passed.";
    } else if (percent === 0) {
      message.textContent = "The timeline has not started yet.";
    } else {
      message.textContent = percent + "% of the timeline has passed. There are " + daysLeft + " days remaining.";
    }
  }

  function setDefaultDates() {
    const start = new Date();
    const end = new Date();

    start.setDate(start.getDate() - 7);
    end.setDate(end.getDate() + 21);

    startInput.value = formatInputDate(start);
    endInput.value = formatInputDate(end);

    updateProgress();
  }

  button.addEventListener("click", updateProgress);
  startInput.addEventListener("change", updateProgress);
  endInput.addEventListener("change", updateProgress);

  setDefaultDates();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const progress = document.querySelector("[data-vb-date-twelve]");
  if (!progress) return;

  const startInput = progress.querySelector("[data-progress-start]");
  const endInput = progress.querySelector("[data-progress-end]");
  const button = progress.querySelector("[data-progress-calculate]");
  const error = progress.querySelector("[data-progress-error]");

  const percentOutput = progress.querySelector("[data-progress-percent]");
  const bar = progress.querySelector("[data-progress-bar]");
  const daysLeftOutput = progress.querySelector("[data-days-left]");
  const totalRangeOutput = progress.querySelector("[data-total-range]");
  const message = progress.querySelector("[data-progress-message]");

  function formatInputDate(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");

    return year + "-" + month + "-" + day;
  }

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function updateProgress() {
    error.textContent = "";

    if (!startInput.value || !endInput.value) {
      error.textContent = "Please select both dates.";
      return;
    }

    const startDate = createLocalDate(startInput.value);
    const endDate = createLocalDate(endInput.value);
    const today = new Date();

    startDate.setHours(0, 0, 0, 0);
    endDate.setHours(0, 0, 0, 0);
    today.setHours(0, 0, 0, 0);

    if (endDate &lt;= startDate) {
      error.textContent = "Deadline must be after the start date.";
      return;
    }

    const totalMs = endDate - startDate;
    const passedMs = today - startDate;
    const remainingMs = endDate - today;

    const totalDays = Math.round(totalMs / (1000 * 60 * 60 * 24));
    const daysLeft = Math.max(0, Math.ceil(remainingMs / (1000 * 60 * 60 * 24)));

    let percent = Math.round((passedMs / totalMs) * 100);
    percent = Math.max(0, Math.min(100, percent));

    percentOutput.textContent = percent + "%";
    bar.style.width = percent + "%";
    daysLeftOutput.textContent = daysLeft + " days";
    totalRangeOutput.textContent = totalDays + " days";

    if (percent &gt;= 100) {
      message.textContent = "The deadline has been reached or passed.";
    } else if (percent === 0) {
      message.textContent = "The timeline has not started yet.";
    } else {
      message.textContent = percent + "% of the timeline has passed. There are " + daysLeft + " days remaining.";
    }
  }

  function setDefaultDates() {
    const start = new Date();
    const end = new Date();

    start.setDate(start.getDate() - 7);
    end.setDate(end.getDate() + 21);

    startInput.value = formatInputDate(start);
    endInput.value = formatInputDate(end);

    updateProgress();
  }

  button.addEventListener("click", updateProgress);
  startInput.addEventListener("change", updateProgress);
  endInput.addEventListener("change", updateProgress);

  setDefaultDates();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-twelve-demo"&gt;
  &lt;div class="vb-date-twelve-card" data-vb-date-twelve&gt;
    &lt;div class="vb-date-twelve-content"&gt;
      &lt;span class="vb-date-twelve-kicker"&gt;Example 12&lt;/span&gt;
      &lt;h3&gt;Deadline Progress&lt;/h3&gt;
      &lt;p&gt;JavaScript calculates progress between a start date and deadline, then updates a visual progress bar.&lt;/p&gt;

      &lt;div class="vb-date-twelve-inputs"&gt;
        &lt;label&gt;
          &lt;span&gt;Start date&lt;/span&gt;
          &lt;input type="date" data-progress-start&gt;
        &lt;/label&gt;

        &lt;label&gt;
          &lt;span&gt;Deadline&lt;/span&gt;
          &lt;input type="date" data-progress-end&gt;
        &lt;/label&gt;
      &lt;/div&gt;

      &lt;button type="button" data-progress-calculate&gt;Update Progress&lt;/button&gt;
      &lt;small data-progress-error&gt;&lt;/small&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-twelve-panel"&gt;
      &lt;div class="vb-date-twelve-number"&gt;
        &lt;span&gt;Progress&lt;/span&gt;
        &lt;strong data-progress-percent&gt;--%&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-twelve-bar"&gt;
        &lt;span data-progress-bar&gt;&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-twelve-stats"&gt;
        &lt;div&gt;
          &lt;span&gt;Remaining&lt;/span&gt;
          &lt;strong data-days-left&gt;--&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Total days&lt;/span&gt;
          &lt;strong data-total-range&gt;--&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;p data-progress-message&gt;Select dates to calculate deadline progress.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-twelve-demo,
.vb-date-twelve-demo * {
  box-sizing: border-box;
}

.vb-date-twelve-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 16%, rgba(124, 58, 237, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(6, 182, 212, 0.18), transparent 34%),
    linear-gradient(135deg, #f5f3ff 0%, #ecfeff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(124, 58, 237, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-twelve-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 430px);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-twelve-content,
.vb-date-twelve-panel {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-twelve-content {
  display: grid;
  align-content: center;
  padding: clamp(22px, 4vw, 36px);
  background: #ffffff;
}

.vb-date-twelve-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-twelve-content h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-twelve-content p {
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-twelve-inputs {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  margin-bottom: 14px;
}

.vb-date-twelve-inputs label {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.vb-date-twelve-inputs label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-twelve-inputs input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-twelve-inputs input:focus {
  border-color: rgba(124, 58, 237, 0.78);
  box-shadow: 0 0 0 4px rgba(124, 58, 237, 0.12);
}

.vb-date-twelve-content button {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #7c3aed, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(124, 58, 237, 0.22);
}

.vb-date-twelve-content small {
  display: block;
  min-height: 20px;
  margin-top: 10px;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 13px;
  line-height: 1.4;
  font-weight: 750;
}

.vb-date-twelve-panel {
  display: grid;
  align-content: center;
  gap: 18px;
  padding: clamp(22px, 4vw, 34px);
  background:
    radial-gradient(circle at 14% 16%, rgba(34, 211, 238, 0.22), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #312e81 100%) !important;
  overflow: hidden;
}

.vb-date-twelve-number {
  display: grid;
  gap: 7px;
}

.vb-date-twelve-number span,
.vb-date-twelve-stats span {
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-twelve-number strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(54px, 9vw, 92px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.075em;
}

.vb-date-twelve-bar {
  width: 100%;
  height: 18px;
  overflow: hidden;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-twelve-bar span {
  display: block;
  width: 0%;
  max-width: 100%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(135deg, #22d3ee, #7c3aed);
  transition: width 0.35s ease;
}

.vb-date-twelve-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-date-twelve-stats div {
  min-width: 0;
  padding: 15px;
  border-radius: 18px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-date-twelve-stats strong {
  display: block;
  margin-top: 5px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1.1;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-date-twelve-panel p {
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-date-twelve-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-twelve-inputs,
  .vb-date-twelve-stats {
    grid-template-columns: 1fr;
  }

  .vb-date-twelve-content,
  .vb-date-twelve-panel {
    border-radius: 24px;
  }

  .vb-date-twelve-content button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript deadline progress bar is useful for project dashboards, campaign trackers, limited-time offers, event registrations, course enrollment pages, project management tools, and custom website status widgets.</p>



<div class="vb24-js-date-mini-cta">
  <p>Need a custom JavaScript date, calendar, booking, or calculator feature for your website?</p>
  <a href="https://veebilehed24.ee/en/contact/">Contact us</a>
</div>

<style>
.vb24-js-date-mini-cta,
.vb24-js-date-mini-cta * {
  box-sizing: border-box;
}

.vb24-js-date-mini-cta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin: 40px 0;
  padding: 18px 20px;
  border: 1px solid rgba(148, 163, 184, 0.24);
  border-radius: 20px;
  background: #f8fafc;
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.06);
}

.vb24-js-date-mini-cta p {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  line-height: 1.55;
  font-weight: 750;
}

.vb24-js-date-mini-cta a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 42px;
  padding: 10px 16px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
  white-space: nowrap;
}

.vb24-js-date-mini-cta a:hover {
  background: #2563eb;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

@media (max-width: 640px) {
  .vb24-js-date-mini-cta {
    align-items: stretch;
    flex-direction: column;
    border-radius: 18px;
  }

  .vb24-js-date-mini-cta a {
    width: 100%;
  }
}
</style>



<h2 class="wp-block-heading">13. Date Input Validator with Minimum and Maximum Dates</h2>



<p class="wp-block-paragraph"><strong>A JavaScript date input validator</strong> is useful for booking forms, appointment systems, registration pages, delivery forms, event signups, rental calculators, and checkout flows. It prevents users from selecting invalid dates before they submit a form.</p>



<p class="wp-block-paragraph">This example validates a selected date against a minimum and maximum allowed date range. JavaScript shows a success or error message immediately, making the form easier to understand and safer to use.</p>



<ul class="wp-block-list">
<li>Validates selected date instantly</li>
<li>Checks minimum and maximum dates</li>
<li>Shows clear success and error states</li>
<li>Responsive form card layout</li>
<li>Useful for bookings, rentals, events, and checkout forms</li>
</ul>



<div class="vb-date-thirteen-demo">
  <div class="vb-date-thirteen-card" data-vb-date-thirteen>
    <div class="vb-date-thirteen-info">
      <span class="vb-date-thirteen-kicker">Example 13</span>
      <h3>Date Validator</h3>
      <p>Select a booking date. JavaScript checks whether the date is inside the allowed booking window.</p>

      <div class="vb-date-thirteen-rules">
        <div>
          <span>Minimum date</span>
          <strong data-min-label>--</strong>
        </div>
        <div>
          <span>Maximum date</span>
          <strong data-max-label>--</strong>
        </div>
      </div>
    </div>

    <div class="vb-date-thirteen-form">
      <label>
        <span>Booking date</span>
        <input type="date" data-booking-date>
      </label>

      <button type="button" data-validate-date>Validate Date</button>

      <div class="vb-date-thirteen-result" data-date-result>
        <strong>Choose a date</strong>
        <p>Your validation result will appear here.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-date-thirteen-demo,
.vb-date-thirteen-demo * {
  box-sizing: border-box;
}

.vb-date-thirteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(59, 130, 246, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #f0fdf4 55%, #ffffff 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-thirteen-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(280px, 410px);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-thirteen-info,
.vb-date-thirteen-form {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-thirteen-info {
  display: grid;
  align-content: center;
  padding: clamp(22px, 4vw, 38px);
  background: #ffffff;
}

.vb-date-thirteen-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-thirteen-info h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-thirteen-info p {
  max-width: 650px;
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-thirteen-rules {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-date-thirteen-rules div {
  min-width: 0;
  padding: 16px;
  border-radius: 20px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-date-thirteen-rules span {
  display: block;
  margin-bottom: 6px;
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.10em;
}

.vb-date-thirteen-rules strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 17px;
  line-height: 1.25;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-date-thirteen-form {
  display: grid;
  align-content: center;
  gap: 14px;
  padding: clamp(22px, 4vw, 34px);
  background:
    radial-gradient(circle at 18% 16%, rgba(34, 197, 94, 0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #064e3b 100%) !important;
}

.vb-date-thirteen-form label {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.vb-date-thirteen-form label span {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-thirteen-form input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: 17px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-thirteen-form input::-webkit-calendar-picker-indicator {
  filter: invert(1);
  opacity: 0.9;
}

.vb-date-thirteen-form input:focus {
  border-color: rgba(134, 239, 172, 0.85);
  box-shadow: 0 0 0 4px rgba(134, 239, 172, 0.14);
}

.vb-date-thirteen-form button {
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #22c55e, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(34, 197, 94, 0.22);
}

.vb-date-thirteen-result {
  display: grid;
  gap: 7px;
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-thirteen-result strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.04em;
  overflow-wrap: anywhere;
}

.vb-date-thirteen-result p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-date-thirteen-result.is-valid {
  background: rgba(34, 197, 94, 0.20);
  border-color: rgba(134, 239, 172, 0.42);
}

.vb-date-thirteen-result.is-invalid {
  background: rgba(248, 113, 113, 0.18);
  border-color: rgba(248, 113, 113, 0.36);
}

@media (max-width: 900px) {
  .vb-date-thirteen-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-thirteen-info,
  .vb-date-thirteen-form,
  .vb-date-thirteen-result {
    border-radius: 24px;
  }

  .vb-date-thirteen-rules {
    grid-template-columns: 1fr;
  }

  .vb-date-thirteen-form button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const validator = document.querySelector("[data-vb-date-thirteen]");
  if (!validator) return;

  const input = validator.querySelector("[data-booking-date]");
  const button = validator.querySelector("[data-validate-date]");
  const result = validator.querySelector("[data-date-result]");
  const minLabel = validator.querySelector("[data-min-label]");
  const maxLabel = validator.querySelector("[data-max-label]");

  const today = new Date();
  const minDate = new Date();
  const maxDate = new Date();

  minDate.setDate(today.getDate() + 2);
  maxDate.setDate(today.getDate() + 45);

  function formatInputDate(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");

    return year + "-" + month + "-" + day;
  }

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function formatReadableDate(date) {
    return new Intl.DateTimeFormat("en", {
      month: "long",
      day: "numeric",
      year: "numeric"
    }).format(date);
  }

  function setResult(title, text, valid) {
    result.classList.remove("is-valid", "is-invalid");
    result.classList.add(valid ? "is-valid" : "is-invalid");

    result.querySelector("strong").textContent = title;
    result.querySelector("p").textContent = text;
  }

  function validateDate() {
    if (!input.value) {
      setResult("Date missing", "Please choose a booking date before validating.", false);
      return;
    }

    const selectedDate = createLocalDate(input.value);

    selectedDate.setHours(0, 0, 0, 0);
    minDate.setHours(0, 0, 0, 0);
    maxDate.setHours(0, 0, 0, 0);

    if (selectedDate < minDate) {
      setResult(
        "Too early",
        "The selected date is before the minimum allowed booking date.",
        false
      );
      return;
    }

    if (selectedDate > maxDate) {
      setResult(
        "Too late",
        "The selected date is outside the maximum allowed booking window.",
        false
      );
      return;
    }

    setResult(
      "Date accepted",
      "The selected booking date is inside the allowed date range.",
      true
    );
  }

  minLabel.textContent = formatReadableDate(minDate);
  maxLabel.textContent = formatReadableDate(maxDate);
  input.min = formatInputDate(minDate);
  input.max = formatInputDate(maxDate);
  input.value = formatInputDate(minDate);

  button.addEventListener("click", validateDate);
  input.addEventListener("change", validateDate);

  validateDate();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const validator = document.querySelector("[data-vb-date-thirteen]");
  if (!validator) return;

  const input = validator.querySelector("[data-booking-date]");
  const button = validator.querySelector("[data-validate-date]");
  const result = validator.querySelector("[data-date-result]");
  const minLabel = validator.querySelector("[data-min-label]");
  const maxLabel = validator.querySelector("[data-max-label]");

  const today = new Date();
  const minDate = new Date();
  const maxDate = new Date();

  minDate.setDate(today.getDate() + 2);
  maxDate.setDate(today.getDate() + 45);

  function formatInputDate(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");

    return year + "-" + month + "-" + day;
  }

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function formatReadableDate(date) {
    return new Intl.DateTimeFormat("en", {
      month: "long",
      day: "numeric",
      year: "numeric"
    }).format(date);
  }

  function setResult(title, text, valid) {
    result.classList.remove("is-valid", "is-invalid");
    result.classList.add(valid ? "is-valid" : "is-invalid");

    result.querySelector("strong").textContent = title;
    result.querySelector("p").textContent = text;
  }

  function validateDate() {
    if (!input.value) {
      setResult("Date missing", "Please choose a booking date before validating.", false);
      return;
    }

    const selectedDate = createLocalDate(input.value);

    selectedDate.setHours(0, 0, 0, 0);
    minDate.setHours(0, 0, 0, 0);
    maxDate.setHours(0, 0, 0, 0);

    if (selectedDate &lt; minDate) {
      setResult(
        "Too early",
        "The selected date is before the minimum allowed booking date.",
        false
      );
      return;
    }

    if (selectedDate &gt; maxDate) {
      setResult(
        "Too late",
        "The selected date is outside the maximum allowed booking window.",
        false
      );
      return;
    }

    setResult(
      "Date accepted",
      "The selected booking date is inside the allowed date range.",
      true
    );
  }

  minLabel.textContent = formatReadableDate(minDate);
  maxLabel.textContent = formatReadableDate(maxDate);
  input.min = formatInputDate(minDate);
  input.max = formatInputDate(maxDate);
  input.value = formatInputDate(minDate);

  button.addEventListener("click", validateDate);
  input.addEventListener("change", validateDate);

  validateDate();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-thirteen-demo"&gt;
  &lt;div class="vb-date-thirteen-card" data-vb-date-thirteen&gt;
    &lt;div class="vb-date-thirteen-info"&gt;
      &lt;span class="vb-date-thirteen-kicker"&gt;Example 13&lt;/span&gt;
      &lt;h3&gt;Date Validator&lt;/h3&gt;
      &lt;p&gt;Select a booking date. JavaScript checks whether the date is inside the allowed booking window.&lt;/p&gt;

      &lt;div class="vb-date-thirteen-rules"&gt;
        &lt;div&gt;
          &lt;span&gt;Minimum date&lt;/span&gt;
          &lt;strong data-min-label&gt;--&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Maximum date&lt;/span&gt;
          &lt;strong data-max-label&gt;--&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-thirteen-form"&gt;
      &lt;label&gt;
        &lt;span&gt;Booking date&lt;/span&gt;
        &lt;input type="date" data-booking-date&gt;
      &lt;/label&gt;

      &lt;button type="button" data-validate-date&gt;Validate Date&lt;/button&gt;

      &lt;div class="vb-date-thirteen-result" data-date-result&gt;
        &lt;strong&gt;Choose a date&lt;/strong&gt;
        &lt;p&gt;Your validation result will appear here.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-thirteen-demo,
.vb-date-thirteen-demo * {
  box-sizing: border-box;
}

.vb-date-thirteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(59, 130, 246, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #f0fdf4 55%, #ffffff 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-thirteen-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(280px, 410px);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-thirteen-info,
.vb-date-thirteen-form {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-thirteen-info {
  display: grid;
  align-content: center;
  padding: clamp(22px, 4vw, 38px);
  background: #ffffff;
}

.vb-date-thirteen-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-thirteen-info h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-thirteen-info p {
  max-width: 650px;
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-thirteen-rules {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-date-thirteen-rules div {
  min-width: 0;
  padding: 16px;
  border-radius: 20px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-date-thirteen-rules span {
  display: block;
  margin-bottom: 6px;
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.10em;
}

.vb-date-thirteen-rules strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 17px;
  line-height: 1.25;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-date-thirteen-form {
  display: grid;
  align-content: center;
  gap: 14px;
  padding: clamp(22px, 4vw, 34px);
  background:
    radial-gradient(circle at 18% 16%, rgba(34, 197, 94, 0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #064e3b 100%) !important;
}

.vb-date-thirteen-form label {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.vb-date-thirteen-form label span {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-thirteen-form input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: 17px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-thirteen-form input::-webkit-calendar-picker-indicator {
  filter: invert(1);
  opacity: 0.9;
}

.vb-date-thirteen-form input:focus {
  border-color: rgba(134, 239, 172, 0.85);
  box-shadow: 0 0 0 4px rgba(134, 239, 172, 0.14);
}

.vb-date-thirteen-form button {
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #22c55e, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(34, 197, 94, 0.22);
}

.vb-date-thirteen-result {
  display: grid;
  gap: 7px;
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-thirteen-result strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.04em;
  overflow-wrap: anywhere;
}

.vb-date-thirteen-result p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-date-thirteen-result.is-valid {
  background: rgba(34, 197, 94, 0.20);
  border-color: rgba(134, 239, 172, 0.42);
}

.vb-date-thirteen-result.is-invalid {
  background: rgba(248, 113, 113, 0.18);
  border-color: rgba(248, 113, 113, 0.36);
}

@media (max-width: 900px) {
  .vb-date-thirteen-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-thirteen-info,
  .vb-date-thirteen-form,
  .vb-date-thirteen-result {
    border-radius: 24px;
  }

  .vb-date-thirteen-rules {
    grid-template-columns: 1fr;
  }

  .vb-date-thirteen-form button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript date validator is useful for appointment booking, rental date selection, event registration, delivery scheduling, checkout forms, reservation systems, and any form that should only allow dates inside a specific range.</p>



<h2 class="wp-block-heading">14. Weekend Detector for Selected Date</h2>



<p class="wp-block-paragraph"><strong>A weekend detector</strong> is a simple but practical JavaScript date example for booking systems, delivery calculators, business forms, support availability widgets, calendar tools, and service request pages. It checks whether a selected date falls on a weekday or weekend.</p>



<p class="wp-block-paragraph">This example reads a selected date, detects the weekday, and displays whether the date is a business day or weekend. It also shows a visual day card for all seven weekdays.</p>



<ul class="wp-block-list">
<li>Detects weekday or weekend</li>
<li>Highlights selected weekday</li>
<li>Uses JavaScript getDay()</li>
<li>Includes clear business day message</li>
<li>Useful for bookings, delivery rules, and service forms</li>
</ul>



<div class="vb-date-fourteen-demo">
  <div class="vb-date-fourteen-shell" data-vb-date-fourteen>
    <div class="vb-date-fourteen-panel">
      <span class="vb-date-fourteen-kicker">Example 14</span>
      <h3>Weekend Detector</h3>
      <p>Choose a date and JavaScript checks whether it is a weekday or weekend.</p>

      <label>
        <span>Select date</span>
        <input type="date" data-weekend-date>
      </label>

      <button type="button" data-check-weekend>Check Date</button>
    </div>

    <div class="vb-date-fourteen-result">
      <div class="vb-date-fourteen-status" data-weekend-status>
        <span data-weekday-name>Weekday</span>
        <strong data-weekend-result>Select a date</strong>
        <p data-weekend-message>Your result will appear here.</p>
      </div>

      <div class="vb-date-fourteen-days">
        <div data-day-index="1">Mon</div>
        <div data-day-index="2">Tue</div>
        <div data-day-index="3">Wed</div>
        <div data-day-index="4">Thu</div>
        <div data-day-index="5">Fri</div>
        <div data-day-index="6">Sat</div>
        <div data-day-index="0">Sun</div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-date-fourteen-demo,
.vb-date-fourteen-demo * {
  box-sizing: border-box;
}

.vb-date-fourteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 16%, rgba(245, 158, 11, 0.18), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #f0fdf4 55%, #ffffff 100%) !important;
  border: 1px solid rgba(245, 158, 11, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-fourteen-shell {
  display: grid;
  grid-template-columns: minmax(280px, 0.8fr) minmax(0, 1.2fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-fourteen-panel,
.vb-date-fourteen-result {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-fourteen-panel {
  display: grid;
  align-content: center;
  padding: clamp(22px, 4vw, 36px);
  background: #ffffff;
}

.vb-date-fourteen-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fef3c7;
  color: #b45309 !important;
  -webkit-text-fill-color: #b45309 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-fourteen-panel h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-fourteen-panel p {
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-fourteen-panel label {
  display: grid;
  gap: 8px;
  margin-bottom: 14px;
}

.vb-date-fourteen-panel label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-fourteen-panel input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-fourteen-panel input:focus {
  border-color: rgba(245, 158, 11, 0.78);
  box-shadow: 0 0 0 4px rgba(245, 158, 11, 0.12);
}

.vb-date-fourteen-panel button {
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #f59e0b, #16a34a);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(245, 158, 11, 0.22);
}

.vb-date-fourteen-result {
  display: grid;
  align-content: center;
  gap: 16px;
  padding: clamp(20px, 4vw, 32px);
  background:
    radial-gradient(circle at 16% 12%, rgba(251, 191, 36, 0.18), transparent 34%),
    linear-gradient(135deg, #111827 0%, #365314 100%) !important;
}

.vb-date-fourteen-status {
  display: grid;
  gap: 9px;
  min-width: 0;
  padding: 22px;
  border-radius: 26px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-fourteen-status span {
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-fourteen-status strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 6vw, 60px);
  line-height: 0.98;
  font-weight: 950;
  letter-spacing: -0.065em;
  overflow-wrap: anywhere;
}

.vb-date-fourteen-status p {
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-date-fourteen-status.is-weekend {
  background: rgba(248, 113, 113, 0.18);
  border-color: rgba(248, 113, 113, 0.34);
}

.vb-date-fourteen-status.is-business {
  background: rgba(34, 197, 94, 0.18);
  border-color: rgba(134, 239, 172, 0.34);
}

.vb-date-fourteen-days {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 8px;
}

.vb-date-fourteen-days div {
  min-width: 0;
  min-height: 48px;
  display: grid;
  place-items: center;
  border-radius: 16px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.13);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-date-fourteen-days div.is-active {
  background: linear-gradient(135deg, #f59e0b, #22c55e);
  border-color: rgba(255,255,255,0.34);
  box-shadow: 0 14px 34px rgba(245, 158, 11, 0.22);
}

@media (max-width: 900px) {
  .vb-date-fourteen-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-fourteen-panel,
  .vb-date-fourteen-result,
  .vb-date-fourteen-status {
    border-radius: 24px;
  }

  .vb-date-fourteen-panel button {
    width: 100%;
  }

  .vb-date-fourteen-days {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (max-width: 420px) {
  .vb-date-fourteen-days {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}
</style>

<script>
(function () {
  const detector = document.querySelector("[data-vb-date-fourteen]");
  if (!detector) return;

  const input = detector.querySelector("[data-weekend-date]");
  const button = detector.querySelector("[data-check-weekend]");
  const statusBox = detector.querySelector("[data-weekend-status]");
  const weekdayName = detector.querySelector("[data-weekday-name]");
  const result = detector.querySelector("[data-weekend-result]");
  const message = detector.querySelector("[data-weekend-message]");
  const dayBoxes = detector.querySelectorAll("[data-day-index]");

  const weekdayNames = [
    "Sunday",
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday"
  ];

  function formatInputDate(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");

    return year + "-" + month + "-" + day;
  }

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function checkWeekend() {
    if (!input.value) return;

    const selectedDate = createLocalDate(input.value);
    const dayIndex = selectedDate.getDay();
    const isWeekend = dayIndex === 0 || dayIndex === 6;

    dayBoxes.forEach(function (box) {
      box.classList.toggle("is-active", Number(box.getAttribute("data-day-index")) === dayIndex);
    });

    statusBox.classList.remove("is-weekend", "is-business");
    statusBox.classList.add(isWeekend ? "is-weekend" : "is-business");

    weekdayName.textContent = weekdayNames[dayIndex];

    if (isWeekend) {
      result.textContent = "Weekend";
      message.textContent = "The selected date falls on a weekend. You may need a different business day.";
    } else {
      result.textContent = "Business day";
      message.textContent = "The selected date is a weekday and can be used for business-day logic.";
    }
  }

  input.value = formatInputDate(new Date());
  button.addEventListener("click", checkWeekend);
  input.addEventListener("change", checkWeekend);

  checkWeekend();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const detector = document.querySelector("[data-vb-date-fourteen]");
  if (!detector) return;

  const input = detector.querySelector("[data-weekend-date]");
  const button = detector.querySelector("[data-check-weekend]");
  const statusBox = detector.querySelector("[data-weekend-status]");
  const weekdayName = detector.querySelector("[data-weekday-name]");
  const result = detector.querySelector("[data-weekend-result]");
  const message = detector.querySelector("[data-weekend-message]");
  const dayBoxes = detector.querySelectorAll("[data-day-index]");

  const weekdayNames = [
    "Sunday",
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday"
  ];

  function formatInputDate(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");

    return year + "-" + month + "-" + day;
  }

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function checkWeekend() {
    if (!input.value) return;

    const selectedDate = createLocalDate(input.value);
    const dayIndex = selectedDate.getDay();
    const isWeekend = dayIndex === 0 || dayIndex === 6;

    dayBoxes.forEach(function (box) {
      box.classList.toggle("is-active", Number(box.getAttribute("data-day-index")) === dayIndex);
    });

    statusBox.classList.remove("is-weekend", "is-business");
    statusBox.classList.add(isWeekend ? "is-weekend" : "is-business");

    weekdayName.textContent = weekdayNames[dayIndex];

    if (isWeekend) {
      result.textContent = "Weekend";
      message.textContent = "The selected date falls on a weekend. You may need a different business day.";
    } else {
      result.textContent = "Business day";
      message.textContent = "The selected date is a weekday and can be used for business-day logic.";
    }
  }

  input.value = formatInputDate(new Date());
  button.addEventListener("click", checkWeekend);
  input.addEventListener("change", checkWeekend);

  checkWeekend();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-fourteen-demo"&gt;
  &lt;div class="vb-date-fourteen-shell" data-vb-date-fourteen&gt;
    &lt;div class="vb-date-fourteen-panel"&gt;
      &lt;span class="vb-date-fourteen-kicker"&gt;Example 14&lt;/span&gt;
      &lt;h3&gt;Weekend Detector&lt;/h3&gt;
      &lt;p&gt;Choose a date and JavaScript checks whether it is a weekday or weekend.&lt;/p&gt;

      &lt;label&gt;
        &lt;span&gt;Select date&lt;/span&gt;
        &lt;input type="date" data-weekend-date&gt;
      &lt;/label&gt;

      &lt;button type="button" data-check-weekend&gt;Check Date&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-fourteen-result"&gt;
      &lt;div class="vb-date-fourteen-status" data-weekend-status&gt;
        &lt;span data-weekday-name&gt;Weekday&lt;/span&gt;
        &lt;strong data-weekend-result&gt;Select a date&lt;/strong&gt;
        &lt;p data-weekend-message&gt;Your result will appear here.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-fourteen-days"&gt;
        &lt;div data-day-index="1"&gt;Mon&lt;/div&gt;
        &lt;div data-day-index="2"&gt;Tue&lt;/div&gt;
        &lt;div data-day-index="3"&gt;Wed&lt;/div&gt;
        &lt;div data-day-index="4"&gt;Thu&lt;/div&gt;
        &lt;div data-day-index="5"&gt;Fri&lt;/div&gt;
        &lt;div data-day-index="6"&gt;Sat&lt;/div&gt;
        &lt;div data-day-index="0"&gt;Sun&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-fourteen-demo,
.vb-date-fourteen-demo * {
  box-sizing: border-box;
}

.vb-date-fourteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 16%, rgba(245, 158, 11, 0.18), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #f0fdf4 55%, #ffffff 100%) !important;
  border: 1px solid rgba(245, 158, 11, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-fourteen-shell {
  display: grid;
  grid-template-columns: minmax(280px, 0.8fr) minmax(0, 1.2fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-fourteen-panel,
.vb-date-fourteen-result {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-fourteen-panel {
  display: grid;
  align-content: center;
  padding: clamp(22px, 4vw, 36px);
  background: #ffffff;
}

.vb-date-fourteen-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fef3c7;
  color: #b45309 !important;
  -webkit-text-fill-color: #b45309 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-fourteen-panel h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-fourteen-panel p {
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-fourteen-panel label {
  display: grid;
  gap: 8px;
  margin-bottom: 14px;
}

.vb-date-fourteen-panel label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-fourteen-panel input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-fourteen-panel input:focus {
  border-color: rgba(245, 158, 11, 0.78);
  box-shadow: 0 0 0 4px rgba(245, 158, 11, 0.12);
}

.vb-date-fourteen-panel button {
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #f59e0b, #16a34a);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(245, 158, 11, 0.22);
}

.vb-date-fourteen-result {
  display: grid;
  align-content: center;
  gap: 16px;
  padding: clamp(20px, 4vw, 32px);
  background:
    radial-gradient(circle at 16% 12%, rgba(251, 191, 36, 0.18), transparent 34%),
    linear-gradient(135deg, #111827 0%, #365314 100%) !important;
}

.vb-date-fourteen-status {
  display: grid;
  gap: 9px;
  min-width: 0;
  padding: 22px;
  border-radius: 26px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-fourteen-status span {
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-fourteen-status strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 6vw, 60px);
  line-height: 0.98;
  font-weight: 950;
  letter-spacing: -0.065em;
  overflow-wrap: anywhere;
}

.vb-date-fourteen-status p {
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-date-fourteen-status.is-weekend {
  background: rgba(248, 113, 113, 0.18);
  border-color: rgba(248, 113, 113, 0.34);
}

.vb-date-fourteen-status.is-business {
  background: rgba(34, 197, 94, 0.18);
  border-color: rgba(134, 239, 172, 0.34);
}

.vb-date-fourteen-days {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 8px;
}

.vb-date-fourteen-days div {
  min-width: 0;
  min-height: 48px;
  display: grid;
  place-items: center;
  border-radius: 16px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.13);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-date-fourteen-days div.is-active {
  background: linear-gradient(135deg, #f59e0b, #22c55e);
  border-color: rgba(255,255,255,0.34);
  box-shadow: 0 14px 34px rgba(245, 158, 11, 0.22);
}

@media (max-width: 900px) {
  .vb-date-fourteen-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-fourteen-panel,
  .vb-date-fourteen-result,
  .vb-date-fourteen-status {
    border-radius: 24px;
  }

  .vb-date-fourteen-panel button {
    width: 100%;
  }

  .vb-date-fourteen-days {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (max-width: 420px) {
  .vb-date-fourteen-days {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript weekend detector is useful for business-day calculators, booking systems, delivery tools, service request forms, checkout date validation, appointment pages, and calendar widgets.</p>



<h2 class="wp-block-heading">15. Time Until Next Business Day</h2>



<p class="wp-block-paragraph"><strong>A time until next business day widget</strong> is useful for contact pages, customer support widgets, ecommerce stores, quote request pages, agencies, clinics, and service businesses. It tells visitors when the business will be available again.</p>



<p class="wp-block-paragraph">This example checks whether the current time is outside business hours and calculates the time remaining until the next business day starts. It updates every minute and handles weekends safely.</p>



<ul class="wp-block-list">
<li>Calculates time until the next business opening</li>
<li>Handles weekends and after-hours periods</li>
<li>Updates automatically every minute</li>
<li>Includes clear open and closed states</li>
<li>Useful for support widgets, contact pages, and service businesses</li>
</ul>



<div class="vb-date-fifteen-demo">
  <div class="vb-date-fifteen-card" data-vb-date-fifteen>
    <div class="vb-date-fifteen-top">
      <span class="vb-date-fifteen-kicker">Example 15</span>
      <h3>Next Business Day</h3>
      <p>JavaScript calculates how long until the next available business opening time.</p>
    </div>

    <div class="vb-date-fifteen-status" data-business-status>
      <span data-status-label>Checking status</span>
      <strong data-countdown-label>--</strong>
      <p data-business-message>Loading current business availability...</p>
    </div>

    <div class="vb-date-fifteen-info-grid">
      <div>
        <span>Business hours</span>
        <strong>Mon-Fri, 09:00-17:00</strong>
      </div>
      <div>
        <span>Current time</span>
        <strong data-current-time>--:--</strong>
      </div>
      <div>
        <span>Next opening</span>
        <strong data-next-opening>--</strong>
      </div>
    </div>
  </div>
</div>

<style>
.vb-date-fifteen-demo,
.vb-date-fifteen-demo * {
  box-sizing: border-box;
}

.vb-date-fifteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(14, 165, 233, 0.18), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #ecfeff 0%, #f0fdf4 55%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-fifteen-card {
  max-width: 1040px;
  margin: 0 auto;
  padding: clamp(22px, 5vw, 44px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 211, 238, 0.20), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(34, 197, 94, 0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #064e3b 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
  overflow: hidden;
}

.vb-date-fifteen-top {
  max-width: 760px;
  margin-bottom: 24px;
}

.vb-date-fifteen-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-fifteen-top h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 7vw, 76px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-fifteen-top p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-fifteen-status {
  display: grid;
  gap: 10px;
  min-width: 0;
  margin-bottom: 16px;
  padding: clamp(20px, 4vw, 32px);
  border-radius: 28px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-fifteen-status span {
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-fifteen-status strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 7vw, 74px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
  font-variant-numeric: tabular-nums;
}

.vb-date-fifteen-status p {
  margin: 0 !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-date-fifteen-status.is-open {
  background: rgba(34, 197, 94, 0.18);
  border-color: rgba(134, 239, 172, 0.34);
}

.vb-date-fifteen-status.is-closed {
  background: rgba(14, 165, 233, 0.16);
  border-color: rgba(125, 211, 252, 0.30);
}

.vb-date-fifteen-info-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-date-fifteen-info-grid div {
  min-width: 0;
  padding: 16px;
  border-radius: 20px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-date-fifteen-info-grid span {
  display: block;
  margin-bottom: 6px;
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 11px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.09em;
}

.vb-date-fifteen-info-grid strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.3;
  font-weight: 850;
  overflow-wrap: anywhere;
}

@media (max-width: 760px) {
  .vb-date-fifteen-info-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 520px) {
  .vb-date-fifteen-card,
  .vb-date-fifteen-status {
    border-radius: 24px;
  }

  .vb-date-fifteen-status strong {
    font-size: 40px;
  }
}
</style>

<script>
(function () {
  const widget = document.querySelector("[data-vb-date-fifteen]");
  if (!widget) return;

  const statusBox = widget.querySelector("[data-business-status]");
  const statusLabel = widget.querySelector("[data-status-label]");
  const countdownLabel = widget.querySelector("[data-countdown-label]");
  const message = widget.querySelector("[data-business-message]");
  const currentTime = widget.querySelector("[data-current-time]");
  const nextOpening = widget.querySelector("[data-next-opening]");

  const openHour = 9;
  const closeHour = 17;

  function isBusinessDay(date) {
    const day = date.getDay();
    return day >= 1 && day <= 5;
  }

  function isOpenNow(date) {
    return isBusinessDay(date) &#038;&#038; date.getHours() >= openHour && date.getHours() < closeHour;
  }

  function getNextOpening(date) {
    const next = new Date(date);
    next.setMinutes(0, 0, 0);

    if (isBusinessDay(next) &#038;&#038; next.getHours() < openHour) {
      next.setHours(openHour);
      return next;
    }

    next.setDate(next.getDate() + 1);
    next.setHours(openHour, 0, 0, 0);

    while (!isBusinessDay(next)) {
      next.setDate(next.getDate() + 1);
    }

    return next;
  }

  function formatDuration(milliseconds) {
    const totalMinutes = Math.max(0, Math.ceil(milliseconds / (1000 * 60)));
    const days = Math.floor(totalMinutes / 1440);
    const hours = Math.floor((totalMinutes % 1440) / 60);
    const minutes = totalMinutes % 60;

    if (days > 0) {
      return days + "d " + hours + "h";
    }

    return hours + "h " + minutes + "m";
  }

  function formatDateTime(date) {
    return new Intl.DateTimeFormat("en", {
      weekday: "short",
      month: "short",
      day: "numeric",
      hour: "2-digit",
      minute: "2-digit"
    }).format(date);
  }

  function updateBusinessCountdown() {
    const now = new Date();

    currentTime.textContent = new Intl.DateTimeFormat("en", {
      hour: "2-digit",
      minute: "2-digit"
    }).format(now);

    statusBox.classList.remove("is-open", "is-closed");

    if (isOpenNow(now)) {
      statusBox.classList.add("is-open");
      statusLabel.textContent = "Open now";
      countdownLabel.textContent = "Available";
      message.textContent = "The business is currently open. Visitors can contact the team during working hours.";
      nextOpening.textContent = "Open now";
      return;
    }

    const openingDate = getNextOpening(now);
    const remainingTime = openingDate - now;

    statusBox.classList.add("is-closed");
    statusLabel.textContent = "Closed now";
    countdownLabel.textContent = formatDuration(remainingTime);
    message.textContent = "Time remaining until the next business opening.";
    nextOpening.textContent = formatDateTime(openingDate);
  }

  updateBusinessCountdown();
  setInterval(updateBusinessCountdown, 60000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const widget = document.querySelector("[data-vb-date-fifteen]");
  if (!widget) return;

  const statusBox = widget.querySelector("[data-business-status]");
  const statusLabel = widget.querySelector("[data-status-label]");
  const countdownLabel = widget.querySelector("[data-countdown-label]");
  const message = widget.querySelector("[data-business-message]");
  const currentTime = widget.querySelector("[data-current-time]");
  const nextOpening = widget.querySelector("[data-next-opening]");

  const openHour = 9;
  const closeHour = 17;

  function isBusinessDay(date) {
    const day = date.getDay();
    return day &gt;= 1 && day &lt;= 5;
  }

  function isOpenNow(date) {
    return isBusinessDay(date) && date.getHours() &gt;= openHour && date.getHours() &lt; closeHour;
  }

  function getNextOpening(date) {
    const next = new Date(date);
    next.setMinutes(0, 0, 0);

    if (isBusinessDay(next) && next.getHours() &lt; openHour) {
      next.setHours(openHour);
      return next;
    }

    next.setDate(next.getDate() + 1);
    next.setHours(openHour, 0, 0, 0);

    while (!isBusinessDay(next)) {
      next.setDate(next.getDate() + 1);
    }

    return next;
  }

  function formatDuration(milliseconds) {
    const totalMinutes = Math.max(0, Math.ceil(milliseconds / (1000 * 60)));
    const days = Math.floor(totalMinutes / 1440);
    const hours = Math.floor((totalMinutes % 1440) / 60);
    const minutes = totalMinutes % 60;

    if (days &gt; 0) {
      return days + "d " + hours + "h";
    }

    return hours + "h " + minutes + "m";
  }

  function formatDateTime(date) {
    return new Intl.DateTimeFormat("en", {
      weekday: "short",
      month: "short",
      day: "numeric",
      hour: "2-digit",
      minute: "2-digit"
    }).format(date);
  }

  function updateBusinessCountdown() {
    const now = new Date();

    currentTime.textContent = new Intl.DateTimeFormat("en", {
      hour: "2-digit",
      minute: "2-digit"
    }).format(now);

    statusBox.classList.remove("is-open", "is-closed");

    if (isOpenNow(now)) {
      statusBox.classList.add("is-open");
      statusLabel.textContent = "Open now";
      countdownLabel.textContent = "Available";
      message.textContent = "The business is currently open. Visitors can contact the team during working hours.";
      nextOpening.textContent = "Open now";
      return;
    }

    const openingDate = getNextOpening(now);
    const remainingTime = openingDate - now;

    statusBox.classList.add("is-closed");
    statusLabel.textContent = "Closed now";
    countdownLabel.textContent = formatDuration(remainingTime);
    message.textContent = "Time remaining until the next business opening.";
    nextOpening.textContent = formatDateTime(openingDate);
  }

  updateBusinessCountdown();
  setInterval(updateBusinessCountdown, 60000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-fifteen-demo"&gt;
  &lt;div class="vb-date-fifteen-card" data-vb-date-fifteen&gt;
    &lt;div class="vb-date-fifteen-top"&gt;
      &lt;span class="vb-date-fifteen-kicker"&gt;Example 15&lt;/span&gt;
      &lt;h3&gt;Next Business Day&lt;/h3&gt;
      &lt;p&gt;JavaScript calculates how long until the next available business opening time.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-fifteen-status" data-business-status&gt;
      &lt;span data-status-label&gt;Checking status&lt;/span&gt;
      &lt;strong data-countdown-label&gt;--&lt;/strong&gt;
      &lt;p data-business-message&gt;Loading current business availability...&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-fifteen-info-grid"&gt;
      &lt;div&gt;
        &lt;span&gt;Business hours&lt;/span&gt;
        &lt;strong&gt;Mon-Fri, 09:00-17:00&lt;/strong&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;span&gt;Current time&lt;/span&gt;
        &lt;strong data-current-time&gt;--:--&lt;/strong&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;span&gt;Next opening&lt;/span&gt;
        &lt;strong data-next-opening&gt;--&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-fifteen-demo,
.vb-date-fifteen-demo * {
  box-sizing: border-box;
}

.vb-date-fifteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(14, 165, 233, 0.18), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #ecfeff 0%, #f0fdf4 55%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-fifteen-card {
  max-width: 1040px;
  margin: 0 auto;
  padding: clamp(22px, 5vw, 44px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 211, 238, 0.20), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(34, 197, 94, 0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #064e3b 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
  overflow: hidden;
}

.vb-date-fifteen-top {
  max-width: 760px;
  margin-bottom: 24px;
}

.vb-date-fifteen-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-fifteen-top h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 7vw, 76px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-fifteen-top p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-fifteen-status {
  display: grid;
  gap: 10px;
  min-width: 0;
  margin-bottom: 16px;
  padding: clamp(20px, 4vw, 32px);
  border-radius: 28px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-fifteen-status span {
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-fifteen-status strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 7vw, 74px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
  font-variant-numeric: tabular-nums;
}

.vb-date-fifteen-status p {
  margin: 0 !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-date-fifteen-status.is-open {
  background: rgba(34, 197, 94, 0.18);
  border-color: rgba(134, 239, 172, 0.34);
}

.vb-date-fifteen-status.is-closed {
  background: rgba(14, 165, 233, 0.16);
  border-color: rgba(125, 211, 252, 0.30);
}

.vb-date-fifteen-info-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-date-fifteen-info-grid div {
  min-width: 0;
  padding: 16px;
  border-radius: 20px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-date-fifteen-info-grid span {
  display: block;
  margin-bottom: 6px;
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 11px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.09em;
}

.vb-date-fifteen-info-grid strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.3;
  font-weight: 850;
  overflow-wrap: anywhere;
}

@media (max-width: 760px) {
  .vb-date-fifteen-info-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 520px) {
  .vb-date-fifteen-card,
  .vb-date-fifteen-status {
    border-radius: 24px;
  }

  .vb-date-fifteen-status strong {
    font-size: 40px;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript next business day widget is useful for contact pages, support availability sections, local business websites, ecommerce customer service widgets, quote request forms, agency websites, and booking interfaces.</p>



<h2 class="wp-block-heading">16. Custom Date Range Picker Summary</h2>



<p class="wp-block-paragraph"><strong>A custom date range picker summary</strong> is useful for booking forms, hotel reservations, rental websites, dashboards, analytics filters, project planners, and ecommerce reports. It lets users select a start and end date, then JavaScript creates a clear range summary.</p>



<p class="wp-block-paragraph">This example validates the selected range, calculates the total number of nights or days, and updates a clean summary card. The layout is fully responsive and keeps all text inside the cards on small screens.</p>



<ul class="wp-block-list">
<li>Selects start and end dates</li>
<li>Validates date order</li>
<li>Calculates total range length</li>
<li>Shows readable range summary</li>
<li>Useful for bookings, rentals, dashboards, and filters</li>
</ul>



<div class="vb-date-sixteen-demo">
  <div class="vb-date-sixteen-card" data-vb-date-sixteen>
    <div class="vb-date-sixteen-form">
      <span class="vb-date-sixteen-kicker">Example 16</span>
      <h3>Date Range Summary</h3>
      <p>Select a start and end date. JavaScript validates the range and creates a readable booking-style summary.</p>

      <div class="vb-date-sixteen-inputs">
        <label>
          <span>Start date</span>
          <input type="date" data-range-start>
        </label>

        <label>
          <span>End date</span>
          <input type="date" data-range-end>
        </label>
      </div>

      <button type="button" data-range-update>Update Range</button>
      <small data-range-error></small>
    </div>

    <div class="vb-date-sixteen-summary">
      <div class="vb-date-sixteen-main">
        <span>Selected range</span>
        <strong data-range-title>Select dates</strong>
        <p data-range-text>Your date range summary will appear here.</p>
      </div>

      <div class="vb-date-sixteen-metrics">
        <div>
          <span>Start</span>
          <strong data-range-start-label>--</strong>
        </div>
        <div>
          <span>End</span>
          <strong data-range-end-label>--</strong>
        </div>
        <div>
          <span>Total</span>
          <strong data-range-total>--</strong>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-date-sixteen-demo,
.vb-date-sixteen-demo * {
  box-sizing: border-box;
}

.vb-date-sixteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(37, 99, 235, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #faf5ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-sixteen-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(310px, 430px);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-sixteen-form,
.vb-date-sixteen-summary {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-sixteen-form {
  display: grid;
  align-content: center;
  padding: clamp(22px, 4vw, 38px);
  background: #ffffff;
}

.vb-date-sixteen-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-sixteen-form h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-sixteen-form p {
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-sixteen-inputs {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  margin-bottom: 14px;
}

.vb-date-sixteen-inputs label {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.vb-date-sixteen-inputs span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-sixteen-inputs input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-sixteen-inputs input:focus {
  border-color: rgba(37, 99, 235, 0.78);
  box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.12);
}

.vb-date-sixteen-form button {
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.22);
}

.vb-date-sixteen-form small {
  display: block;
  min-height: 20px;
  margin-top: 10px;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 13px;
  line-height: 1.4;
  font-weight: 750;
}

.vb-date-sixteen-summary {
  display: grid;
  gap: 14px;
  padding: clamp(20px, 4vw, 32px);
  background:
    radial-gradient(circle at 12% 16%, rgba(129, 140, 248, 0.20), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #312e81 100%) !important;
}

.vb-date-sixteen-main {
  display: grid;
  gap: 9px;
  min-width: 0;
  padding: 22px;
  border-radius: 26px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-sixteen-main span,
.vb-date-sixteen-metrics span {
  color: #c4b5fd !important;
  -webkit-text-fill-color: #c4b5fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-sixteen-main strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 5vw, 52px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
  overflow-wrap: anywhere;
}

.vb-date-sixteen-main p {
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-date-sixteen-metrics {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
}

.vb-date-sixteen-metrics div {
  min-width: 0;
  padding: 14px;
  border-radius: 18px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-date-sixteen-metrics strong {
  display: block;
  margin-top: 5px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  line-height: 1.3;
  font-weight: 850;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-date-sixteen-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-sixteen-inputs {
    grid-template-columns: 1fr;
  }

  .vb-date-sixteen-form,
  .vb-date-sixteen-summary,
  .vb-date-sixteen-main {
    border-radius: 24px;
  }

  .vb-date-sixteen-form button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const picker = document.querySelector("[data-vb-date-sixteen]");
  if (!picker) return;

  const startInput = picker.querySelector("[data-range-start]");
  const endInput = picker.querySelector("[data-range-end]");
  const button = picker.querySelector("[data-range-update]");
  const error = picker.querySelector("[data-range-error]");

  const title = picker.querySelector("[data-range-title]");
  const text = picker.querySelector("[data-range-text]");
  const startLabel = picker.querySelector("[data-range-start-label]");
  const endLabel = picker.querySelector("[data-range-end-label]");
  const totalLabel = picker.querySelector("[data-range-total]");

  function formatInputDate(date) {
    return date.getFullYear() + "-" +
      String(date.getMonth() + 1).padStart(2, "0") + "-" +
      String(date.getDate()).padStart(2, "0");
  }

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function formatReadableDate(date) {
    return new Intl.DateTimeFormat("en", {
      month: "short",
      day: "numeric",
      year: "numeric"
    }).format(date);
  }

  function updateRange() {
    error.textContent = "";

    if (!startInput.value || !endInput.value) {
      error.textContent = "Please select both start and end dates.";
      return;
    }

    const startDate = createLocalDate(startInput.value);
    const endDate = createLocalDate(endInput.value);

    if (endDate < startDate) {
      error.textContent = "End date must be after the start date.";
      title.textContent = "Invalid range";
      text.textContent = "Please choose an end date that comes after the start date.";
      startLabel.textContent = "--";
      endLabel.textContent = "--";
      totalLabel.textContent = "--";
      return;
    }

    const diffMs = endDate - startDate;
    const totalDays = Math.round(diffMs / (1000 * 60 * 60 * 24));

    title.textContent = totalDays + " day" + (totalDays === 1 ? "" : "s");
    text.textContent = "Your selected range runs from " + formatReadableDate(startDate) + " to " + formatReadableDate(endDate) + ".";
    startLabel.textContent = formatReadableDate(startDate);
    endLabel.textContent = formatReadableDate(endDate);
    totalLabel.textContent = totalDays + " days";
  }

  function setDefaultDates() {
    const start = new Date();
    const end = new Date();
    end.setDate(start.getDate() + 5);

    startInput.value = formatInputDate(start);
    endInput.value = formatInputDate(end);

    updateRange();
  }

  button.addEventListener("click", updateRange);
  startInput.addEventListener("change", updateRange);
  endInput.addEventListener("change", updateRange);

  setDefaultDates();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const picker = document.querySelector("[data-vb-date-sixteen]");
  if (!picker) return;

  const startInput = picker.querySelector("[data-range-start]");
  const endInput = picker.querySelector("[data-range-end]");
  const button = picker.querySelector("[data-range-update]");
  const error = picker.querySelector("[data-range-error]");

  const title = picker.querySelector("[data-range-title]");
  const text = picker.querySelector("[data-range-text]");
  const startLabel = picker.querySelector("[data-range-start-label]");
  const endLabel = picker.querySelector("[data-range-end-label]");
  const totalLabel = picker.querySelector("[data-range-total]");

  function formatInputDate(date) {
    return date.getFullYear() + "-" +
      String(date.getMonth() + 1).padStart(2, "0") + "-" +
      String(date.getDate()).padStart(2, "0");
  }

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function formatReadableDate(date) {
    return new Intl.DateTimeFormat("en", {
      month: "short",
      day: "numeric",
      year: "numeric"
    }).format(date);
  }

  function updateRange() {
    error.textContent = "";

    if (!startInput.value || !endInput.value) {
      error.textContent = "Please select both start and end dates.";
      return;
    }

    const startDate = createLocalDate(startInput.value);
    const endDate = createLocalDate(endInput.value);

    if (endDate &lt; startDate) {
      error.textContent = "End date must be after the start date.";
      title.textContent = "Invalid range";
      text.textContent = "Please choose an end date that comes after the start date.";
      startLabel.textContent = "--";
      endLabel.textContent = "--";
      totalLabel.textContent = "--";
      return;
    }

    const diffMs = endDate - startDate;
    const totalDays = Math.round(diffMs / (1000 * 60 * 60 * 24));

    title.textContent = totalDays + " day" + (totalDays === 1 ? "" : "s");
    text.textContent = "Your selected range runs from " + formatReadableDate(startDate) + " to " + formatReadableDate(endDate) + ".";
    startLabel.textContent = formatReadableDate(startDate);
    endLabel.textContent = formatReadableDate(endDate);
    totalLabel.textContent = totalDays + " days";
  }

  function setDefaultDates() {
    const start = new Date();
    const end = new Date();
    end.setDate(start.getDate() + 5);

    startInput.value = formatInputDate(start);
    endInput.value = formatInputDate(end);

    updateRange();
  }

  button.addEventListener("click", updateRange);
  startInput.addEventListener("change", updateRange);
  endInput.addEventListener("change", updateRange);

  setDefaultDates();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-sixteen-demo"&gt;
  &lt;div class="vb-date-sixteen-card" data-vb-date-sixteen&gt;
    &lt;div class="vb-date-sixteen-form"&gt;
      &lt;span class="vb-date-sixteen-kicker"&gt;Example 16&lt;/span&gt;
      &lt;h3&gt;Date Range Summary&lt;/h3&gt;
      &lt;p&gt;Select a start and end date. JavaScript validates the range and creates a readable booking-style summary.&lt;/p&gt;

      &lt;div class="vb-date-sixteen-inputs"&gt;
        &lt;label&gt;
          &lt;span&gt;Start date&lt;/span&gt;
          &lt;input type="date" data-range-start&gt;
        &lt;/label&gt;

        &lt;label&gt;
          &lt;span&gt;End date&lt;/span&gt;
          &lt;input type="date" data-range-end&gt;
        &lt;/label&gt;
      &lt;/div&gt;

      &lt;button type="button" data-range-update&gt;Update Range&lt;/button&gt;
      &lt;small data-range-error&gt;&lt;/small&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-sixteen-summary"&gt;
      &lt;div class="vb-date-sixteen-main"&gt;
        &lt;span&gt;Selected range&lt;/span&gt;
        &lt;strong data-range-title&gt;Select dates&lt;/strong&gt;
        &lt;p data-range-text&gt;Your date range summary will appear here.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-sixteen-metrics"&gt;
        &lt;div&gt;
          &lt;span&gt;Start&lt;/span&gt;
          &lt;strong data-range-start-label&gt;--&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;End&lt;/span&gt;
          &lt;strong data-range-end-label&gt;--&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Total&lt;/span&gt;
          &lt;strong data-range-total&gt;--&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-sixteen-demo,
.vb-date-sixteen-demo * {
  box-sizing: border-box;
}

.vb-date-sixteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(37, 99, 235, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #faf5ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-sixteen-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(310px, 430px);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-sixteen-form,
.vb-date-sixteen-summary {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-sixteen-form {
  display: grid;
  align-content: center;
  padding: clamp(22px, 4vw, 38px);
  background: #ffffff;
}

.vb-date-sixteen-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-sixteen-form h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-sixteen-form p {
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-sixteen-inputs {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  margin-bottom: 14px;
}

.vb-date-sixteen-inputs label {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.vb-date-sixteen-inputs span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-sixteen-inputs input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-sixteen-inputs input:focus {
  border-color: rgba(37, 99, 235, 0.78);
  box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.12);
}

.vb-date-sixteen-form button {
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.22);
}

.vb-date-sixteen-form small {
  display: block;
  min-height: 20px;
  margin-top: 10px;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 13px;
  line-height: 1.4;
  font-weight: 750;
}

.vb-date-sixteen-summary {
  display: grid;
  gap: 14px;
  padding: clamp(20px, 4vw, 32px);
  background:
    radial-gradient(circle at 12% 16%, rgba(129, 140, 248, 0.20), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #312e81 100%) !important;
}

.vb-date-sixteen-main {
  display: grid;
  gap: 9px;
  min-width: 0;
  padding: 22px;
  border-radius: 26px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-sixteen-main span,
.vb-date-sixteen-metrics span {
  color: #c4b5fd !important;
  -webkit-text-fill-color: #c4b5fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-sixteen-main strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 5vw, 52px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
  overflow-wrap: anywhere;
}

.vb-date-sixteen-main p {
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-date-sixteen-metrics {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
}

.vb-date-sixteen-metrics div {
  min-width: 0;
  padding: 14px;
  border-radius: 18px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-date-sixteen-metrics strong {
  display: block;
  margin-top: 5px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  line-height: 1.3;
  font-weight: 850;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-date-sixteen-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-sixteen-inputs {
    grid-template-columns: 1fr;
  }

  .vb-date-sixteen-form,
  .vb-date-sixteen-summary,
  .vb-date-sixteen-main {
    border-radius: 24px;
  }

  .vb-date-sixteen-form button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript date range summary example is useful for hotel bookings, rental forms, dashboard filters, analytics date ranges, reporting tools, travel planners, project timelines, and reservation interfaces.</p>



<h2 class="wp-block-heading">17. Event Schedule Timeline by Date</h2>



<p class="wp-block-paragraph"><strong>An event schedule timeline</strong> is useful for conference websites, webinar pages, course schedules, launch events, workshops, festival pages, and internal dashboards. It organizes time-based events in a clean visual timeline.</p>



<p class="wp-block-paragraph">This example uses a small JavaScript event array and renders a schedule timeline automatically. Users can filter between all events, today’s events, and upcoming events.</p>



<ul class="wp-block-list">
<li>Renders events from a JavaScript array</li>
<li>Shows event date and time</li>
<li>Includes filter buttons</li>
<li>Responsive timeline layout</li>
<li>Useful for conferences, courses, webinars, and launch pages</li>
</ul>



<div class="vb-date-seventeen-demo">
  <div class="vb-date-seventeen-shell" data-vb-date-seventeen>
    <div class="vb-date-seventeen-header">
      <span class="vb-date-seventeen-kicker">Example 17</span>
      <h3>Event Timeline</h3>
      <p>JavaScript renders a schedule timeline from event data and filters events by date status.</p>

      <div class="vb-date-seventeen-filters">
        <button type="button" data-filter="all">All</button>
        <button type="button" data-filter="today">Today</button>
        <button type="button" data-filter="upcoming">Upcoming</button>
      </div>
    </div>

    <div class="vb-date-seventeen-list" data-timeline-list></div>
  </div>
</div>

<style>
.vb-date-seventeen-demo,
.vb-date-seventeen-demo * {
  box-sizing: border-box;
}

.vb-date-seventeen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(249, 115, 22, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(236, 72, 153, 0.15), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #fdf2f8 55%, #ffffff 100%) !important;
  border: 1px solid rgba(249, 115, 22, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-seventeen-shell {
  display: grid;
  grid-template-columns: minmax(280px, 0.82fr) minmax(0, 1.18fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-seventeen-header,
.vb-date-seventeen-list {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-seventeen-header {
  display: grid;
  align-content: center;
  padding: clamp(22px, 4vw, 36px);
  background:
    radial-gradient(circle at 16% 14%, rgba(251, 146, 60, 0.18), transparent 34%),
    linear-gradient(135deg, #111827 0%, #7c2d12 100%) !important;
}

.vb-date-seventeen-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-seventeen-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 6vw, 68px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-seventeen-header p {
  margin: 0 0 22px !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-seventeen-filters {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.vb-date-seventeen-filters button {
  min-height: 42px;
  padding: 10px 14px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-date-seventeen-filters button.is-active {
  background: linear-gradient(135deg, #f97316, #db2777);
  border-color: rgba(255,255,255,0.32);
}

.vb-date-seventeen-list {
  display: grid;
  gap: 12px;
  padding: clamp(18px, 4vw, 28px);
  background: #ffffff;
}

.vb-date-seventeen-item {
  display: grid;
  grid-template-columns: 88px minmax(0, 1fr);
  gap: 14px;
  min-width: 0;
  padding: 16px;
  border-radius: 24px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-date-seventeen-date {
  display: grid;
  place-items: center;
  align-content: center;
  min-height: 86px;
  padding: 10px;
  border-radius: 20px;
  background: linear-gradient(135deg, #f97316, #db2777);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-date-seventeen-date strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 26px;
  line-height: 1;
  font-weight: 950;
}

.vb-date-seventeen-date span {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-date-seventeen-content {
  min-width: 0;
  display: grid;
  align-content: center;
  gap: 6px;
}

.vb-date-seventeen-content h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.25 !important;
  font-weight: 900 !important;
  overflow-wrap: anywhere;
}

.vb-date-seventeen-content p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-date-seventeen-content small {
  color: #ea580c !important;
  -webkit-text-fill-color: #ea580c !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-date-seventeen-empty {
  margin: 0 !important;
  padding: 20px;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px dashed rgba(148, 163, 184, 0.45);
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 15px;
  line-height: 1.55;
  font-weight: 750;
}

@media (max-width: 900px) {
  .vb-date-seventeen-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-seventeen-header,
  .vb-date-seventeen-list,
  .vb-date-seventeen-item {
    border-radius: 24px;
  }

  .vb-date-seventeen-item {
    grid-template-columns: 1fr;
  }

  .vb-date-seventeen-date {
    width: 100%;
    min-height: 70px;
  }

  .vb-date-seventeen-filters button {
    flex: 1;
  }
}
</style>

<script>
(function () {
  const timeline = document.querySelector("[data-vb-date-seventeen]");
  if (!timeline) return;

  const list = timeline.querySelector("[data-timeline-list]");
  const filters = timeline.querySelectorAll("[data-filter]");

  const today = new Date();
  today.setHours(0, 0, 0, 0);

  const events = [
    {
      title: "Opening Keynote",
      description: "A practical introduction to the event topic and main schedule.",
      offset: 0,
      time: "10:00"
    },
    {
      title: "JavaScript Workshop",
      description: "Hands-on session with date, form, and UI examples.",
      offset: 1,
      time: "13:30"
    },
    {
      title: "Client Demo Review",
      description: "Review the interface and timeline with the project team.",
      offset: 3,
      time: "15:00"
    },
    {
      title: "Final Q&A Session",
      description: "Live questions, feedback, and next steps.",
      offset: 7,
      time: "11:00"
    }
  ];

  function getEventDate(offset) {
    const date = new Date(today);
    date.setDate(today.getDate() + offset);
    return date;
  }

  function renderEvents(filter) {
    list.innerHTML = "";

    const visibleEvents = events.filter(function (event) {
      if (filter === "today") return event.offset === 0;
      if (filter === "upcoming") return event.offset > 0;
      return true;
    });

    if (visibleEvents.length === 0) {
      list.innerHTML = '<p class="vb-date-seventeen-empty">No events found for this filter.</p>';
      return;
    }

    visibleEvents.forEach(function (event) {
      const eventDate = getEventDate(event.offset);
      const day = new Intl.DateTimeFormat("en", { day: "2-digit" }).format(eventDate);
      const month = new Intl.DateTimeFormat("en", { month: "short" }).format(eventDate);

      const item = document.createElement("article");
      item.className = "vb-date-seventeen-item";

      item.innerHTML =
        '<div class="vb-date-seventeen-date">' +
          '<strong>' + day + '</strong>' +
          '<span>' + month + '</span>' +
        '</div>' +
        '<div class="vb-date-seventeen-content">' +
          '<small>' + event.time + '</small>' +
          '<h4>' + event.title + '</h4>' +
          '<p>' + event.description + '</p>' +
        '</div>';

      list.appendChild(item);
    });
  }

  filters.forEach(function (button) {
    button.addEventListener("click", function () {
      filters.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      renderEvents(button.getAttribute("data-filter"));
    });
  });

  filters[0].classList.add("is-active");
  renderEvents("all");
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timeline = document.querySelector("[data-vb-date-seventeen]");
  if (!timeline) return;

  const list = timeline.querySelector("[data-timeline-list]");
  const filters = timeline.querySelectorAll("[data-filter]");

  const today = new Date();
  today.setHours(0, 0, 0, 0);

  const events = [
    {
      title: "Opening Keynote",
      description: "A practical introduction to the event topic and main schedule.",
      offset: 0,
      time: "10:00"
    },
    {
      title: "JavaScript Workshop",
      description: "Hands-on session with date, form, and UI examples.",
      offset: 1,
      time: "13:30"
    },
    {
      title: "Client Demo Review",
      description: "Review the interface and timeline with the project team.",
      offset: 3,
      time: "15:00"
    },
    {
      title: "Final Q&A Session",
      description: "Live questions, feedback, and next steps.",
      offset: 7,
      time: "11:00"
    }
  ];

  function getEventDate(offset) {
    const date = new Date(today);
    date.setDate(today.getDate() + offset);
    return date;
  }

  function renderEvents(filter) {
    list.innerHTML = "";

    const visibleEvents = events.filter(function (event) {
      if (filter === "today") return event.offset === 0;
      if (filter === "upcoming") return event.offset &gt; 0;
      return true;
    });

    if (visibleEvents.length === 0) {
      list.innerHTML = '&lt;p class="vb-date-seventeen-empty"&gt;No events found for this filter.&lt;/p&gt;';
      return;
    }

    visibleEvents.forEach(function (event) {
      const eventDate = getEventDate(event.offset);
      const day = new Intl.DateTimeFormat("en", { day: "2-digit" }).format(eventDate);
      const month = new Intl.DateTimeFormat("en", { month: "short" }).format(eventDate);

      const item = document.createElement("article");
      item.className = "vb-date-seventeen-item";

      item.innerHTML =
        '&lt;div class="vb-date-seventeen-date"&gt;' +
          '&lt;strong&gt;' + day + '&lt;/strong&gt;' +
          '&lt;span&gt;' + month + '&lt;/span&gt;' +
        '&lt;/div&gt;' +
        '&lt;div class="vb-date-seventeen-content"&gt;' +
          '&lt;small&gt;' + event.time + '&lt;/small&gt;' +
          '&lt;h4&gt;' + event.title + '&lt;/h4&gt;' +
          '&lt;p&gt;' + event.description + '&lt;/p&gt;' +
        '&lt;/div&gt;';

      list.appendChild(item);
    });
  }

  filters.forEach(function (button) {
    button.addEventListener("click", function () {
      filters.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      renderEvents(button.getAttribute("data-filter"));
    });
  });

  filters[0].classList.add("is-active");
  renderEvents("all");
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-seventeen-demo"&gt;
  &lt;div class="vb-date-seventeen-shell" data-vb-date-seventeen&gt;
    &lt;div class="vb-date-seventeen-header"&gt;
      &lt;span class="vb-date-seventeen-kicker"&gt;Example 17&lt;/span&gt;
      &lt;h3&gt;Event Timeline&lt;/h3&gt;
      &lt;p&gt;JavaScript renders a schedule timeline from event data and filters events by date status.&lt;/p&gt;

      &lt;div class="vb-date-seventeen-filters"&gt;
        &lt;button type="button" data-filter="all"&gt;All&lt;/button&gt;
        &lt;button type="button" data-filter="today"&gt;Today&lt;/button&gt;
        &lt;button type="button" data-filter="upcoming"&gt;Upcoming&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-seventeen-list" data-timeline-list&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-seventeen-demo,
.vb-date-seventeen-demo * {
  box-sizing: border-box;
}

.vb-date-seventeen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(249, 115, 22, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(236, 72, 153, 0.15), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #fdf2f8 55%, #ffffff 100%) !important;
  border: 1px solid rgba(249, 115, 22, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-seventeen-shell {
  display: grid;
  grid-template-columns: minmax(280px, 0.82fr) minmax(0, 1.18fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-seventeen-header,
.vb-date-seventeen-list {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-seventeen-header {
  display: grid;
  align-content: center;
  padding: clamp(22px, 4vw, 36px);
  background:
    radial-gradient(circle at 16% 14%, rgba(251, 146, 60, 0.18), transparent 34%),
    linear-gradient(135deg, #111827 0%, #7c2d12 100%) !important;
}

.vb-date-seventeen-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-seventeen-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 6vw, 68px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-seventeen-header p {
  margin: 0 0 22px !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-seventeen-filters {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.vb-date-seventeen-filters button {
  min-height: 42px;
  padding: 10px 14px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-date-seventeen-filters button.is-active {
  background: linear-gradient(135deg, #f97316, #db2777);
  border-color: rgba(255,255,255,0.32);
}

.vb-date-seventeen-list {
  display: grid;
  gap: 12px;
  padding: clamp(18px, 4vw, 28px);
  background: #ffffff;
}

.vb-date-seventeen-item {
  display: grid;
  grid-template-columns: 88px minmax(0, 1fr);
  gap: 14px;
  min-width: 0;
  padding: 16px;
  border-radius: 24px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-date-seventeen-date {
  display: grid;
  place-items: center;
  align-content: center;
  min-height: 86px;
  padding: 10px;
  border-radius: 20px;
  background: linear-gradient(135deg, #f97316, #db2777);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-date-seventeen-date strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 26px;
  line-height: 1;
  font-weight: 950;
}

.vb-date-seventeen-date span {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-date-seventeen-content {
  min-width: 0;
  display: grid;
  align-content: center;
  gap: 6px;
}

.vb-date-seventeen-content h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.25 !important;
  font-weight: 900 !important;
  overflow-wrap: anywhere;
}

.vb-date-seventeen-content p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-date-seventeen-content small {
  color: #ea580c !important;
  -webkit-text-fill-color: #ea580c !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-date-seventeen-empty {
  margin: 0 !important;
  padding: 20px;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px dashed rgba(148, 163, 184, 0.45);
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 15px;
  line-height: 1.55;
  font-weight: 750;
}

@media (max-width: 900px) {
  .vb-date-seventeen-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-seventeen-header,
  .vb-date-seventeen-list,
  .vb-date-seventeen-item {
    border-radius: 24px;
  }

  .vb-date-seventeen-item {
    grid-template-columns: 1fr;
  }

  .vb-date-seventeen-date {
    width: 100%;
    min-height: 70px;
  }

  .vb-date-seventeen-filters button {
    flex: 1;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript event schedule timeline is useful for webinar pages, conference schedules, workshop pages, launch timelines, course schedules, dashboard event lists, and content planning interfaces.</p>



<h2 class="wp-block-heading">18. Time-Based Greeting Message</h2>



<p class="wp-block-paragraph"><strong>A time-based greeting message</strong> is a simple but effective JavaScript date and time feature for dashboards, hero sections, membership areas, customer portals, admin panels, and landing pages. It changes the message based on the visitor’s current time.</p>



<p class="wp-block-paragraph">This example detects morning, afternoon, evening, and night with JavaScript. It then updates the greeting text, helper message, and visual state automatically.</p>



<ul class="wp-block-list">
<li>Changes greeting based on current hour</li>
<li>Detects morning, afternoon, evening, and night</li>
<li>Updates message and visual status</li>
<li>Responsive hero-style card</li>
<li>Useful for dashboards, portals, admin panels, and landing pages</li>
</ul>



<div class="vb-date-eighteen-demo">
  <div class="vb-date-eighteen-card" data-vb-date-eighteen>
    <div class="vb-date-eighteen-glow"></div>

    <div class="vb-date-eighteen-content">
      <span class="vb-date-eighteen-kicker">Example 18</span>
      <h3 data-greeting-title>Loading greeting...</h3>
      <p data-greeting-message>JavaScript is checking the current time.</p>

      <div class="vb-date-eighteen-time">
        <span>Current local time</span>
        <strong data-greeting-time>--:--</strong>
      </div>
    </div>

    <div class="vb-date-eighteen-status">
      <span data-greeting-period>Time period</span>
      <strong data-greeting-icon>●</strong>
    </div>
  </div>
</div>

<style>
.vb-date-eighteen-demo,
.vb-date-eighteen-demo * {
  box-sizing: border-box;
}

.vb-date-eighteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(14, 165, 233, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(245, 158, 11, 0.16), transparent 34%),
    linear-gradient(135deg, #ecfeff 0%, #fffbeb 55%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-eighteen-card {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(180px, 260px);
  gap: 18px;
  max-width: 1060px;
  margin: 0 auto;
  overflow: hidden;
  padding: clamp(24px, 5vw, 48px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 16% 14%, rgba(34, 211, 238, 0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #1e3a8a 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
}

.vb-date-eighteen-glow {
  position: absolute;
  right: -90px;
  top: -90px;
  width: 280px;
  height: 280px;
  border-radius: 999px;
  background: rgba(34, 211, 238, 0.22);
  filter: blur(8px);
  pointer-events: none;
}

.vb-date-eighteen-card.is-morning {
  background:
    radial-gradient(circle at 16% 14%, rgba(253, 186, 116, 0.24), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #7c2d12 100%) !important;
}

.vb-date-eighteen-card.is-afternoon {
  background:
    radial-gradient(circle at 16% 14%, rgba(96, 165, 250, 0.24), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #1e40af 100%) !important;
}

.vb-date-eighteen-card.is-evening {
  background:
    radial-gradient(circle at 16% 14%, rgba(168, 85, 247, 0.24), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #581c87 100%) !important;
}

.vb-date-eighteen-card.is-night {
  background:
    radial-gradient(circle at 16% 14%, rgba(148, 163, 184, 0.20), transparent 34%),
    linear-gradient(135deg, #020617 0%, #111827 100%) !important;
}

.vb-date-eighteen-content {
  position: relative;
  z-index: 2;
  min-width: 0;
}

.vb-date-eighteen-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-eighteen-content h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 7vw, 78px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-date-eighteen-content p {
  max-width: 660px;
  margin: 0 0 24px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-eighteen-time {
  display: inline-grid;
  gap: 7px;
  min-width: min(100%, 260px);
  padding: 16px 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-eighteen-time span {
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-date-eighteen-time strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 28px;
  line-height: 1;
  font-weight: 950;
  font-variant-numeric: tabular-nums;
}

.vb-date-eighteen-status {
  position: relative;
  z-index: 2;
  align-self: stretch;
  display: grid;
  place-items: center;
  align-content: center;
  gap: 14px;
  min-width: 0;
  padding: 20px;
  border-radius: 28px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-eighteen-status span {
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 13px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.10em;
  text-align: center;
}

.vb-date-eighteen-status strong {
  display: grid;
  place-items: center;
  width: 88px;
  height: 88px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22d3ee, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 36px;
  line-height: 1;
  font-weight: 950;
  box-shadow: 0 18px 42px rgba(37, 99, 235, 0.30);
}

@media (max-width: 820px) {
  .vb-date-eighteen-card {
    grid-template-columns: 1fr;
  }

  .vb-date-eighteen-status {
    min-height: 160px;
  }
}

@media (max-width: 520px) {
  .vb-date-eighteen-card,
  .vb-date-eighteen-status {
    border-radius: 24px;
  }

  .vb-date-eighteen-time {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const greeting = document.querySelector("[data-vb-date-eighteen]");
  if (!greeting) return;

  const title = greeting.querySelector("[data-greeting-title]");
  const message = greeting.querySelector("[data-greeting-message]");
  const time = greeting.querySelector("[data-greeting-time]");
  const period = greeting.querySelector("[data-greeting-period]");
  const icon = greeting.querySelector("[data-greeting-icon]");

  function updateGreeting() {
    const now = new Date();
    const hour = now.getHours();

    greeting.classList.remove("is-morning", "is-afternoon", "is-evening", "is-night");

    time.textContent = new Intl.DateTimeFormat("en", {
      hour: "2-digit",
      minute: "2-digit"
    }).format(now);

    if (hour >= 5 && hour < 12) {
      greeting.classList.add("is-morning");
      title.textContent = "Good morning";
      message.textContent = "Start the day with a clear schedule, fresh tasks, and updated website data.";
      period.textContent = "Morning";
      icon.textContent = "☀";
      return;
    }

    if (hour >= 12 && hour < 17) {
      greeting.classList.add("is-afternoon");
      title.textContent = "Good afternoon";
      message.textContent = "A smart dashboard can show time-based messages, tasks, reminders, and useful user context.";
      period.textContent = "Afternoon";
      icon.textContent = "●";
      return;
    }

    if (hour >= 17 && hour < 22) {
      greeting.classList.add("is-evening");
      title.textContent = "Good evening";
      message.textContent = "Use JavaScript time checks to personalize landing pages, portals, and customer dashboards.";
      period.textContent = "Evening";
      icon.textContent = "◐";
      return;
    }

    greeting.classList.add("is-night");
    title.textContent = "Good night";
    message.textContent = "Night mode messages can help dashboards feel more personal and context-aware.";
    period.textContent = "Night";
    icon.textContent = "☾";
  }

  updateGreeting();
  setInterval(updateGreeting, 60000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const greeting = document.querySelector("[data-vb-date-eighteen]");
  if (!greeting) return;

  const title = greeting.querySelector("[data-greeting-title]");
  const message = greeting.querySelector("[data-greeting-message]");
  const time = greeting.querySelector("[data-greeting-time]");
  const period = greeting.querySelector("[data-greeting-period]");
  const icon = greeting.querySelector("[data-greeting-icon]");

  function updateGreeting() {
    const now = new Date();
    const hour = now.getHours();

    greeting.classList.remove("is-morning", "is-afternoon", "is-evening", "is-night");

    time.textContent = new Intl.DateTimeFormat("en", {
      hour: "2-digit",
      minute: "2-digit"
    }).format(now);

    if (hour &gt;= 5 && hour &lt; 12) {
      greeting.classList.add("is-morning");
      title.textContent = "Good morning";
      message.textContent = "Start the day with a clear schedule, fresh tasks, and updated website data.";
      period.textContent = "Morning";
      icon.textContent = "☀";
      return;
    }

    if (hour &gt;= 12 && hour &lt; 17) {
      greeting.classList.add("is-afternoon");
      title.textContent = "Good afternoon";
      message.textContent = "A smart dashboard can show time-based messages, tasks, reminders, and useful user context.";
      period.textContent = "Afternoon";
      icon.textContent = "●";
      return;
    }

    if (hour &gt;= 17 && hour &lt; 22) {
      greeting.classList.add("is-evening");
      title.textContent = "Good evening";
      message.textContent = "Use JavaScript time checks to personalize landing pages, portals, and customer dashboards.";
      period.textContent = "Evening";
      icon.textContent = "◐";
      return;
    }

    greeting.classList.add("is-night");
    title.textContent = "Good night";
    message.textContent = "Night mode messages can help dashboards feel more personal and context-aware.";
    period.textContent = "Night";
    icon.textContent = "☾";
  }

  updateGreeting();
  setInterval(updateGreeting, 60000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-eighteen-demo"&gt;
  &lt;div class="vb-date-eighteen-card" data-vb-date-eighteen&gt;
    &lt;div class="vb-date-eighteen-glow"&gt;&lt;/div&gt;

    &lt;div class="vb-date-eighteen-content"&gt;
      &lt;span class="vb-date-eighteen-kicker"&gt;Example 18&lt;/span&gt;
      &lt;h3 data-greeting-title&gt;Loading greeting...&lt;/h3&gt;
      &lt;p data-greeting-message&gt;JavaScript is checking the current time.&lt;/p&gt;

      &lt;div class="vb-date-eighteen-time"&gt;
        &lt;span&gt;Current local time&lt;/span&gt;
        &lt;strong data-greeting-time&gt;--:--&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-eighteen-status"&gt;
      &lt;span data-greeting-period&gt;Time period&lt;/span&gt;
      &lt;strong data-greeting-icon&gt;●&lt;/strong&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-eighteen-demo,
.vb-date-eighteen-demo * {
  box-sizing: border-box;
}

.vb-date-eighteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(14, 165, 233, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(245, 158, 11, 0.16), transparent 34%),
    linear-gradient(135deg, #ecfeff 0%, #fffbeb 55%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-eighteen-card {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(180px, 260px);
  gap: 18px;
  max-width: 1060px;
  margin: 0 auto;
  overflow: hidden;
  padding: clamp(24px, 5vw, 48px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 16% 14%, rgba(34, 211, 238, 0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #1e3a8a 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
}

.vb-date-eighteen-glow {
  position: absolute;
  right: -90px;
  top: -90px;
  width: 280px;
  height: 280px;
  border-radius: 999px;
  background: rgba(34, 211, 238, 0.22);
  filter: blur(8px);
  pointer-events: none;
}

.vb-date-eighteen-card.is-morning {
  background:
    radial-gradient(circle at 16% 14%, rgba(253, 186, 116, 0.24), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #7c2d12 100%) !important;
}

.vb-date-eighteen-card.is-afternoon {
  background:
    radial-gradient(circle at 16% 14%, rgba(96, 165, 250, 0.24), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #1e40af 100%) !important;
}

.vb-date-eighteen-card.is-evening {
  background:
    radial-gradient(circle at 16% 14%, rgba(168, 85, 247, 0.24), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #581c87 100%) !important;
}

.vb-date-eighteen-card.is-night {
  background:
    radial-gradient(circle at 16% 14%, rgba(148, 163, 184, 0.20), transparent 34%),
    linear-gradient(135deg, #020617 0%, #111827 100%) !important;
}

.vb-date-eighteen-content {
  position: relative;
  z-index: 2;
  min-width: 0;
}

.vb-date-eighteen-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-eighteen-content h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 7vw, 78px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-date-eighteen-content p {
  max-width: 660px;
  margin: 0 0 24px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-eighteen-time {
  display: inline-grid;
  gap: 7px;
  min-width: min(100%, 260px);
  padding: 16px 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-eighteen-time span {
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-date-eighteen-time strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 28px;
  line-height: 1;
  font-weight: 950;
  font-variant-numeric: tabular-nums;
}

.vb-date-eighteen-status {
  position: relative;
  z-index: 2;
  align-self: stretch;
  display: grid;
  place-items: center;
  align-content: center;
  gap: 14px;
  min-width: 0;
  padding: 20px;
  border-radius: 28px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-eighteen-status span {
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 13px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.10em;
  text-align: center;
}

.vb-date-eighteen-status strong {
  display: grid;
  place-items: center;
  width: 88px;
  height: 88px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22d3ee, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 36px;
  line-height: 1;
  font-weight: 950;
  box-shadow: 0 18px 42px rgba(37, 99, 235, 0.30);
}

@media (max-width: 820px) {
  .vb-date-eighteen-card {
    grid-template-columns: 1fr;
  }

  .vb-date-eighteen-status {
    min-height: 160px;
  }
}

@media (max-width: 520px) {
  .vb-date-eighteen-card,
  .vb-date-eighteen-status {
    border-radius: 24px;
  }

  .vb-date-eighteen-time {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript time-based greeting example is useful for dashboards, user portals, SaaS apps, admin panels, homepage hero sections, membership websites, and personalized landing pages.</p>



<div class="vb24-js-date-mini-cta">
  <p>Need a custom JavaScript date, calendar, booking, or calculator feature for your website?</p>
  <a href="https://veebilehed24.ee/en/contact/">Contact us</a>
</div>

<style>
.vb24-js-date-mini-cta,
.vb24-js-date-mini-cta * {
  box-sizing: border-box;
}

.vb24-js-date-mini-cta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin: 40px 0;
  padding: 18px 20px;
  border: 1px solid rgba(148, 163, 184, 0.24);
  border-radius: 20px;
  background: #f8fafc;
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.06);
}

.vb24-js-date-mini-cta p {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  line-height: 1.55;
  font-weight: 750;
}

.vb24-js-date-mini-cta a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 42px;
  padding: 10px 16px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
  white-space: nowrap;
}

.vb24-js-date-mini-cta a:hover {
  background: #2563eb;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

@media (max-width: 640px) {
  .vb24-js-date-mini-cta {
    align-items: stretch;
    flex-direction: column;
    border-radius: 18px;
  }

  .vb24-js-date-mini-cta a {
    width: 100%;
  }
}
</style>



<h2 class="wp-block-heading">19. Auto-Renewing Daily Deal Countdown</h2>



<p class="wp-block-paragraph"><strong>An auto-renewing daily deal countdown</strong> is useful for ecommerce stores, landing pages, promo banners, SaaS offers, course pages, and campaign sections. Unlike a fixed countdown, this timer never permanently ends because it automatically resets for the next day.</p>



<p class="wp-block-paragraph">This example counts down to midnight. When the day ends, JavaScript automatically starts the next daily cycle, updates the date label, and keeps the countdown running forever without needing a manual date change.</p>



<ul class="wp-block-list">
<li>Counts down to the next midnight</li>
<li>Automatically renews every day</li>
<li>Never ends permanently</li>
<li>Shows hours, minutes, and seconds</li>
<li>Useful for daily deals, banners, ecommerce offers, and landing pages</li>
</ul>



<div class="vb-date-nineteen-demo">
  <div class="vb-date-nineteen-card" data-vb-date-nineteen>
    <div class="vb-date-nineteen-left">
      <span class="vb-date-nineteen-kicker">Example 19</span>
      <h3>Daily Deal Countdown</h3>
      <p>This countdown automatically resets every day at midnight, so the example keeps working forever.</p>

      <div class="vb-date-nineteen-label">
        <span>Current deal cycle</span>
        <strong data-cycle-label>Loading...</strong>
      </div>
    </div>

    <div class="vb-date-nineteen-timer">
      <div>
        <strong data-hours>00</strong>
        <span>Hours</span>
      </div>
      <div>
        <strong data-minutes>00</strong>
        <span>Minutes</span>
      </div>
      <div>
        <strong data-seconds>00</strong>
        <span>Seconds</span>
      </div>
    </div>
  </div>
</div>

<style>
.vb-date-nineteen-demo,
.vb-date-nineteen-demo * {
  box-sizing: border-box;
}

.vb-date-nineteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 14% 16%, rgba(248, 113, 113, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(245, 158, 11, 0.18), transparent 34%),
    linear-gradient(135deg, #fef2f2 0%, #fffbeb 55%, #ffffff 100%) !important;
  border: 1px solid rgba(248, 113, 113, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-nineteen-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(320px, 480px);
  gap: 22px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(22px, 5vw, 44px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(251, 146, 60, 0.22), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(239, 68, 68, 0.22), transparent 34%),
    linear-gradient(135deg, #111827 0%, #7f1d1d 58%, #9a3412 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 30px 90px rgba(127, 29, 29, 0.28);
  overflow: hidden;
}

.vb-date-nineteen-left {
  display: grid;
  align-content: center;
  min-width: 0;
}

.vb-date-nineteen-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-nineteen-left h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 7vw, 76px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-date-nineteen-left p {
  max-width: 620px;
  margin: 0 0 22px !important;
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-nineteen-label {
  display: inline-grid;
  gap: 7px;
  max-width: 100%;
  padding: 16px 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-nineteen-label span {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.10em;
}

.vb-date-nineteen-label strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 900;
  overflow-wrap: anywhere;
}

.vb-date-nineteen-timer {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  min-width: 0;
  align-content: center;
}

.vb-date-nineteen-timer div {
  display: grid;
  place-items: center;
  gap: 9px;
  min-width: 0;
  min-height: 170px;
  padding: 18px 12px;
  border-radius: 26px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.16);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.10);
}

.vb-date-nineteen-timer strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(40px, 7vw, 70px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.065em;
  font-variant-numeric: tabular-nums;
}

.vb-date-nineteen-timer span {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.10em;
}

@media (max-width: 920px) {
  .vb-date-nineteen-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-nineteen-card,
  .vb-date-nineteen-timer div {
    border-radius: 24px;
  }

  .vb-date-nineteen-timer {
    grid-template-columns: 1fr;
  }

  .vb-date-nineteen-timer div {
    min-height: 110px;
  }
}
</style>

<script>
(function () {
  const countdown = document.querySelector("[data-vb-date-nineteen]");
  if (!countdown) return;

  const hoursElement = countdown.querySelector("[data-hours]");
  const minutesElement = countdown.querySelector("[data-minutes]");
  const secondsElement = countdown.querySelector("[data-seconds]");
  const cycleLabel = countdown.querySelector("[data-cycle-label]");

  function pad(value) {
    return String(value).padStart(2, "0");
  }

  function getNextMidnight(now) {
    const midnight = new Date(now);
    midnight.setDate(now.getDate() + 1);
    midnight.setHours(0, 0, 0, 0);
    return midnight;
  }

  function updateCountdown() {
    const now = new Date();
    const nextMidnight = getNextMidnight(now);
    const remaining = nextMidnight - now;

    const totalSeconds = Math.max(0, Math.floor(remaining / 1000));
    const hours = Math.floor(totalSeconds / 3600);
    const minutes = Math.floor((totalSeconds % 3600) / 60);
    const seconds = totalSeconds % 60;

    hoursElement.textContent = pad(hours);
    minutesElement.textContent = pad(minutes);
    secondsElement.textContent = pad(seconds);

    cycleLabel.textContent = "Ends today, renews tomorrow automatically";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const countdown = document.querySelector("[data-vb-date-nineteen]");
  if (!countdown) return;

  const hoursElement = countdown.querySelector("[data-hours]");
  const minutesElement = countdown.querySelector("[data-minutes]");
  const secondsElement = countdown.querySelector("[data-seconds]");
  const cycleLabel = countdown.querySelector("[data-cycle-label]");

  function pad(value) {
    return String(value).padStart(2, "0");
  }

  function getNextMidnight(now) {
    const midnight = new Date(now);
    midnight.setDate(now.getDate() + 1);
    midnight.setHours(0, 0, 0, 0);
    return midnight;
  }

  function updateCountdown() {
    const now = new Date();
    const nextMidnight = getNextMidnight(now);
    const remaining = nextMidnight - now;

    const totalSeconds = Math.max(0, Math.floor(remaining / 1000));
    const hours = Math.floor(totalSeconds / 3600);
    const minutes = Math.floor((totalSeconds % 3600) / 60);
    const seconds = totalSeconds % 60;

    hoursElement.textContent = pad(hours);
    minutesElement.textContent = pad(minutes);
    secondsElement.textContent = pad(seconds);

    cycleLabel.textContent = "Ends today, renews tomorrow automatically";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-nineteen-demo"&gt;
  &lt;div class="vb-date-nineteen-card" data-vb-date-nineteen&gt;
    &lt;div class="vb-date-nineteen-left"&gt;
      &lt;span class="vb-date-nineteen-kicker"&gt;Example 19&lt;/span&gt;
      &lt;h3&gt;Daily Deal Countdown&lt;/h3&gt;
      &lt;p&gt;This countdown automatically resets every day at midnight, so the example keeps working forever.&lt;/p&gt;

      &lt;div class="vb-date-nineteen-label"&gt;
        &lt;span&gt;Current deal cycle&lt;/span&gt;
        &lt;strong data-cycle-label&gt;Loading...&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-nineteen-timer"&gt;
      &lt;div&gt;
        &lt;strong data-hours&gt;00&lt;/strong&gt;
        &lt;span&gt;Hours&lt;/span&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;strong data-minutes&gt;00&lt;/strong&gt;
        &lt;span&gt;Minutes&lt;/span&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;strong data-seconds&gt;00&lt;/strong&gt;
        &lt;span&gt;Seconds&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-nineteen-demo,
.vb-date-nineteen-demo * {
  box-sizing: border-box;
}

.vb-date-nineteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 14% 16%, rgba(248, 113, 113, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(245, 158, 11, 0.18), transparent 34%),
    linear-gradient(135deg, #fef2f2 0%, #fffbeb 55%, #ffffff 100%) !important;
  border: 1px solid rgba(248, 113, 113, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-nineteen-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(320px, 480px);
  gap: 22px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(22px, 5vw, 44px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(251, 146, 60, 0.22), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(239, 68, 68, 0.22), transparent 34%),
    linear-gradient(135deg, #111827 0%, #7f1d1d 58%, #9a3412 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 30px 90px rgba(127, 29, 29, 0.28);
  overflow: hidden;
}

.vb-date-nineteen-left {
  display: grid;
  align-content: center;
  min-width: 0;
}

.vb-date-nineteen-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-nineteen-left h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 7vw, 76px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-date-nineteen-left p {
  max-width: 620px;
  margin: 0 0 22px !important;
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-nineteen-label {
  display: inline-grid;
  gap: 7px;
  max-width: 100%;
  padding: 16px 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-nineteen-label span {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.10em;
}

.vb-date-nineteen-label strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 900;
  overflow-wrap: anywhere;
}

.vb-date-nineteen-timer {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  min-width: 0;
  align-content: center;
}

.vb-date-nineteen-timer div {
  display: grid;
  place-items: center;
  gap: 9px;
  min-width: 0;
  min-height: 170px;
  padding: 18px 12px;
  border-radius: 26px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.16);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.10);
}

.vb-date-nineteen-timer strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(40px, 7vw, 70px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.065em;
  font-variant-numeric: tabular-nums;
}

.vb-date-nineteen-timer span {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.10em;
}

@media (max-width: 920px) {
  .vb-date-nineteen-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-nineteen-card,
  .vb-date-nineteen-timer div {
    border-radius: 24px;
  }

  .vb-date-nineteen-timer {
    grid-template-columns: 1fr;
  }

  .vb-date-nineteen-timer div {
    min-height: 110px;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript daily deal countdown is useful for ecommerce banners, promo sections, landing pages, SaaS offers, daily campaigns, course promotions, and any timer that should automatically renew instead of permanently ending.</p>



<h2 class="wp-block-heading">20. Auto-Rolling Weekly Event Countdown</h2>



<p class="wp-block-paragraph"><strong>An auto-rolling weekly event countdown</strong> is useful for recurring webinars, weekly meetings, live streams, online classes, community events, and support sessions. It does not use a fixed one-time deadline, so it keeps working week after week.</p>



<p class="wp-block-paragraph">This example counts down to the next Monday at 10:00. After that time passes, JavaScript automatically targets the following Monday, keeping the countdown active forever.</p>



<ul class="wp-block-list">
<li>Counts down to the next weekly event</li>
<li>Automatically rolls to the following week</li>
<li>Never permanently expires</li>
<li>Shows days, hours, minutes, and seconds</li>
<li>Useful for recurring webinars, classes, streams, and meetings</li>
</ul>



<div class="vb-date-twenty-demo">
  <div class="vb-date-twenty-card" data-vb-date-twenty>
    <div class="vb-date-twenty-header">
      <span class="vb-date-twenty-kicker">Example 20</span>
      <h3>Weekly Event Countdown</h3>
      <p>This countdown always targets the next Monday event and automatically rolls forward every week.</p>
    </div>

    <div class="vb-date-twenty-next">
      <span>Next session</span>
      <strong data-next-session>Loading...</strong>
    </div>

    <div class="vb-date-twenty-grid">
      <div>
        <strong data-days>00</strong>
        <span>Days</span>
      </div>
      <div>
        <strong data-hours>00</strong>
        <span>Hours</span>
      </div>
      <div>
        <strong data-minutes>00</strong>
        <span>Minutes</span>
      </div>
      <div>
        <strong data-seconds>00</strong>
        <span>Seconds</span>
      </div>
    </div>
  </div>
</div>

<style>
.vb-date-twenty-demo,
.vb-date-twenty-demo * {
  box-sizing: border-box;
}

.vb-date-twenty-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 14% 16%, rgba(37, 99, 235, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfeff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-twenty-card {
  max-width: 1080px;
  margin: 0 auto;
  padding: clamp(22px, 5vw, 44px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 16%, rgba(56, 189, 248, 0.20), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #1e3a8a 58%, #164e63 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
  overflow: hidden;
}

.vb-date-twenty-header {
  max-width: 760px;
  margin-bottom: 20px;
}

.vb-date-twenty-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-twenty-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 7vw, 76px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-date-twenty-header p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-twenty-next {
  display: grid;
  gap: 7px;
  margin-bottom: 16px;
  padding: 18px;
  border-radius: 24px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-twenty-next span {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-twenty-next strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(22px, 4vw, 36px);
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.04em;
  overflow-wrap: anywhere;
}

.vb-date-twenty-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
}

.vb-date-twenty-grid div {
  display: grid;
  place-items: center;
  gap: 9px;
  min-width: 0;
  min-height: 155px;
  padding: 18px 10px;
  border-radius: 24px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.15);
}

.vb-date-twenty-grid strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 6vw, 64px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.06em;
  font-variant-numeric: tabular-nums;
}

.vb-date-twenty-grid span {
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

@media (max-width: 760px) {
  .vb-date-twenty-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-date-twenty-grid div {
    min-height: 130px;
  }
}

@media (max-width: 460px) {
  .vb-date-twenty-card,
  .vb-date-twenty-grid div {
    border-radius: 24px;
  }

  .vb-date-twenty-grid {
    grid-template-columns: 1fr;
  }

  .vb-date-twenty-grid div {
    min-height: 105px;
  }
}
</style>

<script>
(function () {
  const countdown = document.querySelector("[data-vb-date-twenty]");
  if (!countdown) return;

  const nextSession = countdown.querySelector("[data-next-session]");
  const daysElement = countdown.querySelector("[data-days]");
  const hoursElement = countdown.querySelector("[data-hours]");
  const minutesElement = countdown.querySelector("[data-minutes]");
  const secondsElement = countdown.querySelector("[data-seconds]");

  const targetWeekday = 1;
  const targetHour = 10;

  function pad(value) {
    return String(value).padStart(2, "0");
  }

  function getNextWeeklyEvent(now) {
    const target = new Date(now);
    target.setHours(targetHour, 0, 0, 0);

    const currentDay = now.getDay();
    let daysUntilTarget = (targetWeekday - currentDay + 7) % 7;

    if (daysUntilTarget === 0 && target <= now) {
      daysUntilTarget = 7;
    }

    target.setDate(now.getDate() + daysUntilTarget);
    return target;
  }

  function updateCountdown() {
    const now = new Date();
    const target = getNextWeeklyEvent(now);
    const distance = target - now;

    const totalSeconds = Math.max(0, Math.floor(distance / 1000));
    const days = Math.floor(totalSeconds / 86400);
    const hours = Math.floor((totalSeconds % 86400) / 3600);
    const minutes = Math.floor((totalSeconds % 3600) / 60);
    const seconds = totalSeconds % 60;

    daysElement.textContent = pad(days);
    hoursElement.textContent = pad(hours);
    minutesElement.textContent = pad(minutes);
    secondsElement.textContent = pad(seconds);

    nextSession.textContent = new Intl.DateTimeFormat("en", {
      weekday: "long",
      month: "long",
      day: "numeric",
      hour: "2-digit",
      minute: "2-digit"
    }).format(target);
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const countdown = document.querySelector("[data-vb-date-twenty]");
  if (!countdown) return;

  const nextSession = countdown.querySelector("[data-next-session]");
  const daysElement = countdown.querySelector("[data-days]");
  const hoursElement = countdown.querySelector("[data-hours]");
  const minutesElement = countdown.querySelector("[data-minutes]");
  const secondsElement = countdown.querySelector("[data-seconds]");

  const targetWeekday = 1;
  const targetHour = 10;

  function pad(value) {
    return String(value).padStart(2, "0");
  }

  function getNextWeeklyEvent(now) {
    const target = new Date(now);
    target.setHours(targetHour, 0, 0, 0);

    const currentDay = now.getDay();
    let daysUntilTarget = (targetWeekday - currentDay + 7) % 7;

    if (daysUntilTarget === 0 && target &lt;= now) {
      daysUntilTarget = 7;
    }

    target.setDate(now.getDate() + daysUntilTarget);
    return target;
  }

  function updateCountdown() {
    const now = new Date();
    const target = getNextWeeklyEvent(now);
    const distance = target - now;

    const totalSeconds = Math.max(0, Math.floor(distance / 1000));
    const days = Math.floor(totalSeconds / 86400);
    const hours = Math.floor((totalSeconds % 86400) / 3600);
    const minutes = Math.floor((totalSeconds % 3600) / 60);
    const seconds = totalSeconds % 60;

    daysElement.textContent = pad(days);
    hoursElement.textContent = pad(hours);
    minutesElement.textContent = pad(minutes);
    secondsElement.textContent = pad(seconds);

    nextSession.textContent = new Intl.DateTimeFormat("en", {
      weekday: "long",
      month: "long",
      day: "numeric",
      hour: "2-digit",
      minute: "2-digit"
    }).format(target);
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-twenty-demo"&gt;
  &lt;div class="vb-date-twenty-card" data-vb-date-twenty&gt;
    &lt;div class="vb-date-twenty-header"&gt;
      &lt;span class="vb-date-twenty-kicker"&gt;Example 20&lt;/span&gt;
      &lt;h3&gt;Weekly Event Countdown&lt;/h3&gt;
      &lt;p&gt;This countdown always targets the next Monday event and automatically rolls forward every week.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-twenty-next"&gt;
      &lt;span&gt;Next session&lt;/span&gt;
      &lt;strong data-next-session&gt;Loading...&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-twenty-grid"&gt;
      &lt;div&gt;
        &lt;strong data-days&gt;00&lt;/strong&gt;
        &lt;span&gt;Days&lt;/span&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;strong data-hours&gt;00&lt;/strong&gt;
        &lt;span&gt;Hours&lt;/span&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;strong data-minutes&gt;00&lt;/strong&gt;
        &lt;span&gt;Minutes&lt;/span&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;strong data-seconds&gt;00&lt;/strong&gt;
        &lt;span&gt;Seconds&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-twenty-demo,
.vb-date-twenty-demo * {
  box-sizing: border-box;
}

.vb-date-twenty-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 14% 16%, rgba(37, 99, 235, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfeff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-twenty-card {
  max-width: 1080px;
  margin: 0 auto;
  padding: clamp(22px, 5vw, 44px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 16%, rgba(56, 189, 248, 0.20), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #1e3a8a 58%, #164e63 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
  overflow: hidden;
}

.vb-date-twenty-header {
  max-width: 760px;
  margin-bottom: 20px;
}

.vb-date-twenty-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-twenty-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 7vw, 76px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-date-twenty-header p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-twenty-next {
  display: grid;
  gap: 7px;
  margin-bottom: 16px;
  padding: 18px;
  border-radius: 24px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-twenty-next span {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-twenty-next strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(22px, 4vw, 36px);
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.04em;
  overflow-wrap: anywhere;
}

.vb-date-twenty-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
}

.vb-date-twenty-grid div {
  display: grid;
  place-items: center;
  gap: 9px;
  min-width: 0;
  min-height: 155px;
  padding: 18px 10px;
  border-radius: 24px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.15);
}

.vb-date-twenty-grid strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 6vw, 64px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.06em;
  font-variant-numeric: tabular-nums;
}

.vb-date-twenty-grid span {
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

@media (max-width: 760px) {
  .vb-date-twenty-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-date-twenty-grid div {
    min-height: 130px;
  }
}

@media (max-width: 460px) {
  .vb-date-twenty-card,
  .vb-date-twenty-grid div {
    border-radius: 24px;
  }

  .vb-date-twenty-grid {
    grid-template-columns: 1fr;
  }

  .vb-date-twenty-grid div {
    min-height: 105px;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript weekly countdown is useful for recurring webinars, weekly live streams, online classes, community events, support sessions, coaching calls, and recurring appointment pages.</p>



<h2 class="wp-block-heading">21. Infinite Rotating Date Quote Widget</h2>



<p class="wp-block-paragraph"><strong>An infinite rotating date quote widget</strong> is a simple JavaScript time-based component that keeps changing content forever. It is useful for dashboards, homepages, blog sidebars, daily motivation sections, learning platforms, and member portals.</p>



<p class="wp-block-paragraph">This example selects a quote based on the current day number. Because the calculation uses the current date dynamically, the widget keeps rotating through the list forever without needing fixed dates.</p>



<ul class="wp-block-list">
<li>Changes quote based on the current date</li>
<li>Cycles forever through a JavaScript array</li>
<li>Uses dynamic day calculation</li>
<li>Shows current date label</li>
<li>Useful for dashboards, homepages, portals, and content widgets</li>
</ul>



<div class="vb-date-twentyone-demo">
  <div class="vb-date-twentyone-card" data-vb-date-twentyone>
    <div class="vb-date-twentyone-date">
      <span>Today</span>
      <strong data-date-label>Loading date...</strong>
    </div>

    <div class="vb-date-twentyone-content">
      <span class="vb-date-twentyone-kicker">Example 21</span>
      <h3>Daily Rotating Quote</h3>
      <blockquote data-daily-quote>Loading quote...</blockquote>
      <p data-daily-note>This widget changes automatically based on the current date and keeps cycling forever.</p>
    </div>
  </div>
</div>

<style>
.vb-date-twentyone-demo,
.vb-date-twentyone-demo * {
  box-sizing: border-box;
}

.vb-date-twentyone-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 14% 16%, rgba(168, 85, 247, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(34, 211, 238, 0.16), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #ecfeff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-twentyone-card {
  display: grid;
  grid-template-columns: minmax(240px, 320px) minmax(0, 1fr);
  gap: 20px;
  max-width: 1060px;
  margin: 0 auto;
  padding: clamp(22px, 5vw, 44px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 16%, rgba(168, 85, 247, 0.20), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(34, 211, 238, 0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #312e81 58%, #164e63 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
  overflow: hidden;
}

.vb-date-twentyone-date {
  display: grid;
  align-content: center;
  gap: 10px;
  min-width: 0;
  padding: 22px;
  border-radius: 28px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-twentyone-date span {
  color: #c4b5fd !important;
  -webkit-text-fill-color: #c4b5fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-twentyone-date strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 5vw, 48px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
  overflow-wrap: anywhere;
}

.vb-date-twentyone-content {
  display: grid;
  align-content: center;
  min-width: 0;
}

.vb-date-twentyone-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-twentyone-content h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-twentyone-content blockquote {
  max-width: 720px;
  margin: 0 0 18px !important;
  padding: 0;
  border: 0;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(24px, 4vw, 42px);
  line-height: 1.12;
  font-weight: 850;
  letter-spacing: -0.045em;
  overflow-wrap: anywhere;
}

.vb-date-twentyone-content p {
  max-width: 680px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

@media (max-width: 820px) {
  .vb-date-twentyone-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 520px) {
  .vb-date-twentyone-card,
  .vb-date-twentyone-date {
    border-radius: 24px;
  }
}
</style>

<script>
(function () {
  const widget = document.querySelector("[data-vb-date-twentyone]");
  if (!widget) return;

  const dateLabel = widget.querySelector("[data-date-label]");
  const quote = widget.querySelector("[data-daily-quote]");
  const note = widget.querySelector("[data-daily-note]");

  const quotes = [
    "Small improvements become powerful systems when they repeat every day.",
    "A useful website remembers context, time, and user intent.",
    "Good JavaScript turns static pages into practical tools.",
    "Responsive details matter because real users visit from every screen size.",
    "The best interface is clear, fast, and helpful at the right moment.",
    "Automation is most valuable when it keeps working without manual updates.",
    "A simple time-based feature can make a website feel much smarter."
  ];

  function getDayNumber(date) {
    const start = new Date(date.getFullYear(), 0, 0);
    const difference = date - start;
    return Math.floor(difference / (1000 * 60 * 60 * 24));
  }

  function updateDailyQuote() {
    const now = new Date();
    const dayNumber = getDayNumber(now);
    const quoteIndex = dayNumber % quotes.length;

    dateLabel.textContent = new Intl.DateTimeFormat("en", {
      weekday: "long",
      month: "long",
      day: "numeric"
    }).format(now);

    quote.textContent = quotes[quoteIndex];
    note.textContent = "Quote " + (quoteIndex + 1) + " of " + quotes.length + " is selected automatically from the current date.";
  }

  updateDailyQuote();
  setInterval(updateDailyQuote, 60000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const widget = document.querySelector("[data-vb-date-twentyone]");
  if (!widget) return;

  const dateLabel = widget.querySelector("[data-date-label]");
  const quote = widget.querySelector("[data-daily-quote]");
  const note = widget.querySelector("[data-daily-note]");

  const quotes = [
    "Small improvements become powerful systems when they repeat every day.",
    "A useful website remembers context, time, and user intent.",
    "Good JavaScript turns static pages into practical tools.",
    "Responsive details matter because real users visit from every screen size.",
    "The best interface is clear, fast, and helpful at the right moment.",
    "Automation is most valuable when it keeps working without manual updates.",
    "A simple time-based feature can make a website feel much smarter."
  ];

  function getDayNumber(date) {
    const start = new Date(date.getFullYear(), 0, 0);
    const difference = date - start;
    return Math.floor(difference / (1000 * 60 * 60 * 24));
  }

  function updateDailyQuote() {
    const now = new Date();
    const dayNumber = getDayNumber(now);
    const quoteIndex = dayNumber % quotes.length;

    dateLabel.textContent = new Intl.DateTimeFormat("en", {
      weekday: "long",
      month: "long",
      day: "numeric"
    }).format(now);

    quote.textContent = quotes[quoteIndex];
    note.textContent = "Quote " + (quoteIndex + 1) + " of " + quotes.length + " is selected automatically from the current date.";
  }

  updateDailyQuote();
  setInterval(updateDailyQuote, 60000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-twentyone-demo"&gt;
  &lt;div class="vb-date-twentyone-card" data-vb-date-twentyone&gt;
    &lt;div class="vb-date-twentyone-date"&gt;
      &lt;span&gt;Today&lt;/span&gt;
      &lt;strong data-date-label&gt;Loading date...&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-twentyone-content"&gt;
      &lt;span class="vb-date-twentyone-kicker"&gt;Example 21&lt;/span&gt;
      &lt;h3&gt;Daily Rotating Quote&lt;/h3&gt;
      &lt;blockquote data-daily-quote&gt;Loading quote...&lt;/blockquote&gt;
      &lt;p data-daily-note&gt;This widget changes automatically based on the current date and keeps cycling forever.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-twentyone-demo,
.vb-date-twentyone-demo * {
  box-sizing: border-box;
}

.vb-date-twentyone-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 14% 16%, rgba(168, 85, 247, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(34, 211, 238, 0.16), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #ecfeff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-twentyone-card {
  display: grid;
  grid-template-columns: minmax(240px, 320px) minmax(0, 1fr);
  gap: 20px;
  max-width: 1060px;
  margin: 0 auto;
  padding: clamp(22px, 5vw, 44px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 16%, rgba(168, 85, 247, 0.20), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(34, 211, 238, 0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #312e81 58%, #164e63 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
  overflow: hidden;
}

.vb-date-twentyone-date {
  display: grid;
  align-content: center;
  gap: 10px;
  min-width: 0;
  padding: 22px;
  border-radius: 28px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-twentyone-date span {
  color: #c4b5fd !important;
  -webkit-text-fill-color: #c4b5fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-twentyone-date strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 5vw, 48px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
  overflow-wrap: anywhere;
}

.vb-date-twentyone-content {
  display: grid;
  align-content: center;
  min-width: 0;
}

.vb-date-twentyone-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-twentyone-content h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-twentyone-content blockquote {
  max-width: 720px;
  margin: 0 0 18px !important;
  padding: 0;
  border: 0;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(24px, 4vw, 42px);
  line-height: 1.12;
  font-weight: 850;
  letter-spacing: -0.045em;
  overflow-wrap: anywhere;
}

.vb-date-twentyone-content p {
  max-width: 680px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

@media (max-width: 820px) {
  .vb-date-twentyone-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 520px) {
  .vb-date-twentyone-card,
  .vb-date-twentyone-date {
    border-radius: 24px;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript daily rotating quote widget is useful for homepages, dashboards, blog sidebars, member areas, learning platforms, admin panels, and any website section that should update automatically without fixed end dates.</p>



<h2 class="wp-block-heading">22. Auto-Renewing Monthly Goal Tracker</h2>



<p class="wp-block-paragraph"><strong>An auto-renewing monthly goal tracker</strong> is useful for dashboards, fitness apps, habit trackers, sales goals, subscription platforms, project dashboards, and business reports. It shows month progress and automatically resets every new month.</p>



<p class="wp-block-paragraph">This example calculates how far the current month has progressed. Because it uses the current month dynamically, it keeps working forever and automatically starts a new cycle every month.</p>



<ul class="wp-block-list">
<li>Calculates current month progress</li>
<li>Automatically resets every month</li>
<li>Never permanently expires</li>
<li>Shows days passed and days remaining</li>
<li>Useful for dashboards, goals, habits, and reports</li>
</ul>



<div class="vb-date-twentytwo-demo">
  <div class="vb-date-twentytwo-card" data-vb-date-twentytwo>
    <div class="vb-date-twentytwo-left">
      <span class="vb-date-twentytwo-kicker">Example 22</span>
      <h3>Monthly Goal Tracker</h3>
      <p>JavaScript calculates the current month progress and automatically starts a new cycle every month.</p>

      <div class="vb-date-twentytwo-month">
        <span>Current month</span>
        <strong data-month-label>Loading...</strong>
      </div>
    </div>

    <div class="vb-date-twentytwo-right">
      <div class="vb-date-twentytwo-percent">
        <span>Month progress</span>
        <strong data-month-percent>--%</strong>
      </div>

      <div class="vb-date-twentytwo-bar">
        <span data-month-bar></span>
      </div>

      <div class="vb-date-twentytwo-stats">
        <div>
          <span>Passed</span>
          <strong data-days-passed>--</strong>
        </div>
        <div>
          <span>Remaining</span>
          <strong data-days-remaining>--</strong>
        </div>
        <div>
          <span>Total</span>
          <strong data-days-total>--</strong>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-date-twentytwo-demo,
.vb-date-twentytwo-demo * {
  box-sizing: border-box;
}

.vb-date-twentytwo-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 197, 94, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #eff6ff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-twentytwo-card {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(320px, 1.1fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(22px, 5vw, 44px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 16%, rgba(34, 197, 94, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(59, 130, 246, 0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #14532d 55%, #1e3a8a 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
  overflow: hidden;
}

.vb-date-twentytwo-left,
.vb-date-twentytwo-right {
  min-width: 0;
}

.vb-date-twentytwo-left {
  display: grid;
  align-content: center;
}

.vb-date-twentytwo-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-twentytwo-left h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 7vw, 74px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-date-twentytwo-left p {
  max-width: 620px;
  margin: 0 0 22px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-twentytwo-month {
  display: inline-grid;
  gap: 7px;
  max-width: 100%;
  padding: 16px 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-twentytwo-month span,
.vb-date-twentytwo-percent span,
.vb-date-twentytwo-stats span {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

.vb-date-twentytwo-month strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  line-height: 1.25;
  font-weight: 900;
  overflow-wrap: anywhere;
}

.vb-date-twentytwo-right {
  display: grid;
  align-content: center;
  gap: 18px;
  padding: clamp(20px, 4vw, 30px);
  border-radius: 28px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-date-twentytwo-percent {
  display: grid;
  gap: 8px;
}

.vb-date-twentytwo-percent strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(58px, 10vw, 98px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.08em;
}

.vb-date-twentytwo-bar {
  width: 100%;
  height: 18px;
  overflow: hidden;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-twentytwo-bar span {
  display: block;
  width: 0%;
  max-width: 100%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(135deg, #22c55e, #3b82f6);
  transition: width 0.35s ease;
}

.vb-date-twentytwo-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}

.vb-date-twentytwo-stats div {
  min-width: 0;
  padding: 14px;
  border-radius: 18px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-date-twentytwo-stats strong {
  display: block;
  margin-top: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  line-height: 1.1;
  font-weight: 950;
}

@media (max-width: 920px) {
  .vb-date-twentytwo-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-twentytwo-card,
  .vb-date-twentytwo-right {
    border-radius: 24px;
  }

  .vb-date-twentytwo-stats {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const tracker = document.querySelector("[data-vb-date-twentytwo]");
  if (!tracker) return;

  const monthLabel = tracker.querySelector("[data-month-label]");
  const percentLabel = tracker.querySelector("[data-month-percent]");
  const progressBar = tracker.querySelector("[data-month-bar]");
  const daysPassed = tracker.querySelector("[data-days-passed]");
  const daysRemaining = tracker.querySelector("[data-days-remaining]");
  const daysTotal = tracker.querySelector("[data-days-total]");

  function updateMonthProgress() {
    const now = new Date();
    const year = now.getFullYear();
    const month = now.getMonth();

    const firstDay = new Date(year, month, 1);
    const nextMonth = new Date(year, month + 1, 1);
    const lastDay = new Date(year, month + 1, 0);

    const totalDays = lastDay.getDate();
    const passed = now.getDate();
    const remaining = Math.max(0, totalDays - passed);

    const percent = Math.max(0, Math.min(100, Math.round(((now - firstDay) / (nextMonth - firstDay)) * 100)));

    monthLabel.textContent = new Intl.DateTimeFormat("en", {
      month: "long",
      year: "numeric"
    }).format(now);

    percentLabel.textContent = percent + "%";
    progressBar.style.width = percent + "%";
    daysPassed.textContent = passed;
    daysRemaining.textContent = remaining;
    daysTotal.textContent = totalDays;
  }

  updateMonthProgress();
  setInterval(updateMonthProgress, 60000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const tracker = document.querySelector("[data-vb-date-twentytwo]");
  if (!tracker) return;

  const monthLabel = tracker.querySelector("[data-month-label]");
  const percentLabel = tracker.querySelector("[data-month-percent]");
  const progressBar = tracker.querySelector("[data-month-bar]");
  const daysPassed = tracker.querySelector("[data-days-passed]");
  const daysRemaining = tracker.querySelector("[data-days-remaining]");
  const daysTotal = tracker.querySelector("[data-days-total]");

  function updateMonthProgress() {
    const now = new Date();
    const year = now.getFullYear();
    const month = now.getMonth();

    const firstDay = new Date(year, month, 1);
    const nextMonth = new Date(year, month + 1, 1);
    const lastDay = new Date(year, month + 1, 0);

    const totalDays = lastDay.getDate();
    const passed = now.getDate();
    const remaining = Math.max(0, totalDays - passed);

    const percent = Math.max(0, Math.min(100, Math.round(((now - firstDay) / (nextMonth - firstDay)) * 100)));

    monthLabel.textContent = new Intl.DateTimeFormat("en", {
      month: "long",
      year: "numeric"
    }).format(now);

    percentLabel.textContent = percent + "%";
    progressBar.style.width = percent + "%";
    daysPassed.textContent = passed;
    daysRemaining.textContent = remaining;
    daysTotal.textContent = totalDays;
  }

  updateMonthProgress();
  setInterval(updateMonthProgress, 60000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-twentytwo-demo"&gt;
  &lt;div class="vb-date-twentytwo-card" data-vb-date-twentytwo&gt;
    &lt;div class="vb-date-twentytwo-left"&gt;
      &lt;span class="vb-date-twentytwo-kicker"&gt;Example 22&lt;/span&gt;
      &lt;h3&gt;Monthly Goal Tracker&lt;/h3&gt;
      &lt;p&gt;JavaScript calculates the current month progress and automatically starts a new cycle every month.&lt;/p&gt;

      &lt;div class="vb-date-twentytwo-month"&gt;
        &lt;span&gt;Current month&lt;/span&gt;
        &lt;strong data-month-label&gt;Loading...&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-twentytwo-right"&gt;
      &lt;div class="vb-date-twentytwo-percent"&gt;
        &lt;span&gt;Month progress&lt;/span&gt;
        &lt;strong data-month-percent&gt;--%&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-twentytwo-bar"&gt;
        &lt;span data-month-bar&gt;&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-twentytwo-stats"&gt;
        &lt;div&gt;
          &lt;span&gt;Passed&lt;/span&gt;
          &lt;strong data-days-passed&gt;--&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Remaining&lt;/span&gt;
          &lt;strong data-days-remaining&gt;--&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Total&lt;/span&gt;
          &lt;strong data-days-total&gt;--&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-twentytwo-demo,
.vb-date-twentytwo-demo * {
  box-sizing: border-box;
}

.vb-date-twentytwo-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 197, 94, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #eff6ff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-twentytwo-card {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(320px, 1.1fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(22px, 5vw, 44px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 16%, rgba(34, 197, 94, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(59, 130, 246, 0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #14532d 55%, #1e3a8a 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
  overflow: hidden;
}

.vb-date-twentytwo-left,
.vb-date-twentytwo-right {
  min-width: 0;
}

.vb-date-twentytwo-left {
  display: grid;
  align-content: center;
}

.vb-date-twentytwo-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-twentytwo-left h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 7vw, 74px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-date-twentytwo-left p {
  max-width: 620px;
  margin: 0 0 22px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-twentytwo-month {
  display: inline-grid;
  gap: 7px;
  max-width: 100%;
  padding: 16px 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-twentytwo-month span,
.vb-date-twentytwo-percent span,
.vb-date-twentytwo-stats span {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

.vb-date-twentytwo-month strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  line-height: 1.25;
  font-weight: 900;
  overflow-wrap: anywhere;
}

.vb-date-twentytwo-right {
  display: grid;
  align-content: center;
  gap: 18px;
  padding: clamp(20px, 4vw, 30px);
  border-radius: 28px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-date-twentytwo-percent {
  display: grid;
  gap: 8px;
}

.vb-date-twentytwo-percent strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(58px, 10vw, 98px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.08em;
}

.vb-date-twentytwo-bar {
  width: 100%;
  height: 18px;
  overflow: hidden;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-twentytwo-bar span {
  display: block;
  width: 0%;
  max-width: 100%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(135deg, #22c55e, #3b82f6);
  transition: width 0.35s ease;
}

.vb-date-twentytwo-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
}

.vb-date-twentytwo-stats div {
  min-width: 0;
  padding: 14px;
  border-radius: 18px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-date-twentytwo-stats strong {
  display: block;
  margin-top: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  line-height: 1.1;
  font-weight: 950;
}

@media (max-width: 920px) {
  .vb-date-twentytwo-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-twentytwo-card,
  .vb-date-twentytwo-right {
    border-radius: 24px;
  }

  .vb-date-twentytwo-stats {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript monthly goal tracker is useful for dashboards, goal apps, sales reports, habit trackers, analytics widgets, business reports, subscription portals, and any monthly cycle that should automatically renew forever.</p>



<h2 class="wp-block-heading">23. Infinite Pomodoro Work Timer</h2>



<p class="wp-block-paragraph"><strong>An infinite Pomodoro work timer</strong> is useful for productivity apps, learning platforms, dashboards, focus tools, online courses, and time management widgets. It keeps switching between work and break sessions automatically.</p>



<p class="wp-block-paragraph">This example uses a repeating 25-minute work session and 5-minute break session. When one session reaches zero, JavaScript immediately starts the next session, so the timer keeps running forever.</p>



<ul class="wp-block-list">
<li>Alternates between work and break sessions</li>
<li>Automatically restarts after every session</li>
<li>Never permanently stops</li>
<li>Includes start, pause, and reset buttons</li>
<li>Useful for productivity tools, learning apps, and dashboards</li>
</ul>



<div class="vb-date-twentythree-demo">
  <div class="vb-date-twentythree-card" data-vb-date-twentythree>
    <div class="vb-date-twentythree-header">
      <span class="vb-date-twentythree-kicker">Example 23</span>
      <h3>Infinite Pomodoro Timer</h3>
      <p>This timer automatically alternates between work and break sessions, so it keeps working forever.</p>
    </div>

    <div class="vb-date-twentythree-timer" data-mode="work">
      <span data-session-label>Work session</span>
      <strong data-time-left>25:00</strong>
      <p data-session-note>Focus mode is ready.</p>
    </div>

    <div class="vb-date-twentythree-controls">
      <button type="button" data-start-timer>Start</button>
      <button type="button" data-pause-timer>Pause</button>
      <button type="button" data-reset-timer>Reset</button>
    </div>
  </div>
</div>

<style>
.vb-date-twentythree-demo,
.vb-date-twentythree-demo * {
  box-sizing: border-box;
}

.vb-date-twentythree-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 14% 16%, rgba(236, 72, 153, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(124, 58, 237, 0.16), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #f5f3ff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(236, 72, 153, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-twentythree-card {
  max-width: 980px;
  margin: 0 auto;
  padding: clamp(22px, 5vw, 46px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 18% 16%, rgba(236, 72, 153, 0.22), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(124, 58, 237, 0.20), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #581c87 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 30px 90px rgba(88, 28, 135, 0.26);
  overflow: hidden;
}

.vb-date-twentythree-header {
  max-width: 760px;
  margin-bottom: 22px;
}

.vb-date-twentythree-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-twentythree-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 7vw, 76px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-date-twentythree-header p {
  margin: 0 !important;
  color: #e9d5ff !important;
  -webkit-text-fill-color: #e9d5ff !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-twentythree-timer {
  display: grid;
  place-items: center;
  gap: 12px;
  min-width: 0;
  min-height: 300px;
  margin-bottom: 16px;
  padding: 24px;
  border-radius: 30px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-twentythree-timer[data-mode="break"] {
  background: rgba(34, 197, 94, 0.14);
  border-color: rgba(134, 239, 172, 0.32);
}

.vb-date-twentythree-timer span {
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-twentythree-timer strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(72px, 15vw, 150px);
  line-height: 0.88;
  font-weight: 950;
  letter-spacing: -0.08em;
  font-variant-numeric: tabular-nums;
}

.vb-date-twentythree-timer p {
  max-width: 520px;
  margin: 0 !important;
  color: #e9d5ff !important;
  -webkit-text-fill-color: #e9d5ff !important;
  font-size: 15px;
  line-height: 1.55;
  font-weight: 650;
  text-align: center;
}

.vb-date-twentythree-controls {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.vb-date-twentythree-controls button {
  flex: 1;
  min-width: 130px;
  min-height: 48px;
  padding: 12px 16px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-date-twentythree-controls button:first-child {
  background: linear-gradient(135deg, #db2777, #7c3aed);
  border-color: rgba(255,255,255,0.24);
}

@media (max-width: 560px) {
  .vb-date-twentythree-card,
  .vb-date-twentythree-timer {
    border-radius: 24px;
  }

  .vb-date-twentythree-timer {
    min-height: 230px;
  }

  .vb-date-twentythree-controls button {
    min-width: 100%;
  }
}
</style>

<script>
(function () {
  const pomodoro = document.querySelector("[data-vb-date-twentythree]");
  if (!pomodoro) return;

  const timerBox = pomodoro.querySelector(".vb-date-twentythree-timer");
  const sessionLabel = pomodoro.querySelector("[data-session-label]");
  const timeLeft = pomodoro.querySelector("[data-time-left]");
  const sessionNote = pomodoro.querySelector("[data-session-note]");

  const startButton = pomodoro.querySelector("[data-start-timer]");
  const pauseButton = pomodoro.querySelector("[data-pause-timer]");
  const resetButton = pomodoro.querySelector("[data-reset-timer]");

  const workSeconds = 25 * 60;
  const breakSeconds = 5 * 60;

  let mode = "work";
  let remainingSeconds = workSeconds;
  let interval = null;

  function formatTime(seconds) {
    const minutes = Math.floor(seconds / 60);
    const restSeconds = seconds % 60;

    return String(minutes).padStart(2, "0") + ":" + String(restSeconds).padStart(2, "0");
  }

  function renderTimer() {
    timerBox.setAttribute("data-mode", mode);
    timeLeft.textContent = formatTime(remainingSeconds);

    if (mode === "work") {
      sessionLabel.textContent = "Work session";
      sessionNote.textContent = "Focus mode is active. The timer will switch to break automatically.";
    } else {
      sessionLabel.textContent = "Break session";
      sessionNote.textContent = "Break mode is active. The timer will switch back to work automatically.";
    }
  }

  function switchSession() {
    if (mode === "work") {
      mode = "break";
      remainingSeconds = breakSeconds;
    } else {
      mode = "work";
      remainingSeconds = workSeconds;
    }

    renderTimer();
  }

  function tick() {
    remainingSeconds -= 1;

    if (remainingSeconds <= 0) {
      switchSession();
      return;
    }

    renderTimer();
  }

  function startTimer() {
    if (interval) return;
    interval = setInterval(tick, 1000);
  }

  function pauseTimer() {
    clearInterval(interval);
    interval = null;
  }

  function resetTimer() {
    pauseTimer();
    mode = "work";
    remainingSeconds = workSeconds;
    renderTimer();
  }

  startButton.addEventListener("click", startTimer);
  pauseButton.addEventListener("click", pauseTimer);
  resetButton.addEventListener("click", resetTimer);

  renderTimer();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const pomodoro = document.querySelector("[data-vb-date-twentythree]");
  if (!pomodoro) return;

  const timerBox = pomodoro.querySelector(".vb-date-twentythree-timer");
  const sessionLabel = pomodoro.querySelector("[data-session-label]");
  const timeLeft = pomodoro.querySelector("[data-time-left]");
  const sessionNote = pomodoro.querySelector("[data-session-note]");

  const startButton = pomodoro.querySelector("[data-start-timer]");
  const pauseButton = pomodoro.querySelector("[data-pause-timer]");
  const resetButton = pomodoro.querySelector("[data-reset-timer]");

  const workSeconds = 25 * 60;
  const breakSeconds = 5 * 60;

  let mode = "work";
  let remainingSeconds = workSeconds;
  let interval = null;

  function formatTime(seconds) {
    const minutes = Math.floor(seconds / 60);
    const restSeconds = seconds % 60;

    return String(minutes).padStart(2, "0") + ":" + String(restSeconds).padStart(2, "0");
  }

  function renderTimer() {
    timerBox.setAttribute("data-mode", mode);
    timeLeft.textContent = formatTime(remainingSeconds);

    if (mode === "work") {
      sessionLabel.textContent = "Work session";
      sessionNote.textContent = "Focus mode is active. The timer will switch to break automatically.";
    } else {
      sessionLabel.textContent = "Break session";
      sessionNote.textContent = "Break mode is active. The timer will switch back to work automatically.";
    }
  }

  function switchSession() {
    if (mode === "work") {
      mode = "break";
      remainingSeconds = breakSeconds;
    } else {
      mode = "work";
      remainingSeconds = workSeconds;
    }

    renderTimer();
  }

  function tick() {
    remainingSeconds -= 1;

    if (remainingSeconds &lt;= 0) {
      switchSession();
      return;
    }

    renderTimer();
  }

  function startTimer() {
    if (interval) return;
    interval = setInterval(tick, 1000);
  }

  function pauseTimer() {
    clearInterval(interval);
    interval = null;
  }

  function resetTimer() {
    pauseTimer();
    mode = "work";
    remainingSeconds = workSeconds;
    renderTimer();
  }

  startButton.addEventListener("click", startTimer);
  pauseButton.addEventListener("click", pauseTimer);
  resetButton.addEventListener("click", resetTimer);

  renderTimer();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-twentythree-demo"&gt;
  &lt;div class="vb-date-twentythree-card" data-vb-date-twentythree&gt;
    &lt;div class="vb-date-twentythree-header"&gt;
      &lt;span class="vb-date-twentythree-kicker"&gt;Example 23&lt;/span&gt;
      &lt;h3&gt;Infinite Pomodoro Timer&lt;/h3&gt;
      &lt;p&gt;This timer automatically alternates between work and break sessions, so it keeps working forever.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-twentythree-timer" data-mode="work"&gt;
      &lt;span data-session-label&gt;Work session&lt;/span&gt;
      &lt;strong data-time-left&gt;25:00&lt;/strong&gt;
      &lt;p data-session-note&gt;Focus mode is ready.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-twentythree-controls"&gt;
      &lt;button type="button" data-start-timer&gt;Start&lt;/button&gt;
      &lt;button type="button" data-pause-timer&gt;Pause&lt;/button&gt;
      &lt;button type="button" data-reset-timer&gt;Reset&lt;/button&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-twentythree-demo,
.vb-date-twentythree-demo * {
  box-sizing: border-box;
}

.vb-date-twentythree-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 14% 16%, rgba(236, 72, 153, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(124, 58, 237, 0.16), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #f5f3ff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(236, 72, 153, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-twentythree-card {
  max-width: 980px;
  margin: 0 auto;
  padding: clamp(22px, 5vw, 46px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 18% 16%, rgba(236, 72, 153, 0.22), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(124, 58, 237, 0.20), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #581c87 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 30px 90px rgba(88, 28, 135, 0.26);
  overflow: hidden;
}

.vb-date-twentythree-header {
  max-width: 760px;
  margin-bottom: 22px;
}

.vb-date-twentythree-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-twentythree-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 7vw, 76px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-date-twentythree-header p {
  margin: 0 !important;
  color: #e9d5ff !important;
  -webkit-text-fill-color: #e9d5ff !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-twentythree-timer {
  display: grid;
  place-items: center;
  gap: 12px;
  min-width: 0;
  min-height: 300px;
  margin-bottom: 16px;
  padding: 24px;
  border-radius: 30px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-twentythree-timer[data-mode="break"] {
  background: rgba(34, 197, 94, 0.14);
  border-color: rgba(134, 239, 172, 0.32);
}

.vb-date-twentythree-timer span {
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-twentythree-timer strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(72px, 15vw, 150px);
  line-height: 0.88;
  font-weight: 950;
  letter-spacing: -0.08em;
  font-variant-numeric: tabular-nums;
}

.vb-date-twentythree-timer p {
  max-width: 520px;
  margin: 0 !important;
  color: #e9d5ff !important;
  -webkit-text-fill-color: #e9d5ff !important;
  font-size: 15px;
  line-height: 1.55;
  font-weight: 650;
  text-align: center;
}

.vb-date-twentythree-controls {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.vb-date-twentythree-controls button {
  flex: 1;
  min-width: 130px;
  min-height: 48px;
  padding: 12px 16px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-date-twentythree-controls button:first-child {
  background: linear-gradient(135deg, #db2777, #7c3aed);
  border-color: rgba(255,255,255,0.24);
}

@media (max-width: 560px) {
  .vb-date-twentythree-card,
  .vb-date-twentythree-timer {
    border-radius: 24px;
  }

  .vb-date-twentythree-timer {
    min-height: 230px;
  }

  .vb-date-twentythree-controls button {
    min-width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This infinite JavaScript Pomodoro timer is useful for productivity apps, focus dashboards, study tools, learning platforms, time management widgets, online courses, and personal workflow pages.</p>



<h2 class="wp-block-heading">24. Always-Current Year Progress Tracker</h2>



<p class="wp-block-paragraph"><strong>An always-current year progress tracker</strong> is useful for dashboards, yearly goals, habit apps, financial reports, project planning pages, business dashboards, and productivity widgets. It automatically uses the current year and resets every January.</p>



<p class="wp-block-paragraph">This example calculates how much of the current year has passed. It does not need a fixed year value, so it stays accurate forever as the calendar moves forward.</p>



<ul class="wp-block-list">
<li>Tracks progress through the current year</li>
<li>Automatically resets every January</li>
<li>Never needs manual year updates</li>
<li>Shows percentage, passed days, and remaining days</li>
<li>Useful for yearly goals, dashboards, and reports</li>
</ul>



<div class="vb-date-twentyfour-demo">
  <div class="vb-date-twentyfour-card" data-vb-date-twentyfour>
    <div class="vb-date-twentyfour-top">
      <span class="vb-date-twentyfour-kicker">Example 24</span>
      <h3>Year Progress Tracker</h3>
      <p>JavaScript calculates the current year progress dynamically and automatically resets every new year.</p>
    </div>

    <div class="vb-date-twentyfour-main">
      <div class="vb-date-twentyfour-circle">
        <strong data-year-percent>--%</strong>
        <span data-year-label>Current year</span>
      </div>

      <div class="vb-date-twentyfour-details">
        <div>
          <span>Days passed</span>
          <strong data-year-passed>--</strong>
        </div>
        <div>
          <span>Days remaining</span>
          <strong data-year-remaining>--</strong>
        </div>
        <div>
          <span>Total days</span>
          <strong data-year-total>--</strong>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-date-twentyfour-demo,
.vb-date-twentyfour-demo * {
  box-sizing: border-box;
}

.vb-date-twentyfour-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 16%, rgba(20, 184, 166, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdfa 0%, #eef2ff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-twentyfour-card {
  max-width: 1080px;
  margin: 0 auto;
  padding: clamp(22px, 5vw, 46px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 16%, rgba(45, 212, 191, 0.20), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(129, 140, 248, 0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #134e4a 55%, #312e81 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
  overflow: hidden;
}

.vb-date-twentyfour-top {
  max-width: 780px;
  margin-bottom: 24px;
}

.vb-date-twentyfour-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #99f6e4 !important;
  -webkit-text-fill-color: #99f6e4 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-twentyfour-top h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 7vw, 76px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-twentyfour-top p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-twentyfour-main {
  display: grid;
  grid-template-columns: minmax(260px, 360px) minmax(0, 1fr);
  gap: 20px;
  align-items: stretch;
}

.vb-date-twentyfour-circle {
  display: grid;
  place-items: center;
  align-content: center;
  gap: 8px;
  min-width: 0;
  min-height: 280px;
  padding: 24px;
  border-radius: 32px;
  background:
    radial-gradient(circle at center, rgba(45, 212, 191, 0.24), transparent 52%),
    rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.15);
}

.vb-date-twentyfour-circle strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(64px, 12vw, 118px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.085em;
}

.vb-date-twentyfour-circle span,
.vb-date-twentyfour-details span {
  color: #99f6e4 !important;
  -webkit-text-fill-color: #99f6e4 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-twentyfour-details {
  display: grid;
  gap: 12px;
  min-width: 0;
}

.vb-date-twentyfour-details div {
  display: grid;
  align-content: center;
  min-width: 0;
  min-height: 86px;
  padding: 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-date-twentyfour-details strong {
  display: block;
  margin-top: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(24px, 4vw, 38px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.05em;
}

@media (max-width: 820px) {
  .vb-date-twentyfour-main {
    grid-template-columns: 1fr;
  }

  .vb-date-twentyfour-circle {
    min-height: 230px;
  }
}

@media (max-width: 520px) {
  .vb-date-twentyfour-card,
  .vb-date-twentyfour-circle,
  .vb-date-twentyfour-details div {
    border-radius: 24px;
  }
}
</style>

<script>
(function () {
  const tracker = document.querySelector("[data-vb-date-twentyfour]");
  if (!tracker) return;

  const percent = tracker.querySelector("[data-year-percent]");
  const yearLabel = tracker.querySelector("[data-year-label]");
  const passed = tracker.querySelector("[data-year-passed]");
  const remaining = tracker.querySelector("[data-year-remaining]");
  const total = tracker.querySelector("[data-year-total]");

  function updateYearProgress() {
    const now = new Date();
    const year = now.getFullYear();

    const start = new Date(year, 0, 1);
    const end = new Date(year + 1, 0, 1);

    const totalDays = Math.round((end - start) / (1000 * 60 * 60 * 24));
    const passedDays = Math.floor((now - start) / (1000 * 60 * 60 * 24)) + 1;
    const remainingDays = Math.max(0, totalDays - passedDays);

    const progressPercent = Math.max(0, Math.min(100, Math.round(((now - start) / (end - start)) * 100)));

    percent.textContent = progressPercent + "%";
    yearLabel.textContent = "Year " + year;
    passed.textContent = passedDays;
    remaining.textContent = remainingDays;
    total.textContent = totalDays;
  }

  updateYearProgress();
  setInterval(updateYearProgress, 60000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const tracker = document.querySelector("[data-vb-date-twentyfour]");
  if (!tracker) return;

  const percent = tracker.querySelector("[data-year-percent]");
  const yearLabel = tracker.querySelector("[data-year-label]");
  const passed = tracker.querySelector("[data-year-passed]");
  const remaining = tracker.querySelector("[data-year-remaining]");
  const total = tracker.querySelector("[data-year-total]");

  function updateYearProgress() {
    const now = new Date();
    const year = now.getFullYear();

    const start = new Date(year, 0, 1);
    const end = new Date(year + 1, 0, 1);

    const totalDays = Math.round((end - start) / (1000 * 60 * 60 * 24));
    const passedDays = Math.floor((now - start) / (1000 * 60 * 60 * 24)) + 1;
    const remainingDays = Math.max(0, totalDays - passedDays);

    const progressPercent = Math.max(0, Math.min(100, Math.round(((now - start) / (end - start)) * 100)));

    percent.textContent = progressPercent + "%";
    yearLabel.textContent = "Year " + year;
    passed.textContent = passedDays;
    remaining.textContent = remainingDays;
    total.textContent = totalDays;
  }

  updateYearProgress();
  setInterval(updateYearProgress, 60000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-twentyfour-demo"&gt;
  &lt;div class="vb-date-twentyfour-card" data-vb-date-twentyfour&gt;
    &lt;div class="vb-date-twentyfour-top"&gt;
      &lt;span class="vb-date-twentyfour-kicker"&gt;Example 24&lt;/span&gt;
      &lt;h3&gt;Year Progress Tracker&lt;/h3&gt;
      &lt;p&gt;JavaScript calculates the current year progress dynamically and automatically resets every new year.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-twentyfour-main"&gt;
      &lt;div class="vb-date-twentyfour-circle"&gt;
        &lt;strong data-year-percent&gt;--%&lt;/strong&gt;
        &lt;span data-year-label&gt;Current year&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-twentyfour-details"&gt;
        &lt;div&gt;
          &lt;span&gt;Days passed&lt;/span&gt;
          &lt;strong data-year-passed&gt;--&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Days remaining&lt;/span&gt;
          &lt;strong data-year-remaining&gt;--&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Total days&lt;/span&gt;
          &lt;strong data-year-total&gt;--&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-twentyfour-demo,
.vb-date-twentyfour-demo * {
  box-sizing: border-box;
}

.vb-date-twentyfour-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 16%, rgba(20, 184, 166, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdfa 0%, #eef2ff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-twentyfour-card {
  max-width: 1080px;
  margin: 0 auto;
  padding: clamp(22px, 5vw, 46px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 16%, rgba(45, 212, 191, 0.20), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(129, 140, 248, 0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #134e4a 55%, #312e81 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
  overflow: hidden;
}

.vb-date-twentyfour-top {
  max-width: 780px;
  margin-bottom: 24px;
}

.vb-date-twentyfour-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #99f6e4 !important;
  -webkit-text-fill-color: #99f6e4 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-twentyfour-top h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 7vw, 76px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-twentyfour-top p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-date-twentyfour-main {
  display: grid;
  grid-template-columns: minmax(260px, 360px) minmax(0, 1fr);
  gap: 20px;
  align-items: stretch;
}

.vb-date-twentyfour-circle {
  display: grid;
  place-items: center;
  align-content: center;
  gap: 8px;
  min-width: 0;
  min-height: 280px;
  padding: 24px;
  border-radius: 32px;
  background:
    radial-gradient(circle at center, rgba(45, 212, 191, 0.24), transparent 52%),
    rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.15);
}

.vb-date-twentyfour-circle strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(64px, 12vw, 118px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.085em;
}

.vb-date-twentyfour-circle span,
.vb-date-twentyfour-details span {
  color: #99f6e4 !important;
  -webkit-text-fill-color: #99f6e4 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-date-twentyfour-details {
  display: grid;
  gap: 12px;
  min-width: 0;
}

.vb-date-twentyfour-details div {
  display: grid;
  align-content: center;
  min-width: 0;
  min-height: 86px;
  padding: 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-date-twentyfour-details strong {
  display: block;
  margin-top: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(24px, 4vw, 38px);
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.05em;
}

@media (max-width: 820px) {
  .vb-date-twentyfour-main {
    grid-template-columns: 1fr;
  }

  .vb-date-twentyfour-circle {
    min-height: 230px;
  }
}

@media (max-width: 520px) {
  .vb-date-twentyfour-card,
  .vb-date-twentyfour-circle,
  .vb-date-twentyfour-details div {
    border-radius: 24px;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript year progress tracker is useful for yearly goal dashboards, business reports, productivity apps, financial planning widgets, personal trackers, project timelines, and admin panels that should always stay current without manual updates.</p>



<div class="vb24-js-date-mini-cta">
  <p>Need a custom JavaScript date, calendar, booking, or calculator feature for your website?</p>
  <a href="https://veebilehed24.ee/en/contact/">Contact us</a>
</div>

<style>
.vb24-js-date-mini-cta,
.vb24-js-date-mini-cta * {
  box-sizing: border-box;
}

.vb24-js-date-mini-cta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin: 40px 0;
  padding: 18px 20px;
  border: 1px solid rgba(148, 163, 184, 0.24);
  border-radius: 20px;
  background: #f8fafc;
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.06);
}

.vb24-js-date-mini-cta p {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  line-height: 1.55;
  font-weight: 750;
}

.vb24-js-date-mini-cta a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 42px;
  padding: 10px 16px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
  white-space: nowrap;
}

.vb24-js-date-mini-cta a:hover {
  background: #2563eb;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

@media (max-width: 640px) {
  .vb24-js-date-mini-cta {
    align-items: stretch;
    flex-direction: column;
    border-radius: 18px;
  }

  .vb24-js-date-mini-cta a {
    width: 100%;
  }
}
</style>



<h2 class="wp-block-heading">25. JavaScript Time Zone Converter</h2>



<p class="wp-block-paragraph"><strong>A JavaScript time zone converter</strong> is one of the most useful date and time examples for booking systems, international websites, remote teams, webinar pages, dashboards, and event tools. It helps users convert one selected time into different time zones.</p>



<p class="wp-block-paragraph">This example lets users choose a date and time, then JavaScript converts it into New York, London, Tallinn, Tokyo, and Sydney times using <code>Intl.DateTimeFormat</code>.</p>



<ul class="wp-block-list">
<li>Converts selected date and time into multiple time zones</li>
<li>Uses JavaScript Intl.DateTimeFormat</li>
<li>Useful for webinars, meetings, dashboards, and international websites</li>
<li>Responsive card layout</li>
<li>Does not depend on a fixed old date</li>
</ul>



<div class="vb-date-twentyfive-demo">
  <div class="vb-date-twentyfive-card" data-vb-date-twentyfive>
    <div class="vb-date-twentyfive-form">
      <span class="vb-date-twentyfive-kicker">Example 25</span>
      <h3>Time Zone Converter</h3>
      <p>Select one date and time, then convert it into multiple international time zones.</p>

      <label>
        <span>Select date and time</span>
        <input type="datetime-local" data-timezone-input>
      </label>

      <button type="button" data-convert-timezones>Convert Time Zones</button>
    </div>

    <div class="vb-date-twentyfive-results">
      <div>
        <span>New York</span>
        <strong data-zone-newyork>--</strong>
      </div>
      <div>
        <span>London</span>
        <strong data-zone-london>--</strong>
      </div>
      <div>
        <span>Tallinn</span>
        <strong data-zone-tallinn>--</strong>
      </div>
      <div>
        <span>Tokyo</span>
        <strong data-zone-tokyo>--</strong>
      </div>
      <div>
        <span>Sydney</span>
        <strong data-zone-sydney>--</strong>
      </div>
    </div>
  </div>
</div>

<style>
.vb-date-twentyfive-demo,
.vb-date-twentyfive-demo * {
  box-sizing: border-box;
}

.vb-date-twentyfive-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(14, 165, 233, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #ecfeff 0%, #eef2ff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-twentyfive-card {
  display: grid;
  grid-template-columns: minmax(280px, 0.85fr) minmax(0, 1.15fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-twentyfive-form,
.vb-date-twentyfive-results {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-twentyfive-form {
  display: grid;
  align-content: center;
  padding: clamp(22px, 4vw, 38px);
  background: #ffffff;
}

.vb-date-twentyfive-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-twentyfive-form h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-twentyfive-form p {
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-twentyfive-form label {
  display: grid;
  gap: 8px;
  margin-bottom: 14px;
}

.vb-date-twentyfive-form label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-twentyfive-form input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-twentyfive-form button {
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-date-twentyfive-results {
  display: grid;
  gap: 12px;
  padding: clamp(20px, 4vw, 30px);
  background:
    radial-gradient(circle at 16% 14%, rgba(34, 211, 238, 0.20), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #1e3a8a 100%) !important;
}

.vb-date-twentyfive-results div {
  min-width: 0;
  display: grid;
  gap: 7px;
  padding: 16px;
  border-radius: 20px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-twentyfive-results span {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-date-twentyfive-results strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(18px, 3vw, 26px);
  line-height: 1.25;
  font-weight: 950;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-date-twentyfive-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-twentyfive-form,
  .vb-date-twentyfive-results,
  .vb-date-twentyfive-results div {
    border-radius: 24px;
  }

  .vb-date-twentyfive-form button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const converter = document.querySelector("[data-vb-date-twentyfive]");
  if (!converter) return;

  const input = converter.querySelector("[data-timezone-input]");
  const button = converter.querySelector("[data-convert-timezones]");

  const outputs = {
    newyork: converter.querySelector("[data-zone-newyork]"),
    london: converter.querySelector("[data-zone-london]"),
    tallinn: converter.querySelector("[data-zone-tallinn]"),
    tokyo: converter.querySelector("[data-zone-tokyo]"),
    sydney: converter.querySelector("[data-zone-sydney]")
  };

  const zones = {
    newyork: "America/New_York",
    london: "Europe/London",
    tallinn: "Europe/Tallinn",
    tokyo: "Asia/Tokyo",
    sydney: "Australia/Sydney"
  };

  function getLocalDateTimeValue(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");
    const hours = String(date.getHours()).padStart(2, "0");
    const minutes = String(date.getMinutes()).padStart(2, "0");

    return year + "-" + month + "-" + day + "T" + hours + ":" + minutes;
  }

  function formatZoneTime(date, timeZone) {
    return new Intl.DateTimeFormat("en", {
      timeZone: timeZone,
      weekday: "short",
      month: "short",
      day: "numeric",
      year: "numeric",
      hour: "2-digit",
      minute: "2-digit"
    }).format(date);
  }

  function convertTimeZones() {
    if (!input.value) return;

    const selectedDate = new Date(input.value);

    Object.keys(zones).forEach(function (key) {
      outputs[key].textContent = formatZoneTime(selectedDate, zones[key]);
    });
  }

  input.value = getLocalDateTimeValue(new Date());
  button.addEventListener("click", convertTimeZones);
  input.addEventListener("change", convertTimeZones);

  convertTimeZones();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const converter = document.querySelector("[data-vb-date-twentyfive]");
  if (!converter) return;

  const input = converter.querySelector("[data-timezone-input]");
  const button = converter.querySelector("[data-convert-timezones]");

  const outputs = {
    newyork: converter.querySelector("[data-zone-newyork]"),
    london: converter.querySelector("[data-zone-london]"),
    tallinn: converter.querySelector("[data-zone-tallinn]"),
    tokyo: converter.querySelector("[data-zone-tokyo]"),
    sydney: converter.querySelector("[data-zone-sydney]")
  };

  const zones = {
    newyork: "America/New_York",
    london: "Europe/London",
    tallinn: "Europe/Tallinn",
    tokyo: "Asia/Tokyo",
    sydney: "Australia/Sydney"
  };

  function getLocalDateTimeValue(date) {
    const year = date.getFullYear();
    const month = String(date.getMonth() + 1).padStart(2, "0");
    const day = String(date.getDate()).padStart(2, "0");
    const hours = String(date.getHours()).padStart(2, "0");
    const minutes = String(date.getMinutes()).padStart(2, "0");

    return year + "-" + month + "-" + day + "T" + hours + ":" + minutes;
  }

  function formatZoneTime(date, timeZone) {
    return new Intl.DateTimeFormat("en", {
      timeZone: timeZone,
      weekday: "short",
      month: "short",
      day: "numeric",
      year: "numeric",
      hour: "2-digit",
      minute: "2-digit"
    }).format(date);
  }

  function convertTimeZones() {
    if (!input.value) return;

    const selectedDate = new Date(input.value);

    Object.keys(zones).forEach(function (key) {
      outputs[key].textContent = formatZoneTime(selectedDate, zones[key]);
    });
  }

  input.value = getLocalDateTimeValue(new Date());
  button.addEventListener("click", convertTimeZones);
  input.addEventListener("change", convertTimeZones);

  convertTimeZones();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-twentyfive-demo"&gt;
  &lt;div class="vb-date-twentyfive-card" data-vb-date-twentyfive&gt;
    &lt;div class="vb-date-twentyfive-form"&gt;
      &lt;span class="vb-date-twentyfive-kicker"&gt;Example 25&lt;/span&gt;
      &lt;h3&gt;Time Zone Converter&lt;/h3&gt;
      &lt;p&gt;Select one date and time, then convert it into multiple international time zones.&lt;/p&gt;

      &lt;label&gt;
        &lt;span&gt;Select date and time&lt;/span&gt;
        &lt;input type="datetime-local" data-timezone-input&gt;
      &lt;/label&gt;

      &lt;button type="button" data-convert-timezones&gt;Convert Time Zones&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-twentyfive-results"&gt;
      &lt;div&gt;
        &lt;span&gt;New York&lt;/span&gt;
        &lt;strong data-zone-newyork&gt;--&lt;/strong&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;span&gt;London&lt;/span&gt;
        &lt;strong data-zone-london&gt;--&lt;/strong&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;span&gt;Tallinn&lt;/span&gt;
        &lt;strong data-zone-tallinn&gt;--&lt;/strong&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;span&gt;Tokyo&lt;/span&gt;
        &lt;strong data-zone-tokyo&gt;--&lt;/strong&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;span&gt;Sydney&lt;/span&gt;
        &lt;strong data-zone-sydney&gt;--&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-twentyfive-demo,
.vb-date-twentyfive-demo * {
  box-sizing: border-box;
}

.vb-date-twentyfive-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(14, 165, 233, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #ecfeff 0%, #eef2ff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-twentyfive-card {
  display: grid;
  grid-template-columns: minmax(280px, 0.85fr) minmax(0, 1.15fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-twentyfive-form,
.vb-date-twentyfive-results {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-twentyfive-form {
  display: grid;
  align-content: center;
  padding: clamp(22px, 4vw, 38px);
  background: #ffffff;
}

.vb-date-twentyfive-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-twentyfive-form h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-twentyfive-form p {
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-twentyfive-form label {
  display: grid;
  gap: 8px;
  margin-bottom: 14px;
}

.vb-date-twentyfive-form label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-twentyfive-form input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-twentyfive-form button {
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-date-twentyfive-results {
  display: grid;
  gap: 12px;
  padding: clamp(20px, 4vw, 30px);
  background:
    radial-gradient(circle at 16% 14%, rgba(34, 211, 238, 0.20), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #1e3a8a 100%) !important;
}

.vb-date-twentyfive-results div {
  min-width: 0;
  display: grid;
  gap: 7px;
  padding: 16px;
  border-radius: 20px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-twentyfive-results span {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-date-twentyfive-results strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(18px, 3vw, 26px);
  line-height: 1.25;
  font-weight: 950;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-date-twentyfive-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-twentyfive-form,
  .vb-date-twentyfive-results,
  .vb-date-twentyfive-results div {
    border-radius: 24px;
  }

  .vb-date-twentyfive-form button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript time zone converter is useful for webinar pages, international booking systems, remote team dashboards, event pages, calendar tools, meeting planners, and SaaS applications with global users.</p>



<h2 class="wp-block-heading">26. JavaScript Business Days Calculator</h2>



<p class="wp-block-paragraph"><strong>A JavaScript business days calculator</strong> is highly practical for delivery estimates, project timelines, invoice due dates, support response times, HR tools, booking systems, and admin dashboards. It calculates weekdays between two selected dates while excluding Saturdays and Sundays.</p>



<p class="wp-block-paragraph">This example lets users select a start date and an end date. JavaScript calculates total calendar days, business days, and weekend days.</p>



<ul class="wp-block-list">
<li>Calculates business days between two dates</li>
<li>Excludes weekends automatically</li>
<li>Shows total days, business days, and weekend days</li>
<li>Useful for delivery, projects, invoices, and support tools</li>
<li>Responsive and safe for mobile screens</li>
</ul>



<div class="vb-date-twentysix-demo">
  <div class="vb-date-twentysix-card" data-vb-date-twentysix>
    <div class="vb-date-twentysix-form">
      <span class="vb-date-twentysix-kicker">Example 26</span>
      <h3>Business Days Calculator</h3>
      <p>Select a start and end date to calculate business days, weekends, and total calendar days.</p>

      <div class="vb-date-twentysix-inputs">
        <label>
          <span>Start date</span>
          <input type="date" data-business-start>
        </label>

        <label>
          <span>End date</span>
          <input type="date" data-business-end>
        </label>
      </div>

      <button type="button" data-calculate-business-days>Calculate Business Days</button>
      <small data-business-error></small>
    </div>

    <div class="vb-date-twentysix-results">
      <div class="vb-date-twentysix-main">
        <span>Business days</span>
        <strong data-business-days>--</strong>
      </div>

      <div class="vb-date-twentysix-stats">
        <div>
          <span>Total days</span>
          <strong data-total-days>--</strong>
        </div>
        <div>
          <span>Weekend days</span>
          <strong data-weekend-days>--</strong>
        </div>
      </div>

      <p data-business-summary>Select dates to calculate the business day range.</p>
    </div>
  </div>
</div>

<style>
.vb-date-twentysix-demo,
.vb-date-twentysix-demo * {
  box-sizing: border-box;
}

.vb-date-twentysix-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(34, 197, 94, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(245, 158, 11, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #fffbeb 55%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-twentysix-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 420px);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-twentysix-form,
.vb-date-twentysix-results {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-twentysix-form {
  display: grid;
  align-content: center;
  padding: clamp(22px, 4vw, 38px);
  background: #ffffff;
}

.vb-date-twentysix-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-twentysix-form h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-twentysix-form p {
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-twentysix-inputs {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  margin-bottom: 14px;
}

.vb-date-twentysix-inputs label {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.vb-date-twentysix-inputs span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-twentysix-inputs input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-twentysix-form button {
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #16a34a, #f59e0b);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-date-twentysix-form small {
  display: block;
  min-height: 20px;
  margin-top: 10px;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 13px;
  line-height: 1.4;
  font-weight: 750;
}

.vb-date-twentysix-results {
  display: grid;
  align-content: center;
  gap: 14px;
  padding: clamp(20px, 4vw, 30px);
  background:
    radial-gradient(circle at 16% 14%, rgba(34, 197, 94, 0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #365314 100%) !important;
}

.vb-date-twentysix-main,
.vb-date-twentysix-stats div {
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-twentysix-main span,
.vb-date-twentysix-stats span {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-date-twentysix-main strong {
  display: block;
  margin-top: 8px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(58px, 10vw, 96px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.08em;
}

.vb-date-twentysix-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-date-twentysix-stats strong {
  display: block;
  margin-top: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 28px;
  line-height: 1;
  font-weight: 950;
}

.vb-date-twentysix-results p {
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-date-twentysix-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-twentysix-inputs,
  .vb-date-twentysix-stats {
    grid-template-columns: 1fr;
  }

  .vb-date-twentysix-form,
  .vb-date-twentysix-results,
  .vb-date-twentysix-main,
  .vb-date-twentysix-stats div {
    border-radius: 24px;
  }

  .vb-date-twentysix-form button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const calculator = document.querySelector("[data-vb-date-twentysix]");
  if (!calculator) return;

  const startInput = calculator.querySelector("[data-business-start]");
  const endInput = calculator.querySelector("[data-business-end]");
  const button = calculator.querySelector("[data-calculate-business-days]");
  const error = calculator.querySelector("[data-business-error]");

  const businessOutput = calculator.querySelector("[data-business-days]");
  const totalOutput = calculator.querySelector("[data-total-days]");
  const weekendOutput = calculator.querySelector("[data-weekend-days]");
  const summary = calculator.querySelector("[data-business-summary]");

  function formatInputDate(date) {
    return date.getFullYear() + "-" +
      String(date.getMonth() + 1).padStart(2, "0") + "-" +
      String(date.getDate()).padStart(2, "0");
  }

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function calculateBusinessDays() {
    error.textContent = "";

    if (!startInput.value || !endInput.value) {
      error.textContent = "Please select both dates.";
      return;
    }

    const startDate = createLocalDate(startInput.value);
    const endDate = createLocalDate(endInput.value);

    if (endDate < startDate) {
      error.textContent = "End date must be after the start date.";
      return;
    }

    let current = new Date(startDate);
    let totalDays = 0;
    let businessDays = 0;
    let weekendDays = 0;

    while (current <= endDate) {
      const day = current.getDay();

      totalDays += 1;

      if (day === 0 || day === 6) {
        weekendDays += 1;
      } else {
        businessDays += 1;
      }

      current.setDate(current.getDate() + 1);
    }

    businessOutput.textContent = businessDays;
    totalOutput.textContent = totalDays;
    weekendOutput.textContent = weekendDays;
    summary.textContent = "This range includes " + businessDays + " business days and " + weekendDays + " weekend days.";
  }

  function setDefaultDates() {
    const start = new Date();
    const end = new Date();

    end.setDate(start.getDate() + 14);

    startInput.value = formatInputDate(start);
    endInput.value = formatInputDate(end);

    calculateBusinessDays();
  }

  button.addEventListener("click", calculateBusinessDays);
  startInput.addEventListener("change", calculateBusinessDays);
  endInput.addEventListener("change", calculateBusinessDays);

  setDefaultDates();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const calculator = document.querySelector("[data-vb-date-twentysix]");
  if (!calculator) return;

  const startInput = calculator.querySelector("[data-business-start]");
  const endInput = calculator.querySelector("[data-business-end]");
  const button = calculator.querySelector("[data-calculate-business-days]");
  const error = calculator.querySelector("[data-business-error]");

  const businessOutput = calculator.querySelector("[data-business-days]");
  const totalOutput = calculator.querySelector("[data-total-days]");
  const weekendOutput = calculator.querySelector("[data-weekend-days]");
  const summary = calculator.querySelector("[data-business-summary]");

  function formatInputDate(date) {
    return date.getFullYear() + "-" +
      String(date.getMonth() + 1).padStart(2, "0") + "-" +
      String(date.getDate()).padStart(2, "0");
  }

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function calculateBusinessDays() {
    error.textContent = "";

    if (!startInput.value || !endInput.value) {
      error.textContent = "Please select both dates.";
      return;
    }

    const startDate = createLocalDate(startInput.value);
    const endDate = createLocalDate(endInput.value);

    if (endDate &lt; startDate) {
      error.textContent = "End date must be after the start date.";
      return;
    }

    let current = new Date(startDate);
    let totalDays = 0;
    let businessDays = 0;
    let weekendDays = 0;

    while (current &lt;= endDate) {
      const day = current.getDay();

      totalDays += 1;

      if (day === 0 || day === 6) {
        weekendDays += 1;
      } else {
        businessDays += 1;
      }

      current.setDate(current.getDate() + 1);
    }

    businessOutput.textContent = businessDays;
    totalOutput.textContent = totalDays;
    weekendOutput.textContent = weekendDays;
    summary.textContent = "This range includes " + businessDays + " business days and " + weekendDays + " weekend days.";
  }

  function setDefaultDates() {
    const start = new Date();
    const end = new Date();

    end.setDate(start.getDate() + 14);

    startInput.value = formatInputDate(start);
    endInput.value = formatInputDate(end);

    calculateBusinessDays();
  }

  button.addEventListener("click", calculateBusinessDays);
  startInput.addEventListener("change", calculateBusinessDays);
  endInput.addEventListener("change", calculateBusinessDays);

  setDefaultDates();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-twentysix-demo"&gt;
  &lt;div class="vb-date-twentysix-card" data-vb-date-twentysix&gt;
    &lt;div class="vb-date-twentysix-form"&gt;
      &lt;span class="vb-date-twentysix-kicker"&gt;Example 26&lt;/span&gt;
      &lt;h3&gt;Business Days Calculator&lt;/h3&gt;
      &lt;p&gt;Select a start and end date to calculate business days, weekends, and total calendar days.&lt;/p&gt;

      &lt;div class="vb-date-twentysix-inputs"&gt;
        &lt;label&gt;
          &lt;span&gt;Start date&lt;/span&gt;
          &lt;input type="date" data-business-start&gt;
        &lt;/label&gt;

        &lt;label&gt;
          &lt;span&gt;End date&lt;/span&gt;
          &lt;input type="date" data-business-end&gt;
        &lt;/label&gt;
      &lt;/div&gt;

      &lt;button type="button" data-calculate-business-days&gt;Calculate Business Days&lt;/button&gt;
      &lt;small data-business-error&gt;&lt;/small&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-twentysix-results"&gt;
      &lt;div class="vb-date-twentysix-main"&gt;
        &lt;span&gt;Business days&lt;/span&gt;
        &lt;strong data-business-days&gt;--&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-twentysix-stats"&gt;
        &lt;div&gt;
          &lt;span&gt;Total days&lt;/span&gt;
          &lt;strong data-total-days&gt;--&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Weekend days&lt;/span&gt;
          &lt;strong data-weekend-days&gt;--&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;p data-business-summary&gt;Select dates to calculate the business day range.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-twentysix-demo,
.vb-date-twentysix-demo * {
  box-sizing: border-box;
}

.vb-date-twentysix-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(34, 197, 94, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(245, 158, 11, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #fffbeb 55%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-twentysix-card {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 420px);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-twentysix-form,
.vb-date-twentysix-results {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-twentysix-form {
  display: grid;
  align-content: center;
  padding: clamp(22px, 4vw, 38px);
  background: #ffffff;
}

.vb-date-twentysix-kicker {
  display: inline-flex;
  justify-self: start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-twentysix-form h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-twentysix-form p {
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-twentysix-inputs {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  margin-bottom: 14px;
}

.vb-date-twentysix-inputs label {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.vb-date-twentysix-inputs span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-twentysix-inputs input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-twentysix-form button {
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #16a34a, #f59e0b);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-date-twentysix-form small {
  display: block;
  min-height: 20px;
  margin-top: 10px;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 13px;
  line-height: 1.4;
  font-weight: 750;
}

.vb-date-twentysix-results {
  display: grid;
  align-content: center;
  gap: 14px;
  padding: clamp(20px, 4vw, 30px);
  background:
    radial-gradient(circle at 16% 14%, rgba(34, 197, 94, 0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #365314 100%) !important;
}

.vb-date-twentysix-main,
.vb-date-twentysix-stats div {
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-twentysix-main span,
.vb-date-twentysix-stats span {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-date-twentysix-main strong {
  display: block;
  margin-top: 8px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(58px, 10vw, 96px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.08em;
}

.vb-date-twentysix-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-date-twentysix-stats strong {
  display: block;
  margin-top: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 28px;
  line-height: 1;
  font-weight: 950;
}

.vb-date-twentysix-results p {
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-date-twentysix-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-twentysix-inputs,
  .vb-date-twentysix-stats {
    grid-template-columns: 1fr;
  }

  .vb-date-twentysix-form,
  .vb-date-twentysix-results,
  .vb-date-twentysix-main,
  .vb-date-twentysix-stats div {
    border-radius: 24px;
  }

  .vb-date-twentysix-form button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript business days calculator is useful for delivery estimates, invoice due dates, project timelines, HR tools, support response calculators, booking systems, and admin dashboards.</p>



<h2 class="wp-block-heading">27. Add or Subtract Days from a Date</h2>



<p class="wp-block-paragraph"><strong>A JavaScript add days to date calculator</strong> is one of the most searched and practical date examples. It is useful for delivery date calculators, warranty estimators, invoice due dates, trial period calculators, subscription renewals, booking systems, and project planning tools.</p>



<p class="wp-block-paragraph">This example lets users select a base date, enter a number of days, and choose whether to add or subtract days. JavaScript calculates the final date instantly.</p>



<ul class="wp-block-list">
<li>Adds days to a selected date</li>
<li>Subtracts days from a selected date</li>
<li>Shows final date in readable and ISO formats</li>
<li>Useful for delivery, invoices, subscriptions, warranties, and project tools</li>
<li>Responsive calculator layout</li>
</ul>



<div class="vb-date-twentyseven-demo">
  <div class="vb-date-twentyseven-card" data-vb-date-twentyseven>
    <div class="vb-date-twentyseven-form">
      <span class="vb-date-twentyseven-kicker">Example 27</span>
      <h3>Add or Subtract Days</h3>
      <p>Select a base date, enter a number of days, and calculate the final date.</p>

      <label>
        <span>Base date</span>
        <input type="date" data-base-date>
      </label>

      <label>
        <span>Number of days</span>
        <input type="number" min="0" value="30" data-day-amount>
      </label>

      <div class="vb-date-twentyseven-actions">
        <button type="button" data-add-days>Add Days</button>
        <button type="button" data-subtract-days>Subtract Days</button>
      </div>
    </div>

    <div class="vb-date-twentyseven-result">
      <div class="vb-date-twentyseven-main">
        <span>Final date</span>
        <strong data-final-readable>--</strong>
      </div>

      <div class="vb-date-twentyseven-mini">
        <div>
          <span>ISO format</span>
          <strong data-final-iso>--</strong>
        </div>
        <div>
          <span>Operation</span>
          <strong data-final-operation>--</strong>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-date-twentyseven-demo,
.vb-date-twentyseven-demo * {
  box-sizing: border-box;
}

.vb-date-twentyseven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(236, 72, 153, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(124, 58, 237, 0.16), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #f5f3ff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(236, 72, 153, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-twentyseven-card {
  display: grid;
  grid-template-columns: minmax(280px, 0.85fr) minmax(0, 1.15fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-twentyseven-form,
.vb-date-twentyseven-result {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-twentyseven-form {
  display: grid;
  align-content: center;
  gap: 14px;
  padding: clamp(22px, 4vw, 38px);
  background: #ffffff;
}

.vb-date-twentyseven-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fce7f3;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-twentyseven-form h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-twentyseven-form p {
  margin: 0 0 8px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-twentyseven-form label {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.vb-date-twentyseven-form label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-twentyseven-form input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-twentyseven-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.vb-date-twentyseven-actions button {
  flex: 1;
  min-width: 140px;
  min-height: 48px;
  padding: 12px 16px;
  border: 0;
  border-radius: 999px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-date-twentyseven-actions button:first-child {
  background: linear-gradient(135deg, #db2777, #7c3aed);
}

.vb-date-twentyseven-actions button:last-child {
  background: linear-gradient(135deg, #0f172a, #475569);
}

.vb-date-twentyseven-result {
  display: grid;
  align-content: center;
  gap: 14px;
  padding: clamp(20px, 4vw, 30px);
  background:
    radial-gradient(circle at 16% 14%, rgba(236, 72, 153, 0.22), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #831843 100%) !important;
}

.vb-date-twentyseven-main,
.vb-date-twentyseven-mini div {
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-twentyseven-main span,
.vb-date-twentyseven-mini span {
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-date-twentyseven-main strong {
  display: block;
  margin-top: 8px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 5vw, 54px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
  overflow-wrap: anywhere;
}

.vb-date-twentyseven-mini {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-date-twentyseven-mini strong {
  display: block;
  margin-top: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-date-twentyseven-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-twentyseven-form,
  .vb-date-twentyseven-result,
  .vb-date-twentyseven-main,
  .vb-date-twentyseven-mini div {
    border-radius: 24px;
  }

  .vb-date-twentyseven-actions,
  .vb-date-twentyseven-mini {
    grid-template-columns: 1fr;
    display: grid;
  }

  .vb-date-twentyseven-actions button {
    width: 100%;
    min-width: 0;
  }
}
</style>

<script>
(function () {
  const calculator = document.querySelector("[data-vb-date-twentyseven]");
  if (!calculator) return;

  const baseInput = calculator.querySelector("[data-base-date]");
  const amountInput = calculator.querySelector("[data-day-amount]");
  const addButton = calculator.querySelector("[data-add-days]");
  const subtractButton = calculator.querySelector("[data-subtract-days]");

  const readableOutput = calculator.querySelector("[data-final-readable]");
  const isoOutput = calculator.querySelector("[data-final-iso]");
  const operationOutput = calculator.querySelector("[data-final-operation]");

  function formatInputDate(date) {
    return date.getFullYear() + "-" +
      String(date.getMonth() + 1).padStart(2, "0") + "-" +
      String(date.getDate()).padStart(2, "0");
  }

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function formatReadableDate(date) {
    return new Intl.DateTimeFormat("en", {
      weekday: "long",
      month: "long",
      day: "numeric",
      year: "numeric"
    }).format(date);
  }

  function calculateDate(direction) {
    if (!baseInput.value) return;

    const amount = Math.max(0, Number(amountInput.value || 0));
    const baseDate = createLocalDate(baseInput.value);
    const resultDate = new Date(baseDate);

    if (direction === "add") {
      resultDate.setDate(resultDate.getDate() + amount);
      operationOutput.textContent = "+" + amount + " days";
    } else {
      resultDate.setDate(resultDate.getDate() - amount);
      operationOutput.textContent = "-" + amount + " days";
    }

    readableOutput.textContent = formatReadableDate(resultDate);
    isoOutput.textContent = formatInputDate(resultDate);
  }

  baseInput.value = formatInputDate(new Date());

  addButton.addEventListener("click", function () {
    calculateDate("add");
  });

  subtractButton.addEventListener("click", function () {
    calculateDate("subtract");
  });

  baseInput.addEventListener("change", function () {
    calculateDate("add");
  });

  amountInput.addEventListener("input", function () {
    calculateDate("add");
  });

  calculateDate("add");
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const calculator = document.querySelector("[data-vb-date-twentyseven]");
  if (!calculator) return;

  const baseInput = calculator.querySelector("[data-base-date]");
  const amountInput = calculator.querySelector("[data-day-amount]");
  const addButton = calculator.querySelector("[data-add-days]");
  const subtractButton = calculator.querySelector("[data-subtract-days]");

  const readableOutput = calculator.querySelector("[data-final-readable]");
  const isoOutput = calculator.querySelector("[data-final-iso]");
  const operationOutput = calculator.querySelector("[data-final-operation]");

  function formatInputDate(date) {
    return date.getFullYear() + "-" +
      String(date.getMonth() + 1).padStart(2, "0") + "-" +
      String(date.getDate()).padStart(2, "0");
  }

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function formatReadableDate(date) {
    return new Intl.DateTimeFormat("en", {
      weekday: "long",
      month: "long",
      day: "numeric",
      year: "numeric"
    }).format(date);
  }

  function calculateDate(direction) {
    if (!baseInput.value) return;

    const amount = Math.max(0, Number(amountInput.value || 0));
    const baseDate = createLocalDate(baseInput.value);
    const resultDate = new Date(baseDate);

    if (direction === "add") {
      resultDate.setDate(resultDate.getDate() + amount);
      operationOutput.textContent = "+" + amount + " days";
    } else {
      resultDate.setDate(resultDate.getDate() - amount);
      operationOutput.textContent = "-" + amount + " days";
    }

    readableOutput.textContent = formatReadableDate(resultDate);
    isoOutput.textContent = formatInputDate(resultDate);
  }

  baseInput.value = formatInputDate(new Date());

  addButton.addEventListener("click", function () {
    calculateDate("add");
  });

  subtractButton.addEventListener("click", function () {
    calculateDate("subtract");
  });

  baseInput.addEventListener("change", function () {
    calculateDate("add");
  });

  amountInput.addEventListener("input", function () {
    calculateDate("add");
  });

  calculateDate("add");
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-twentyseven-demo"&gt;
  &lt;div class="vb-date-twentyseven-card" data-vb-date-twentyseven&gt;
    &lt;div class="vb-date-twentyseven-form"&gt;
      &lt;span class="vb-date-twentyseven-kicker"&gt;Example 27&lt;/span&gt;
      &lt;h3&gt;Add or Subtract Days&lt;/h3&gt;
      &lt;p&gt;Select a base date, enter a number of days, and calculate the final date.&lt;/p&gt;

      &lt;label&gt;
        &lt;span&gt;Base date&lt;/span&gt;
        &lt;input type="date" data-base-date&gt;
      &lt;/label&gt;

      &lt;label&gt;
        &lt;span&gt;Number of days&lt;/span&gt;
        &lt;input type="number" min="0" value="30" data-day-amount&gt;
      &lt;/label&gt;

      &lt;div class="vb-date-twentyseven-actions"&gt;
        &lt;button type="button" data-add-days&gt;Add Days&lt;/button&gt;
        &lt;button type="button" data-subtract-days&gt;Subtract Days&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-twentyseven-result"&gt;
      &lt;div class="vb-date-twentyseven-main"&gt;
        &lt;span&gt;Final date&lt;/span&gt;
        &lt;strong data-final-readable&gt;--&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-twentyseven-mini"&gt;
        &lt;div&gt;
          &lt;span&gt;ISO format&lt;/span&gt;
          &lt;strong data-final-iso&gt;--&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Operation&lt;/span&gt;
          &lt;strong data-final-operation&gt;--&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-twentyseven-demo,
.vb-date-twentyseven-demo * {
  box-sizing: border-box;
}

.vb-date-twentyseven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(236, 72, 153, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(124, 58, 237, 0.16), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #f5f3ff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(236, 72, 153, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-twentyseven-card {
  display: grid;
  grid-template-columns: minmax(280px, 0.85fr) minmax(0, 1.15fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-twentyseven-form,
.vb-date-twentyseven-result {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-twentyseven-form {
  display: grid;
  align-content: center;
  gap: 14px;
  padding: clamp(22px, 4vw, 38px);
  background: #ffffff;
}

.vb-date-twentyseven-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fce7f3;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-twentyseven-form h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-twentyseven-form p {
  margin: 0 0 8px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-twentyseven-form label {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.vb-date-twentyseven-form label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-twentyseven-form input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-twentyseven-actions {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.vb-date-twentyseven-actions button {
  flex: 1;
  min-width: 140px;
  min-height: 48px;
  padding: 12px 16px;
  border: 0;
  border-radius: 999px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-date-twentyseven-actions button:first-child {
  background: linear-gradient(135deg, #db2777, #7c3aed);
}

.vb-date-twentyseven-actions button:last-child {
  background: linear-gradient(135deg, #0f172a, #475569);
}

.vb-date-twentyseven-result {
  display: grid;
  align-content: center;
  gap: 14px;
  padding: clamp(20px, 4vw, 30px);
  background:
    radial-gradient(circle at 16% 14%, rgba(236, 72, 153, 0.22), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #831843 100%) !important;
}

.vb-date-twentyseven-main,
.vb-date-twentyseven-mini div {
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-twentyseven-main span,
.vb-date-twentyseven-mini span {
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-date-twentyseven-main strong {
  display: block;
  margin-top: 8px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 5vw, 54px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
  overflow-wrap: anywhere;
}

.vb-date-twentyseven-mini {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-date-twentyseven-mini strong {
  display: block;
  margin-top: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-date-twentyseven-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-twentyseven-form,
  .vb-date-twentyseven-result,
  .vb-date-twentyseven-main,
  .vb-date-twentyseven-mini div {
    border-radius: 24px;
  }

  .vb-date-twentyseven-actions,
  .vb-date-twentyseven-mini {
    grid-template-columns: 1fr;
    display: grid;
  }

  .vb-date-twentyseven-actions button {
    width: 100%;
    min-width: 0;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript add or subtract days calculator is useful for delivery date calculators, invoice due date tools, warranty calculators, subscription renewal dates, booking systems, trial period calculators, and project planning dashboards.</p>



<h2 class="wp-block-heading">28. JavaScript Age Calculator from Date of Birth</h2>



<p class="wp-block-paragraph"><strong>A JavaScript age calculator</strong> is one of the most practical date examples for forms, registration pages, profile tools, healthcare forms, insurance calculators, HR systems, and user dashboards. It calculates a user’s exact age from their date of birth.</p>



<p class="wp-block-paragraph">This example lets users select a birth date and calculates years, months, and days. JavaScript also validates that the selected date is not in the future.</p>



<ul class="wp-block-list">
<li>Calculates age from date of birth</li>
<li>Shows years, months, and days</li>
<li>Validates future dates</li>
<li>Useful for forms, profiles, registration pages, and calculators</li>
<li>Responsive card layout</li>
</ul>



<div class="vb-date-twentyeight-demo">
  <div class="vb-date-twentyeight-card" data-vb-date-twentyeight>
    <div class="vb-date-twentyeight-form">
      <span class="vb-date-twentyeight-kicker">Example 28</span>
      <h3>Age Calculator</h3>
      <p>Select a date of birth and JavaScript calculates the exact age in years, months, and days.</p>

      <label>
        <span>Date of birth</span>
        <input type="date" data-birth-date>
      </label>

      <button type="button" data-calculate-age>Calculate Age</button>
      <small data-age-error></small>
    </div>

    <div class="vb-date-twentyeight-results">
      <div class="vb-date-twentyeight-main">
        <span>Calculated age</span>
        <strong data-age-summary>--</strong>
      </div>

      <div class="vb-date-twentyeight-grid">
        <div>
          <span>Years</span>
          <strong data-age-years>--</strong>
        </div>
        <div>
          <span>Months</span>
          <strong data-age-months>--</strong>
        </div>
        <div>
          <span>Days</span>
          <strong data-age-days>--</strong>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-date-twentyeight-demo,
.vb-date-twentyeight-demo * {
  box-sizing: border-box;
}

.vb-date-twentyeight-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(59, 130, 246, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #f0fdf4 55%, #ffffff 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-twentyeight-card {
  display: grid;
  grid-template-columns: minmax(280px, 0.85fr) minmax(0, 1.15fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-twentyeight-form,
.vb-date-twentyeight-results {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-twentyeight-form {
  display: grid;
  align-content: center;
  gap: 14px;
  padding: clamp(22px, 4vw, 38px);
  background: #ffffff;
}

.vb-date-twentyeight-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-twentyeight-form h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-twentyeight-form p {
  margin: 0 0 8px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-twentyeight-form label {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.vb-date-twentyeight-form label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-twentyeight-form input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-twentyeight-form button {
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #16a34a);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-date-twentyeight-form small {
  min-height: 20px;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 13px;
  line-height: 1.4;
  font-weight: 750;
}

.vb-date-twentyeight-results {
  display: grid;
  align-content: center;
  gap: 14px;
  padding: clamp(20px, 4vw, 30px);
  background:
    radial-gradient(circle at 16% 14%, rgba(34, 197, 94, 0.20), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #14532d 100%) !important;
}

.vb-date-twentyeight-main,
.vb-date-twentyeight-grid div {
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-twentyeight-main span,
.vb-date-twentyeight-grid span {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-date-twentyeight-main strong {
  display: block;
  margin-top: 8px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 5vw, 54px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
  overflow-wrap: anywhere;
}

.vb-date-twentyeight-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-date-twentyeight-grid strong {
  display: block;
  margin-top: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 32px;
  line-height: 1;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vb-date-twentyeight-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-twentyeight-form,
  .vb-date-twentyeight-results,
  .vb-date-twentyeight-main,
  .vb-date-twentyeight-grid div {
    border-radius: 24px;
  }

  .vb-date-twentyeight-grid {
    grid-template-columns: 1fr;
  }

  .vb-date-twentyeight-form button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const calculator = document.querySelector("[data-vb-date-twentyeight]");
  if (!calculator) return;

  const birthInput = calculator.querySelector("[data-birth-date]");
  const button = calculator.querySelector("[data-calculate-age]");
  const error = calculator.querySelector("[data-age-error]");

  const summary = calculator.querySelector("[data-age-summary]");
  const yearsOutput = calculator.querySelector("[data-age-years]");
  const monthsOutput = calculator.querySelector("[data-age-months]");
  const daysOutput = calculator.querySelector("[data-age-days]");

  function formatInputDate(date) {
    return date.getFullYear() + "-" +
      String(date.getMonth() + 1).padStart(2, "0") + "-" +
      String(date.getDate()).padStart(2, "0");
  }

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function calculateAge() {
    error.textContent = "";

    if (!birthInput.value) {
      error.textContent = "Please select a date of birth.";
      return;
    }

    const birthDate = createLocalDate(birthInput.value);
    const today = new Date();

    birthDate.setHours(0, 0, 0, 0);
    today.setHours(0, 0, 0, 0);

    if (birthDate > today) {
      error.textContent = "Birth date cannot be in the future.";
      return;
    }

    let years = today.getFullYear() - birthDate.getFullYear();
    let months = today.getMonth() - birthDate.getMonth();
    let days = today.getDate() - birthDate.getDate();

    if (days < 0) {
      months -= 1;
      const previousMonth = new Date(today.getFullYear(), today.getMonth(), 0);
      days += previousMonth.getDate();
    }

    if (months < 0) {
      years -= 1;
      months += 12;
    }

    yearsOutput.textContent = years;
    monthsOutput.textContent = months;
    daysOutput.textContent = days;
    summary.textContent = years + " years, " + months + " months, " + days + " days";
  }

  const defaultDate = new Date();
  defaultDate.setFullYear(defaultDate.getFullYear() - 25);
  birthInput.value = formatInputDate(defaultDate);

  button.addEventListener("click", calculateAge);
  birthInput.addEventListener("change", calculateAge);

  calculateAge();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const calculator = document.querySelector("[data-vb-date-twentyeight]");
  if (!calculator) return;

  const birthInput = calculator.querySelector("[data-birth-date]");
  const button = calculator.querySelector("[data-calculate-age]");
  const error = calculator.querySelector("[data-age-error]");

  const summary = calculator.querySelector("[data-age-summary]");
  const yearsOutput = calculator.querySelector("[data-age-years]");
  const monthsOutput = calculator.querySelector("[data-age-months]");
  const daysOutput = calculator.querySelector("[data-age-days]");

  function formatInputDate(date) {
    return date.getFullYear() + "-" +
      String(date.getMonth() + 1).padStart(2, "0") + "-" +
      String(date.getDate()).padStart(2, "0");
  }

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function calculateAge() {
    error.textContent = "";

    if (!birthInput.value) {
      error.textContent = "Please select a date of birth.";
      return;
    }

    const birthDate = createLocalDate(birthInput.value);
    const today = new Date();

    birthDate.setHours(0, 0, 0, 0);
    today.setHours(0, 0, 0, 0);

    if (birthDate &gt; today) {
      error.textContent = "Birth date cannot be in the future.";
      return;
    }

    let years = today.getFullYear() - birthDate.getFullYear();
    let months = today.getMonth() - birthDate.getMonth();
    let days = today.getDate() - birthDate.getDate();

    if (days &lt; 0) {
      months -= 1;
      const previousMonth = new Date(today.getFullYear(), today.getMonth(), 0);
      days += previousMonth.getDate();
    }

    if (months &lt; 0) {
      years -= 1;
      months += 12;
    }

    yearsOutput.textContent = years;
    monthsOutput.textContent = months;
    daysOutput.textContent = days;
    summary.textContent = years + " years, " + months + " months, " + days + " days";
  }

  const defaultDate = new Date();
  defaultDate.setFullYear(defaultDate.getFullYear() - 25);
  birthInput.value = formatInputDate(defaultDate);

  button.addEventListener("click", calculateAge);
  birthInput.addEventListener("change", calculateAge);

  calculateAge();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-twentyeight-demo"&gt;
  &lt;div class="vb-date-twentyeight-card" data-vb-date-twentyeight&gt;
    &lt;div class="vb-date-twentyeight-form"&gt;
      &lt;span class="vb-date-twentyeight-kicker"&gt;Example 28&lt;/span&gt;
      &lt;h3&gt;Age Calculator&lt;/h3&gt;
      &lt;p&gt;Select a date of birth and JavaScript calculates the exact age in years, months, and days.&lt;/p&gt;

      &lt;label&gt;
        &lt;span&gt;Date of birth&lt;/span&gt;
        &lt;input type="date" data-birth-date&gt;
      &lt;/label&gt;

      &lt;button type="button" data-calculate-age&gt;Calculate Age&lt;/button&gt;
      &lt;small data-age-error&gt;&lt;/small&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-twentyeight-results"&gt;
      &lt;div class="vb-date-twentyeight-main"&gt;
        &lt;span&gt;Calculated age&lt;/span&gt;
        &lt;strong data-age-summary&gt;--&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-twentyeight-grid"&gt;
        &lt;div&gt;
          &lt;span&gt;Years&lt;/span&gt;
          &lt;strong data-age-years&gt;--&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Months&lt;/span&gt;
          &lt;strong data-age-months&gt;--&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Days&lt;/span&gt;
          &lt;strong data-age-days&gt;--&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-twentyeight-demo,
.vb-date-twentyeight-demo * {
  box-sizing: border-box;
}

.vb-date-twentyeight-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(59, 130, 246, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #f0fdf4 55%, #ffffff 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-twentyeight-card {
  display: grid;
  grid-template-columns: minmax(280px, 0.85fr) minmax(0, 1.15fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-twentyeight-form,
.vb-date-twentyeight-results {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-twentyeight-form {
  display: grid;
  align-content: center;
  gap: 14px;
  padding: clamp(22px, 4vw, 38px);
  background: #ffffff;
}

.vb-date-twentyeight-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-twentyeight-form h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-twentyeight-form p {
  margin: 0 0 8px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-twentyeight-form label {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.vb-date-twentyeight-form label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-twentyeight-form input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-twentyeight-form button {
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #16a34a);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-date-twentyeight-form small {
  min-height: 20px;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 13px;
  line-height: 1.4;
  font-weight: 750;
}

.vb-date-twentyeight-results {
  display: grid;
  align-content: center;
  gap: 14px;
  padding: clamp(20px, 4vw, 30px);
  background:
    radial-gradient(circle at 16% 14%, rgba(34, 197, 94, 0.20), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #14532d 100%) !important;
}

.vb-date-twentyeight-main,
.vb-date-twentyeight-grid div {
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-twentyeight-main span,
.vb-date-twentyeight-grid span {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-date-twentyeight-main strong {
  display: block;
  margin-top: 8px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 5vw, 54px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
  overflow-wrap: anywhere;
}

.vb-date-twentyeight-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-date-twentyeight-grid strong {
  display: block;
  margin-top: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 32px;
  line-height: 1;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vb-date-twentyeight-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-twentyeight-form,
  .vb-date-twentyeight-results,
  .vb-date-twentyeight-main,
  .vb-date-twentyeight-grid div {
    border-radius: 24px;
  }

  .vb-date-twentyeight-grid {
    grid-template-columns: 1fr;
  }

  .vb-date-twentyeight-form button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript age calculator is useful for signup forms, profile pages, HR tools, insurance calculators, healthcare forms, registration pages, user dashboards, and date of birth validation examples.</p>



<h2 class="wp-block-heading">29. JavaScript Relative Time Formatter</h2>



<p class="wp-block-paragraph"><strong>A JavaScript relative time formatter</strong> is a highly practical date and time example for blogs, comments, notifications, dashboards, activity feeds, chat apps, and social interfaces. It turns dates into readable labels like “5 minutes ago” or “in 2 days”.</p>



<p class="wp-block-paragraph">This example lets users select a date and time, then JavaScript calculates whether that time is in the past or future and formats it as a human-friendly relative time label.</p>



<ul class="wp-block-list">
<li>Formats dates as relative time</li>
<li>Supports past and future dates</li>
<li>Uses minutes, hours, days, weeks, months, and years</li>
<li>Useful for comments, posts, notifications, and dashboards</li>
<li>Responsive UI with live output</li>
</ul>



<div class="vb-date-twentynine-demo">
  <div class="vb-date-twentynine-card" data-vb-date-twentynine>
    <div class="vb-date-twentynine-form">
      <span class="vb-date-twentynine-kicker">Example 29</span>
      <h3>Relative Time Formatter</h3>
      <p>Select a date and time to convert it into a human-friendly relative time label.</p>

      <label>
        <span>Date and time</span>
        <input type="datetime-local" data-relative-input>
      </label>

      <button type="button" data-format-relative>Format Relative Time</button>
    </div>

    <div class="vb-date-twentynine-output">
      <div>
        <span>Relative time</span>
        <strong data-relative-label>--</strong>
      </div>

      <p data-relative-details>Select a date and time to generate a relative time label.</p>
    </div>
  </div>
</div>

<style>
.vb-date-twentynine-demo,
.vb-date-twentynine-demo * {
  box-sizing: border-box;
}

.vb-date-twentynine-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(168, 85, 247, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #ecfeff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-twentynine-card {
  display: grid;
  grid-template-columns: minmax(280px, 0.9fr) minmax(0, 1.1fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-twentynine-form,
.vb-date-twentynine-output {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-twentynine-form {
  display: grid;
  align-content: center;
  gap: 14px;
  padding: clamp(22px, 4vw, 38px);
  background: #ffffff;
}

.vb-date-twentynine-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-twentynine-form h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-twentynine-form p {
  margin: 0 0 8px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-twentynine-form label {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.vb-date-twentynine-form label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-twentynine-form input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-twentynine-form button {
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #7c3aed, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-date-twentynine-output {
  display: grid;
  align-content: center;
  gap: 14px;
  padding: clamp(20px, 4vw, 30px);
  background:
    radial-gradient(circle at 16% 14%, rgba(168, 85, 247, 0.22), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #312e81 100%) !important;
}

.vb-date-twentynine-output div {
  min-width: 0;
  padding: 22px;
  border-radius: 24px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-twentynine-output span {
  color: #c4b5fd !important;
  -webkit-text-fill-color: #c4b5fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-date-twentynine-output strong {
  display: block;
  margin-top: 8px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 6vw, 66px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.065em;
  overflow-wrap: anywhere;
}

.vb-date-twentynine-output p {
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-date-twentynine-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-twentynine-form,
  .vb-date-twentynine-output,
  .vb-date-twentynine-output div {
    border-radius: 24px;
  }

  .vb-date-twentynine-form button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const formatter = document.querySelector("[data-vb-date-twentynine]");
  if (!formatter) return;

  const input = formatter.querySelector("[data-relative-input]");
  const button = formatter.querySelector("[data-format-relative]");
  const label = formatter.querySelector("[data-relative-label]");
  const details = formatter.querySelector("[data-relative-details]");

  function getLocalDateTimeValue(date) {
    return date.getFullYear() + "-" +
      String(date.getMonth() + 1).padStart(2, "0") + "-" +
      String(date.getDate()).padStart(2, "0") + "T" +
      String(date.getHours()).padStart(2, "0") + ":" +
      String(date.getMinutes()).padStart(2, "0");
  }

  function getRelativeTime(date) {
    const now = new Date();
    const diffSeconds = Math.round((date - now) / 1000);
    const absSeconds = Math.abs(diffSeconds);

    const units = [
      { name: "year", seconds: 31536000 },
      { name: "month", seconds: 2592000 },
      { name: "week", seconds: 604800 },
      { name: "day", seconds: 86400 },
      { name: "hour", seconds: 3600 },
      { name: "minute", seconds: 60 },
      { name: "second", seconds: 1 }
    ];

    for (let i = 0; i < units.length; i += 1) {
      const unit = units[i];

      if (absSeconds >= unit.seconds || unit.name === "second") {
        const value = Math.round(diffSeconds / unit.seconds);
        return new Intl.RelativeTimeFormat("en", { numeric: "auto" }).format(value, unit.name);
      }
    }
  }

  function formatRelativeTime() {
    if (!input.value) return;

    const selectedDate = new Date(input.value);
    const readableDate = new Intl.DateTimeFormat("en", {
      month: "long",
      day: "numeric",
      year: "numeric",
      hour: "2-digit",
      minute: "2-digit"
    }).format(selectedDate);

    label.textContent = getRelativeTime(selectedDate);
    details.textContent = "Selected date: " + readableDate;
  }

  const defaultDate = new Date();
  defaultDate.setHours(defaultDate.getHours() - 3);

  input.value = getLocalDateTimeValue(defaultDate);

  button.addEventListener("click", formatRelativeTime);
  input.addEventListener("change", formatRelativeTime);

  formatRelativeTime();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const formatter = document.querySelector("[data-vb-date-twentynine]");
  if (!formatter) return;

  const input = formatter.querySelector("[data-relative-input]");
  const button = formatter.querySelector("[data-format-relative]");
  const label = formatter.querySelector("[data-relative-label]");
  const details = formatter.querySelector("[data-relative-details]");

  function getLocalDateTimeValue(date) {
    return date.getFullYear() + "-" +
      String(date.getMonth() + 1).padStart(2, "0") + "-" +
      String(date.getDate()).padStart(2, "0") + "T" +
      String(date.getHours()).padStart(2, "0") + ":" +
      String(date.getMinutes()).padStart(2, "0");
  }

  function getRelativeTime(date) {
    const now = new Date();
    const diffSeconds = Math.round((date - now) / 1000);
    const absSeconds = Math.abs(diffSeconds);

    const units = [
      { name: "year", seconds: 31536000 },
      { name: "month", seconds: 2592000 },
      { name: "week", seconds: 604800 },
      { name: "day", seconds: 86400 },
      { name: "hour", seconds: 3600 },
      { name: "minute", seconds: 60 },
      { name: "second", seconds: 1 }
    ];

    for (let i = 0; i &lt; units.length; i += 1) {
      const unit = units[i];

      if (absSeconds &gt;= unit.seconds || unit.name === "second") {
        const value = Math.round(diffSeconds / unit.seconds);
        return new Intl.RelativeTimeFormat("en", { numeric: "auto" }).format(value, unit.name);
      }
    }
  }

  function formatRelativeTime() {
    if (!input.value) return;

    const selectedDate = new Date(input.value);
    const readableDate = new Intl.DateTimeFormat("en", {
      month: "long",
      day: "numeric",
      year: "numeric",
      hour: "2-digit",
      minute: "2-digit"
    }).format(selectedDate);

    label.textContent = getRelativeTime(selectedDate);
    details.textContent = "Selected date: " + readableDate;
  }

  const defaultDate = new Date();
  defaultDate.setHours(defaultDate.getHours() - 3);

  input.value = getLocalDateTimeValue(defaultDate);

  button.addEventListener("click", formatRelativeTime);
  input.addEventListener("change", formatRelativeTime);

  formatRelativeTime();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-twentynine-demo"&gt;
  &lt;div class="vb-date-twentynine-card" data-vb-date-twentynine&gt;
    &lt;div class="vb-date-twentynine-form"&gt;
      &lt;span class="vb-date-twentynine-kicker"&gt;Example 29&lt;/span&gt;
      &lt;h3&gt;Relative Time Formatter&lt;/h3&gt;
      &lt;p&gt;Select a date and time to convert it into a human-friendly relative time label.&lt;/p&gt;

      &lt;label&gt;
        &lt;span&gt;Date and time&lt;/span&gt;
        &lt;input type="datetime-local" data-relative-input&gt;
      &lt;/label&gt;

      &lt;button type="button" data-format-relative&gt;Format Relative Time&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-twentynine-output"&gt;
      &lt;div&gt;
        &lt;span&gt;Relative time&lt;/span&gt;
        &lt;strong data-relative-label&gt;--&lt;/strong&gt;
      &lt;/div&gt;

      &lt;p data-relative-details&gt;Select a date and time to generate a relative time label.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-twentynine-demo,
.vb-date-twentynine-demo * {
  box-sizing: border-box;
}

.vb-date-twentynine-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(168, 85, 247, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #ecfeff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-twentynine-card {
  display: grid;
  grid-template-columns: minmax(280px, 0.9fr) minmax(0, 1.1fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-twentynine-form,
.vb-date-twentynine-output {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-twentynine-form {
  display: grid;
  align-content: center;
  gap: 14px;
  padding: clamp(22px, 4vw, 38px);
  background: #ffffff;
}

.vb-date-twentynine-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-twentynine-form h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-twentynine-form p {
  margin: 0 0 8px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-twentynine-form label {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.vb-date-twentynine-form label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-twentynine-form input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-twentynine-form button {
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #7c3aed, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-date-twentynine-output {
  display: grid;
  align-content: center;
  gap: 14px;
  padding: clamp(20px, 4vw, 30px);
  background:
    radial-gradient(circle at 16% 14%, rgba(168, 85, 247, 0.22), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #312e81 100%) !important;
}

.vb-date-twentynine-output div {
  min-width: 0;
  padding: 22px;
  border-radius: 24px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-twentynine-output span {
  color: #c4b5fd !important;
  -webkit-text-fill-color: #c4b5fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-date-twentynine-output strong {
  display: block;
  margin-top: 8px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 6vw, 66px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.065em;
  overflow-wrap: anywhere;
}

.vb-date-twentynine-output p {
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-date-twentynine-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-twentynine-form,
  .vb-date-twentynine-output,
  .vb-date-twentynine-output div {
    border-radius: 24px;
  }

  .vb-date-twentynine-form button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript relative time formatter is useful for blogs, comment sections, notification systems, activity feeds, chat interfaces, admin dashboards, social UI components, and content timestamps.</p>



<h2 class="wp-block-heading">30. JavaScript Week Number Calculator</h2>



<p class="wp-block-paragraph"><strong>A JavaScript week number calculator</strong> is useful for project planning, work schedules, reporting dashboards, booking systems, content calendars, payroll tools, logistics tools, and business applications. It calculates the ISO week number for a selected date.</p>



<p class="wp-block-paragraph">This example lets users select any date and JavaScript calculates the ISO week number, year, weekday, and readable date label.</p>



<ul class="wp-block-list">
<li>Calculates ISO week number</li>
<li>Shows selected weekday and ISO year</li>
<li>Useful for planning, logistics, dashboards, and reporting</li>
<li>Responsive result layout</li>
<li>Practical JavaScript date calculation example</li>
</ul>



<div class="vb-date-thirty-demo">
  <div class="vb-date-thirty-card" data-vb-date-thirty>
    <div class="vb-date-thirty-form">
      <span class="vb-date-thirty-kicker">Example 30</span>
      <h3>Week Number Calculator</h3>
      <p>Select a date and JavaScript calculates the ISO week number and related date details.</p>

      <label>
        <span>Select date</span>
        <input type="date" data-week-date>
      </label>

      <button type="button" data-calculate-week>Calculate Week Number</button>
    </div>

    <div class="vb-date-thirty-results">
      <div class="vb-date-thirty-main">
        <span>ISO week number</span>
        <strong data-week-number>--</strong>
      </div>

      <div class="vb-date-thirty-grid">
        <div>
          <span>ISO year</span>
          <strong data-week-year>--</strong>
        </div>
        <div>
          <span>Weekday</span>
          <strong data-weekday-name>--</strong>
        </div>
      </div>

      <p data-week-summary>Select a date to calculate its week number.</p>
    </div>
  </div>
</div>

<style>
.vb-date-thirty-demo,
.vb-date-thirty-demo * {
  box-sizing: border-box;
}

.vb-date-thirty-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(245, 158, 11, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(239, 68, 68, 0.14), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fef2f2 55%, #ffffff 100%) !important;
  border: 1px solid rgba(245, 158, 11, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-thirty-card {
  display: grid;
  grid-template-columns: minmax(280px, 0.85fr) minmax(0, 1.15fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-thirty-form,
.vb-date-thirty-results {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-thirty-form {
  display: grid;
  align-content: center;
  gap: 14px;
  padding: clamp(22px, 4vw, 38px);
  background: #ffffff;
}

.vb-date-thirty-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fef3c7;
  color: #b45309 !important;
  -webkit-text-fill-color: #b45309 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-thirty-form h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-thirty-form p {
  margin: 0 0 8px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-thirty-form label {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.vb-date-thirty-form label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-thirty-form input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-thirty-form button {
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #f59e0b, #ef4444);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-date-thirty-results {
  display: grid;
  align-content: center;
  gap: 14px;
  padding: clamp(20px, 4vw, 30px);
  background:
    radial-gradient(circle at 16% 14%, rgba(251, 191, 36, 0.20), transparent 34%),
    linear-gradient(135deg, #111827 0%, #7c2d12 100%) !important;
}

.vb-date-thirty-main,
.vb-date-thirty-grid div {
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-thirty-main span,
.vb-date-thirty-grid span {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-date-thirty-main strong {
  display: block;
  margin-top: 8px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(70px, 12vw, 120px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.08em;
}

.vb-date-thirty-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-date-thirty-grid strong {
  display: block;
  margin-top: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  line-height: 1.15;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-date-thirty-results p {
  margin: 0 !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-date-thirty-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-thirty-form,
  .vb-date-thirty-results,
  .vb-date-thirty-main,
  .vb-date-thirty-grid div {
    border-radius: 24px;
  }

  .vb-date-thirty-grid {
    grid-template-columns: 1fr;
  }

  .vb-date-thirty-form button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const calculator = document.querySelector("[data-vb-date-thirty]");
  if (!calculator) return;

  const input = calculator.querySelector("[data-week-date]");
  const button = calculator.querySelector("[data-calculate-week]");

  const weekNumber = calculator.querySelector("[data-week-number]");
  const weekYear = calculator.querySelector("[data-week-year]");
  const weekdayName = calculator.querySelector("[data-weekday-name]");
  const summary = calculator.querySelector("[data-week-summary]");

  function formatInputDate(date) {
    return date.getFullYear() + "-" +
      String(date.getMonth() + 1).padStart(2, "0") + "-" +
      String(date.getDate()).padStart(2, "0");
  }

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function getISOWeekData(date) {
    const target = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
    const dayNumber = target.getUTCDay() || 7;

    target.setUTCDate(target.getUTCDate() + 4 - dayNumber);

    const isoYear = target.getUTCFullYear();
    const yearStart = new Date(Date.UTC(isoYear, 0, 1));
    const isoWeek = Math.ceil((((target - yearStart) / 86400000) + 1) / 7);

    return {
      week: isoWeek,
      year: isoYear
    };
  }

  function calculateWeekNumber() {
    if (!input.value) return;

    const selectedDate = createLocalDate(input.value);
    const weekData = getISOWeekData(selectedDate);

    weekNumber.textContent = weekData.week;
    weekYear.textContent = weekData.year;

    weekdayName.textContent = new Intl.DateTimeFormat("en", {
      weekday: "long"
    }).format(selectedDate);

    summary.textContent = "The selected date is in ISO week " + weekData.week + " of " + weekData.year + ".";
  }

  input.value = formatInputDate(new Date());

  button.addEventListener("click", calculateWeekNumber);
  input.addEventListener("change", calculateWeekNumber);

  calculateWeekNumber();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const calculator = document.querySelector("[data-vb-date-thirty]");
  if (!calculator) return;

  const input = calculator.querySelector("[data-week-date]");
  const button = calculator.querySelector("[data-calculate-week]");

  const weekNumber = calculator.querySelector("[data-week-number]");
  const weekYear = calculator.querySelector("[data-week-year]");
  const weekdayName = calculator.querySelector("[data-weekday-name]");
  const summary = calculator.querySelector("[data-week-summary]");

  function formatInputDate(date) {
    return date.getFullYear() + "-" +
      String(date.getMonth() + 1).padStart(2, "0") + "-" +
      String(date.getDate()).padStart(2, "0");
  }

  function createLocalDate(value) {
    const parts = value.split("-");
    return new Date(Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));
  }

  function getISOWeekData(date) {
    const target = new Date(Date.UTC(date.getFullYear(), date.getMonth(), date.getDate()));
    const dayNumber = target.getUTCDay() || 7;

    target.setUTCDate(target.getUTCDate() + 4 - dayNumber);

    const isoYear = target.getUTCFullYear();
    const yearStart = new Date(Date.UTC(isoYear, 0, 1));
    const isoWeek = Math.ceil((((target - yearStart) / 86400000) + 1) / 7);

    return {
      week: isoWeek,
      year: isoYear
    };
  }

  function calculateWeekNumber() {
    if (!input.value) return;

    const selectedDate = createLocalDate(input.value);
    const weekData = getISOWeekData(selectedDate);

    weekNumber.textContent = weekData.week;
    weekYear.textContent = weekData.year;

    weekdayName.textContent = new Intl.DateTimeFormat("en", {
      weekday: "long"
    }).format(selectedDate);

    summary.textContent = "The selected date is in ISO week " + weekData.week + " of " + weekData.year + ".";
  }

  input.value = formatInputDate(new Date());

  button.addEventListener("click", calculateWeekNumber);
  input.addEventListener("change", calculateWeekNumber);

  calculateWeekNumber();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-date-thirty-demo"&gt;
  &lt;div class="vb-date-thirty-card" data-vb-date-thirty&gt;
    &lt;div class="vb-date-thirty-form"&gt;
      &lt;span class="vb-date-thirty-kicker"&gt;Example 30&lt;/span&gt;
      &lt;h3&gt;Week Number Calculator&lt;/h3&gt;
      &lt;p&gt;Select a date and JavaScript calculates the ISO week number and related date details.&lt;/p&gt;

      &lt;label&gt;
        &lt;span&gt;Select date&lt;/span&gt;
        &lt;input type="date" data-week-date&gt;
      &lt;/label&gt;

      &lt;button type="button" data-calculate-week&gt;Calculate Week Number&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-date-thirty-results"&gt;
      &lt;div class="vb-date-thirty-main"&gt;
        &lt;span&gt;ISO week number&lt;/span&gt;
        &lt;strong data-week-number&gt;--&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-date-thirty-grid"&gt;
        &lt;div&gt;
          &lt;span&gt;ISO year&lt;/span&gt;
          &lt;strong data-week-year&gt;--&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Weekday&lt;/span&gt;
          &lt;strong data-weekday-name&gt;--&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;p data-week-summary&gt;Select a date to calculate its week number.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-date-thirty-demo,
.vb-date-thirty-demo * {
  box-sizing: border-box;
}

.vb-date-thirty-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 12% 18%, rgba(245, 158, 11, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(239, 68, 68, 0.14), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fef2f2 55%, #ffffff 100%) !important;
  border: 1px solid rgba(245, 158, 11, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-date-thirty-card {
  display: grid;
  grid-template-columns: minmax(280px, 0.85fr) minmax(0, 1.15fr);
  gap: 20px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-date-thirty-form,
.vb-date-thirty-results {
  min-width: 0;
  border-radius: 34px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.10);
}

.vb-date-thirty-form {
  display: grid;
  align-content: center;
  gap: 14px;
  padding: clamp(22px, 4vw, 38px);
  background: #ffffff;
}

.vb-date-thirty-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fef3c7;
  color: #b45309 !important;
  -webkit-text-fill-color: #b45309 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-date-thirty-form h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-date-thirty-form p {
  margin: 0 0 8px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-date-thirty-form label {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.vb-date-thirty-form label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-date-thirty-form input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.36);
  border-radius: 17px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-date-thirty-form button {
  min-height: 48px;
  padding: 12px 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #f59e0b, #ef4444);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-date-thirty-results {
  display: grid;
  align-content: center;
  gap: 14px;
  padding: clamp(20px, 4vw, 30px);
  background:
    radial-gradient(circle at 16% 14%, rgba(251, 191, 36, 0.20), transparent 34%),
    linear-gradient(135deg, #111827 0%, #7c2d12 100%) !important;
}

.vb-date-thirty-main,
.vb-date-thirty-grid div {
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-date-thirty-main span,
.vb-date-thirty-grid span {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-date-thirty-main strong {
  display: block;
  margin-top: 8px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(70px, 12vw, 120px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.08em;
}

.vb-date-thirty-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-date-thirty-grid strong {
  display: block;
  margin-top: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  line-height: 1.15;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-date-thirty-results p {
  margin: 0 !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-date-thirty-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-date-thirty-form,
  .vb-date-thirty-results,
  .vb-date-thirty-main,
  .vb-date-thirty-grid div {
    border-radius: 24px;
  }

  .vb-date-thirty-grid {
    grid-template-columns: 1fr;
  }

  .vb-date-thirty-form button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This JavaScript week number calculator is useful for reporting dashboards, payroll tools, logistics systems, booking calendars, project planning pages, content calendars, work schedules, and business applications.</p>



<div class="vb24-date-bottom-ad-wrap">
  <a class="vb24-date-bottom-ad" href="https://veebilehed24.ee/en/shop/entityschema-pro/" target="_blank" rel="sponsored noopener">
    <div class="vb24-date-bottom-ad-media">
      <img decoding="async" src="https://veebilehed24.ee/wp-content/uploads/2026/03/entityschema-cover-600x400.webp" width="300" height="200" alt="EntitySchema Pro WordPress structured data and entity SEO plugin" loading="lazy">
    </div>

    <div class="vb24-date-bottom-ad-content">
      <span>WordPress SEO Plugin</span>
      <h3>EntitySchema Pro</h3>
      <p>Build entity-based structured data for modern WordPress SEO, AI-readable content, schema markup, and stronger search visibility.</p>

      <div class="vb24-date-bottom-ad-price">
        <strong>29€</strong>
        <small><del>89€</del> Save 60€</small>
      </div>

      <em>View Plugin</em>
    </div>
  </a>
</div>

<style>
.vb24-date-bottom-ad-wrap,
.vb24-date-bottom-ad-wrap * {
  box-sizing: border-box;
}

.vb24-date-bottom-ad-wrap {
  margin: 54px 0 44px;
}

.vb24-date-bottom-ad {
  display: grid;
  grid-template-columns: 300px minmax(0, 1fr);
  gap: 22px;
  align-items: center;
  padding: clamp(16px, 3vw, 22px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 14% 12%, rgba(34, 211, 238, 0.24), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(249, 115, 22, 0.22), transparent 36%),
    linear-gradient(135deg, #0f172a 0%, #312e81 50%, #7c2d12 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 24px 76px rgba(15, 23, 42, 0.22);
  text-decoration: none !important;
  overflow: hidden;
}

.vb24-date-bottom-ad-media {
  overflow: hidden;
  border-radius: 22px;
  border: 1px solid rgba(255,255,255,0.16);
  background: rgba(255,255,255,0.08);
}

.vb24-date-bottom-ad-media img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 22px;
}

.vb24-date-bottom-ad-content {
  min-width: 0;
  padding: 6px 4px;
}

.vb24-date-bottom-ad-content span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb24-date-bottom-ad-content h3 {
  margin: 0 0 10px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 5vw, 52px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.065em;
}

.vb24-date-bottom-ad-content p {
  max-width: 720px;
  margin: 0 0 16px !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb24-date-bottom-ad-price {
  display: flex;
  align-items: center;
  gap: 14px;
  flex-wrap: wrap;
  margin-bottom: 16px;
}

.vb24-date-bottom-ad-price strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 38px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb24-date-bottom-ad-price small {
  display: inline-flex;
  gap: 8px;
  align-items: center;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.16);
  border: 1px solid rgba(74, 222, 128, 0.28);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 900;
}

.vb24-date-bottom-ad-price del {
  color: rgba(255,255,255,0.62) !important;
  -webkit-text-fill-color: rgba(255,255,255,0.62) !important;
  text-decoration-color: rgba(248,113,113,0.95);
  text-decoration-thickness: 2px;
}

.vb24-date-bottom-ad-content em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 12px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22d3ee, #2563eb 55%, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-style: normal;
  font-weight: 950;
  box-shadow: 0 14px 34px rgba(37,99,235,0.30);
}

.vb24-date-bottom-ad:hover {
  transform: translateY(-2px);
  filter: saturate(1.06);
}

@media (max-width: 760px) {
  .vb24-date-bottom-ad {
    grid-template-columns: 1fr;
    border-radius: 24px;
  }

  .vb24-date-bottom-ad-media {
    max-width: 360px;
  }
}
</style>



<h2 class="wp-block-heading" id="javascript-date-time-best-practices">JavaScript Date and Time Best Practices</h2>



<p class="wp-block-paragraph">JavaScript date and time examples can look simple, but real website features need careful planning. A good date component should display clear information, handle invalid input, work across devices, and avoid confusing users with unclear date formats or broken countdown states.</p>



<p class="wp-block-paragraph">The most important rule is to make the result understandable. Users should not need to guess whether a date means month/day/year or day/month/year, whether a countdown is based on their local time, whether a booking date is valid, or why a deadline has already expired.</p>



<ul class="wp-block-list">
  <li><strong>Use readable date labels</strong> instead of only numeric formats when the result is shown to normal website visitors.</li>
  <li><strong>Use <code>Intl.DateTimeFormat</code></strong> for clean formatting, weekday names, month names, and locale-friendly output.</li>
  <li><strong>Validate input dates</strong> before calculating age, delivery dates, business days, booking windows, or date ranges.</li>
  <li><strong>Handle past and expired states</strong> so countdowns, deadlines, and event widgets do not show confusing negative values.</li>
  <li><strong>Keep timezone context visible</strong> when showing international times, meeting times, event times, or support hours.</li>
  <li><strong>Test month endings</strong> because adding days, calculating date ranges, and checking deadlines can behave differently near the end of a month.</li>
  <li><strong>Check leap years</strong> when building age calculators, year progress trackers, date difference tools, and calendar logic.</li>
  <li><strong>Scope JavaScript selectors</strong> so multiple examples can work on the same WordPress page without affecting each other.</li>
  <li><strong>Use unique CSS class names</strong> for each example to avoid theme conflicts and repeated styles.</li>
  <li><strong>Keep interactive controls accessible</strong> by using real buttons, labels, inputs, and clear focus states.</li>
</ul>



<p class="wp-block-paragraph">For simple website features, vanilla JavaScript is often enough. You can create date formatters, countdowns, delivery date calculators, business day tools, age calculators, relative time labels, timestamp converters, and week number calculators without a large framework. For larger booking systems or international scheduling tools, server-side validation and timezone-safe backend logic may also be needed.</p>



<h2 class="wp-block-heading" id="responsive-date-time-ui-tips">Responsive Date and Time UI Tips</h2>



<p class="wp-block-paragraph">Date and time components often include big numbers, multiple cards, form inputs, buttons, countdown blocks, and result panels. These layouts can look good on desktop but break quickly on mobile if the grid is not planned correctly.</p>



<div class="vb24-date-tips-grid">
  <div>
    <h3>Use flexible grids</h3>
    <p>Countdown cards, date result panels, and calculator sections should collapse into one column on smaller screens.</p>
  </div>

  <div>
    <h3>Prevent text overflow</h3>
    <p>Long timezone names, formatted dates, and relative time labels should use wrapping rules so they stay inside the card.</p>
  </div>

  <div>
    <h3>Keep inputs full width</h3>
    <p>Date inputs, datetime fields, select boxes, and number fields are easier to use on mobile when they stretch to the card width.</p>
  </div>

  <div>
    <h3>Reduce oversized numbers</h3>
    <p>Large countdown digits and week numbers should use responsive font sizes with <code>clamp()</code> instead of fixed desktop sizes.</p>
  </div>
</div>

<style>
.vb24-date-tips-grid,
.vb24-date-tips-grid * {
  box-sizing: border-box;
}

.vb24-date-tips-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 30px;
}

.vb24-date-tips-grid div {
  min-width: 0;
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 18% 12%, rgba(249, 115, 22, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #fff7ed) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb24-date-tips-grid h3 {
  margin: 0 0 10px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px !important;
  line-height: 1.25 !important;
  font-weight: 900 !important;
}

.vb24-date-tips-grid p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

@media (max-width: 980px) {
  .vb24-date-tips-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-date-tips-grid {
    grid-template-columns: 1fr;
  }

  .vb24-date-tips-grid div {
    border-radius: 20px;
  }
}
</style>



<p class="wp-block-paragraph">Responsive design is especially important for date pickers, calculators, and dashboards because users often interact with them from mobile devices. A delivery date calculator, booking form, age calculator, or countdown timer should remain readable and usable even when the screen is narrow.</p>



<ul class="wp-block-list">
  <li>Use <code>grid-template-columns: 1fr</code> on mobile for form and result layouts.</li>
  <li>Use <code>minmax(0, 1fr)</code> in grid columns to prevent child elements from forcing overflow.</li>
  <li>Add <code>overflow-wrap: anywhere</code> to long date labels, timezone names, and generated output text.</li>
  <li>Make buttons full width on small screens when they sit below form inputs.</li>
  <li>Keep live previews scroll-safe if a demo has many cards or a large calendar-style layout.</li>
  <li>Use enough spacing between date inputs so touch users can select values comfortably.</li>
</ul>



<h2 class="wp-block-heading" id="common-javascript-date-time-mistakes">Common JavaScript Date and Time Mistakes</h2>



<p class="wp-block-paragraph">Many JavaScript date problems come from small assumptions. A developer may assume every month has the same number of days, forget that JavaScript months are zero-based, show unclear numeric formats, or build a countdown that breaks when the date passes.</p>



<p class="wp-block-paragraph">These mistakes can make forms, booking systems, dashboards, ecommerce pages, and countdown sections feel unreliable. Always test realistic user scenarios before publishing a date or time feature.</p>



<ul class="wp-block-list">
  <li><strong>Forgetting that JavaScript months start at 0</strong> when creating dates manually with <code>new Date(year, month, day)</code>.</li>
  <li><strong>Using unclear date formats</strong> such as <code>03/04/2026</code> without context because users may read it differently by region.</li>
  <li><strong>Not checking invalid inputs</strong> before calculating age, date differences, delivery estimates, or booking windows.</li>
  <li><strong>Letting countdowns go negative</strong> instead of showing an expired, complete, or next-cycle state.</li>
  <li><strong>Ignoring time zones</strong> on international event pages, webinar pages, and remote meeting tools.</li>
  <li><strong>Using fixed old dates in examples</strong> when the demo should stay useful for future visitors.</li>
  <li><strong>Not testing leap years</strong> in age calculators, year progress widgets, and date difference examples.</li>
  <li><strong>Running too many intervals</strong> when the component only needs to update once per minute or after user input.</li>
  <li><strong>Using global selectors carelessly</strong> when multiple demos or widgets exist on the same page.</li>
  <li><strong>Forgetting mobile layout</strong> when countdown numbers, date cards, or formatted output become too wide.</li>
</ul>



<p class="wp-block-paragraph">A professional JavaScript date component should be predictable. If the selected date is invalid, show a clear message. If a deadline has passed, show a complete state. If the output depends on local time, make that clear. If the feature is part of a real booking, payment, legal, or business system, validate the final result on the server too.</p>



<h2 class="wp-block-heading" id="javascript-date-time-faq">JavaScript Date and Time FAQ</h2>



<p class="wp-block-paragraph">Here are common questions about building JavaScript date and time components for websites, dashboards, ecommerce pages, forms, calculators, booking tools, and practical UI examples.</p>



<div class="vb24-date-faq" data-vb24-date-faq>
  <details>
    <summary>What is the JavaScript Date object?</summary>
    <p>The JavaScript <code>Date</code> object is the built-in browser object used to create, read, compare, and format dates and times. It can represent the current moment, a selected user date, a future deadline, or a custom timestamp.</p>
  </details>

  <details>
    <summary>How do I format a date in JavaScript?</summary>
    <p>You can format dates with <code>Intl.DateTimeFormat</code>, manual helper functions, or methods like <code>toLocaleDateString()</code>. For readable website UI, <code>Intl.DateTimeFormat</code> is usually cleaner because it supports weekdays, month names, years, hours, minutes, and locale-aware formatting.</p>
  </details>

  <details>
    <summary>How do I calculate the difference between two dates?</summary>
    <p>Convert both dates to milliseconds by subtracting one <code>Date</code> object from another. Then divide the difference by the number of milliseconds in a day, hour, or minute depending on what you need to calculate.</p>
  </details>

  <details>
    <summary>How do I create a JavaScript countdown timer?</summary>
    <p>Create a target date, compare it with the current date, calculate the remaining milliseconds, convert that value into days, hours, minutes, and seconds, then update the HTML with <code>setInterval()</code>.</p>
  </details>

  <details>
    <summary>How can I stop a countdown from breaking when it expires?</summary>
    <p>Check whether the remaining time is less than or equal to zero. Then show an expired state, complete message, hidden button, or a new dynamic target date instead of allowing negative values to appear.</p>
  </details>

  <details>
    <summary>How do I validate a date input with JavaScript?</summary>
    <p>Read the input value, convert it into a local <code>Date</code> object, then compare it with your minimum date, maximum date, current date, or other business rules. Always show a clear error message when the selected date is not allowed.</p>
  </details>

  <details>
    <summary>How do I calculate business days in JavaScript?</summary>
    <p>Loop through the date range one day at a time and count only days where <code>getDay()</code> is not Saturday or Sunday. For real business systems, you may also need to exclude holidays from a custom list.</p>
  </details>

  <details>
    <summary>Should I handle time zones in JavaScript?</summary>
    <p>JavaScript can display time in different time zones using <code>Intl.DateTimeFormat</code> with a <code>timeZone</code> option. For serious booking, payment, or scheduling systems, store important times on the server in a reliable format and use JavaScript mainly for display.</p>
  </details>

  <details>
    <summary>Why do JavaScript months start at 0?</summary>
    <p>When creating dates with <code>new Date(year, month, day)</code>, JavaScript uses zero-based months. January is <code>0</code>, February is <code>1</code>, and December is <code>11</code>. This is one of the most common beginner mistakes in JavaScript date examples.</p>
  </details>

  <details>
    <summary>Can I use these JavaScript date examples in WordPress?</summary>
    <p>Yes. These examples are written as vanilla JavaScript, HTML, and CSS, so they can be placed in a Gutenberg Custom HTML block, a custom theme template, a plugin, or a static HTML page. For WordPress posts, keep class names unique so examples do not conflict with theme styles.</p>
  </details>
</div>

<style>
.vb24-date-faq,
.vb24-date-faq * {
  box-sizing: border-box;
}

.vb24-date-faq {
  display: grid;
  gap: 12px;
  margin: 24px 0 36px;
}

.vb24-date-faq details {
  overflow: hidden;
  border-radius: 20px;
  border: 1px solid rgba(148, 163, 184, 0.24);
  background: #ffffff;
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb24-date-faq summary {
  cursor: pointer;
  list-style: none;
  position: relative;
  padding: 18px 54px 18px 20px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 17px;
  line-height: 1.35;
  font-weight: 900;
}

.vb24-date-faq summary::-webkit-details-marker {
  display: none;
}

.vb24-date-faq summary::after {
  content: "+";
  position: absolute;
  right: 18px;
  top: 50%;
  width: 30px;
  height: 30px;
  transform: translateY(-50%);
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: linear-gradient(135deg, #7c3aed, #f97316);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  line-height: 1;
  font-weight: 950;
}

.vb24-date-faq details[open] summary::after {
  content: "–";
}

.vb24-date-faq p {
  margin: 0 !important;
  padding: 0 20px 18px;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb24-date-faq code {
  padding: 2px 6px;
  border-radius: 7px;
  background: #f1f5f9;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 0.92em;
  font-weight: 800;
}

@media (max-width: 640px) {
  .vb24-date-faq summary {
    padding: 16px 50px 16px 16px;
    font-size: 16px;
  }

  .vb24-date-faq p {
    padding: 0 16px 16px;
  }
}
</style>



<h2 class="wp-block-heading" id="javascript-date-time-conclusion">Conclusion</h2>



<p class="wp-block-paragraph">JavaScript date and time features are some of the most useful small tools you can add to a website. They help users understand deadlines, compare dates, calculate delivery times, validate forms, check business days, convert timestamps, display time zones, and interact with dashboards, booking systems, ecommerce pages, event pages, and productivity tools.</p>



<p class="wp-block-paragraph">The 30 examples in this guide show how flexible vanilla JavaScript can be. You can build live clocks, countdowns, date formatters, age calculators, booking validators, business day calculators, timestamp converters, timezone displays, relative time labels, and week number tools with simple HTML, CSS, and JavaScript.</p>



<p class="wp-block-paragraph">For best results, keep every date component clear and practical. Use readable formats, handle invalid input, avoid broken expired states, test mobile layouts, and make sure the user understands exactly what the date or time result means. When a feature affects real bookings, payments, schedules, or business rules, combine the front-end JavaScript with reliable server-side validation.</p>



<h2 class="wp-block-heading" id="related-javascript-and-css-guides">Related JavaScript and CSS Guides</h2>



<p class="wp-block-paragraph">Continue with these related guides if you want more practical JavaScript examples, UI components, calculators, form logic, saved browser state, and responsive front-end patterns.</p>



<div class="vb24-date-related-grid">
  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-countdown-timer-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Countdown Timer Examples</strong>
    <p>Sale timers, event timers, countdown cards, and practical timer UI components.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-calculator-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Calculator Examples</strong>
    <p>Price calculators, loan calculators, BMI calculators, discount tools, and form calculators.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-form-validation-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Form Validation Examples</strong>
    <p>Input validation, signup validation, checkout validation, and practical form rules.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-localstorage-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript LocalStorage Examples</strong>
    <p>Save form data, carts, preferences, app state, UI settings, and browser data.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-fetch-api-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Fetch API Examples</strong>
    <p>GET requests, POST requests, JSON handling, API errors, and real request examples.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-forms/">
    <span>CSS</span>
    <strong>30 Modern CSS Forms for Websites</strong>
    <p>Contact forms, login forms, checkout forms, booking forms, and modern form UI examples.</p>
  </a>
</div>

<style>
.vb24-date-related-grid,
.vb24-date-related-grid * {
  box-sizing: border-box;
}

.vb24-date-related-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 42px;
}

.vb24-date-related-grid a {
  display: grid;
  gap: 10px;
  min-width: 0;
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 16% 12%, rgba(124, 58, 237, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
  text-decoration: none !important;
  transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}

.vb24-date-related-grid a:hover {
  transform: translateY(-3px);
  border-color: rgba(249, 115, 22, 0.48);
  box-shadow: 0 22px 52px rgba(15, 23, 42, 0.12);
}

.vb24-date-related-grid span {
  display: inline-flex;
  justify-self: start;
  padding: 6px 9px;
  border-radius: 999px;
  background: #fff7ed;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb24-date-related-grid strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 19px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.035em;
}

.vb24-date-related-grid p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.62;
  font-weight: 650;
}

@media (max-width: 960px) {
  .vb24-date-related-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-date-related-grid {
    grid-template-columns: 1fr;
  }

  .vb24-date-related-grid a {
    border-radius: 20px;
  }
}
</style>
]]></content:encoded>
					
					<wfw:commentRss>https://veebilehed24.ee/en/blog/javascript/javascript-date-time-examples/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>30 JavaScript LocalStorage Examples – Save Form Data, Carts, Preferences &#038; App State</title>
		<link>https://veebilehed24.ee/en/blog/javascript/javascript-localstorage-examples/</link>
					<comments>https://veebilehed24.ee/en/blog/javascript/javascript-localstorage-examples/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Tue, 16 Jun 2026 05:05:34 +0000</pubDate>
				<category><![CDATA[Javascript]]></category>
		<guid isPermaLink="false">https://veebilehed24.ee/?p=1755</guid>

					<description><![CDATA[JavaScript localStorage is one of the most useful browser features for saving small pieces of data directly inside a visitor’s browser. It can be used for form drafts, shopping carts, dark mode preferences, saved filters, recently viewed products, favorite items, user settings, notes, quiz progress, dashboard widgets, and many other interactive website features that should [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">JavaScript localStorage is one of the most useful browser features for saving small pieces of data directly inside a visitor’s browser. It can be used for form drafts, shopping carts, dark mode preferences, saved filters, recently viewed products, favorite items, user settings, notes, quiz progress, dashboard widgets, and many other interactive website features that should remember something after the page reloads.</p>



<p class="wp-block-paragraph">In this guide, you will find 30 JavaScript localStorage examples for real website projects, including saved form data, persistent shopping carts, dark mode settings, product favorites, recently viewed items, saved search filters, tab preferences, accordion states, draft notes, to-do lists, mini CRM notes, quiz progress, price calculator history, cookie-style banners, and reusable vanilla JavaScript storage components.</p>



<p class="wp-block-paragraph">This post focuses on practical JavaScript localStorage logic, including <code>localStorage.setItem()</code>, <code>localStorage.getItem()</code>, <code>localStorage.removeItem()</code>, JSON storage, arrays, objects, form state, browser persistence, reset buttons, UI updates, and copy-paste-ready HTML, CSS, and JavaScript examples. For related JavaScript UI components, you can also explore our <a href="https://veebilehed24.ee/en/blog/javascript/javascript-form-validation-examples/">JavaScript form validation examples</a>, <a href="https://veebilehed24.ee/en/blog/javascript/javascript-search-filter-examples/">JavaScript search filter examples</a>, <a href="https://veebilehed24.ee/en/blog/javascript/javascript-dropdown-menu-examples/">JavaScript dropdown menu examples</a>, and <a href="https://veebilehed24.ee/en/blog/javascript/javascript-countdown-timer-examples/">JavaScript countdown timer examples</a>.</p>



<div class="vb24-js-storage-jump-box">
  <a class="vb24-js-storage-jump-button" href="#javascript-localstorage-examples">View All 30 JavaScript LocalStorage Examples</a>
</div>

<style>
.vb24-js-storage-jump-box {
  margin: 28px 0 36px;
}

.vb24-js-storage-jump-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 14px 22px;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #06b6d4 52%, #10b981);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 850;
  line-height: 1.2;
  text-decoration: none !important;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.26);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-js-storage-jump-button::after {
  content: "↓";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.18);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  line-height: 1;
}

.vb24-js-storage-jump-button:hover {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transform: translateY(-2px);
  filter: saturate(1.08);
  box-shadow: 0 20px 46px rgba(37, 99, 235, 0.34);
}

@media (max-width: 640px) {
  .vb24-js-storage-jump-button {
    width: 100%;
    padding: 14px 16px;
    font-size: 14px;
  }
}
</style>



<div class="toc-affiliate-wrap vb24-js-storage-toc-wrap">

  <div class="toc-left vb24-js-storage-toc-left">

    <div class="vb24-js-storage-toc-kicker">On this page</div>

    <h2>Table of Contents</h2>

    <ul class="vl24-toc vb24-js-storage-toc">
      <li><a href="#what-is-javascript-localstorage">What Is JavaScript LocalStorage?</a></li>
      <li><a href="#why-localstorage-matters">Why LocalStorage Matters</a></li>
      <li><a href="#javascript-localstorage-use-cases">JavaScript LocalStorage Use Cases</a></li>
      <li><a href="#what-should-a-good-localstorage-feature-include">What Should a Good LocalStorage Feature Include?</a></li>
      <li><a class="vb24-featured-toc-link" href="#javascript-localstorage-examples">30 JavaScript LocalStorage Examples</a></li>
      <li><a href="#javascript-localstorage-best-practices">JavaScript LocalStorage Best Practices</a></li>
      <li><a href="#responsive-localstorage-ui-tips">Responsive LocalStorage UI Tips</a></li>
      <li><a href="#common-javascript-localstorage-mistakes">Common JavaScript LocalStorage Mistakes</a></li>
      <li><a href="#javascript-localstorage-faq">JavaScript LocalStorage FAQ</a></li>
      <li><a href="#javascript-localstorage-conclusion">Conclusion</a></li>
      <li><a href="#related-javascript-and-css-guides">Related JavaScript and CSS Guides</a></li>
    </ul>

  </div>

  <div class="toc-right vb24-js-storage-toc-right">

    <a class="vb24-entityschema-ad-card" href="https://veebilehed24.ee/en/shop/entityschema-pro/" target="_blank" rel="sponsored noopener">
      <span class="vb24-entityschema-ad-badge">WordPress SEO Plugin</span>

      <div class="vb24-entityschema-ad-image">
        <img decoding="async" src="https://veebilehed24.ee/wp-content/uploads/2026/03/entityschema-cover-600x400.webp" width="300" height="200" alt="EntitySchema Pro WordPress structured data and entity SEO plugin" loading="lazy">
      </div>

      <div class="vb24-entityschema-ad-content">
        <h3>EntitySchema Pro</h3>
        <p>Build a real entity-based structured data system for WordPress, modern SEO, and AI-readable websites.</p>

        <div class="vb24-entityschema-ad-price">
          <div class="vb24-entityschema-ad-price-left">
            <span class="vb24-entityschema-ad-price-label">Sale price</span>
            <span class="vb24-entityschema-ad-old-price">89€</span>
          </div>

          <strong class="vb24-entityschema-ad-sale-price">29€</strong>

          <span class="vb24-entityschema-ad-save">Save 60€</span>
        </div>

        <span class="vb24-entityschema-ad-button">View Plugin</span>
      </div>
    </a>

  </div>

</div>

<style>
.vb24-js-storage-toc-wrap {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 26px;
  align-items: stretch;
  margin: 34px 0 44px;
}

.vb24-js-storage-toc-left,
.vb24-js-storage-toc-right {
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 28px;
  background: linear-gradient(135deg, #0f172a 0%, #1e3a8a 48%, #065f46 100%);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.18);
}

.vb24-js-storage-toc-left {
  padding: 28px 30px 30px;
}

.vb24-js-storage-toc-kicker {
  margin-bottom: 10px;
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 13px;
  font-weight: 850;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb24-js-storage-toc-left h2 {
  margin: 0 0 22px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px !important;
  line-height: 1.15 !important;
  font-weight: 850 !important;
}

.vb24-js-storage-toc {
  display: grid !important;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px !important;
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb24-js-storage-toc li {
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb24-js-storage-toc li::before {
  display: none !important;
  content: none !important;
}

.vb24-js-storage-toc a {
  display: flex;
  align-items: center;
  min-height: 54px;
  padding: 13px 15px;
  border: 1px solid rgba(148, 163, 184, 0.18);
  border-radius: 15px;
  background: rgba(255, 255, 255, 0.065);
  color: #f3f4f6 !important;
  -webkit-text-fill-color: #f3f4f6 !important;
  font-size: 15px;
  font-weight: 750;
  line-height: 1.35;
  text-decoration: none !important;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.05);
  transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease;
}

.vb24-js-storage-toc a:hover {
  transform: translateY(-2px);
  border-color: rgba(16, 185, 129, 0.70);
  background: rgba(16, 185, 129, 0.16);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb24-js-storage-toc .vb24-featured-toc-link {
  border-color: rgba(34, 211, 238, 0.78);
  background: linear-gradient(135deg, rgba(37, 99, 235, 0.34), rgba(6, 182, 212, 0.28), rgba(16, 185, 129, 0.26));
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb24-js-storage-toc-right {
  display: flex;
  align-items: stretch;
  justify-content: center;
  padding: 16px;
  overflow: hidden;
}

.vb24-entityschema-ad-card,
.vb24-entityschema-ad-card * {
  box-sizing: border-box;
}

.vb24-entityschema-ad-card {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  min-height: 100%;
  padding: 12px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(34, 211, 238, 0.28), transparent 34%),
    radial-gradient(circle at 86% 14%, rgba(236, 72, 153, 0.24), transparent 36%),
    linear-gradient(135deg, #111827 0%, #312e81 52%, #701a75 100%) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  overflow: hidden;
  box-shadow: 0 20px 56px rgba(2, 6, 23, 0.32);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-entityschema-ad-card:hover {
  transform: translateY(-3px);
  filter: saturate(1.08);
  box-shadow: 0 26px 70px rgba(2, 6, 23, 0.42);
}

.vb24-entityschema-ad-badge {
  position: absolute;
  z-index: 3;
  top: 18px;
  left: 18px;
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.70);
  border: 1px solid rgba(255,255,255,0.22);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb24-entityschema-ad-image {
  overflow: hidden;
  border-radius: 17px;
  border: 1px solid rgba(255,255,255,0.16);
  background: rgba(255,255,255,0.08);
}

.vb24-entityschema-ad-image img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 17px;
}

.vb24-entityschema-ad-content {
  padding: 15px 8px 4px;
}

.vb24-entityschema-ad-content h3 {
  margin: 0 0 8px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 23px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb24-entityschema-ad-content p {
  margin: 0 0 14px !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 13px;
  line-height: 1.5;
  font-weight: 650;
}

.vb24-entityschema-ad-price {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin: 0 0 12px;
  padding: 11px 12px;
  border-radius: 16px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.16);
}

.vb24-entityschema-ad-price-left {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.vb24-entityschema-ad-price-label {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 11px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb24-entityschema-ad-old-price {
  color: rgba(255,255,255,0.62) !important;
  -webkit-text-fill-color: rgba(255,255,255,0.62) !important;
  font-size: 15px;
  line-height: 1;
  font-weight: 850;
  text-decoration: line-through;
  text-decoration-thickness: 2px;
  text-decoration-color: rgba(248, 113, 113, 0.95);
}

.vb24-entityschema-ad-sale-price {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 31px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb24-entityschema-ad-save {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 28px;
  padding: 6px 9px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.18);
  border: 1px solid rgba(74, 222, 128, 0.34);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 11px;
  font-weight: 950;
  white-space: nowrap;
}

.vb24-entityschema-ad-button {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 43px;
  padding: 12px 14px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22d3ee, #2563eb 55%, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
  box-shadow: 0 14px 34px rgba(37, 99, 235, 0.30);
}

@media (max-width: 900px) {
  .vb24-js-storage-toc-wrap {
    grid-template-columns: 1fr;
  }

  .vb24-js-storage-toc-right {
    justify-content: flex-start;
    max-width: 360px;
  }
}

@media (max-width: 640px) {
  .vb24-js-storage-toc-left {
    padding: 22px 18px;
    border-radius: 22px;
  }

  .vb24-js-storage-toc-left h2 {
    font-size: 26px !important;
  }

  .vb24-js-storage-toc {
    grid-template-columns: 1fr;
  }

  .vb24-js-storage-toc a {
    min-height: 48px;
    font-size: 14px;
  }

  .vb24-js-storage-toc-right {
    max-width: 100%;
    border-radius: 22px;
  }
}
</style>



<h2 class="wp-block-heading" id="what-is-javascript-localstorage">What Is JavaScript LocalStorage?</h2>



<p class="wp-block-paragraph">JavaScript localStorage is a browser storage feature that lets websites save small pieces of data on the user’s device. Unlike temporary JavaScript variables, localStorage data can stay available after the page reloads, after the browser tab closes, and after the visitor returns later.</p>



<p class="wp-block-paragraph">The main purpose of localStorage is to remember simple user data in the browser without needing a database for every small interaction. For example, a website can remember a visitor’s dark mode preference, a partially completed form, selected filters, favorite products, dismissed banners, cart items, or the last active tab in a content section.</p>



<p class="wp-block-paragraph">LocalStorage is especially useful for front-end demos, UI components, small tools, ecommerce prototypes, landing pages, dashboards, and WordPress custom HTML blocks where you want a simple persistent browser feature. It is not a replacement for secure server-side storage, but it is very useful for interface state, preferences, and non-sensitive data.</p>



<h2 class="wp-block-heading" id="why-localstorage-matters">Why LocalStorage Matters</h2>



<p class="wp-block-paragraph">LocalStorage matters because many modern websites need to remember small actions. A visitor may expect their form draft to stay available after refresh, their selected theme to stay active, their cart to stay visible, or their filters to remain selected while browsing a product list.</p>



<ul class="wp-block-list">
  <li><strong>It improves user experience</strong> by remembering small choices such as dark mode, selected layout, active tabs, and preferred filters.</li>
  <li><strong>It helps forms feel safer</strong> by saving draft text, contact fields, multi-step progress, and unfinished input data.</li>
  <li><strong>It supports ecommerce UI</strong> by storing cart items, favorites, recently viewed products, comparison lists, and discount states.</li>
  <li><strong>It makes demos more practical</strong> because examples can keep data after refresh without a backend or database.</li>
  <li><strong>It teaches real JavaScript logic</strong> because localStorage often uses events, JSON, arrays, objects, DOM updates, reset buttons, and UI state.</li>
</ul>



<p class="wp-block-paragraph">LocalStorage should still be used carefully. It is best for non-sensitive browser data. You should not store passwords, private tokens, payment details, personal identity numbers, or confidential data in localStorage. For simple UI memory, saved preferences, carts, drafts, and browser-based examples, it is one of the easiest JavaScript features to learn and use.</p>



<h2 class="wp-block-heading" id="javascript-localstorage-use-cases">JavaScript LocalStorage Use Cases</h2>



<p class="wp-block-paragraph">There are many practical localStorage use cases for websites and web apps. Some are small interface improvements, while others can feel like complete mini applications. The key is to store the right amount of data and update the interface whenever the saved data changes.</p>



<p class="wp-block-paragraph">A simple localStorage feature may save one value, such as a dark mode setting. A more advanced feature may save an array of cart products, an object with user preferences, a list of saved notes, multi-step form progress, or filter settings that rebuild the UI when the page loads again.</p>



<ul class="wp-block-list">
  <li><strong>Form draft storage</strong> saves typed input so visitors do not lose progress after refresh.</li>
  <li><strong>Shopping cart storage</strong> keeps product items, quantities, prices, and totals in the browser.</li>
  <li><strong>Preference storage</strong> remembers dark mode, compact layout, language choice, active tab, or selected view.</li>
  <li><strong>Saved item storage</strong> can store favorites, bookmarks, recently viewed products, or comparison lists.</li>
  <li><strong>Tool history storage</strong> can save calculator results, quote requests, generated values, search history, or previous actions.</li>
  <li><strong>Progress storage</strong> can remember quiz steps, onboarding progress, checklist status, course progress, or dashboard task states.</li>
</ul>



<p class="wp-block-paragraph">This guide focuses on JavaScript localStorage examples, so every demo will include visible JavaScript, HTML, and CSS code. The examples are designed to be copy-paste friendly, easy to customize, and different in layout, purpose, storage logic, UI behavior, and responsive design.</p>



<h2 class="wp-block-heading" id="what-should-a-good-localstorage-feature-include">What Should a Good LocalStorage Feature Include?</h2>



<p class="wp-block-paragraph">A good localStorage feature should be useful, predictable, and easy to reset. Users should understand what is being saved, the interface should update immediately after changes, and the saved data should load correctly when the page opens again.</p>



<div class="vb24-js-storage-checklist">
  <div class="vb24-js-storage-check-item">
    <h3>Clear saved data purpose</h3>
    <p>The feature should have a clear reason to save data, such as a form draft, cart, preference, favorite item, note, or progress state.</p>
  </div>

  <div class="vb24-js-storage-check-item">
    <h3>Reliable page reload behavior</h3>
    <p>The saved value should appear again after refresh, and the UI should match what is stored in the browser.</p>
  </div>

  <div class="vb24-js-storage-check-item">
    <h3>Safe data handling</h3>
    <p>LocalStorage should be used for non-sensitive data only. Private, secure, or payment-related information belongs on the server.</p>
  </div>

  <div class="vb24-js-storage-check-item">
    <h3>Reset and remove option</h3>
    <p>Users should be able to clear saved drafts, remove cart items, reset preferences, or delete stored browser data when needed.</p>
  </div>
</div>

<style>
.vb24-js-storage-checklist {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 30px;
}

.vb24-js-storage-check-item {
  padding: 20px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 22px;
  background:
    radial-gradient(circle at 18% 10%, rgba(37, 99, 235, 0.10), transparent 32%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb24-js-storage-check-item h3 {
  margin: 0 0 10px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 850;
}

.vb24-js-storage-check-item p {
  margin: 0;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb24-js-storage-checklist {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-js-storage-checklist {
    grid-template-columns: 1fr;
  }

  .vb24-js-storage-check-item {
    padding: 18px;
    border-radius: 20px;
  }
}
</style>



<p class="wp-block-paragraph">Before building a localStorage feature, decide exactly what should be saved and what should happen when the visitor returns. Should the form refill automatically? Should the cart rebuild itself? Should the selected tab reopen? Should the user see a “clear saved data” button? These small decisions make the difference between a basic demo and a professional JavaScript component.</p>



<ul class="wp-block-list">
  <li><strong>Use localStorage for non-sensitive data</strong> such as preferences, drafts, carts, filters, and UI state.</li>
  <li><strong>Use JSON for arrays and objects</strong> because localStorage stores values as strings.</li>
  <li><strong>Load saved data on page start</strong> so the interface matches the browser storage immediately.</li>
  <li><strong>Update storage after user actions</strong> such as typing, clicking, adding items, removing items, or changing settings.</li>
  <li><strong>Add remove and reset buttons</strong> so users can clear saved browser data easily.</li>
  <li><strong>Use unique storage keys</strong> so different examples or features do not overwrite each other.</li>
  <li><strong>Keep JavaScript scoped</strong> so multiple localStorage components can work on the same page.</li>
  <li><strong>Validate stored data</strong> before using it, especially when parsing JSON from the browser.</li>
  <li><strong>Keep the UI responsive</strong> so saved carts, forms, and dashboard widgets work on mobile screens.</li>
  <li><strong>Avoid storing private data</strong> because localStorage is not designed for secure confidential information.</li>
</ul>



<p class="wp-block-paragraph">You can combine JavaScript localStorage with many other website UI patterns. Saved form drafts work well with <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-forms/">modern CSS forms</a>, persistent carts can support ecommerce layouts and <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-pricing-tables/">modern CSS pricing tables</a>, saved tabs can be used with <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-tabs/">modern CSS tabs</a>, and preference panels can fit inside layouts from our <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-layouts/">modern CSS layouts</a> guide.</p>



<h2 class="wp-block-heading" id="javascript-localstorage-examples">30 JavaScript LocalStorage Examples</h2>



<p class="wp-block-paragraph">Now let’s look at 30 JavaScript localStorage examples for real website projects. Each example uses a different storage purpose, layout style, interface pattern, saved data structure, browser persistence behavior, reset option, form logic, cart logic, preference setting, or responsive UI approach, so you can build useful browser-based features with visible JavaScript, HTML, and CSS code.</p>



<h2 class="wp-block-heading">1. Auto-Save Contact Form Draft with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>An auto-save contact form draft</strong> is one of the most practical JavaScript localStorage examples. It helps users keep their typed message, name, email, and project details even if they accidentally refresh the page or leave the browser tab.</p>



<p class="wp-block-paragraph">This example saves form fields automatically while the visitor types. When the page loads again, JavaScript reads the saved values from localStorage and restores the form. The user can also clear the saved draft with one button.</p>



<ul class="wp-block-list">
<li>Auto-save form draft</li>
<li>Restores name, email, project type, and message</li>
<li>Uses localStorage with JSON</li>
<li>Includes clear draft button</li>
<li>Useful for contact pages and quote request forms</li>
</ul>



<div class="vb-storage-one-demo">
  <div class="vb-storage-one-card" data-vb-storage-one>
    <div class="vb-storage-one-info">
      <span class="vb-storage-one-kicker">Example 01</span>
      <h3>Saved Contact Draft</h3>
      <p>This form saves your draft in the browser while you type. Refresh the page and the values will still be there.</p>

      <div class="vb-storage-one-status" data-status>
        Draft status: waiting for input
      </div>
    </div>

    <form class="vb-storage-one-form">
      <label>
        <span>Your name</span>
        <input type="text" name="name" placeholder="Alex Morgan">
      </label>

      <label>
        <span>Email address</span>
        <input type="email" name="email" placeholder="alex@example.com">
      </label>

      <label>
        <span>Project type</span>
        <select name="project">
          <option value="">Choose project type</option>
          <option value="Website design">Website design</option>
          <option value="WordPress plugin">WordPress plugin</option>
          <option value="Ecommerce store">Ecommerce store</option>
          <option value="JavaScript feature">JavaScript feature</option>
        </select>
      </label>

      <label>
        <span>Project message</span>
        <textarea name="message" rows="5" placeholder="Tell us what you want to build..."></textarea>
      </label>

      <div class="vb-storage-one-actions">
        <button type="button" data-clear>Clear Saved Draft</button>
        <span data-saved-time>No saved draft yet</span>
      </div>
    </form>
  </div>
</div>

<style>
.vb-storage-one-demo,
.vb-storage-one-demo * {
  box-sizing: border-box;
}

.vb-storage-one-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 16% 12%, rgba(59, 130, 246, 0.18), transparent 34%),
    radial-gradient(circle at 86% 20%, rgba(16, 185, 129, 0.18), transparent 36%),
    linear-gradient(135deg, #eff6ff 0%, #f0fdfa 55%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-storage-one-card {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: clamp(22px, 4vw, 34px);
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.12);
}

.vb-storage-one-info {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
}

.vb-storage-one-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-one-info h3 {
  margin: 0 0 16px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 6vw, 68px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-one-info p {
  max-width: 520px;
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-storage-one-status {
  display: inline-flex;
  align-self: flex-start;
  padding: 13px 15px;
  border-radius: 18px;
  background: #ecfdf5;
  border: 1px solid rgba(16, 185, 129, 0.24);
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 850;
}

.vb-storage-one-form {
  display: grid;
  gap: 14px;
  min-width: 0;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 24px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-one-form label {
  display: grid;
  gap: 7px;
}

.vb-storage-one-form label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-storage-one-form input,
.vb-storage-one-form select,
.vb-storage-one-form textarea {
  width: 100%;
  border: 1px solid rgba(148, 163, 184, 0.34);
  border-radius: 16px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 650;
  outline: none;
  box-shadow: none;
}

.vb-storage-one-form input,
.vb-storage-one-form select {
  min-height: 48px;
  padding: 0 14px;
}

.vb-storage-one-form textarea {
  resize: vertical;
  padding: 13px 14px;
  line-height: 1.55;
}

.vb-storage-one-form input:focus,
.vb-storage-one-form select:focus,
.vb-storage-one-form textarea:focus {
  border-color: rgba(37, 99, 235, 0.76);
  box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.10);
}

.vb-storage-one-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  margin-top: 2px;
}

.vb-storage-one-actions button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 11px 15px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 14px 34px rgba(37, 99, 235, 0.22);
}

.vb-storage-one-actions span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 750;
}

@media (max-width: 880px) {
  .vb-storage-one-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-storage-one-card {
    padding: 18px;
    border-radius: 22px;
  }

  .vb-storage-one-info h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }

  .vb-storage-one-actions button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-one]");
  if (!wrapper) return;

  const storageKey = "vbStorageOneContactDraft";
  const form = wrapper.querySelector(".vb-storage-one-form");
  const status = wrapper.querySelector("[data-status]");
  const savedTime = wrapper.querySelector("[data-saved-time]");
  const clearButton = wrapper.querySelector("[data-clear]");

  const fields = {
    name: form.elements.name,
    email: form.elements.email,
    project: form.elements.project,
    message: form.elements.message
  };

  function getDraftData() {
    return {
      name: fields.name.value,
      email: fields.email.value,
      project: fields.project.value,
      message: fields.message.value,
      savedAt: new Date().toLocaleTimeString([], {
        hour: "2-digit",
        minute: "2-digit"
      })
    };
  }

  function saveDraft() {
    const draft = getDraftData();
    localStorage.setItem(storageKey, JSON.stringify(draft));
    status.textContent = "Draft status: saved in this browser";
    savedTime.textContent = "Last saved at " + draft.savedAt;
  }

  function loadDraft() {
    const savedDraft = localStorage.getItem(storageKey);
    if (!savedDraft) return;

    try {
      const draft = JSON.parse(savedDraft);

      fields.name.value = draft.name || "";
      fields.email.value = draft.email || "";
      fields.project.value = draft.project || "";
      fields.message.value = draft.message || "";

      status.textContent = "Draft status: restored from localStorage";
      savedTime.textContent = draft.savedAt
        ? "Restored draft saved at " + draft.savedAt
        : "Restored saved draft";
    } catch (error) {
      localStorage.removeItem(storageKey);
      status.textContent = "Draft status: saved data was reset";
    }
  }

  function clearDraft() {
    localStorage.removeItem(storageKey);
    form.reset();
    status.textContent = "Draft status: cleared";
    savedTime.textContent = "No saved draft yet";
  }

  Object.values(fields).forEach(function (field) {
    field.addEventListener("input", saveDraft);
    field.addEventListener("change", saveDraft);
  });

  clearButton.addEventListener("click", clearDraft);

  loadDraft();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-one]");
  if (!wrapper) return;

  const storageKey = "vbStorageOneContactDraft";
  const form = wrapper.querySelector(".vb-storage-one-form");
  const status = wrapper.querySelector("[data-status]");
  const savedTime = wrapper.querySelector("[data-saved-time]");
  const clearButton = wrapper.querySelector("[data-clear]");

  const fields = {
    name: form.elements.name,
    email: form.elements.email,
    project: form.elements.project,
    message: form.elements.message
  };

  function getDraftData() {
    return {
      name: fields.name.value,
      email: fields.email.value,
      project: fields.project.value,
      message: fields.message.value,
      savedAt: new Date().toLocaleTimeString([], {
        hour: "2-digit",
        minute: "2-digit"
      })
    };
  }

  function saveDraft() {
    const draft = getDraftData();
    localStorage.setItem(storageKey, JSON.stringify(draft));
    status.textContent = "Draft status: saved in this browser";
    savedTime.textContent = "Last saved at " + draft.savedAt;
  }

  function loadDraft() {
    const savedDraft = localStorage.getItem(storageKey);
    if (!savedDraft) return;

    try {
      const draft = JSON.parse(savedDraft);

      fields.name.value = draft.name || "";
      fields.email.value = draft.email || "";
      fields.project.value = draft.project || "";
      fields.message.value = draft.message || "";

      status.textContent = "Draft status: restored from localStorage";
      savedTime.textContent = draft.savedAt
        ? "Restored draft saved at " + draft.savedAt
        : "Restored saved draft";
    } catch (error) {
      localStorage.removeItem(storageKey);
      status.textContent = "Draft status: saved data was reset";
    }
  }

  function clearDraft() {
    localStorage.removeItem(storageKey);
    form.reset();
    status.textContent = "Draft status: cleared";
    savedTime.textContent = "No saved draft yet";
  }

  Object.values(fields).forEach(function (field) {
    field.addEventListener("input", saveDraft);
    field.addEventListener("change", saveDraft);
  });

  clearButton.addEventListener("click", clearDraft);

  loadDraft();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-one-demo"&gt;
  &lt;div class="vb-storage-one-card" data-vb-storage-one&gt;
    &lt;div class="vb-storage-one-info"&gt;
      &lt;span class="vb-storage-one-kicker"&gt;Example 01&lt;/span&gt;
      &lt;h3&gt;Saved Contact Draft&lt;/h3&gt;
      &lt;p&gt;This form saves your draft in the browser while you type. Refresh the page and the values will still be there.&lt;/p&gt;

      &lt;div class="vb-storage-one-status" data-status&gt;
        Draft status: waiting for input
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;form class="vb-storage-one-form"&gt;
      &lt;label&gt;
        &lt;span&gt;Your name&lt;/span&gt;
        &lt;input type="text" name="name" placeholder="Alex Morgan"&gt;
      &lt;/label&gt;

      &lt;label&gt;
        &lt;span&gt;Email address&lt;/span&gt;
        &lt;input type="email" name="email" placeholder="alex@example.com"&gt;
      &lt;/label&gt;

      &lt;label&gt;
        &lt;span&gt;Project type&lt;/span&gt;
        &lt;select name="project"&gt;
          &lt;option value=""&gt;Choose project type&lt;/option&gt;
          &lt;option value="Website design"&gt;Website design&lt;/option&gt;
          &lt;option value="WordPress plugin"&gt;WordPress plugin&lt;/option&gt;
          &lt;option value="Ecommerce store"&gt;Ecommerce store&lt;/option&gt;
          &lt;option value="JavaScript feature"&gt;JavaScript feature&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;

      &lt;label&gt;
        &lt;span&gt;Project message&lt;/span&gt;
        &lt;textarea name="message" rows="5" placeholder="Tell us what you want to build..."&gt;&lt;/textarea&gt;
      &lt;/label&gt;

      &lt;div class="vb-storage-one-actions"&gt;
        &lt;button type="button" data-clear&gt;Clear Saved Draft&lt;/button&gt;
        &lt;span data-saved-time&gt;No saved draft yet&lt;/span&gt;
      &lt;/div&gt;
    &lt;/form&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-one-demo,
.vb-storage-one-demo * {
  box-sizing: border-box;
}

.vb-storage-one-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 16% 12%, rgba(59, 130, 246, 0.18), transparent 34%),
    radial-gradient(circle at 86% 20%, rgba(16, 185, 129, 0.18), transparent 36%),
    linear-gradient(135deg, #eff6ff 0%, #f0fdfa 55%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-storage-one-card {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: clamp(22px, 4vw, 34px);
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.12);
}

.vb-storage-one-info {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
}

.vb-storage-one-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-one-info h3 {
  margin: 0 0 16px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 6vw, 68px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-one-info p {
  max-width: 520px;
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-storage-one-status {
  display: inline-flex;
  align-self: flex-start;
  padding: 13px 15px;
  border-radius: 18px;
  background: #ecfdf5;
  border: 1px solid rgba(16, 185, 129, 0.24);
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 850;
}

.vb-storage-one-form {
  display: grid;
  gap: 14px;
  min-width: 0;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 24px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-one-form label {
  display: grid;
  gap: 7px;
}

.vb-storage-one-form label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-storage-one-form input,
.vb-storage-one-form select,
.vb-storage-one-form textarea {
  width: 100%;
  border: 1px solid rgba(148, 163, 184, 0.34);
  border-radius: 16px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 650;
  outline: none;
  box-shadow: none;
}

.vb-storage-one-form input,
.vb-storage-one-form select {
  min-height: 48px;
  padding: 0 14px;
}

.vb-storage-one-form textarea {
  resize: vertical;
  padding: 13px 14px;
  line-height: 1.55;
}

.vb-storage-one-form input:focus,
.vb-storage-one-form select:focus,
.vb-storage-one-form textarea:focus {
  border-color: rgba(37, 99, 235, 0.76);
  box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.10);
}

.vb-storage-one-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  margin-top: 2px;
}

.vb-storage-one-actions button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 11px 15px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 14px 34px rgba(37, 99, 235, 0.22);
}

.vb-storage-one-actions span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 750;
}

@media (max-width: 880px) {
  .vb-storage-one-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-storage-one-card {
    padding: 18px;
    border-radius: 22px;
  }

  .vb-storage-one-info h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }

  .vb-storage-one-actions button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This localStorage form draft example is useful for contact pages, lead generation forms, quote request forms, support forms, onboarding forms, and long message fields where users should not lose their progress after a page refresh.</p>



<h2 class="wp-block-heading">2. LocalStorage Shopping Cart with Quantity Updates</h2>



<p class="wp-block-paragraph"><strong>A localStorage shopping cart</strong> is a great way to learn how browser storage works with arrays, objects, buttons, totals, and dynamic UI rendering. It can store cart items in the browser without a backend, making it useful for demos, prototypes, and small front-end ecommerce examples.</p>



<p class="wp-block-paragraph">This example lets users add products to a mini cart, increase or decrease quantities, remove items, clear the cart, and keep the cart saved after refresh. JavaScript stores the cart as a JSON array in localStorage and rebuilds the cart interface on page load.</p>



<ul class="wp-block-list">
<li>Persistent shopping cart</li>
<li>Add, remove, increase, and decrease items</li>
<li>Stores array of cart products as JSON</li>
<li>Calculates cart total automatically</li>
<li>Works after page refresh</li>
</ul>



<div class="vb-storage-two-demo">
  <div class="vb-storage-two-shop" data-vb-storage-two>
    <div class="vb-storage-two-header">
      <span class="vb-storage-two-kicker">Example 02</span>
      <h3>Persistent Mini Cart</h3>
      <p>Add products to the cart, refresh the page, and the selected items will still be saved in localStorage.</p>
    </div>

    <div class="vb-storage-two-layout">
      <div class="vb-storage-two-products">
        <article class="vb-storage-two-product">
          <div class="vb-storage-two-product-icon">JS</div>
          <div>
            <h4>JavaScript UI Kit</h4>
            <p>Reusable UI components</p>
          </div>
          <strong>29€</strong>
          <button type="button" data-add-cart data-id="ui-kit" data-name="JavaScript UI Kit" data-price="29">Add</button>
        </article>

        <article class="vb-storage-two-product">
          <div class="vb-storage-two-product-icon">WP</div>
          <div>
            <h4>WordPress Snippet Pack</h4>
            <p>Useful frontend features</p>
          </div>
          <strong>39€</strong>
          <button type="button" data-add-cart data-id="wp-pack" data-name="WordPress Snippet Pack" data-price="39">Add</button>
        </article>

        <article class="vb-storage-two-product">
          <div class="vb-storage-two-product-icon">SEO</div>
          <div>
            <h4>SEO Schema Template</h4>
            <p>Structured data starter</p>
          </div>
          <strong>19€</strong>
          <button type="button" data-add-cart data-id="schema-template" data-name="SEO Schema Template" data-price="19">Add</button>
        </article>
      </div>

      <div class="vb-storage-two-cart">
        <div class="vb-storage-two-cart-head">
          <strong>Your Cart</strong>
          <span data-cart-count>0 items</span>
        </div>

        <div class="vb-storage-two-cart-list" data-cart-list>
          <p class="vb-storage-two-empty">Your cart is empty.</p>
        </div>

        <div class="vb-storage-two-total">
          <span>Total</span>
          <strong data-cart-total>0€</strong>
        </div>

        <button class="vb-storage-two-clear" type="button" data-clear-cart>Clear Cart</button>
      </div>
    </div>
  </div>
</div>

<style>
.vb-storage-two-demo,
.vb-storage-two-demo * {
  box-sizing: border-box;
}

.vb-storage-two-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 42px;
  background:
    radial-gradient(circle at 12% 18%, rgba(14, 165, 233, 0.18), transparent 34%),
    radial-gradient(circle at 88% 14%, rgba(168, 85, 247, 0.18), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.18);
  box-shadow: 0 28px 80px rgba(79, 70, 229, 0.10);
}

.vb-storage-two-shop {
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #0f172a;
  overflow: hidden;
  box-shadow: 0 28px 90px rgba(15, 23, 42, 0.28);
}

.vb-storage-two-header {
  display: grid;
  gap: 12px;
  margin-bottom: 24px;
}

.vb-storage-two-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-two-header h3 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-two-header p {
  max-width: 720px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-two-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(310px, 390px);
  gap: 20px;
  align-items: start;
}

.vb-storage-two-products {
  display: grid;
  gap: 14px;
}

.vb-storage-two-product {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr) auto auto;
  gap: 14px;
  align-items: center;
  min-width: 0;
  padding: 16px;
  border-radius: 24px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-two-product-icon {
  display: grid;
  place-items: center;
  width: 64px;
  height: 64px;
  border-radius: 20px;
  background: linear-gradient(135deg, #2563eb, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 17px;
  font-weight: 950;
}

.vb-storage-two-product h4 {
  margin: 0 0 5px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 17px !important;
  line-height: 1.2 !important;
  font-weight: 900 !important;
}

.vb-storage-two-product p {
  margin: 0 !important;
  color: #94a3b8 !important;
  -webkit-text-fill-color: #94a3b8 !important;
  font-size: 13px;
  font-weight: 650;
}

.vb-storage-two-product strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 19px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-storage-two-product button,
.vb-storage-two-clear {
  border: 0;
  cursor: pointer;
  font-weight: 950;
}

.vb-storage-two-product button {
  min-height: 42px;
  padding: 10px 14px;
  border-radius: 999px;
  background: #ffffff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
}

.vb-storage-two-cart {
  display: grid;
  gap: 14px;
  padding: 18px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 20px 60px rgba(2, 6, 23, 0.20);
}

.vb-storage-two-cart-head,
.vb-storage-two-total {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.vb-storage-two-cart-head strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 22px;
  font-weight: 950;
}

.vb-storage-two-cart-head span {
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-storage-two-cart-list {
  display: grid;
  gap: 10px;
  min-height: 110px;
}

.vb-storage-two-empty {
  display: grid;
  place-items: center;
  min-height: 110px;
  margin: 0 !important;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  border-radius: 18px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-two-cart-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  padding: 12px;
  border-radius: 18px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-two-cart-item h5 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px !important;
  line-height: 1.2 !important;
  font-weight: 900 !important;
}

.vb-storage-two-cart-item p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 750;
}

.vb-storage-two-qty {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}

.vb-storage-two-qty button {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border: 0;
  border-radius: 999px;
  background: #e0e7ff;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: 16px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-two-qty span {
  min-width: 24px;
  text-align: center;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-two-total {
  padding: 14px;
  border-radius: 18px;
  background: #eff6ff;
}

.vb-storage-two-total span {
  color: #1e3a8a !important;
  -webkit-text-fill-color: #1e3a8a !important;
  font-size: 13px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-storage-two-total strong {
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 26px;
  line-height: 1;
  font-weight: 950;
}

.vb-storage-two-clear {
  min-height: 44px;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
}

@media (max-width: 980px) {
  .vb-storage-two-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 680px) {
  .vb-storage-two-product {
    grid-template-columns: 54px minmax(0, 1fr);
  }

  .vb-storage-two-product strong,
  .vb-storage-two-product button {
    grid-column: 2;
    justify-self: start;
  }

  .vb-storage-two-product-icon {
    width: 54px;
    height: 54px;
    border-radius: 17px;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-two]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwoMiniCart";
  const addButtons = wrapper.querySelectorAll("[data-add-cart]");
  const cartList = wrapper.querySelector("[data-cart-list]");
  const cartCount = wrapper.querySelector("[data-cart-count]");
  const cartTotal = wrapper.querySelector("[data-cart-total]");
  const clearCartButton = wrapper.querySelector("[data-clear-cart]");

  let cart = [];

  function saveCart() {
    localStorage.setItem(storageKey, JSON.stringify(cart));
  }

  function loadCart() {
    const savedCart = localStorage.getItem(storageKey);
    if (!savedCart) return;

    try {
      const parsedCart = JSON.parse(savedCart);
      cart = Array.isArray(parsedCart) ? parsedCart : [];
    } catch (error) {
      cart = [];
      localStorage.removeItem(storageKey);
    }
  }

  function getTotalItems() {
    return cart.reduce(function (sum, item) {
      return sum + item.quantity;
    }, 0);
  }

  function getTotalPrice() {
    return cart.reduce(function (sum, item) {
      return sum + item.price * item.quantity;
    }, 0);
  }

  function renderCart() {
    cartList.innerHTML = "";

    if (cart.length === 0) {
      cartList.innerHTML = '&lt;p class="vb-storage-two-empty"&gt;Your cart is empty.&lt;/p&gt;';
    } else {
      cart.forEach(function (item) {
        const cartItem = document.createElement("div");
        cartItem.className = "vb-storage-two-cart-item";

        cartItem.innerHTML =
          '&lt;div&gt;' +
            '&lt;h5&gt;' + item.name + '&lt;/h5&gt;' +
            '&lt;p&gt;' + item.price + '€ each&lt;/p&gt;' +
          '&lt;/div&gt;' +
          '&lt;div class="vb-storage-two-qty"&gt;' +
            '&lt;button type="button" data-decrease="' + item.id + '"&gt;-&lt;/button&gt;' +
            '&lt;span&gt;' + item.quantity + '&lt;/span&gt;' +
            '&lt;button type="button" data-increase="' + item.id + '"&gt;+&lt;/button&gt;' +
          '&lt;/div&gt;';

        cartList.appendChild(cartItem);
      });
    }

    const totalItems = getTotalItems();
    cartCount.textContent = totalItems === 1 ? "1 item" : totalItems + " items";
    cartTotal.textContent = getTotalPrice() + "€";
  }

  function addToCart(product) {
    const existingItem = cart.find(function (item) {
      return item.id === product.id;
    });

    if (existingItem) {
      existingItem.quantity += 1;
    } else {
      cart.push({
        id: product.id,
        name: product.name,
        price: product.price,
        quantity: 1
      });
    }

    saveCart();
    renderCart();
  }

  function changeQuantity(productId, direction) {
    const item = cart.find(function (cartItem) {
      return cartItem.id === productId;
    });

    if (!item) return;

    item.quantity += direction;

    if (item.quantity <= 0) {
      cart = cart.filter(function (cartItem) {
        return cartItem.id !== productId;
      });
    }

    saveCart();
    renderCart();
  }

  addButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      addToCart({
        id: button.getAttribute("data-id"),
        name: button.getAttribute("data-name"),
        price: Number(button.getAttribute("data-price"))
      });
    });
  });

  cartList.addEventListener("click", function (event) {
    const increaseId = event.target.getAttribute("data-increase");
    const decreaseId = event.target.getAttribute("data-decrease");

    if (increaseId) {
      changeQuantity(increaseId, 1);
    }

    if (decreaseId) {
      changeQuantity(decreaseId, -1);
    }
  });

  clearCartButton.addEventListener("click", function () {
    cart = [];
    saveCart();
    renderCart();
  });

  loadCart();
  renderCart();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-two]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwoMiniCart";
  const addButtons = wrapper.querySelectorAll("[data-add-cart]");
  const cartList = wrapper.querySelector("[data-cart-list]");
  const cartCount = wrapper.querySelector("[data-cart-count]");
  const cartTotal = wrapper.querySelector("[data-cart-total]");
  const clearCartButton = wrapper.querySelector("[data-clear-cart]");

  let cart = [];

  function saveCart() {
    localStorage.setItem(storageKey, JSON.stringify(cart));
  }

  function loadCart() {
    const savedCart = localStorage.getItem(storageKey);
    if (!savedCart) return;

    try {
      const parsedCart = JSON.parse(savedCart);
      cart = Array.isArray(parsedCart) ? parsedCart : [];
    } catch (error) {
      cart = [];
      localStorage.removeItem(storageKey);
    }
  }

  function getTotalItems() {
    return cart.reduce(function (sum, item) {
      return sum + item.quantity;
    }, 0);
  }

  function getTotalPrice() {
    return cart.reduce(function (sum, item) {
      return sum + item.price * item.quantity;
    }, 0);
  }

  function renderCart() {
    cartList.innerHTML = "";

    if (cart.length === 0) {
      cartList.innerHTML = '&lt;p class="vb-storage-two-empty"&gt;Your cart is empty.&lt;/p&gt;';
    } else {
      cart.forEach(function (item) {
        const cartItem = document.createElement("div");
        cartItem.className = "vb-storage-two-cart-item";

        cartItem.innerHTML =
          '&lt;div&gt;' +
            '&lt;h5&gt;' + item.name + '&lt;/h5&gt;' +
            '&lt;p&gt;' + item.price + '€ each&lt;/p&gt;' +
          '&lt;/div&gt;' +
          '&lt;div class="vb-storage-two-qty"&gt;' +
            '&lt;button type="button" data-decrease="' + item.id + '"&gt;-&lt;/button&gt;' +
            '&lt;span&gt;' + item.quantity + '&lt;/span&gt;' +
            '&lt;button type="button" data-increase="' + item.id + '"&gt;+&lt;/button&gt;' +
          '&lt;/div&gt;';

        cartList.appendChild(cartItem);
      });
    }

    const totalItems = getTotalItems();
    cartCount.textContent = totalItems === 1 ? "1 item" : totalItems + " items";
    cartTotal.textContent = getTotalPrice() + "€";
  }

  function addToCart(product) {
    const existingItem = cart.find(function (item) {
      return item.id === product.id;
    });

    if (existingItem) {
      existingItem.quantity += 1;
    } else {
      cart.push({
        id: product.id,
        name: product.name,
        price: product.price,
        quantity: 1
      });
    }

    saveCart();
    renderCart();
  }

  function changeQuantity(productId, direction) {
    const item = cart.find(function (cartItem) {
      return cartItem.id === productId;
    });

    if (!item) return;

    item.quantity += direction;

    if (item.quantity &lt;= 0) {
      cart = cart.filter(function (cartItem) {
        return cartItem.id !== productId;
      });
    }

    saveCart();
    renderCart();
  }

  addButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      addToCart({
        id: button.getAttribute("data-id"),
        name: button.getAttribute("data-name"),
        price: Number(button.getAttribute("data-price"))
      });
    });
  });

  cartList.addEventListener("click", function (event) {
    const increaseId = event.target.getAttribute("data-increase");
    const decreaseId = event.target.getAttribute("data-decrease");

    if (increaseId) {
      changeQuantity(increaseId, 1);
    }

    if (decreaseId) {
      changeQuantity(decreaseId, -1);
    }
  });

  clearCartButton.addEventListener("click", function () {
    cart = [];
    saveCart();
    renderCart();
  });

  loadCart();
  renderCart();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-two-demo"&gt;
  &lt;div class="vb-storage-two-shop" data-vb-storage-two&gt;
    &lt;div class="vb-storage-two-header"&gt;
      &lt;span class="vb-storage-two-kicker"&gt;Example 02&lt;/span&gt;
      &lt;h3&gt;Persistent Mini Cart&lt;/h3&gt;
      &lt;p&gt;Add products to the cart, refresh the page, and the selected items will still be saved in localStorage.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-two-layout"&gt;
      &lt;div class="vb-storage-two-products"&gt;
        &lt;article class="vb-storage-two-product"&gt;
          &lt;div class="vb-storage-two-product-icon"&gt;JS&lt;/div&gt;
          &lt;div&gt;
            &lt;h4&gt;JavaScript UI Kit&lt;/h4&gt;
            &lt;p&gt;Reusable UI components&lt;/p&gt;
          &lt;/div&gt;
          &lt;strong&gt;29€&lt;/strong&gt;
          &lt;button type="button" data-add-cart data-id="ui-kit" data-name="JavaScript UI Kit" data-price="29"&gt;Add&lt;/button&gt;
        &lt;/article&gt;

        &lt;article class="vb-storage-two-product"&gt;
          &lt;div class="vb-storage-two-product-icon"&gt;WP&lt;/div&gt;
          &lt;div&gt;
            &lt;h4&gt;WordPress Snippet Pack&lt;/h4&gt;
            &lt;p&gt;Useful frontend features&lt;/p&gt;
          &lt;/div&gt;
          &lt;strong&gt;39€&lt;/strong&gt;
          &lt;button type="button" data-add-cart data-id="wp-pack" data-name="WordPress Snippet Pack" data-price="39"&gt;Add&lt;/button&gt;
        &lt;/article&gt;

        &lt;article class="vb-storage-two-product"&gt;
          &lt;div class="vb-storage-two-product-icon"&gt;SEO&lt;/div&gt;
          &lt;div&gt;
            &lt;h4&gt;SEO Schema Template&lt;/h4&gt;
            &lt;p&gt;Structured data starter&lt;/p&gt;
          &lt;/div&gt;
          &lt;strong&gt;19€&lt;/strong&gt;
          &lt;button type="button" data-add-cart data-id="schema-template" data-name="SEO Schema Template" data-price="19"&gt;Add&lt;/button&gt;
        &lt;/article&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-two-cart"&gt;
        &lt;div class="vb-storage-two-cart-head"&gt;
          &lt;strong&gt;Your Cart&lt;/strong&gt;
          &lt;span data-cart-count&gt;0 items&lt;/span&gt;
        &lt;/div&gt;

        &lt;div class="vb-storage-two-cart-list" data-cart-list&gt;
          &lt;p class="vb-storage-two-empty"&gt;Your cart is empty.&lt;/p&gt;
        &lt;/div&gt;

        &lt;div class="vb-storage-two-total"&gt;
          &lt;span&gt;Total&lt;/span&gt;
          &lt;strong data-cart-total&gt;0€&lt;/strong&gt;
        &lt;/div&gt;

        &lt;button class="vb-storage-two-clear" type="button" data-clear-cart&gt;Clear Cart&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-two-demo,
.vb-storage-two-demo * {
  box-sizing: border-box;
}

.vb-storage-two-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 42px;
  background:
    radial-gradient(circle at 12% 18%, rgba(14, 165, 233, 0.18), transparent 34%),
    radial-gradient(circle at 88% 14%, rgba(168, 85, 247, 0.18), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.18);
  box-shadow: 0 28px 80px rgba(79, 70, 229, 0.10);
}

.vb-storage-two-shop {
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #0f172a;
  overflow: hidden;
  box-shadow: 0 28px 90px rgba(15, 23, 42, 0.28);
}

.vb-storage-two-header {
  display: grid;
  gap: 12px;
  margin-bottom: 24px;
}

.vb-storage-two-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-two-header h3 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-two-header p {
  max-width: 720px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-two-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(310px, 390px);
  gap: 20px;
  align-items: start;
}

.vb-storage-two-products {
  display: grid;
  gap: 14px;
}

.vb-storage-two-product {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr) auto auto;
  gap: 14px;
  align-items: center;
  min-width: 0;
  padding: 16px;
  border-radius: 24px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-two-product-icon {
  display: grid;
  place-items: center;
  width: 64px;
  height: 64px;
  border-radius: 20px;
  background: linear-gradient(135deg, #2563eb, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 17px;
  font-weight: 950;
}

.vb-storage-two-product h4 {
  margin: 0 0 5px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 17px !important;
  line-height: 1.2 !important;
  font-weight: 900 !important;
}

.vb-storage-two-product p {
  margin: 0 !important;
  color: #94a3b8 !important;
  -webkit-text-fill-color: #94a3b8 !important;
  font-size: 13px;
  font-weight: 650;
}

.vb-storage-two-product strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 19px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-storage-two-product button,
.vb-storage-two-clear {
  border: 0;
  cursor: pointer;
  font-weight: 950;
}

.vb-storage-two-product button {
  min-height: 42px;
  padding: 10px 14px;
  border-radius: 999px;
  background: #ffffff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
}

.vb-storage-two-cart {
  display: grid;
  gap: 14px;
  padding: 18px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 20px 60px rgba(2, 6, 23, 0.20);
}

.vb-storage-two-cart-head,
.vb-storage-two-total {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.vb-storage-two-cart-head strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 22px;
  font-weight: 950;
}

.vb-storage-two-cart-head span {
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-storage-two-cart-list {
  display: grid;
  gap: 10px;
  min-height: 110px;
}

.vb-storage-two-empty {
  display: grid;
  place-items: center;
  min-height: 110px;
  margin: 0 !important;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  border-radius: 18px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-two-cart-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  padding: 12px;
  border-radius: 18px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-two-cart-item h5 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px !important;
  line-height: 1.2 !important;
  font-weight: 900 !important;
}

.vb-storage-two-cart-item p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 750;
}

.vb-storage-two-qty {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  white-space: nowrap;
}

.vb-storage-two-qty button {
  display: grid;
  place-items: center;
  width: 28px;
  height: 28px;
  border: 0;
  border-radius: 999px;
  background: #e0e7ff;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: 16px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-two-qty span {
  min-width: 24px;
  text-align: center;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-two-total {
  padding: 14px;
  border-radius: 18px;
  background: #eff6ff;
}

.vb-storage-two-total span {
  color: #1e3a8a !important;
  -webkit-text-fill-color: #1e3a8a !important;
  font-size: 13px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-storage-two-total strong {
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 26px;
  line-height: 1;
  font-weight: 950;
}

.vb-storage-two-clear {
  min-height: 44px;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
}

@media (max-width: 980px) {
  .vb-storage-two-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 680px) {
  .vb-storage-two-product {
    grid-template-columns: 54px minmax(0, 1fr);
  }

  .vb-storage-two-product strong,
  .vb-storage-two-product button {
    grid-column: 2;
    justify-self: start;
  }

  .vb-storage-two-product-icon {
    width: 54px;
    height: 54px;
    border-radius: 17px;
  }
}</pre>



<p class="wp-block-paragraph">This localStorage shopping cart example is useful for ecommerce prototypes, product landing pages, mini carts, digital product pages, simple checkout demos, and JavaScript projects that need persistent cart state without a backend.</p>



<h2 class="wp-block-heading">3. Dark Mode Preference Saved with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>A dark mode preference saved with localStorage</strong> lets visitors choose their preferred interface style and keep that choice after refreshing or returning to the page later. This is one of the most common and useful localStorage patterns for modern websites.</p>



<p class="wp-block-paragraph">This example uses a polished settings card with light mode, dark mode, and system-style buttons. JavaScript saves the selected theme name in localStorage, updates the demo instantly, and restores the same theme when the page loads again.</p>



<ul class="wp-block-list">
<li>Save dark mode preference</li>
<li>Light, dark, and soft system-style modes</li>
<li>Instant UI update</li>
<li>Restores selected theme after refresh</li>
<li>Useful for dashboards, blogs, and web apps</li>
</ul>



<div class="vb-storage-three-demo">
  <div class="vb-storage-three-app" data-vb-storage-three data-theme="soft">
    <div class="vb-storage-three-sidebar">
      <span class="vb-storage-three-kicker">Example 03</span>
      <h3>Saved Theme Preference</h3>
      <p>Choose a theme and refresh the page. The selected style is saved in localStorage and restored automatically.</p>

      <div class="vb-storage-three-buttons" role="group" aria-label="Theme preference buttons">
        <button type="button" data-theme-button="light">Light</button>
        <button type="button" data-theme-button="dark">Dark</button>
        <button type="button" data-theme-button="soft">Soft</button>
      </div>

      <div class="vb-storage-three-current">
        Current theme: <strong data-current-theme>Soft</strong>
      </div>
    </div>

    <div class="vb-storage-three-panel">
      <div class="vb-storage-three-topbar">
        <span></span>
        <span></span>
        <span></span>
      </div>

      <div class="vb-storage-three-content">
        <div class="vb-storage-three-avatar">UI</div>
        <div>
          <h4>Dashboard Appearance</h4>
          <p>Your theme preference is stored locally in the browser, so this dashboard remembers the selected look.</p>
        </div>
      </div>

      <div class="vb-storage-three-metrics">
        <div>
          <span>Saved setting</span>
          <strong data-setting-label>theme: soft</strong>
        </div>

        <div>
          <span>Storage type</span>
          <strong>localStorage</strong>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-storage-three-demo,
.vb-storage-three-demo * {
  box-sizing: border-box;
}

.vb-storage-three-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 22px 54px 22px 54px;
  background:
    linear-gradient(90deg, rgba(15, 23, 42, 0.045) 1px, transparent 1px),
    linear-gradient(0deg, rgba(15, 23, 42, 0.045) 1px, transparent 1px),
    linear-gradient(135deg, #ffffff 0%, #f8fafc 100%) !important;
  background-size: 26px 26px, 26px 26px, auto !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-storage-three-app {
  display: grid;
  grid-template-columns: minmax(0, 0.78fr) minmax(0, 1.22fr);
  gap: 22px;
  max-width: 1140px;
  margin: 0 auto;
  padding: clamp(18px, 4vw, 30px);
  border-radius: 18px 42px 18px 42px;
  transition: background 0.25s ease, color 0.25s ease;
}

.vb-storage-three-app[data-theme="light"] {
  background: #ffffff;
  color: #0f172a;
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.12);
}

.vb-storage-three-app[data-theme="dark"] {
  background: #0f172a;
  color: #ffffff;
  box-shadow: 0 24px 70px rgba(2, 6, 23, 0.34);
}

.vb-storage-three-app[data-theme="soft"] {
  background: linear-gradient(135deg, #eef2ff, #ecfdf5);
  color: #0f172a;
  box-shadow: 0 24px 70px rgba(79, 70, 229, 0.14);
}

.vb-storage-three-sidebar,
.vb-storage-three-panel {
  min-width: 0;
}

.vb-storage-three-sidebar {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(18px, 3vw, 28px);
  border-radius: 18px 34px 18px 34px;
}

.vb-storage-three-app[data-theme="light"] .vb-storage-three-sidebar {
  background: #f8fafc;
}

.vb-storage-three-app[data-theme="dark"] .vb-storage-three-sidebar {
  background: rgba(255,255,255,0.07);
}

.vb-storage-three-app[data-theme="soft"] .vb-storage-three-sidebar {
  background: rgba(255,255,255,0.72);
}

.vb-storage-three-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-three-app[data-theme="dark"] .vb-storage-three-kicker {
  background: rgba(96, 165, 250, 0.18);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
}

.vb-storage-three-sidebar h3 {
  margin: 0 0 16px !important;
  font-size: clamp(35px, 5.8vw, 66px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-three-app[data-theme="light"] .vb-storage-three-sidebar h3,
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-sidebar h3 {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
}

.vb-storage-three-app[data-theme="dark"] .vb-storage-three-sidebar h3 {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-three-sidebar p {
  max-width: 520px;
  margin: 0 0 22px !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-storage-three-app[data-theme="light"] .vb-storage-three-sidebar p,
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-sidebar p {
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
}

.vb-storage-three-app[data-theme="dark"] .vb-storage-three-sidebar p {
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
}

.vb-storage-three-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 18px;
}

.vb-storage-three-buttons button {
  min-height: 44px;
  padding: 10px 15px;
  border: 0;
  border-radius: 999px;
  background: #2563eb;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 14px 34px rgba(37, 99, 235, 0.20);
}

.vb-storage-three-buttons button.is-active {
  background: linear-gradient(135deg, #10b981, #06b6d4);
}

.vb-storage-three-current {
  display: inline-flex;
  align-self: flex-start;
  padding: 12px 14px;
  border-radius: 16px;
  font-size: 14px;
  font-weight: 850;
}

.vb-storage-three-app[data-theme="light"] .vb-storage-three-current,
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-current {
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
}

.vb-storage-three-app[data-theme="dark"] .vb-storage-three-current {
  background: rgba(255,255,255,0.09);
  color: #e2e8f0 !important;
  -webkit-text-fill-color: #e2e8f0 !important;
}

.vb-storage-three-current strong {
  margin-left: 5px;
}

.vb-storage-three-panel {
  display: grid;
  gap: 18px;
  align-content: center;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 34px 12px 34px 12px;
}

.vb-storage-three-app[data-theme="light"] .vb-storage-three-panel {
  background: #eff6ff;
  border: 1px solid rgba(37, 99, 235, 0.16);
}

.vb-storage-three-app[data-theme="dark"] .vb-storage-three-panel {
  background: rgba(255,255,255,0.07);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-three-app[data-theme="soft"] .vb-storage-three-panel {
  background: rgba(255,255,255,0.76);
  border: 1px solid rgba(255,255,255,0.72);
}

.vb-storage-three-topbar {
  display: flex;
  gap: 8px;
}

.vb-storage-three-topbar span {
  width: 12px;
  height: 12px;
  border-radius: 999px;
  background: #60a5fa;
}

.vb-storage-three-topbar span:nth-child(2) {
  background: #34d399;
}

.vb-storage-three-topbar span:nth-child(3) {
  background: #a78bfa;
}

.vb-storage-three-content {
  display: grid;
  grid-template-columns: 78px minmax(0, 1fr);
  gap: 18px;
  align-items: center;
  padding: 22px;
  border-radius: 26px;
}

.vb-storage-three-app[data-theme="light"] .vb-storage-three-content,
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-content {
  background: #ffffff;
}

.vb-storage-three-app[data-theme="dark"] .vb-storage-three-content {
  background: rgba(15, 23, 42, 0.70);
}

.vb-storage-three-avatar {
  display: grid;
  place-items: center;
  width: 78px;
  height: 78px;
  border-radius: 24px;
  background: linear-gradient(135deg, #2563eb, #10b981);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  font-weight: 950;
}

.vb-storage-three-content h4 {
  margin: 0 0 8px !important;
  font-size: clamp(22px, 3vw, 32px) !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
}

.vb-storage-three-app[data-theme="light"] .vb-storage-three-content h4,
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-content h4 {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
}

.vb-storage-three-app[data-theme="dark"] .vb-storage-three-content h4 {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-three-content p {
  margin: 0 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-storage-three-app[data-theme="light"] .vb-storage-three-content p,
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-content p {
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
}

.vb-storage-three-app[data-theme="dark"] .vb-storage-three-content p {
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
}

.vb-storage-three-metrics {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-storage-three-metrics div {
  padding: 16px;
  border-radius: 22px;
}

.vb-storage-three-app[data-theme="light"] .vb-storage-three-metrics div,
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-metrics div {
  background: #ffffff;
}

.vb-storage-three-app[data-theme="dark"] .vb-storage-three-metrics div {
  background: rgba(15, 23, 42, 0.70);
}

.vb-storage-three-metrics span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-storage-three-metrics strong {
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 18px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-storage-three-app[data-theme="dark"] .vb-storage-three-metrics strong {
  color: #93c5fd !important;
  -webkit-text-fill-color: #93c5fd !important;
}

@media (max-width: 900px) {
  .vb-storage-three-app {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-storage-three-content {
    grid-template-columns: 1fr;
  }

  .vb-storage-three-metrics {
    grid-template-columns: 1fr;
  }

  .vb-storage-three-sidebar h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}
</style>

<script>
(function () {
  const app = document.querySelector("[data-vb-storage-three]");
  if (!app) return;

  const storageKey = "vbStorageThreeTheme";
  const buttons = app.querySelectorAll("[data-theme-button]");
  const currentTheme = app.querySelector("[data-current-theme]");
  const settingLabel = app.querySelector("[data-setting-label]");

  function formatThemeName(theme) {
    return theme.charAt(0).toUpperCase() + theme.slice(1);
  }

  function applyTheme(theme) {
    app.setAttribute("data-theme", theme);
    currentTheme.textContent = formatThemeName(theme);
    settingLabel.textContent = "theme: " + theme;

    buttons.forEach(function (button) {
      const isActive = button.getAttribute("data-theme-button") === theme;
      button.classList.toggle("is-active", isActive);
    });
  }

  function saveTheme(theme) {
    localStorage.setItem(storageKey, theme);
    applyTheme(theme);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      const selectedTheme = button.getAttribute("data-theme-button");
      saveTheme(selectedTheme);
    });
  });

  const savedTheme = localStorage.getItem(storageKey) || "soft";
  applyTheme(savedTheme);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const app = document.querySelector("[data-vb-storage-three]");
  if (!app) return;

  const storageKey = "vbStorageThreeTheme";
  const buttons = app.querySelectorAll("[data-theme-button]");
  const currentTheme = app.querySelector("[data-current-theme]");
  const settingLabel = app.querySelector("[data-setting-label]");

  function formatThemeName(theme) {
    return theme.charAt(0).toUpperCase() + theme.slice(1);
  }

  function applyTheme(theme) {
    app.setAttribute("data-theme", theme);
    currentTheme.textContent = formatThemeName(theme);
    settingLabel.textContent = "theme: " + theme;

    buttons.forEach(function (button) {
      const isActive = button.getAttribute("data-theme-button") === theme;
      button.classList.toggle("is-active", isActive);
    });
  }

  function saveTheme(theme) {
    localStorage.setItem(storageKey, theme);
    applyTheme(theme);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      const selectedTheme = button.getAttribute("data-theme-button");
      saveTheme(selectedTheme);
    });
  });

  const savedTheme = localStorage.getItem(storageKey) || "soft";
  applyTheme(savedTheme);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-three-demo"&gt;
  &lt;div class="vb-storage-three-app" data-vb-storage-three data-theme="soft"&gt;
    &lt;div class="vb-storage-three-sidebar"&gt;
      &lt;span class="vb-storage-three-kicker"&gt;Example 03&lt;/span&gt;
      &lt;h3&gt;Saved Theme Preference&lt;/h3&gt;
      &lt;p&gt;Choose a theme and refresh the page. The selected style is saved in localStorage and restored automatically.&lt;/p&gt;

      &lt;div class="vb-storage-three-buttons" role="group" aria-label="Theme preference buttons"&gt;
        &lt;button type="button" data-theme-button="light"&gt;Light&lt;/button&gt;
        &lt;button type="button" data-theme-button="dark"&gt;Dark&lt;/button&gt;
        &lt;button type="button" data-theme-button="soft"&gt;Soft&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-three-current"&gt;
        Current theme: &lt;strong data-current-theme&gt;Soft&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-three-panel"&gt;
      &lt;div class="vb-storage-three-topbar"&gt;
        &lt;span&gt;&lt;/span&gt;
        &lt;span&gt;&lt;/span&gt;
        &lt;span&gt;&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-three-content"&gt;
        &lt;div class="vb-storage-three-avatar"&gt;UI&lt;/div&gt;
        &lt;div&gt;
          &lt;h4&gt;Dashboard Appearance&lt;/h4&gt;
          &lt;p&gt;Your theme preference is stored locally in the browser, so this dashboard remembers the selected look.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-three-metrics"&gt;
        &lt;div&gt;
          &lt;span&gt;Saved setting&lt;/span&gt;
          &lt;strong data-setting-label&gt;theme: soft&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;span&gt;Storage type&lt;/span&gt;
          &lt;strong&gt;localStorage&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-three-demo,
.vb-storage-three-demo * {
  box-sizing: border-box;
}

.vb-storage-three-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 22px 54px 22px 54px;
  background:
    linear-gradient(90deg, rgba(15, 23, 42, 0.045) 1px, transparent 1px),
    linear-gradient(0deg, rgba(15, 23, 42, 0.045) 1px, transparent 1px),
    linear-gradient(135deg, #ffffff 0%, #f8fafc 100%) !important;
  background-size: 26px 26px, 26px 26px, auto !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-storage-three-app {
  display: grid;
  grid-template-columns: minmax(0, 0.78fr) minmax(0, 1.22fr);
  gap: 22px;
  max-width: 1140px;
  margin: 0 auto;
  padding: clamp(18px, 4vw, 30px);
  border-radius: 18px 42px 18px 42px;
  transition: background 0.25s ease, color 0.25s ease;
}

.vb-storage-three-app[data-theme="light"] {
  background: #ffffff;
  color: #0f172a;
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.12);
}

.vb-storage-three-app[data-theme="dark"] {
  background: #0f172a;
  color: #ffffff;
  box-shadow: 0 24px 70px rgba(2, 6, 23, 0.34);
}

.vb-storage-three-app[data-theme="soft"] {
  background: linear-gradient(135deg, #eef2ff, #ecfdf5);
  color: #0f172a;
  box-shadow: 0 24px 70px rgba(79, 70, 229, 0.14);
}

.vb-storage-three-sidebar,
.vb-storage-three-panel {
  min-width: 0;
}

.vb-storage-three-sidebar {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(18px, 3vw, 28px);
  border-radius: 18px 34px 18px 34px;
}

.vb-storage-three-app[data-theme="light"] .vb-storage-three-sidebar {
  background: #f8fafc;
}

.vb-storage-three-app[data-theme="dark"] .vb-storage-three-sidebar {
  background: rgba(255,255,255,0.07);
}

.vb-storage-three-app[data-theme="soft"] .vb-storage-three-sidebar {
  background: rgba(255,255,255,0.72);
}

.vb-storage-three-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-three-app[data-theme="dark"] .vb-storage-three-kicker {
  background: rgba(96, 165, 250, 0.18);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
}

.vb-storage-three-sidebar h3 {
  margin: 0 0 16px !important;
  font-size: clamp(35px, 5.8vw, 66px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-three-app[data-theme="light"] .vb-storage-three-sidebar h3,
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-sidebar h3 {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
}

.vb-storage-three-app[data-theme="dark"] .vb-storage-three-sidebar h3 {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-three-sidebar p {
  max-width: 520px;
  margin: 0 0 22px !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-storage-three-app[data-theme="light"] .vb-storage-three-sidebar p,
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-sidebar p {
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
}

.vb-storage-three-app[data-theme="dark"] .vb-storage-three-sidebar p {
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
}

.vb-storage-three-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 18px;
}

.vb-storage-three-buttons button {
  min-height: 44px;
  padding: 10px 15px;
  border: 0;
  border-radius: 999px;
  background: #2563eb;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 14px 34px rgba(37, 99, 235, 0.20);
}

.vb-storage-three-buttons button.is-active {
  background: linear-gradient(135deg, #10b981, #06b6d4);
}

.vb-storage-three-current {
  display: inline-flex;
  align-self: flex-start;
  padding: 12px 14px;
  border-radius: 16px;
  font-size: 14px;
  font-weight: 850;
}

.vb-storage-three-app[data-theme="light"] .vb-storage-three-current,
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-current {
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
}

.vb-storage-three-app[data-theme="dark"] .vb-storage-three-current {
  background: rgba(255,255,255,0.09);
  color: #e2e8f0 !important;
  -webkit-text-fill-color: #e2e8f0 !important;
}

.vb-storage-three-current strong {
  margin-left: 5px;
}

.vb-storage-three-panel {
  display: grid;
  gap: 18px;
  align-content: center;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 34px 12px 34px 12px;
}

.vb-storage-three-app[data-theme="light"] .vb-storage-three-panel {
  background: #eff6ff;
  border: 1px solid rgba(37, 99, 235, 0.16);
}

.vb-storage-three-app[data-theme="dark"] .vb-storage-three-panel {
  background: rgba(255,255,255,0.07);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-three-app[data-theme="soft"] .vb-storage-three-panel {
  background: rgba(255,255,255,0.76);
  border: 1px solid rgba(255,255,255,0.72);
}

.vb-storage-three-topbar {
  display: flex;
  gap: 8px;
}

.vb-storage-three-topbar span {
  width: 12px;
  height: 12px;
  border-radius: 999px;
  background: #60a5fa;
}

.vb-storage-three-topbar span:nth-child(2) {
  background: #34d399;
}

.vb-storage-three-topbar span:nth-child(3) {
  background: #a78bfa;
}

.vb-storage-three-content {
  display: grid;
  grid-template-columns: 78px minmax(0, 1fr);
  gap: 18px;
  align-items: center;
  padding: 22px;
  border-radius: 26px;
}

.vb-storage-three-app[data-theme="light"] .vb-storage-three-content,
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-content {
  background: #ffffff;
}

.vb-storage-three-app[data-theme="dark"] .vb-storage-three-content {
  background: rgba(15, 23, 42, 0.70);
}

.vb-storage-three-avatar {
  display: grid;
  place-items: center;
  width: 78px;
  height: 78px;
  border-radius: 24px;
  background: linear-gradient(135deg, #2563eb, #10b981);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  font-weight: 950;
}

.vb-storage-three-content h4 {
  margin: 0 0 8px !important;
  font-size: clamp(22px, 3vw, 32px) !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
}

.vb-storage-three-app[data-theme="light"] .vb-storage-three-content h4,
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-content h4 {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
}

.vb-storage-three-app[data-theme="dark"] .vb-storage-three-content h4 {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-three-content p {
  margin: 0 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-storage-three-app[data-theme="light"] .vb-storage-three-content p,
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-content p {
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
}

.vb-storage-three-app[data-theme="dark"] .vb-storage-three-content p {
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
}

.vb-storage-three-metrics {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-storage-three-metrics div {
  padding: 16px;
  border-radius: 22px;
}

.vb-storage-three-app[data-theme="light"] .vb-storage-three-metrics div,
.vb-storage-three-app[data-theme="soft"] .vb-storage-three-metrics div {
  background: #ffffff;
}

.vb-storage-three-app[data-theme="dark"] .vb-storage-three-metrics div {
  background: rgba(15, 23, 42, 0.70);
}

.vb-storage-three-metrics span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-storage-three-metrics strong {
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 18px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-storage-three-app[data-theme="dark"] .vb-storage-three-metrics strong {
  color: #93c5fd !important;
  -webkit-text-fill-color: #93c5fd !important;
}

@media (max-width: 900px) {
  .vb-storage-three-app {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-storage-three-content {
    grid-template-columns: 1fr;
  }

  .vb-storage-three-metrics {
    grid-template-columns: 1fr;
  }

  .vb-storage-three-sidebar h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}</pre>



<p class="wp-block-paragraph">This dark mode localStorage example is useful for dashboards, blogs, SaaS apps, user account pages, admin panels, documentation websites, and any interface where users should be able to keep their preferred visual theme.</p>



<h2 class="wp-block-heading">4. Recently Viewed Products Saved with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>A recently viewed products section</strong> is a very practical localStorage feature for ecommerce websites, product catalogs, affiliate sites, digital product shops, and WooCommerce-style layouts. It helps visitors return to products they checked earlier without needing a backend system.</p>



<p class="wp-block-paragraph">This example lets users click product cards and stores the latest viewed products in localStorage. The recently viewed list updates instantly, avoids duplicates, keeps the newest product first, and restores the same list after page refresh.</p>



<ul class="wp-block-list">
<li>Recently viewed products section</li>
<li>Saves clicked products in localStorage</li>
<li>Avoids duplicate product entries</li>
<li>Shows newest viewed product first</li>
<li>Useful for ecommerce and affiliate websites</li>
</ul>



<div class="vb-storage-four-demo">
  <div class="vb-storage-four-shop" data-vb-storage-four>
    <div class="vb-storage-four-intro">
      <span class="vb-storage-four-kicker">Example 04</span>
      <h3>Recently Viewed Products</h3>
      <p>Click a product card. The recently viewed list is saved in localStorage and restored after refresh.</p>
    </div>

    <div class="vb-storage-four-grid">
      <div class="vb-storage-four-products">
        <button type="button" class="vb-storage-four-product" data-view-product data-id="greenhouse-kit" data-name="Greenhouse Starter Kit" data-category="Garden" data-price="249€">
          <span class="vb-storage-four-visual">GH</span>
          <strong>Greenhouse Starter Kit</strong>
          <small>Garden · 249€</small>
        </button>

        <button type="button" class="vb-storage-four-product" data-view-product data-id="seo-plugin" data-name="SEO Schema Plugin" data-category="WordPress" data-price="29€">
          <span class="vb-storage-four-visual">SEO</span>
          <strong>SEO Schema Plugin</strong>
          <small>WordPress · 29€</small>
        </button>

        <button type="button" class="vb-storage-four-product" data-view-product data-id="ui-template" data-name="Landing Page UI Template" data-category="Design" data-price="19€">
          <span class="vb-storage-four-visual">UI</span>
          <strong>Landing Page UI Template</strong>
          <small>Design · 19€</small>
        </button>

        <button type="button" class="vb-storage-four-product" data-view-product data-id="cart-script" data-name="Mini Cart JavaScript" data-category="JavaScript" data-price="15€">
          <span class="vb-storage-four-visual">JS</span>
          <strong>Mini Cart JavaScript</strong>
          <small>JavaScript · 15€</small>
        </button>
      </div>

      <aside class="vb-storage-four-sidebar">
        <div class="vb-storage-four-sidebar-head">
          <strong>Recently Viewed</strong>
          <button type="button" data-clear-recent>Clear</button>
        </div>

        <div class="vb-storage-four-list" data-recent-list>
          <p class="vb-storage-four-empty">No products viewed yet.</p>
        </div>
      </aside>
    </div>
  </div>
</div>

<style>
.vb-storage-four-demo,
.vb-storage-four-demo * {
  box-sizing: border-box;
}

.vb-storage-four-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 42px;
  background:
    radial-gradient(circle at 12% 18%, rgba(34, 197, 94, 0.18), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #f8fafc 58%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.18);
  box-shadow: 0 28px 80px rgba(22, 101, 52, 0.10);
}

.vb-storage-four-shop {
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-four-intro {
  display: grid;
  gap: 12px;
  margin-bottom: 24px;
}

.vb-storage-four-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-four-intro h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-four-intro p {
  max-width: 740px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-four-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 380px);
  gap: 20px;
  align-items: start;
}

.vb-storage-four-products {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-storage-four-product {
  display: grid;
  gap: 12px;
  min-width: 0;
  padding: 18px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 26px;
  background: #f8fafc;
  text-align: left;
  cursor: pointer;
  transition: transform 0.22s ease, box-shadow 0.22s ease, border-color 0.22s ease;
}

.vb-storage-four-product:hover {
  transform: translateY(-3px);
  border-color: rgba(34, 197, 94, 0.50);
  box-shadow: 0 18px 44px rgba(15, 23, 42, 0.10);
}

.vb-storage-four-visual {
  display: grid;
  place-items: center;
  width: 68px;
  height: 68px;
  border-radius: 22px;
  background: linear-gradient(135deg, #22c55e, #0ea5e9);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-storage-four-product strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-storage-four-product small {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 750;
}

.vb-storage-four-sidebar {
  display: grid;
  gap: 14px;
  padding: 18px;
  border-radius: 28px;
  background: #0f172a;
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.24);
}

.vb-storage-four-sidebar-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.vb-storage-four-sidebar-head strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  font-weight: 950;
}

.vb-storage-four-sidebar-head button {
  min-height: 36px;
  padding: 8px 12px;
  border: 0;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 900;
  cursor: pointer;
}

.vb-storage-four-list {
  display: grid;
  gap: 10px;
  min-height: 220px;
}

.vb-storage-four-empty {
  display: grid;
  place-items: center;
  min-height: 220px;
  margin: 0 !important;
  border: 1px dashed rgba(255,255,255,0.22);
  border-radius: 20px;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-four-recent-item {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 12px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-four-recent-icon {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border-radius: 16px;
  background: linear-gradient(135deg, #22c55e, #0ea5e9);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-four-recent-item strong {
  display: block;
  margin-bottom: 5px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 900;
}

.vb-storage-four-recent-item span {
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 12px;
  font-weight: 800;
}

@media (max-width: 940px) {
  .vb-storage-four-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-storage-four-products {
    grid-template-columns: 1fr;
  }

  .vb-storage-four-intro h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-four]");
  if (!wrapper) return;

  const storageKey = "vbStorageFourRecentlyViewed";
  const productButtons = wrapper.querySelectorAll("[data-view-product]");
  const recentList = wrapper.querySelector("[data-recent-list]");
  const clearButton = wrapper.querySelector("[data-clear-recent]");

  let recentlyViewed = [];

  function saveRecentlyViewed() {
    localStorage.setItem(storageKey, JSON.stringify(recentlyViewed));
  }

  function loadRecentlyViewed() {
    const savedItems = localStorage.getItem(storageKey);
    if (!savedItems) return;

    try {
      const parsedItems = JSON.parse(savedItems);
      recentlyViewed = Array.isArray(parsedItems) ? parsedItems : [];
    } catch (error) {
      recentlyViewed = [];
      localStorage.removeItem(storageKey);
    }
  }

  function renderRecentlyViewed() {
    recentList.innerHTML = "";

    if (recentlyViewed.length === 0) {
      recentList.innerHTML = '<p class="vb-storage-four-empty">No products viewed yet.</p>';
      return;
    }

    recentlyViewed.forEach(function (product) {
      const item = document.createElement("div");
      item.className = "vb-storage-four-recent-item";

      item.innerHTML =
        '<div class="vb-storage-four-recent-icon">' + product.shortLabel + '</div>' +
        '<div>' +
          '<strong>' + product.name + '</strong>' +
          '<span>' + product.category + ' · ' + product.price + '</span>' +
        '</div>';

      recentList.appendChild(item);
    });
  }

  function addViewedProduct(product) {
    recentlyViewed = recentlyViewed.filter(function (item) {
      return item.id !== product.id;
    });

    recentlyViewed.unshift(product);
    recentlyViewed = recentlyViewed.slice(0, 4);

    saveRecentlyViewed();
    renderRecentlyViewed();
  }

  productButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      const product = {
        id: button.getAttribute("data-id"),
        name: button.getAttribute("data-name"),
        category: button.getAttribute("data-category"),
        price: button.getAttribute("data-price"),
        shortLabel: button.querySelector(".vb-storage-four-visual").textContent
      };

      addViewedProduct(product);
    });
  });

  clearButton.addEventListener("click", function () {
    recentlyViewed = [];
    saveRecentlyViewed();
    renderRecentlyViewed();
  });

  loadRecentlyViewed();
  renderRecentlyViewed();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-four]");
  if (!wrapper) return;

  const storageKey = "vbStorageFourRecentlyViewed";
  const productButtons = wrapper.querySelectorAll("[data-view-product]");
  const recentList = wrapper.querySelector("[data-recent-list]");
  const clearButton = wrapper.querySelector("[data-clear-recent]");

  let recentlyViewed = [];

  function saveRecentlyViewed() {
    localStorage.setItem(storageKey, JSON.stringify(recentlyViewed));
  }

  function loadRecentlyViewed() {
    const savedItems = localStorage.getItem(storageKey);
    if (!savedItems) return;

    try {
      const parsedItems = JSON.parse(savedItems);
      recentlyViewed = Array.isArray(parsedItems) ? parsedItems : [];
    } catch (error) {
      recentlyViewed = [];
      localStorage.removeItem(storageKey);
    }
  }

  function renderRecentlyViewed() {
    recentList.innerHTML = "";

    if (recentlyViewed.length === 0) {
      recentList.innerHTML = '&lt;p class="vb-storage-four-empty"&gt;No products viewed yet.&lt;/p&gt;';
      return;
    }

    recentlyViewed.forEach(function (product) {
      const item = document.createElement("div");
      item.className = "vb-storage-four-recent-item";

      item.innerHTML =
        '&lt;div class="vb-storage-four-recent-icon"&gt;' + product.shortLabel + '&lt;/div&gt;' +
        '&lt;div&gt;' +
          '&lt;strong&gt;' + product.name + '&lt;/strong&gt;' +
          '&lt;span&gt;' + product.category + ' · ' + product.price + '&lt;/span&gt;' +
        '&lt;/div&gt;';

      recentList.appendChild(item);
    });
  }

  function addViewedProduct(product) {
    recentlyViewed = recentlyViewed.filter(function (item) {
      return item.id !== product.id;
    });

    recentlyViewed.unshift(product);
    recentlyViewed = recentlyViewed.slice(0, 4);

    saveRecentlyViewed();
    renderRecentlyViewed();
  }

  productButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      const product = {
        id: button.getAttribute("data-id"),
        name: button.getAttribute("data-name"),
        category: button.getAttribute("data-category"),
        price: button.getAttribute("data-price"),
        shortLabel: button.querySelector(".vb-storage-four-visual").textContent
      };

      addViewedProduct(product);
    });
  });

  clearButton.addEventListener("click", function () {
    recentlyViewed = [];
    saveRecentlyViewed();
    renderRecentlyViewed();
  });

  loadRecentlyViewed();
  renderRecentlyViewed();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-four-demo"&gt;
  &lt;div class="vb-storage-four-shop" data-vb-storage-four&gt;
    &lt;div class="vb-storage-four-intro"&gt;
      &lt;span class="vb-storage-four-kicker"&gt;Example 04&lt;/span&gt;
      &lt;h3&gt;Recently Viewed Products&lt;/h3&gt;
      &lt;p&gt;Click a product card. The recently viewed list is saved in localStorage and restored after refresh.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-four-grid"&gt;
      &lt;div class="vb-storage-four-products"&gt;
        &lt;button type="button" class="vb-storage-four-product" data-view-product data-id="greenhouse-kit" data-name="Greenhouse Starter Kit" data-category="Garden" data-price="249€"&gt;
          &lt;span class="vb-storage-four-visual"&gt;GH&lt;/span&gt;
          &lt;strong&gt;Greenhouse Starter Kit&lt;/strong&gt;
          &lt;small&gt;Garden · 249€&lt;/small&gt;
        &lt;/button&gt;

        &lt;button type="button" class="vb-storage-four-product" data-view-product data-id="seo-plugin" data-name="SEO Schema Plugin" data-category="WordPress" data-price="29€"&gt;
          &lt;span class="vb-storage-four-visual"&gt;SEO&lt;/span&gt;
          &lt;strong&gt;SEO Schema Plugin&lt;/strong&gt;
          &lt;small&gt;WordPress · 29€&lt;/small&gt;
        &lt;/button&gt;

        &lt;button type="button" class="vb-storage-four-product" data-view-product data-id="ui-template" data-name="Landing Page UI Template" data-category="Design" data-price="19€"&gt;
          &lt;span class="vb-storage-four-visual"&gt;UI&lt;/span&gt;
          &lt;strong&gt;Landing Page UI Template&lt;/strong&gt;
          &lt;small&gt;Design · 19€&lt;/small&gt;
        &lt;/button&gt;

        &lt;button type="button" class="vb-storage-four-product" data-view-product data-id="cart-script" data-name="Mini Cart JavaScript" data-category="JavaScript" data-price="15€"&gt;
          &lt;span class="vb-storage-four-visual"&gt;JS&lt;/span&gt;
          &lt;strong&gt;Mini Cart JavaScript&lt;/strong&gt;
          &lt;small&gt;JavaScript · 15€&lt;/small&gt;
        &lt;/button&gt;
      &lt;/div&gt;

      &lt;aside class="vb-storage-four-sidebar"&gt;
        &lt;div class="vb-storage-four-sidebar-head"&gt;
          &lt;strong&gt;Recently Viewed&lt;/strong&gt;
          &lt;button type="button" data-clear-recent&gt;Clear&lt;/button&gt;
        &lt;/div&gt;

        &lt;div class="vb-storage-four-list" data-recent-list&gt;
          &lt;p class="vb-storage-four-empty"&gt;No products viewed yet.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/aside&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-four-demo,
.vb-storage-four-demo * {
  box-sizing: border-box;
}

.vb-storage-four-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 42px;
  background:
    radial-gradient(circle at 12% 18%, rgba(34, 197, 94, 0.18), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #f8fafc 58%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.18);
  box-shadow: 0 28px 80px rgba(22, 101, 52, 0.10);
}

.vb-storage-four-shop {
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-four-intro {
  display: grid;
  gap: 12px;
  margin-bottom: 24px;
}

.vb-storage-four-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-four-intro h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-four-intro p {
  max-width: 740px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-four-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 380px);
  gap: 20px;
  align-items: start;
}

.vb-storage-four-products {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-storage-four-product {
  display: grid;
  gap: 12px;
  min-width: 0;
  padding: 18px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 26px;
  background: #f8fafc;
  text-align: left;
  cursor: pointer;
  transition: transform 0.22s ease, box-shadow 0.22s ease, border-color 0.22s ease;
}

.vb-storage-four-product:hover {
  transform: translateY(-3px);
  border-color: rgba(34, 197, 94, 0.50);
  box-shadow: 0 18px 44px rgba(15, 23, 42, 0.10);
}

.vb-storage-four-visual {
  display: grid;
  place-items: center;
  width: 68px;
  height: 68px;
  border-radius: 22px;
  background: linear-gradient(135deg, #22c55e, #0ea5e9);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-storage-four-product strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-storage-four-product small {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 750;
}

.vb-storage-four-sidebar {
  display: grid;
  gap: 14px;
  padding: 18px;
  border-radius: 28px;
  background: #0f172a;
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.24);
}

.vb-storage-four-sidebar-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.vb-storage-four-sidebar-head strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  font-weight: 950;
}

.vb-storage-four-sidebar-head button {
  min-height: 36px;
  padding: 8px 12px;
  border: 0;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 900;
  cursor: pointer;
}

.vb-storage-four-list {
  display: grid;
  gap: 10px;
  min-height: 220px;
}

.vb-storage-four-empty {
  display: grid;
  place-items: center;
  min-height: 220px;
  margin: 0 !important;
  border: 1px dashed rgba(255,255,255,0.22);
  border-radius: 20px;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-four-recent-item {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 12px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-four-recent-icon {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border-radius: 16px;
  background: linear-gradient(135deg, #22c55e, #0ea5e9);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-four-recent-item strong {
  display: block;
  margin-bottom: 5px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 900;
}

.vb-storage-four-recent-item span {
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 12px;
  font-weight: 800;
}

@media (max-width: 940px) {
  .vb-storage-four-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-storage-four-products {
    grid-template-columns: 1fr;
  }

  .vb-storage-four-intro h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}</pre>



<p class="wp-block-paragraph">This recently viewed products localStorage example is useful for ecommerce stores, WooCommerce product pages, affiliate product roundups, comparison websites, product directories, and catalog-style landing pages.</p>



<h2 class="wp-block-heading">5. Saved Search Filters with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>Saved search filters</strong> are useful for product directories, blog archives, job boards, real estate listings, service pages, SaaS dashboards, course libraries, and any interface where users filter a list. LocalStorage can remember the selected search text, category, price range, or sorting option after refresh.</p>



<p class="wp-block-paragraph">This example uses a small resource directory with search, category filter, and sort options. JavaScript saves the selected filter state in localStorage, restores it when the page loads again, and updates the visible results automatically.</p>



<ul class="wp-block-list">
<li>Saved search and filter state</li>
<li>Restores search keyword, category, and sorting</li>
<li>Filters cards instantly</li>
<li>Uses localStorage with a JSON object</li>
<li>Useful for directories, blogs, shops, and dashboards</li>
</ul>



<div class="vb-storage-five-demo">
  <div class="vb-storage-five-directory" data-vb-storage-five>
    <div class="vb-storage-five-head">
      <span class="vb-storage-five-kicker">Example 05</span>
      <h3>Saved Search Filters</h3>
      <p>Search, filter, sort, refresh the page, and your selected directory filters will stay saved in localStorage.</p>
    </div>

    <div class="vb-storage-five-controls">
      <label>
        <span>Search resources</span>
        <input type="search" data-search placeholder="Search JavaScript, WordPress, SEO...">
      </label>

      <label>
        <span>Category</span>
        <select data-category>
          <option value="all">All categories</option>
          <option value="JavaScript">JavaScript</option>
          <option value="WordPress">WordPress</option>
          <option value="SEO">SEO</option>
        </select>
      </label>

      <label>
        <span>Sort by</span>
        <select data-sort>
          <option value="popular">Most popular</option>
          <option value="newest">Newest first</option>
          <option value="az">Name A-Z</option>
        </select>
      </label>

      <button type="button" data-reset-filters>Reset</button>
    </div>

    <div class="vb-storage-five-summary">
      <strong data-result-count>0 results</strong>
      <span data-filter-status>Filters are ready.</span>
    </div>

    <div class="vb-storage-five-results" data-results>
      <article data-item data-title="JavaScript LocalStorage Guide" data-category="JavaScript" data-date="2026-06-01" data-popularity="98">
        <span>JavaScript</span>
        <h4>JavaScript LocalStorage Guide</h4>
        <p>Save form data, carts, preferences, and UI state in the browser.</p>
      </article>

      <article data-item data-title="WordPress Custom Plugin Starter" data-category="WordPress" data-date="2026-05-12" data-popularity="91">
        <span>WordPress</span>
        <h4>WordPress Custom Plugin Starter</h4>
        <p>Build lightweight WordPress plugins with custom frontend features.</p>
      </article>

      <article data-item data-title="Entity SEO Checklist" data-category="SEO" data-date="2026-05-30" data-popularity="96">
        <span>SEO</span>
        <h4>Entity SEO Checklist</h4>
        <p>Improve structured data, internal links, and AI-readable content.</p>
      </article>

      <article data-item data-title="JavaScript Filter UI Examples" data-category="JavaScript" data-date="2026-04-20" data-popularity="89">
        <span>JavaScript</span>
        <h4>JavaScript Filter UI Examples</h4>
        <p>Create searchable and filterable user interfaces with vanilla JavaScript.</p>
      </article>

      <article data-item data-title="WooCommerce Product UX Tips" data-category="WordPress" data-date="2026-03-18" data-popularity="86">
        <span>WordPress</span>
        <h4>WooCommerce Product UX Tips</h4>
        <p>Improve product cards, checkout flows, quote forms, and mini carts.</p>
      </article>

      <article data-item data-title="Schema Markup for Blogs" data-category="SEO" data-date="2026-02-10" data-popularity="82">
        <span>SEO</span>
        <h4>Schema Markup for Blogs</h4>
        <p>Add useful structured data to long-form SEO content and guides.</p>
      </article>
    </div>
  </div>
</div>

<style>
.vb-storage-five-demo,
.vb-storage-five-demo * {
  box-sizing: border-box;
}

.vb-storage-five-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(99, 102, 241, 0.16), transparent 34%),
    radial-gradient(circle at 84% 18%, rgba(236, 72, 153, 0.14), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #faf5ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.18);
  box-shadow: 0 28px 80px rgba(88, 28, 135, 0.10);
}

.vb-storage-five-directory {
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-five-head {
  display: grid;
  gap: 12px;
  margin-bottom: 22px;
}

.vb-storage-five-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-five-head h3 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-five-head p {
  max-width: 760px;
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-five-controls {
  display: grid;
  grid-template-columns: minmax(240px, 1fr) minmax(180px, 230px) minmax(180px, 230px) auto;
  gap: 12px;
  align-items: end;
  padding: 16px;
  border-radius: 24px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-five-controls label {
  display: grid;
  gap: 7px;
  min-width: 0;
}

.vb-storage-five-controls label span {
  color: #374151 !important;
  -webkit-text-fill-color: #374151 !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-storage-five-controls input,
.vb-storage-five-controls select {
  width: 100%;
  min-height: 48px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.34);
  border-radius: 16px;
  background: #ffffff;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 700;
  outline: none;
}

.vb-storage-five-controls input:focus,
.vb-storage-five-controls select:focus {
  border-color: rgba(147, 51, 234, 0.68);
  box-shadow: 0 0 0 4px rgba(147, 51, 234, 0.10);
}

.vb-storage-five-controls button {
  min-height: 48px;
  padding: 0 16px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #7c3aed, #db2777);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-five-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  margin: 18px 0;
  padding: 13px 15px;
  border-radius: 18px;
  background: #faf5ff;
  border: 1px solid rgba(168, 85, 247, 0.18);
}

.vb-storage-five-summary strong {
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-storage-five-summary span {
  color: #6b21a8 !important;
  -webkit-text-fill-color: #6b21a8 !important;
  font-size: 13px;
  font-weight: 750;
}

.vb-storage-five-results {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.vb-storage-five-results article {
  display: grid;
  align-content: start;
  gap: 10px;
  min-height: 210px;
  padding: 18px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 15px 38px rgba(15, 23, 42, 0.07);
}

.vb-storage-five-results article.is-hidden {
  display: none;
}

.vb-storage-five-results article span {
  display: inline-flex;
  justify-self: start;
  padding: 7px 10px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-storage-five-results article h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
}

.vb-storage-five-results article p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 980px) {
  .vb-storage-five-controls {
    grid-template-columns: 1fr 1fr;
  }

  .vb-storage-five-results {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-storage-five-controls,
  .vb-storage-five-results {
    grid-template-columns: 1fr;
  }

  .vb-storage-five-controls button {
    width: 100%;
  }

  .vb-storage-five-head h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-five]");
  if (!wrapper) return;

  const storageKey = "vbStorageFiveFilters";
  const searchInput = wrapper.querySelector("[data-search]");
  const categorySelect = wrapper.querySelector("[data-category]");
  const sortSelect = wrapper.querySelector("[data-sort]");
  const resetButton = wrapper.querySelector("[data-reset-filters]");
  const resultCount = wrapper.querySelector("[data-result-count]");
  const filterStatus = wrapper.querySelector("[data-filter-status]");
  const resultsContainer = wrapper.querySelector("[data-results]");
  const items = Array.from(wrapper.querySelectorAll("[data-item]"));

  function getFilterState() {
    return {
      search: searchInput.value.trim().toLowerCase(),
      category: categorySelect.value,
      sort: sortSelect.value
    };
  }

  function saveFilterState() {
    localStorage.setItem(storageKey, JSON.stringify(getFilterState()));
  }

  function loadFilterState() {
    const savedState = localStorage.getItem(storageKey);
    if (!savedState) return;

    try {
      const state = JSON.parse(savedState);
      searchInput.value = state.search || "";
      categorySelect.value = state.category || "all";
      sortSelect.value = state.sort || "popular";
    } catch (error) {
      localStorage.removeItem(storageKey);
    }
  }

  function sortItems(itemsToSort, sortType) {
    return itemsToSort.slice().sort(function (a, b) {
      if (sortType === "az") {
        return a.dataset.title.localeCompare(b.dataset.title);
      }

      if (sortType === "newest") {
        return new Date(b.dataset.date) - new Date(a.dataset.date);
      }

      return Number(b.dataset.popularity) - Number(a.dataset.popularity);
    });
  }

  function updateResults() {
    const state = getFilterState();
    const sortedItems = sortItems(items, state.sort);
    let visibleCount = 0;

    sortedItems.forEach(function (item) {
      resultsContainer.appendChild(item);

      const title = item.dataset.title.toLowerCase();
      const category = item.dataset.category;
      const matchesSearch = title.includes(state.search);
      const matchesCategory = state.category === "all" || category === state.category;
      const isVisible = matchesSearch && matchesCategory;

      item.classList.toggle("is-hidden", !isVisible);

      if (isVisible) {
        visibleCount += 1;
      }
    });

    resultCount.textContent = visibleCount === 1 ? "1 result" : visibleCount + " results";
    filterStatus.textContent = "Saved filter: " + (state.category === "all" ? "all categories" : state.category) + " · " + state.sort;
    saveFilterState();
  }

  function resetFilters() {
    searchInput.value = "";
    categorySelect.value = "all";
    sortSelect.value = "popular";
    localStorage.removeItem(storageKey);
    updateResults();
  }

  searchInput.addEventListener("input", updateResults);
  categorySelect.addEventListener("change", updateResults);
  sortSelect.addEventListener("change", updateResults);
  resetButton.addEventListener("click", resetFilters);

  loadFilterState();
  updateResults();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-five]");
  if (!wrapper) return;

  const storageKey = "vbStorageFiveFilters";
  const searchInput = wrapper.querySelector("[data-search]");
  const categorySelect = wrapper.querySelector("[data-category]");
  const sortSelect = wrapper.querySelector("[data-sort]");
  const resetButton = wrapper.querySelector("[data-reset-filters]");
  const resultCount = wrapper.querySelector("[data-result-count]");
  const filterStatus = wrapper.querySelector("[data-filter-status]");
  const resultsContainer = wrapper.querySelector("[data-results]");
  const items = Array.from(wrapper.querySelectorAll("[data-item]"));

  function getFilterState() {
    return {
      search: searchInput.value.trim().toLowerCase(),
      category: categorySelect.value,
      sort: sortSelect.value
    };
  }

  function saveFilterState() {
    localStorage.setItem(storageKey, JSON.stringify(getFilterState()));
  }

  function loadFilterState() {
    const savedState = localStorage.getItem(storageKey);
    if (!savedState) return;

    try {
      const state = JSON.parse(savedState);
      searchInput.value = state.search || "";
      categorySelect.value = state.category || "all";
      sortSelect.value = state.sort || "popular";
    } catch (error) {
      localStorage.removeItem(storageKey);
    }
  }

  function sortItems(itemsToSort, sortType) {
    return itemsToSort.slice().sort(function (a, b) {
      if (sortType === "az") {
        return a.dataset.title.localeCompare(b.dataset.title);
      }

      if (sortType === "newest") {
        return new Date(b.dataset.date) - new Date(a.dataset.date);
      }

      return Number(b.dataset.popularity) - Number(a.dataset.popularity);
    });
  }

  function updateResults() {
    const state = getFilterState();
    const sortedItems = sortItems(items, state.sort);
    let visibleCount = 0;

    sortedItems.forEach(function (item) {
      resultsContainer.appendChild(item);

      const title = item.dataset.title.toLowerCase();
      const category = item.dataset.category;
      const matchesSearch = title.includes(state.search);
      const matchesCategory = state.category === "all" || category === state.category;
      const isVisible = matchesSearch && matchesCategory;

      item.classList.toggle("is-hidden", !isVisible);

      if (isVisible) {
        visibleCount += 1;
      }
    });

    resultCount.textContent = visibleCount === 1 ? "1 result" : visibleCount + " results";
    filterStatus.textContent = "Saved filter: " + (state.category === "all" ? "all categories" : state.category) + " · " + state.sort;
    saveFilterState();
  }

  function resetFilters() {
    searchInput.value = "";
    categorySelect.value = "all";
    sortSelect.value = "popular";
    localStorage.removeItem(storageKey);
    updateResults();
  }

  searchInput.addEventListener("input", updateResults);
  categorySelect.addEventListener("change", updateResults);
  sortSelect.addEventListener("change", updateResults);
  resetButton.addEventListener("click", resetFilters);

  loadFilterState();
  updateResults();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-five-demo"&gt;
  &lt;div class="vb-storage-five-directory" data-vb-storage-five&gt;
    &lt;div class="vb-storage-five-head"&gt;
      &lt;span class="vb-storage-five-kicker"&gt;Example 05&lt;/span&gt;
      &lt;h3&gt;Saved Search Filters&lt;/h3&gt;
      &lt;p&gt;Search, filter, sort, refresh the page, and your selected directory filters will stay saved in localStorage.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-five-controls"&gt;
      &lt;label&gt;
        &lt;span&gt;Search resources&lt;/span&gt;
        &lt;input type="search" data-search placeholder="Search JavaScript, WordPress, SEO..."&gt;
      &lt;/label&gt;

      &lt;label&gt;
        &lt;span&gt;Category&lt;/span&gt;
        &lt;select data-category&gt;
          &lt;option value="all"&gt;All categories&lt;/option&gt;
          &lt;option value="JavaScript"&gt;JavaScript&lt;/option&gt;
          &lt;option value="WordPress"&gt;WordPress&lt;/option&gt;
          &lt;option value="SEO"&gt;SEO&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;

      &lt;label&gt;
        &lt;span&gt;Sort by&lt;/span&gt;
        &lt;select data-sort&gt;
          &lt;option value="popular"&gt;Most popular&lt;/option&gt;
          &lt;option value="newest"&gt;Newest first&lt;/option&gt;
          &lt;option value="az"&gt;Name A-Z&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;

      &lt;button type="button" data-reset-filters&gt;Reset&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-five-summary"&gt;
      &lt;strong data-result-count&gt;0 results&lt;/strong&gt;
      &lt;span data-filter-status&gt;Filters are ready.&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-five-results" data-results&gt;
      &lt;article data-item data-title="JavaScript LocalStorage Guide" data-category="JavaScript" data-date="2026-06-01" data-popularity="98"&gt;
        &lt;span&gt;JavaScript&lt;/span&gt;
        &lt;h4&gt;JavaScript LocalStorage Guide&lt;/h4&gt;
        &lt;p&gt;Save form data, carts, preferences, and UI state in the browser.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-item data-title="WordPress Custom Plugin Starter" data-category="WordPress" data-date="2026-05-12" data-popularity="91"&gt;
        &lt;span&gt;WordPress&lt;/span&gt;
        &lt;h4&gt;WordPress Custom Plugin Starter&lt;/h4&gt;
        &lt;p&gt;Build lightweight WordPress plugins with custom frontend features.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-item data-title="Entity SEO Checklist" data-category="SEO" data-date="2026-05-30" data-popularity="96"&gt;
        &lt;span&gt;SEO&lt;/span&gt;
        &lt;h4&gt;Entity SEO Checklist&lt;/h4&gt;
        &lt;p&gt;Improve structured data, internal links, and AI-readable content.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-item data-title="JavaScript Filter UI Examples" data-category="JavaScript" data-date="2026-04-20" data-popularity="89"&gt;
        &lt;span&gt;JavaScript&lt;/span&gt;
        &lt;h4&gt;JavaScript Filter UI Examples&lt;/h4&gt;
        &lt;p&gt;Create searchable and filterable user interfaces with vanilla JavaScript.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-item data-title="WooCommerce Product UX Tips" data-category="WordPress" data-date="2026-03-18" data-popularity="86"&gt;
        &lt;span&gt;WordPress&lt;/span&gt;
        &lt;h4&gt;WooCommerce Product UX Tips&lt;/h4&gt;
        &lt;p&gt;Improve product cards, checkout flows, quote forms, and mini carts.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-item data-title="Schema Markup for Blogs" data-category="SEO" data-date="2026-02-10" data-popularity="82"&gt;
        &lt;span&gt;SEO&lt;/span&gt;
        &lt;h4&gt;Schema Markup for Blogs&lt;/h4&gt;
        &lt;p&gt;Add useful structured data to long-form SEO content and guides.&lt;/p&gt;
      &lt;/article&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-five-demo,
.vb-storage-five-demo * {
  box-sizing: border-box;
}

.vb-storage-five-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(99, 102, 241, 0.16), transparent 34%),
    radial-gradient(circle at 84% 18%, rgba(236, 72, 153, 0.14), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #faf5ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.18);
  box-shadow: 0 28px 80px rgba(88, 28, 135, 0.10);
}

.vb-storage-five-directory {
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-five-head {
  display: grid;
  gap: 12px;
  margin-bottom: 22px;
}

.vb-storage-five-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-five-head h3 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-five-head p {
  max-width: 760px;
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-five-controls {
  display: grid;
  grid-template-columns: minmax(240px, 1fr) minmax(180px, 230px) minmax(180px, 230px) auto;
  gap: 12px;
  align-items: end;
  padding: 16px;
  border-radius: 24px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-five-controls label {
  display: grid;
  gap: 7px;
  min-width: 0;
}

.vb-storage-five-controls label span {
  color: #374151 !important;
  -webkit-text-fill-color: #374151 !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-storage-five-controls input,
.vb-storage-five-controls select {
  width: 100%;
  min-height: 48px;
  padding: 0 14px;
  border: 1px solid rgba(148, 163, 184, 0.34);
  border-radius: 16px;
  background: #ffffff;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 700;
  outline: none;
}

.vb-storage-five-controls input:focus,
.vb-storage-five-controls select:focus {
  border-color: rgba(147, 51, 234, 0.68);
  box-shadow: 0 0 0 4px rgba(147, 51, 234, 0.10);
}

.vb-storage-five-controls button {
  min-height: 48px;
  padding: 0 16px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #7c3aed, #db2777);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-five-summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  margin: 18px 0;
  padding: 13px 15px;
  border-radius: 18px;
  background: #faf5ff;
  border: 1px solid rgba(168, 85, 247, 0.18);
}

.vb-storage-five-summary strong {
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-storage-five-summary span {
  color: #6b21a8 !important;
  -webkit-text-fill-color: #6b21a8 !important;
  font-size: 13px;
  font-weight: 750;
}

.vb-storage-five-results {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.vb-storage-five-results article {
  display: grid;
  align-content: start;
  gap: 10px;
  min-height: 210px;
  padding: 18px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 15px 38px rgba(15, 23, 42, 0.07);
}

.vb-storage-five-results article.is-hidden {
  display: none;
}

.vb-storage-five-results article span {
  display: inline-flex;
  justify-self: start;
  padding: 7px 10px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-storage-five-results article h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
}

.vb-storage-five-results article p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 980px) {
  .vb-storage-five-controls {
    grid-template-columns: 1fr 1fr;
  }

  .vb-storage-five-results {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-storage-five-controls,
  .vb-storage-five-results {
    grid-template-columns: 1fr;
  }

  .vb-storage-five-controls button {
    width: 100%;
  }

  .vb-storage-five-head h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}</pre>



<p class="wp-block-paragraph">This saved search filters localStorage example is useful for product archives, blog directories, resource libraries, job boards, real estate listings, course catalogs, SaaS dashboards, and searchable WordPress content sections.</p>



<h2 class="wp-block-heading">6. LocalStorage To-Do List with Completed Tasks</h2>



<p class="wp-block-paragraph"><strong>A localStorage to-do list</strong> is one of the most searched JavaScript beginner projects, but it is also very useful for real UI features. The same logic can power saved checklists, task widgets, onboarding steps, dashboard notes, project lists, and progress trackers.</p>



<p class="wp-block-paragraph">This example lets users add tasks, mark them complete, delete individual tasks, clear completed tasks, and keep the full task list saved after refresh. JavaScript stores the task array in localStorage and renders the list from saved browser data.</p>



<ul class="wp-block-list">
<li>Persistent localStorage to-do list</li>
<li>Add, complete, and delete tasks</li>
<li>Clear completed tasks</li>
<li>Stores task array as JSON</li>
<li>Useful for dashboards and checklist widgets</li>
</ul>



<div class="vb-storage-six-demo">
  <div class="vb-storage-six-app" data-vb-storage-six>
    <div class="vb-storage-six-left">
      <span class="vb-storage-six-kicker">Example 06</span>
      <h3>Saved To-Do List</h3>
      <p>Add tasks and mark them complete. Your checklist is saved in localStorage and restored after page refresh.</p>

      <form class="vb-storage-six-form" data-task-form>
        <input type="text" data-task-input placeholder="Add a new task...">
        <button type="submit">Add Task</button>
      </form>

      <div class="vb-storage-six-stats">
        <div>
          <span>Total</span>
          <strong data-total-count>0</strong>
        </div>
        <div>
          <span>Done</span>
          <strong data-done-count>0</strong>
        </div>
      </div>
    </div>

    <div class="vb-storage-six-list-card">
      <div class="vb-storage-six-list-head">
        <strong>Project Checklist</strong>
        <button type="button" data-clear-completed>Clear Completed</button>
      </div>

      <div class="vb-storage-six-list" data-task-list>
        <p class="vb-storage-six-empty">No tasks yet. Add your first task.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-storage-six-demo,
.vb-storage-six-demo * {
  box-sizing: border-box;
}

.vb-storage-six-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 18% 18%, rgba(245, 158, 11, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(244, 63, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fff1f2 55%, #ffffff 100%) !important;
  border: 1px solid rgba(245, 158, 11, 0.22);
  box-shadow: 0 28px 80px rgba(146, 64, 14, 0.10);
}

.vb-storage-six-app {
  display: grid;
  grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
  gap: 22px;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #111827;
  box-shadow: 0 28px 90px rgba(17, 24, 39, 0.28);
}

.vb-storage-six-left,
.vb-storage-six-list-card {
  min-width: 0;
}

.vb-storage-six-left {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 28px;
  background:
    radial-gradient(circle at 18% 18%, rgba(251, 191, 36, 0.15), transparent 34%),
    rgba(255,255,255,0.07);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-six-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(251, 191, 36, 0.14);
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-six-left h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-six-left p {
  max-width: 540px;
  margin: 0 0 22px !important;
  color: #d1d5db !important;
  -webkit-text-fill-color: #d1d5db !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-six-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  margin-bottom: 18px;
}

.vb-storage-six-form input {
  min-width: 0;
  min-height: 50px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 750;
  outline: none;
}

.vb-storage-six-form input::placeholder {
  color: #9ca3af;
  -webkit-text-fill-color: #9ca3af;
}

.vb-storage-six-form input:focus {
  border-color: rgba(251, 191, 36, 0.70);
  box-shadow: 0 0 0 4px rgba(251, 191, 36, 0.12);
}

.vb-storage-six-form button,
.vb-storage-six-list-head button,
.vb-storage-six-delete {
  border: 0;
  cursor: pointer;
  font-weight: 950;
}

.vb-storage-six-form button {
  min-height: 50px;
  padding: 0 16px;
  border-radius: 999px;
  background: linear-gradient(135deg, #f59e0b, #f43f5e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  box-shadow: 0 16px 38px rgba(244, 63, 94, 0.28);
}

.vb-storage-six-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-storage-six-stats div {
  padding: 16px;
  border-radius: 22px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-six-stats span {
  display: block;
  margin-bottom: 7px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-storage-six-stats strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 32px;
  line-height: 1;
  font-weight: 950;
}

.vb-storage-six-list-card {
  display: grid;
  gap: 14px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-six-list-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}

.vb-storage-six-list-head strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-storage-six-list-head button {
  min-height: 40px;
  padding: 9px 13px;
  border-radius: 999px;
  background: #fff7ed;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 12px;
}

.vb-storage-six-list {
  display: grid;
  gap: 10px;
  min-height: 270px;
}

.vb-storage-six-empty {
  display: grid;
  place-items: center;
  min-height: 270px;
  margin: 0 !important;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  border-radius: 22px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-six-task {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  padding: 13px;
  border-radius: 18px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-six-task input {
  width: 20px;
  height: 20px;
  accent-color: #f59e0b;
}

.vb-storage-six-task span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 15px;
  line-height: 1.4;
  font-weight: 750;
  overflow-wrap: anywhere;
}

.vb-storage-six-task.is-complete span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  text-decoration: line-through;
}

.vb-storage-six-delete {
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 16px;
}

@media (max-width: 900px) {
  .vb-storage-six-app {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-storage-six-form {
    grid-template-columns: 1fr;
  }

  .vb-storage-six-left h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }

  .vb-storage-six-form button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-six]");
  if (!wrapper) return;

  const storageKey = "vbStorageSixTasks";
  const form = wrapper.querySelector("[data-task-form]");
  const input = wrapper.querySelector("[data-task-input]");
  const taskList = wrapper.querySelector("[data-task-list]");
  const clearCompletedButton = wrapper.querySelector("[data-clear-completed]");
  const totalCount = wrapper.querySelector("[data-total-count]");
  const doneCount = wrapper.querySelector("[data-done-count]");

  let tasks = [];

  function saveTasks() {
    localStorage.setItem(storageKey, JSON.stringify(tasks));
  }

  function loadTasks() {
    const savedTasks = localStorage.getItem(storageKey);
    if (!savedTasks) return;

    try {
      const parsedTasks = JSON.parse(savedTasks);
      tasks = Array.isArray(parsedTasks) ? parsedTasks : [];
    } catch (error) {
      tasks = [];
      localStorage.removeItem(storageKey);
    }
  }

  function updateStats() {
    const completedTasks = tasks.filter(function (task) {
      return task.completed;
    });

    totalCount.textContent = tasks.length;
    doneCount.textContent = completedTasks.length;
  }

  function renderTasks() {
    taskList.innerHTML = "";

    if (tasks.length === 0) {
      taskList.innerHTML = '<p class="vb-storage-six-empty">No tasks yet. Add your first task.</p>';
      updateStats();
      return;
    }

    tasks.forEach(function (task) {
      const item = document.createElement("div");
      item.className = "vb-storage-six-task";
      item.classList.toggle("is-complete", task.completed);

      item.innerHTML =
        '<input type="checkbox" data-toggle-task="' + task.id + '"' + (task.completed ? " checked" : "") + '>' +
        '<span>' + task.text + '</span>' +
        '<button class="vb-storage-six-delete" type="button" data-delete-task="' + task.id + '">×</button>';

      taskList.appendChild(item);
    });

    updateStats();
  }

  function addTask(text) {
    tasks.unshift({
      id: String(Date.now()),
      text: text,
      completed: false
    });

    saveTasks();
    renderTasks();
  }

  function toggleTask(taskId) {
    tasks = tasks.map(function (task) {
      if (task.id === taskId) {
        return {
          id: task.id,
          text: task.text,
          completed: !task.completed
        };
      }

      return task;
    });

    saveTasks();
    renderTasks();
  }

  function deleteTask(taskId) {
    tasks = tasks.filter(function (task) {
      return task.id !== taskId;
    });

    saveTasks();
    renderTasks();
  }

  form.addEventListener("submit", function (event) {
    event.preventDefault();

    const taskText = input.value.trim();
    if (!taskText) return;

    addTask(taskText);
    input.value = "";
    input.focus();
  });

  taskList.addEventListener("click", function (event) {
    const toggleId = event.target.getAttribute("data-toggle-task");
    const deleteId = event.target.getAttribute("data-delete-task");

    if (toggleId) {
      toggleTask(toggleId);
    }

    if (deleteId) {
      deleteTask(deleteId);
    }
  });

  clearCompletedButton.addEventListener("click", function () {
    tasks = tasks.filter(function (task) {
      return !task.completed;
    });

    saveTasks();
    renderTasks();
  });

  loadTasks();
  renderTasks();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-six]");
  if (!wrapper) return;

  const storageKey = "vbStorageSixTasks";
  const form = wrapper.querySelector("[data-task-form]");
  const input = wrapper.querySelector("[data-task-input]");
  const taskList = wrapper.querySelector("[data-task-list]");
  const clearCompletedButton = wrapper.querySelector("[data-clear-completed]");
  const totalCount = wrapper.querySelector("[data-total-count]");
  const doneCount = wrapper.querySelector("[data-done-count]");

  let tasks = [];

  function saveTasks() {
    localStorage.setItem(storageKey, JSON.stringify(tasks));
  }

  function loadTasks() {
    const savedTasks = localStorage.getItem(storageKey);
    if (!savedTasks) return;

    try {
      const parsedTasks = JSON.parse(savedTasks);
      tasks = Array.isArray(parsedTasks) ? parsedTasks : [];
    } catch (error) {
      tasks = [];
      localStorage.removeItem(storageKey);
    }
  }

  function updateStats() {
    const completedTasks = tasks.filter(function (task) {
      return task.completed;
    });

    totalCount.textContent = tasks.length;
    doneCount.textContent = completedTasks.length;
  }

  function renderTasks() {
    taskList.innerHTML = "";

    if (tasks.length === 0) {
      taskList.innerHTML = '&lt;p class="vb-storage-six-empty"&gt;No tasks yet. Add your first task.&lt;/p&gt;';
      updateStats();
      return;
    }

    tasks.forEach(function (task) {
      const item = document.createElement("div");
      item.className = "vb-storage-six-task";
      item.classList.toggle("is-complete", task.completed);

      item.innerHTML =
        '&lt;input type="checkbox" data-toggle-task="' + task.id + '"' + (task.completed ? " checked" : "") + '&gt;' +
        '&lt;span&gt;' + task.text + '&lt;/span&gt;' +
        '&lt;button class="vb-storage-six-delete" type="button" data-delete-task="' + task.id + '"&gt;×&lt;/button&gt;';

      taskList.appendChild(item);
    });

    updateStats();
  }

  function addTask(text) {
    tasks.unshift({
      id: String(Date.now()),
      text: text,
      completed: false
    });

    saveTasks();
    renderTasks();
  }

  function toggleTask(taskId) {
    tasks = tasks.map(function (task) {
      if (task.id === taskId) {
        return {
          id: task.id,
          text: task.text,
          completed: !task.completed
        };
      }

      return task;
    });

    saveTasks();
    renderTasks();
  }

  function deleteTask(taskId) {
    tasks = tasks.filter(function (task) {
      return task.id !== taskId;
    });

    saveTasks();
    renderTasks();
  }

  form.addEventListener("submit", function (event) {
    event.preventDefault();

    const taskText = input.value.trim();
    if (!taskText) return;

    addTask(taskText);
    input.value = "";
    input.focus();
  });

  taskList.addEventListener("click", function (event) {
    const toggleId = event.target.getAttribute("data-toggle-task");
    const deleteId = event.target.getAttribute("data-delete-task");

    if (toggleId) {
      toggleTask(toggleId);
    }

    if (deleteId) {
      deleteTask(deleteId);
    }
  });

  clearCompletedButton.addEventListener("click", function () {
    tasks = tasks.filter(function (task) {
      return !task.completed;
    });

    saveTasks();
    renderTasks();
  });

  loadTasks();
  renderTasks();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-six-demo"&gt;
  &lt;div class="vb-storage-six-app" data-vb-storage-six&gt;
    &lt;div class="vb-storage-six-left"&gt;
      &lt;span class="vb-storage-six-kicker"&gt;Example 06&lt;/span&gt;
      &lt;h3&gt;Saved To-Do List&lt;/h3&gt;
      &lt;p&gt;Add tasks and mark them complete. Your checklist is saved in localStorage and restored after page refresh.&lt;/p&gt;

      &lt;form class="vb-storage-six-form" data-task-form&gt;
        &lt;input type="text" data-task-input placeholder="Add a new task..."&gt;
        &lt;button type="submit"&gt;Add Task&lt;/button&gt;
      &lt;/form&gt;

      &lt;div class="vb-storage-six-stats"&gt;
        &lt;div&gt;
          &lt;span&gt;Total&lt;/span&gt;
          &lt;strong data-total-count&gt;0&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Done&lt;/span&gt;
          &lt;strong data-done-count&gt;0&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-six-list-card"&gt;
      &lt;div class="vb-storage-six-list-head"&gt;
        &lt;strong&gt;Project Checklist&lt;/strong&gt;
        &lt;button type="button" data-clear-completed&gt;Clear Completed&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-six-list" data-task-list&gt;
        &lt;p class="vb-storage-six-empty"&gt;No tasks yet. Add your first task.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-six-demo,
.vb-storage-six-demo * {
  box-sizing: border-box;
}

.vb-storage-six-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 18% 18%, rgba(245, 158, 11, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(244, 63, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fff1f2 55%, #ffffff 100%) !important;
  border: 1px solid rgba(245, 158, 11, 0.22);
  box-shadow: 0 28px 80px rgba(146, 64, 14, 0.10);
}

.vb-storage-six-app {
  display: grid;
  grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
  gap: 22px;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #111827;
  box-shadow: 0 28px 90px rgba(17, 24, 39, 0.28);
}

.vb-storage-six-left,
.vb-storage-six-list-card {
  min-width: 0;
}

.vb-storage-six-left {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 28px;
  background:
    radial-gradient(circle at 18% 18%, rgba(251, 191, 36, 0.15), transparent 34%),
    rgba(255,255,255,0.07);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-six-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(251, 191, 36, 0.14);
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-six-left h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-six-left p {
  max-width: 540px;
  margin: 0 0 22px !important;
  color: #d1d5db !important;
  -webkit-text-fill-color: #d1d5db !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-six-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  margin-bottom: 18px;
}

.vb-storage-six-form input {
  min-width: 0;
  min-height: 50px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 750;
  outline: none;
}

.vb-storage-six-form input::placeholder {
  color: #9ca3af;
  -webkit-text-fill-color: #9ca3af;
}

.vb-storage-six-form input:focus {
  border-color: rgba(251, 191, 36, 0.70);
  box-shadow: 0 0 0 4px rgba(251, 191, 36, 0.12);
}

.vb-storage-six-form button,
.vb-storage-six-list-head button,
.vb-storage-six-delete {
  border: 0;
  cursor: pointer;
  font-weight: 950;
}

.vb-storage-six-form button {
  min-height: 50px;
  padding: 0 16px;
  border-radius: 999px;
  background: linear-gradient(135deg, #f59e0b, #f43f5e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  box-shadow: 0 16px 38px rgba(244, 63, 94, 0.28);
}

.vb-storage-six-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-storage-six-stats div {
  padding: 16px;
  border-radius: 22px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-six-stats span {
  display: block;
  margin-bottom: 7px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-storage-six-stats strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 32px;
  line-height: 1;
  font-weight: 950;
}

.vb-storage-six-list-card {
  display: grid;
  gap: 14px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-six-list-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}

.vb-storage-six-list-head strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-storage-six-list-head button {
  min-height: 40px;
  padding: 9px 13px;
  border-radius: 999px;
  background: #fff7ed;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 12px;
}

.vb-storage-six-list {
  display: grid;
  gap: 10px;
  min-height: 270px;
}

.vb-storage-six-empty {
  display: grid;
  place-items: center;
  min-height: 270px;
  margin: 0 !important;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  border-radius: 22px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-six-task {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  padding: 13px;
  border-radius: 18px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-six-task input {
  width: 20px;
  height: 20px;
  accent-color: #f59e0b;
}

.vb-storage-six-task span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 15px;
  line-height: 1.4;
  font-weight: 750;
  overflow-wrap: anywhere;
}

.vb-storage-six-task.is-complete span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  text-decoration: line-through;
}

.vb-storage-six-delete {
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 16px;
}

@media (max-width: 900px) {
  .vb-storage-six-app {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-storage-six-form {
    grid-template-columns: 1fr;
  }

  .vb-storage-six-left h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }

  .vb-storage-six-form button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This localStorage to-do list example is useful for JavaScript beginner projects, dashboard checklist widgets, onboarding task lists, project planning tools, saved notes, habit trackers, and lightweight browser-based productivity apps.</p>



<div class="vb24-service-cta-box">
  <div class="vb24-service-cta-content">
    <span>Need this on your website?</span>
    <h3>Can’t build it yourself? We can create it for you.</h3>
    <p>If you like these JavaScript localStorage features but want a custom version for your website, landing page, ecommerce store, or WordPress project, contact us and tell us what you need.</p>
  </div>

  <a class="vb24-service-cta-button" href="https://veebilehed24.ee/en/contact-us/">Contact Us</a>
</div>

<style>
.vb24-service-cta-box,
.vb24-service-cta-box * {
  box-sizing: border-box;
}

.vb24-service-cta-box {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 22px;
  margin: 34px 0;
  padding: clamp(20px, 3vw, 28px);
  border: 1px solid rgba(148, 163, 184, 0.24);
  border-radius: 26px;
  background:
    radial-gradient(circle at 10% 20%, rgba(37, 99, 235, 0.10), transparent 32%),
    linear-gradient(135deg, #ffffff 0%, #f8fafc 100%) !important;
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb24-service-cta-content {
  min-width: 0;
}

.vb24-service-cta-content span {
  display: inline-flex;
  margin-bottom: 8px;
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb24-service-cta-content h3 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(22px, 3vw, 32px) !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb24-service-cta-content p {
  max-width: 760px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb24-service-cta-button {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  text-decoration: none !important;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.22);
}

.vb24-service-cta-button:hover {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transform: translateY(-2px);
}

@media (max-width: 720px) {
  .vb24-service-cta-box {
    align-items: stretch;
    flex-direction: column;
  }

  .vb24-service-cta-button {
    width: 100%;
  }
}
</style>



<h2 class="wp-block-heading">7. Favorite Products Saved with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>A favorite products feature</strong> is useful for ecommerce stores, affiliate product lists, directories, comparison pages, SaaS template galleries, and digital product shops. Visitors can save items they like and return to the page later without losing their selected favorites.</p>



<p class="wp-block-paragraph">This example lets users favorite and unfavorite product cards. JavaScript saves the selected favorite product IDs in localStorage, updates the heart buttons instantly, shows a saved favorites panel, and restores the same state after refresh.</p>



<ul class="wp-block-list">
<li>Save favorite products in localStorage</li>
<li>Toggle favorite and unfavorite state</li>
<li>Updates saved favorites panel instantly</li>
<li>Restores favorites after page refresh</li>
<li>Useful for shops, directories, and comparison pages</li>
</ul>



<div class="vb-storage-seven-demo">
  <div class="vb-storage-seven-wrap" data-vb-storage-seven>
    <div class="vb-storage-seven-head">
      <span class="vb-storage-seven-kicker">Example 07</span>
      <h3>Saved Favorite Products</h3>
      <p>Click the heart buttons to save favorite products. Refresh the page and your selected products will still be marked.</p>
    </div>

    <div class="vb-storage-seven-layout">
      <div class="vb-storage-seven-products">
        <article class="vb-storage-seven-card" data-product-card data-id="website-audit" data-name="Website SEO Audit">
          <button type="button" class="vb-storage-seven-heart" data-favorite-button aria-label="Save favorite">♡</button>
          <div class="vb-storage-seven-icon">SEO</div>
          <h4>Website SEO Audit</h4>
          <p>Technical SEO, content structure, speed, and schema review.</p>
          <strong>149€</strong>
        </article>

        <article class="vb-storage-seven-card" data-product-card data-id="plugin-build" data-name="Custom WordPress Plugin">
          <button type="button" class="vb-storage-seven-heart" data-favorite-button aria-label="Save favorite">♡</button>
          <div class="vb-storage-seven-icon">WP</div>
          <h4>Custom WordPress Plugin</h4>
          <p>Lightweight custom plugin built for your exact website workflow.</p>
          <strong>399€</strong>
        </article>

        <article class="vb-storage-seven-card" data-product-card data-id="landing-section" data-name="Landing Page Section">
          <button type="button" class="vb-storage-seven-heart" data-favorite-button aria-label="Save favorite">♡</button>
          <div class="vb-storage-seven-icon">UI</div>
          <h4>Landing Page Section</h4>
          <p>Modern responsive section with custom HTML, CSS, and JavaScript.</p>
          <strong>99€</strong>
        </article>

        <article class="vb-storage-seven-card" data-product-card data-id="shop-feature" data-name="Ecommerce Feature">
          <button type="button" class="vb-storage-seven-heart" data-favorite-button aria-label="Save favorite">♡</button>
          <div class="vb-storage-seven-icon">EC</div>
          <h4>Ecommerce Feature</h4>
          <p>Mini cart, product filter, quote form, or saved product feature.</p>
          <strong>249€</strong>
        </article>
      </div>

      <aside class="vb-storage-seven-panel">
        <div class="vb-storage-seven-panel-head">
          <strong>Saved Favorites</strong>
          <span data-favorite-count>0 saved</span>
        </div>

        <div class="vb-storage-seven-list" data-favorite-list>
          <p class="vb-storage-seven-empty">No favorites saved yet.</p>
        </div>

        <button type="button" data-clear-favorites>Clear Favorites</button>
      </aside>
    </div>
  </div>
</div>

<style>
.vb-storage-seven-demo,
.vb-storage-seven-demo * {
  box-sizing: border-box;
}

.vb-storage-seven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 46px;
  background:
    radial-gradient(circle at 12% 18%, rgba(244, 63, 94, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #faf5ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(244, 63, 94, 0.18);
  box-shadow: 0 28px 80px rgba(159, 18, 57, 0.10);
}

.vb-storage-seven-wrap {
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-seven-head {
  display: grid;
  gap: 12px;
  margin-bottom: 24px;
}

.vb-storage-seven-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-seven-head h3 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-seven-head p {
  max-width: 760px;
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-seven-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 380px);
  gap: 20px;
  align-items: start;
}

.vb-storage-seven-products {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-storage-seven-card {
  position: relative;
  display: grid;
  align-content: start;
  gap: 12px;
  min-height: 270px;
  padding: 18px;
  border-radius: 26px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.24);
  transition: transform 0.22s ease, border-color 0.22s ease, box-shadow 0.22s ease;
}

.vb-storage-seven-card.is-favorite {
  border-color: rgba(244, 63, 94, 0.52);
  background: linear-gradient(135deg, #fff1f2, #ffffff) !important;
  box-shadow: 0 18px 46px rgba(244, 63, 94, 0.12);
}

.vb-storage-seven-card:hover {
  transform: translateY(-3px);
}

.vb-storage-seven-heart {
  position: absolute;
  top: 16px;
  right: 16px;
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 25px;
  line-height: 1;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 12px 28px rgba(15, 23, 42, 0.10);
}

.vb-storage-seven-card.is-favorite .vb-storage-seven-heart {
  background: #e11d48;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-seven-icon {
  display: grid;
  place-items: center;
  width: 74px;
  height: 74px;
  border-radius: 24px;
  background: linear-gradient(135deg, #e11d48, #9333ea);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-storage-seven-card h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
}

.vb-storage-seven-card p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-storage-seven-card strong {
  align-self: end;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 24px;
  line-height: 1;
  font-weight: 950;
}

.vb-storage-seven-panel {
  display: grid;
  gap: 14px;
  padding: 18px;
  border-radius: 28px;
  background: #111827;
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.24);
}

.vb-storage-seven-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.vb-storage-seven-panel-head strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  font-weight: 950;
}

.vb-storage-seven-panel-head span {
  color: #fecdd3 !important;
  -webkit-text-fill-color: #fecdd3 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-storage-seven-list {
  display: grid;
  gap: 10px;
  min-height: 250px;
}

.vb-storage-seven-empty {
  display: grid;
  place-items: center;
  min-height: 250px;
  margin: 0 !important;
  border: 1px dashed rgba(255,255,255,0.22);
  border-radius: 20px;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-seven-favorite-item {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 12px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-seven-favorite-item span {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 15px;
  background: linear-gradient(135deg, #e11d48, #9333ea);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-storage-seven-favorite-item strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 900;
}

.vb-storage-seven-panel > button {
  min-height: 44px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #e11d48, #9333ea);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

@media (max-width: 940px) {
  .vb-storage-seven-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-storage-seven-products {
    grid-template-columns: 1fr;
  }

  .vb-storage-seven-head h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-seven]");
  if (!wrapper) return;

  const storageKey = "vbStorageSevenFavorites";
  const productCards = Array.from(wrapper.querySelectorAll("[data-product-card]"));
  const favoriteButtons = wrapper.querySelectorAll("[data-favorite-button]");
  const favoriteList = wrapper.querySelector("[data-favorite-list]");
  const favoriteCount = wrapper.querySelector("[data-favorite-count]");
  const clearButton = wrapper.querySelector("[data-clear-favorites]");

  let favoriteIds = [];

  function saveFavorites() {
    localStorage.setItem(storageKey, JSON.stringify(favoriteIds));
  }

  function loadFavorites() {
    const savedFavorites = localStorage.getItem(storageKey);
    if (!savedFavorites) return;

    try {
      const parsedFavorites = JSON.parse(savedFavorites);
      favoriteIds = Array.isArray(parsedFavorites) ? parsedFavorites : [];
    } catch (error) {
      favoriteIds = [];
      localStorage.removeItem(storageKey);
    }
  }

  function getProductById(productId) {
    return productCards.find(function (card) {
      return card.getAttribute("data-id") === productId;
    });
  }

  function renderFavorites() {
    favoriteList.innerHTML = "";

    productCards.forEach(function (card) {
      const productId = card.getAttribute("data-id");
      const isFavorite = favoriteIds.includes(productId);
      const heart = card.querySelector("[data-favorite-button]");

      card.classList.toggle("is-favorite", isFavorite);
      heart.textContent = isFavorite ? "♥" : "♡";
    });

    favoriteCount.textContent = favoriteIds.length === 1 ? "1 saved" : favoriteIds.length + " saved";

    if (favoriteIds.length === 0) {
      favoriteList.innerHTML = '<p class="vb-storage-seven-empty">No favorites saved yet.</p>';
      return;
    }

    favoriteIds.forEach(function (productId) {
      const card = getProductById(productId);
      if (!card) return;

      const item = document.createElement("div");
      item.className = "vb-storage-seven-favorite-item";
      item.innerHTML =
        '<span>♥</span>' +
        '<strong>' + card.getAttribute("data-name") + '</strong>';

      favoriteList.appendChild(item);
    });
  }

  function toggleFavorite(productId) {
    if (favoriteIds.includes(productId)) {
      favoriteIds = favoriteIds.filter(function (id) {
        return id !== productId;
      });
    } else {
      favoriteIds.push(productId);
    }

    saveFavorites();
    renderFavorites();
  }

  favoriteButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      const card = button.closest("[data-product-card]");
      toggleFavorite(card.getAttribute("data-id"));
    });
  });

  clearButton.addEventListener("click", function () {
    favoriteIds = [];
    saveFavorites();
    renderFavorites();
  });

  loadFavorites();
  renderFavorites();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-seven]");
  if (!wrapper) return;

  const storageKey = "vbStorageSevenFavorites";
  const productCards = Array.from(wrapper.querySelectorAll("[data-product-card]"));
  const favoriteButtons = wrapper.querySelectorAll("[data-favorite-button]");
  const favoriteList = wrapper.querySelector("[data-favorite-list]");
  const favoriteCount = wrapper.querySelector("[data-favorite-count]");
  const clearButton = wrapper.querySelector("[data-clear-favorites]");

  let favoriteIds = [];

  function saveFavorites() {
    localStorage.setItem(storageKey, JSON.stringify(favoriteIds));
  }

  function loadFavorites() {
    const savedFavorites = localStorage.getItem(storageKey);
    if (!savedFavorites) return;

    try {
      const parsedFavorites = JSON.parse(savedFavorites);
      favoriteIds = Array.isArray(parsedFavorites) ? parsedFavorites : [];
    } catch (error) {
      favoriteIds = [];
      localStorage.removeItem(storageKey);
    }
  }

  function getProductById(productId) {
    return productCards.find(function (card) {
      return card.getAttribute("data-id") === productId;
    });
  }

  function renderFavorites() {
    favoriteList.innerHTML = "";

    productCards.forEach(function (card) {
      const productId = card.getAttribute("data-id");
      const isFavorite = favoriteIds.includes(productId);
      const heart = card.querySelector("[data-favorite-button]");

      card.classList.toggle("is-favorite", isFavorite);
      heart.textContent = isFavorite ? "♥" : "♡";
    });

    favoriteCount.textContent = favoriteIds.length === 1 ? "1 saved" : favoriteIds.length + " saved";

    if (favoriteIds.length === 0) {
      favoriteList.innerHTML = '&lt;p class="vb-storage-seven-empty"&gt;No favorites saved yet.&lt;/p&gt;';
      return;
    }

    favoriteIds.forEach(function (productId) {
      const card = getProductById(productId);
      if (!card) return;

      const item = document.createElement("div");
      item.className = "vb-storage-seven-favorite-item";
      item.innerHTML =
        '&lt;span&gt;♥&lt;/span&gt;' +
        '&lt;strong&gt;' + card.getAttribute("data-name") + '&lt;/strong&gt;';

      favoriteList.appendChild(item);
    });
  }

  function toggleFavorite(productId) {
    if (favoriteIds.includes(productId)) {
      favoriteIds = favoriteIds.filter(function (id) {
        return id !== productId;
      });
    } else {
      favoriteIds.push(productId);
    }

    saveFavorites();
    renderFavorites();
  }

  favoriteButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      const card = button.closest("[data-product-card]");
      toggleFavorite(card.getAttribute("data-id"));
    });
  });

  clearButton.addEventListener("click", function () {
    favoriteIds = [];
    saveFavorites();
    renderFavorites();
  });

  loadFavorites();
  renderFavorites();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-seven-demo"&gt;
  &lt;div class="vb-storage-seven-wrap" data-vb-storage-seven&gt;
    &lt;div class="vb-storage-seven-head"&gt;
      &lt;span class="vb-storage-seven-kicker"&gt;Example 07&lt;/span&gt;
      &lt;h3&gt;Saved Favorite Products&lt;/h3&gt;
      &lt;p&gt;Click the heart buttons to save favorite products. Refresh the page and your selected products will still be marked.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-seven-layout"&gt;
      &lt;div class="vb-storage-seven-products"&gt;
        &lt;article class="vb-storage-seven-card" data-product-card data-id="website-audit" data-name="Website SEO Audit"&gt;
          &lt;button type="button" class="vb-storage-seven-heart" data-favorite-button aria-label="Save favorite"&gt;♡&lt;/button&gt;
          &lt;div class="vb-storage-seven-icon"&gt;SEO&lt;/div&gt;
          &lt;h4&gt;Website SEO Audit&lt;/h4&gt;
          &lt;p&gt;Technical SEO, content structure, speed, and schema review.&lt;/p&gt;
          &lt;strong&gt;149€&lt;/strong&gt;
        &lt;/article&gt;

        &lt;article class="vb-storage-seven-card" data-product-card data-id="plugin-build" data-name="Custom WordPress Plugin"&gt;
          &lt;button type="button" class="vb-storage-seven-heart" data-favorite-button aria-label="Save favorite"&gt;♡&lt;/button&gt;
          &lt;div class="vb-storage-seven-icon"&gt;WP&lt;/div&gt;
          &lt;h4&gt;Custom WordPress Plugin&lt;/h4&gt;
          &lt;p&gt;Lightweight custom plugin built for your exact website workflow.&lt;/p&gt;
          &lt;strong&gt;399€&lt;/strong&gt;
        &lt;/article&gt;

        &lt;article class="vb-storage-seven-card" data-product-card data-id="landing-section" data-name="Landing Page Section"&gt;
          &lt;button type="button" class="vb-storage-seven-heart" data-favorite-button aria-label="Save favorite"&gt;♡&lt;/button&gt;
          &lt;div class="vb-storage-seven-icon"&gt;UI&lt;/div&gt;
          &lt;h4&gt;Landing Page Section&lt;/h4&gt;
          &lt;p&gt;Modern responsive section with custom HTML, CSS, and JavaScript.&lt;/p&gt;
          &lt;strong&gt;99€&lt;/strong&gt;
        &lt;/article&gt;

        &lt;article class="vb-storage-seven-card" data-product-card data-id="shop-feature" data-name="Ecommerce Feature"&gt;
          &lt;button type="button" class="vb-storage-seven-heart" data-favorite-button aria-label="Save favorite"&gt;♡&lt;/button&gt;
          &lt;div class="vb-storage-seven-icon"&gt;EC&lt;/div&gt;
          &lt;h4&gt;Ecommerce Feature&lt;/h4&gt;
          &lt;p&gt;Mini cart, product filter, quote form, or saved product feature.&lt;/p&gt;
          &lt;strong&gt;249€&lt;/strong&gt;
        &lt;/article&gt;
      &lt;/div&gt;

      &lt;aside class="vb-storage-seven-panel"&gt;
        &lt;div class="vb-storage-seven-panel-head"&gt;
          &lt;strong&gt;Saved Favorites&lt;/strong&gt;
          &lt;span data-favorite-count&gt;0 saved&lt;/span&gt;
        &lt;/div&gt;

        &lt;div class="vb-storage-seven-list" data-favorite-list&gt;
          &lt;p class="vb-storage-seven-empty"&gt;No favorites saved yet.&lt;/p&gt;
        &lt;/div&gt;

        &lt;button type="button" data-clear-favorites&gt;Clear Favorites&lt;/button&gt;
      &lt;/aside&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-seven-demo,
.vb-storage-seven-demo * {
  box-sizing: border-box;
}

.vb-storage-seven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 46px;
  background:
    radial-gradient(circle at 12% 18%, rgba(244, 63, 94, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #faf5ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(244, 63, 94, 0.18);
  box-shadow: 0 28px 80px rgba(159, 18, 57, 0.10);
}

.vb-storage-seven-wrap {
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-seven-head {
  display: grid;
  gap: 12px;
  margin-bottom: 24px;
}

.vb-storage-seven-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-seven-head h3 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-seven-head p {
  max-width: 760px;
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-seven-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 380px);
  gap: 20px;
  align-items: start;
}

.vb-storage-seven-products {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-storage-seven-card {
  position: relative;
  display: grid;
  align-content: start;
  gap: 12px;
  min-height: 270px;
  padding: 18px;
  border-radius: 26px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.24);
  transition: transform 0.22s ease, border-color 0.22s ease, box-shadow 0.22s ease;
}

.vb-storage-seven-card.is-favorite {
  border-color: rgba(244, 63, 94, 0.52);
  background: linear-gradient(135deg, #fff1f2, #ffffff) !important;
  box-shadow: 0 18px 46px rgba(244, 63, 94, 0.12);
}

.vb-storage-seven-card:hover {
  transform: translateY(-3px);
}

.vb-storage-seven-heart {
  position: absolute;
  top: 16px;
  right: 16px;
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 25px;
  line-height: 1;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 12px 28px rgba(15, 23, 42, 0.10);
}

.vb-storage-seven-card.is-favorite .vb-storage-seven-heart {
  background: #e11d48;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-seven-icon {
  display: grid;
  place-items: center;
  width: 74px;
  height: 74px;
  border-radius: 24px;
  background: linear-gradient(135deg, #e11d48, #9333ea);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-storage-seven-card h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
}

.vb-storage-seven-card p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-storage-seven-card strong {
  align-self: end;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 24px;
  line-height: 1;
  font-weight: 950;
}

.vb-storage-seven-panel {
  display: grid;
  gap: 14px;
  padding: 18px;
  border-radius: 28px;
  background: #111827;
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.24);
}

.vb-storage-seven-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.vb-storage-seven-panel-head strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  font-weight: 950;
}

.vb-storage-seven-panel-head span {
  color: #fecdd3 !important;
  -webkit-text-fill-color: #fecdd3 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-storage-seven-list {
  display: grid;
  gap: 10px;
  min-height: 250px;
}

.vb-storage-seven-empty {
  display: grid;
  place-items: center;
  min-height: 250px;
  margin: 0 !important;
  border: 1px dashed rgba(255,255,255,0.22);
  border-radius: 20px;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-seven-favorite-item {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 12px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-seven-favorite-item span {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border-radius: 15px;
  background: linear-gradient(135deg, #e11d48, #9333ea);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-storage-seven-favorite-item strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 900;
}

.vb-storage-seven-panel > button {
  min-height: 44px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #e11d48, #9333ea);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

@media (max-width: 940px) {
  .vb-storage-seven-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-storage-seven-products {
    grid-template-columns: 1fr;
  }

  .vb-storage-seven-head h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}</pre>



<p class="wp-block-paragraph">This favorite products localStorage example is useful for ecommerce stores, affiliate websites, product comparison pages, service package lists, saved template galleries, and WooCommerce-style product cards.</p>



<h2 class="wp-block-heading">8. Multi-Step Form Progress Saved with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>Saving multi-step form progress</strong> is very useful for quote forms, onboarding flows, checkout forms, application forms, booking forms, and lead generation pages. It prevents users from losing their progress when they refresh the page or come back later.</p>



<p class="wp-block-paragraph">This example saves the active step and form values in localStorage. Visitors can move between steps, fill in fields, refresh the page, and continue from the same step with the same saved answers.</p>



<ul class="wp-block-list">
<li>Save multi-step form progress</li>
<li>Restores current step after refresh</li>
<li>Saves form field values automatically</li>
<li>Includes back, next, and reset buttons</li>
<li>Useful for quote forms and onboarding flows</li>
</ul>



<div class="vb-storage-eight-demo">
  <div class="vb-storage-eight-formbox" data-vb-storage-eight>
    <div class="vb-storage-eight-intro">
      <span class="vb-storage-eight-kicker">Example 08</span>
      <h3>Saved Multi-Step Form</h3>
      <p>Fill out the steps, refresh the page, and your form progress will be restored from localStorage.</p>
    </div>

    <div class="vb-storage-eight-progress">
      <span data-progress-line></span>
    </div>

    <form class="vb-storage-eight-form">
      <section class="vb-storage-eight-step is-active" data-step="0">
        <h4>Project Basics</h4>
        <label>
          <span>Project name</span>
          <input type="text" name="projectName" placeholder="New website project">
        </label>
        <label>
          <span>Project type</span>
          <select name="projectType">
            <option value="">Choose type</option>
            <option value="Website">Website</option>
            <option value="Ecommerce">Ecommerce</option>
            <option value="WordPress Plugin">WordPress Plugin</option>
          </select>
        </label>
      </section>

      <section class="vb-storage-eight-step" data-step="1">
        <h4>Budget and Timeline</h4>
        <label>
          <span>Estimated budget</span>
          <select name="budget">
            <option value="">Choose budget</option>
            <option value="500-1000€">500-1000€</option>
            <option value="1000-3000€">1000-3000€</option>
            <option value="3000€+">3000€+</option>
          </select>
        </label>
        <label>
          <span>Timeline</span>
          <input type="text" name="timeline" placeholder="Example: 2-4 weeks">
        </label>
      </section>

      <section class="vb-storage-eight-step" data-step="2">
        <h4>Final Notes</h4>
        <label>
          <span>What should be included?</span>
          <textarea name="notes" rows="5" placeholder="Describe the features, pages, design style, or functionality..."></textarea>
        </label>
      </section>

      <div class="vb-storage-eight-actions">
        <button type="button" data-prev-step>Back</button>
        <span data-step-label>Step 1 of 3</span>
        <button type="button" data-next-step>Next</button>
      </div>

      <button class="vb-storage-eight-reset" type="button" data-reset-form>Reset Saved Progress</button>
    </form>
  </div>
</div>

<style>
.vb-storage-eight-demo,
.vb-storage-eight-demo * {
  box-sizing: border-box;
}

.vb-storage-eight-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 42px;
  background:
    radial-gradient(circle at 12% 18%, rgba(37, 99, 235, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(20, 184, 166, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #f0fdfa 54%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.18);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-storage-eight-formbox {
  max-width: 920px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.11);
}

.vb-storage-eight-intro {
  display: grid;
  gap: 12px;
  margin-bottom: 22px;
}

.vb-storage-eight-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-eight-intro h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 6vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-eight-intro p {
  max-width: 720px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-eight-progress {
  height: 12px;
  overflow: hidden;
  margin-bottom: 20px;
  border-radius: 999px;
  background: #e2e8f0;
}

.vb-storage-eight-progress span {
  display: block;
  width: 33.33%;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #14b8a6);
  transition: width 0.25s ease;
}

.vb-storage-eight-form {
  display: grid;
  gap: 16px;
}

.vb-storage-eight-step {
  display: none;
  gap: 14px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 26px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-eight-step.is-active {
  display: grid;
}

.vb-storage-eight-step h4 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 28px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
}

.vb-storage-eight-step label {
  display: grid;
  gap: 7px;
}

.vb-storage-eight-step label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-storage-eight-step input,
.vb-storage-eight-step select,
.vb-storage-eight-step textarea {
  width: 100%;
  border: 1px solid rgba(148, 163, 184, 0.34);
  border-radius: 16px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 650;
  outline: none;
}

.vb-storage-eight-step input,
.vb-storage-eight-step select {
  min-height: 50px;
  padding: 0 14px;
}

.vb-storage-eight-step textarea {
  resize: vertical;
  padding: 13px 14px;
  line-height: 1.55;
}

.vb-storage-eight-step input:focus,
.vb-storage-eight-step select:focus,
.vb-storage-eight-step textarea:focus {
  border-color: rgba(37, 99, 235, 0.74);
  box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.10);
}

.vb-storage-eight-actions {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
}

.vb-storage-eight-actions button,
.vb-storage-eight-reset {
  border: 0;
  cursor: pointer;
  font-weight: 950;
}

.vb-storage-eight-actions button {
  min-height: 46px;
  padding: 0 16px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 13px;
}

.vb-storage-eight-actions button:last-child {
  background: linear-gradient(135deg, #2563eb, #14b8a6);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-eight-actions span {
  text-align: center;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-storage-eight-reset {
  justify-self: start;
  min-height: 42px;
  padding: 0 14px;
  border-radius: 999px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 12px;
}

@media (max-width: 560px) {
  .vb-storage-eight-intro h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }

  .vb-storage-eight-actions {
    grid-template-columns: 1fr;
  }

  .vb-storage-eight-actions span {
    order: -1;
  }

  .vb-storage-eight-actions button,
  .vb-storage-eight-reset {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-eight]");
  if (!wrapper) return;

  const storageKey = "vbStorageEightMultiStepForm";
  const steps = Array.from(wrapper.querySelectorAll("[data-step]"));
  const form = wrapper.querySelector(".vb-storage-eight-form");
  const fields = Array.from(form.querySelectorAll("input, select, textarea"));
  const previousButton = wrapper.querySelector("[data-prev-step]");
  const nextButton = wrapper.querySelector("[data-next-step]");
  const resetButton = wrapper.querySelector("[data-reset-form]");
  const stepLabel = wrapper.querySelector("[data-step-label]");
  const progressLine = wrapper.querySelector("[data-progress-line]");

  let currentStep = 0;

  function getFormData() {
    const data = {};

    fields.forEach(function (field) {
      data[field.name] = field.value;
    });

    return data;
  }

  function saveProgress() {
    localStorage.setItem(storageKey, JSON.stringify({
      currentStep: currentStep,
      formData: getFormData()
    }));
  }

  function loadProgress() {
    const savedProgress = localStorage.getItem(storageKey);
    if (!savedProgress) return;

    try {
      const progress = JSON.parse(savedProgress);
      currentStep = Number(progress.currentStep) || 0;

      if (progress.formData) {
        fields.forEach(function (field) {
          field.value = progress.formData[field.name] || "";
        });
      }
    } catch (error) {
      currentStep = 0;
      localStorage.removeItem(storageKey);
    }
  }

  function showStep(stepIndex) {
    currentStep = Math.max(0, Math.min(stepIndex, steps.length - 1));

    steps.forEach(function (step, index) {
      step.classList.toggle("is-active", index === currentStep);
    });

    previousButton.disabled = currentStep === 0;
    nextButton.textContent = currentStep === steps.length - 1 ? "Finish" : "Next";
    stepLabel.textContent = "Step " + (currentStep + 1) + " of " + steps.length;
    progressLine.style.width = ((currentStep + 1) / steps.length * 100) + "%";

    saveProgress();
  }

  fields.forEach(function (field) {
    field.addEventListener("input", saveProgress);
    field.addEventListener("change", saveProgress);
  });

  previousButton.addEventListener("click", function () {
    showStep(currentStep - 1);
  });

  nextButton.addEventListener("click", function () {
    if (currentStep < steps.length - 1) {
      showStep(currentStep + 1);
    } else {
      saveProgress();
      stepLabel.textContent = "Progress saved in localStorage";
    }
  });

  resetButton.addEventListener("click", function () {
    localStorage.removeItem(storageKey);
    form.reset();
    currentStep = 0;
    showStep(0);
  });

  loadProgress();
  showStep(currentStep);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-eight]");
  if (!wrapper) return;

  const storageKey = "vbStorageEightMultiStepForm";
  const steps = Array.from(wrapper.querySelectorAll("[data-step]"));
  const form = wrapper.querySelector(".vb-storage-eight-form");
  const fields = Array.from(form.querySelectorAll("input, select, textarea"));
  const previousButton = wrapper.querySelector("[data-prev-step]");
  const nextButton = wrapper.querySelector("[data-next-step]");
  const resetButton = wrapper.querySelector("[data-reset-form]");
  const stepLabel = wrapper.querySelector("[data-step-label]");
  const progressLine = wrapper.querySelector("[data-progress-line]");

  let currentStep = 0;

  function getFormData() {
    const data = {};

    fields.forEach(function (field) {
      data[field.name] = field.value;
    });

    return data;
  }

  function saveProgress() {
    localStorage.setItem(storageKey, JSON.stringify({
      currentStep: currentStep,
      formData: getFormData()
    }));
  }

  function loadProgress() {
    const savedProgress = localStorage.getItem(storageKey);
    if (!savedProgress) return;

    try {
      const progress = JSON.parse(savedProgress);
      currentStep = Number(progress.currentStep) || 0;

      if (progress.formData) {
        fields.forEach(function (field) {
          field.value = progress.formData[field.name] || "";
        });
      }
    } catch (error) {
      currentStep = 0;
      localStorage.removeItem(storageKey);
    }
  }

  function showStep(stepIndex) {
    currentStep = Math.max(0, Math.min(stepIndex, steps.length - 1));

    steps.forEach(function (step, index) {
      step.classList.toggle("is-active", index === currentStep);
    });

    previousButton.disabled = currentStep === 0;
    nextButton.textContent = currentStep === steps.length - 1 ? "Finish" : "Next";
    stepLabel.textContent = "Step " + (currentStep + 1) + " of " + steps.length;
    progressLine.style.width = ((currentStep + 1) / steps.length * 100) + "%";

    saveProgress();
  }

  fields.forEach(function (field) {
    field.addEventListener("input", saveProgress);
    field.addEventListener("change", saveProgress);
  });

  previousButton.addEventListener("click", function () {
    showStep(currentStep - 1);
  });

  nextButton.addEventListener("click", function () {
    if (currentStep &lt; steps.length - 1) {
      showStep(currentStep + 1);
    } else {
      saveProgress();
      stepLabel.textContent = "Progress saved in localStorage";
    }
  });

  resetButton.addEventListener("click", function () {
    localStorage.removeItem(storageKey);
    form.reset();
    currentStep = 0;
    showStep(0);
  });

  loadProgress();
  showStep(currentStep);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-eight-demo"&gt;
  &lt;div class="vb-storage-eight-formbox" data-vb-storage-eight&gt;
    &lt;div class="vb-storage-eight-intro"&gt;
      &lt;span class="vb-storage-eight-kicker"&gt;Example 08&lt;/span&gt;
      &lt;h3&gt;Saved Multi-Step Form&lt;/h3&gt;
      &lt;p&gt;Fill out the steps, refresh the page, and your form progress will be restored from localStorage.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-eight-progress"&gt;
      &lt;span data-progress-line&gt;&lt;/span&gt;
    &lt;/div&gt;

    &lt;form class="vb-storage-eight-form"&gt;
      &lt;section class="vb-storage-eight-step is-active" data-step="0"&gt;
        &lt;h4&gt;Project Basics&lt;/h4&gt;
        &lt;label&gt;
          &lt;span&gt;Project name&lt;/span&gt;
          &lt;input type="text" name="projectName" placeholder="New website project"&gt;
        &lt;/label&gt;
        &lt;label&gt;
          &lt;span&gt;Project type&lt;/span&gt;
          &lt;select name="projectType"&gt;
            &lt;option value=""&gt;Choose type&lt;/option&gt;
            &lt;option value="Website"&gt;Website&lt;/option&gt;
            &lt;option value="Ecommerce"&gt;Ecommerce&lt;/option&gt;
            &lt;option value="WordPress Plugin"&gt;WordPress Plugin&lt;/option&gt;
          &lt;/select&gt;
        &lt;/label&gt;
      &lt;/section&gt;

      &lt;section class="vb-storage-eight-step" data-step="1"&gt;
        &lt;h4&gt;Budget and Timeline&lt;/h4&gt;
        &lt;label&gt;
          &lt;span&gt;Estimated budget&lt;/span&gt;
          &lt;select name="budget"&gt;
            &lt;option value=""&gt;Choose budget&lt;/option&gt;
            &lt;option value="500-1000€"&gt;500-1000€&lt;/option&gt;
            &lt;option value="1000-3000€"&gt;1000-3000€&lt;/option&gt;
            &lt;option value="3000€+"&gt;3000€+&lt;/option&gt;
          &lt;/select&gt;
        &lt;/label&gt;
        &lt;label&gt;
          &lt;span&gt;Timeline&lt;/span&gt;
          &lt;input type="text" name="timeline" placeholder="Example: 2-4 weeks"&gt;
        &lt;/label&gt;
      &lt;/section&gt;

      &lt;section class="vb-storage-eight-step" data-step="2"&gt;
        &lt;h4&gt;Final Notes&lt;/h4&gt;
        &lt;label&gt;
          &lt;span&gt;What should be included?&lt;/span&gt;
          &lt;textarea name="notes" rows="5" placeholder="Describe the features, pages, design style, or functionality..."&gt;&lt;/textarea&gt;
        &lt;/label&gt;
      &lt;/section&gt;

      &lt;div class="vb-storage-eight-actions"&gt;
        &lt;button type="button" data-prev-step&gt;Back&lt;/button&gt;
        &lt;span data-step-label&gt;Step 1 of 3&lt;/span&gt;
        &lt;button type="button" data-next-step&gt;Next&lt;/button&gt;
      &lt;/div&gt;

      &lt;button class="vb-storage-eight-reset" type="button" data-reset-form&gt;Reset Saved Progress&lt;/button&gt;
    &lt;/form&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-eight-demo,
.vb-storage-eight-demo * {
  box-sizing: border-box;
}

.vb-storage-eight-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 42px;
  background:
    radial-gradient(circle at 12% 18%, rgba(37, 99, 235, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(20, 184, 166, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #f0fdfa 54%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.18);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-storage-eight-formbox {
  max-width: 920px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.11);
}

.vb-storage-eight-intro {
  display: grid;
  gap: 12px;
  margin-bottom: 22px;
}

.vb-storage-eight-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-eight-intro h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 6vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-eight-intro p {
  max-width: 720px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-eight-progress {
  height: 12px;
  overflow: hidden;
  margin-bottom: 20px;
  border-radius: 999px;
  background: #e2e8f0;
}

.vb-storage-eight-progress span {
  display: block;
  width: 33.33%;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #14b8a6);
  transition: width 0.25s ease;
}

.vb-storage-eight-form {
  display: grid;
  gap: 16px;
}

.vb-storage-eight-step {
  display: none;
  gap: 14px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 26px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-eight-step.is-active {
  display: grid;
}

.vb-storage-eight-step h4 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 28px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
}

.vb-storage-eight-step label {
  display: grid;
  gap: 7px;
}

.vb-storage-eight-step label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-storage-eight-step input,
.vb-storage-eight-step select,
.vb-storage-eight-step textarea {
  width: 100%;
  border: 1px solid rgba(148, 163, 184, 0.34);
  border-radius: 16px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 650;
  outline: none;
}

.vb-storage-eight-step input,
.vb-storage-eight-step select {
  min-height: 50px;
  padding: 0 14px;
}

.vb-storage-eight-step textarea {
  resize: vertical;
  padding: 13px 14px;
  line-height: 1.55;
}

.vb-storage-eight-step input:focus,
.vb-storage-eight-step select:focus,
.vb-storage-eight-step textarea:focus {
  border-color: rgba(37, 99, 235, 0.74);
  box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.10);
}

.vb-storage-eight-actions {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
}

.vb-storage-eight-actions button,
.vb-storage-eight-reset {
  border: 0;
  cursor: pointer;
  font-weight: 950;
}

.vb-storage-eight-actions button {
  min-height: 46px;
  padding: 0 16px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 13px;
}

.vb-storage-eight-actions button:last-child {
  background: linear-gradient(135deg, #2563eb, #14b8a6);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-eight-actions span {
  text-align: center;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-storage-eight-reset {
  justify-self: start;
  min-height: 42px;
  padding: 0 14px;
  border-radius: 999px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 12px;
}

@media (max-width: 560px) {
  .vb-storage-eight-intro h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }

  .vb-storage-eight-actions {
    grid-template-columns: 1fr;
  }

  .vb-storage-eight-actions span {
    order: -1;
  }

  .vb-storage-eight-actions button,
  .vb-storage-eight-reset {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This localStorage multi-step form example is useful for quote request forms, checkout forms, onboarding flows, booking forms, lead generation pages, application forms, and longer WordPress contact forms.</p>



<h2 class="wp-block-heading">9. Dismissible Banner Saved with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>A dismissible banner saved with localStorage</strong> is useful for cookie notices, announcement bars, discount banners, onboarding messages, update notices, and promotional website messages. Once the visitor closes the banner, localStorage can remember that choice.</p>



<p class="wp-block-paragraph">This example shows a floating announcement banner with close and reset controls. JavaScript stores the dismissed state in localStorage, hides the banner after closing, and keeps it hidden after refresh until the demo reset button is used.</p>



<ul class="wp-block-list">
<li>Dismissible website banner</li>
<li>Saves closed state in localStorage</li>
<li>Restores hidden state after refresh</li>
<li>Includes reset demo button</li>
<li>Useful for cookie notices and announcement bars</li>
</ul>



<div class="vb-storage-nine-demo">
  <div class="vb-storage-nine-stage" data-vb-storage-nine>
    <div class="vb-storage-nine-page">
      <span class="vb-storage-nine-kicker">Example 09</span>
      <h3>Dismissible Saved Banner</h3>
      <p>Close the banner and refresh the page. localStorage remembers that this message was dismissed.</p>

      <div class="vb-storage-nine-browser">
        <div class="vb-storage-nine-browser-top">
          <span></span>
          <span></span>
          <span></span>
        </div>

        <div class="vb-storage-nine-hero">
          <strong>Website Content Area</strong>
          <p>The announcement banner appears inside this demo browser until the visitor closes it.</p>
        </div>

        <div class="vb-storage-nine-banner" data-banner>
          <div>
            <strong>New website feature available</strong>
            <p>Use localStorage to remember dismissed banners, cookie notices, and promo messages.</p>
          </div>
          <button type="button" data-close-banner>Close</button>
        </div>
      </div>

      <div class="vb-storage-nine-footer">
        <span data-banner-status>Banner status: visible</span>
        <button type="button" data-reset-banner>Show Banner Again</button>
      </div>
    </div>
  </div>
</div>

<style>
.vb-storage-nine-demo,
.vb-storage-nine-demo * {
  box-sizing: border-box;
}

.vb-storage-nine-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 12% 18%, rgba(14, 165, 233, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(245, 158, 11, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #fffbeb 54%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  box-shadow: 0 28px 80px rgba(12, 74, 110, 0.10);
}

.vb-storage-nine-stage {
  max-width: 1080px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #0f172a;
  box-shadow: 0 28px 90px rgba(15, 23, 42, 0.30);
}

.vb-storage-nine-page {
  display: grid;
  gap: 16px;
}

.vb-storage-nine-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(14, 165, 233, 0.16);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-nine-page h3 {
  max-width: 760px;
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-nine-page > p {
  max-width: 760px;
  margin: 0 0 8px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-nine-browser {
  position: relative;
  min-height: 390px;
  overflow: hidden;
  border-radius: 28px;
  background: linear-gradient(135deg, #f8fafc, #e0f2fe) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.24);
}

.vb-storage-nine-browser-top {
  display: flex;
  gap: 8px;
  padding: 16px;
  background: #ffffff;
  border-bottom: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-storage-nine-browser-top span {
  width: 12px;
  height: 12px;
  border-radius: 999px;
  background: #f87171;
}

.vb-storage-nine-browser-top span:nth-child(2) {
  background: #fbbf24;
}

.vb-storage-nine-browser-top span:nth-child(3) {
  background: #34d399;
}

.vb-storage-nine-hero {
  display: grid;
  place-items: center;
  align-content: center;
  min-height: 300px;
  padding: 30px;
  text-align: center;
}

.vb-storage-nine-hero strong {
  margin-bottom: 10px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(28px, 5vw, 48px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-storage-nine-hero p {
  max-width: 480px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-storage-nine-banner {
  position: absolute;
  left: 18px;
  right: 18px;
  bottom: 18px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  padding: 16px;
  border-radius: 22px;
  background: #0f172a;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.28);
}

.vb-storage-nine-banner.is-hidden {
  display: none;
}

.vb-storage-nine-banner strong {
  display: block;
  margin-bottom: 5px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 17px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-storage-nine-banner p {
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 13px;
  line-height: 1.45;
  font-weight: 650;
}

.vb-storage-nine-banner button,
.vb-storage-nine-footer button {
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  font-weight: 950;
  white-space: nowrap;
}

.vb-storage-nine-banner button {
  min-height: 42px;
  padding: 10px 14px;
  background: linear-gradient(135deg, #0ea5e9, #f59e0b);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
}

.vb-storage-nine-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 14px 16px;
  border-radius: 20px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-nine-footer span {
  color: #e2e8f0 !important;
  -webkit-text-fill-color: #e2e8f0 !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-storage-nine-footer button {
  min-height: 40px;
  padding: 9px 13px;
  background: #ffffff;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 12px;
}

@media (max-width: 640px) {
  .vb-storage-nine-page h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }

  .vb-storage-nine-banner {
    align-items: stretch;
    flex-direction: column;
  }

  .vb-storage-nine-banner button,
  .vb-storage-nine-footer button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-nine]");
  if (!wrapper) return;

  const storageKey = "vbStorageNineBannerDismissed";
  const banner = wrapper.querySelector("[data-banner]");
  const closeButton = wrapper.querySelector("[data-close-banner]");
  const resetButton = wrapper.querySelector("[data-reset-banner]");
  const status = wrapper.querySelector("[data-banner-status]");

  function updateBanner() {
    const isDismissed = localStorage.getItem(storageKey) === "true";

    banner.classList.toggle("is-hidden", isDismissed);
    status.textContent = isDismissed
      ? "Banner status: hidden by localStorage"
      : "Banner status: visible";
  }

  closeButton.addEventListener("click", function () {
    localStorage.setItem(storageKey, "true");
    updateBanner();
  });

  resetButton.addEventListener("click", function () {
    localStorage.removeItem(storageKey);
    updateBanner();
  });

  updateBanner();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-nine]");
  if (!wrapper) return;

  const storageKey = "vbStorageNineBannerDismissed";
  const banner = wrapper.querySelector("[data-banner]");
  const closeButton = wrapper.querySelector("[data-close-banner]");
  const resetButton = wrapper.querySelector("[data-reset-banner]");
  const status = wrapper.querySelector("[data-banner-status]");

  function updateBanner() {
    const isDismissed = localStorage.getItem(storageKey) === "true";

    banner.classList.toggle("is-hidden", isDismissed);
    status.textContent = isDismissed
      ? "Banner status: hidden by localStorage"
      : "Banner status: visible";
  }

  closeButton.addEventListener("click", function () {
    localStorage.setItem(storageKey, "true");
    updateBanner();
  });

  resetButton.addEventListener("click", function () {
    localStorage.removeItem(storageKey);
    updateBanner();
  });

  updateBanner();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-nine-demo"&gt;
  &lt;div class="vb-storage-nine-stage" data-vb-storage-nine&gt;
    &lt;div class="vb-storage-nine-page"&gt;
      &lt;span class="vb-storage-nine-kicker"&gt;Example 09&lt;/span&gt;
      &lt;h3&gt;Dismissible Saved Banner&lt;/h3&gt;
      &lt;p&gt;Close the banner and refresh the page. localStorage remembers that this message was dismissed.&lt;/p&gt;

      &lt;div class="vb-storage-nine-browser"&gt;
        &lt;div class="vb-storage-nine-browser-top"&gt;
          &lt;span&gt;&lt;/span&gt;
          &lt;span&gt;&lt;/span&gt;
          &lt;span&gt;&lt;/span&gt;
        &lt;/div&gt;

        &lt;div class="vb-storage-nine-hero"&gt;
          &lt;strong&gt;Website Content Area&lt;/strong&gt;
          &lt;p&gt;The announcement banner appears inside this demo browser until the visitor closes it.&lt;/p&gt;
        &lt;/div&gt;

        &lt;div class="vb-storage-nine-banner" data-banner&gt;
          &lt;div&gt;
            &lt;strong&gt;New website feature available&lt;/strong&gt;
            &lt;p&gt;Use localStorage to remember dismissed banners, cookie notices, and promo messages.&lt;/p&gt;
          &lt;/div&gt;
          &lt;button type="button" data-close-banner&gt;Close&lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-nine-footer"&gt;
        &lt;span data-banner-status&gt;Banner status: visible&lt;/span&gt;
        &lt;button type="button" data-reset-banner&gt;Show Banner Again&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-nine-demo,
.vb-storage-nine-demo * {
  box-sizing: border-box;
}

.vb-storage-nine-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 12% 18%, rgba(14, 165, 233, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(245, 158, 11, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #fffbeb 54%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  box-shadow: 0 28px 80px rgba(12, 74, 110, 0.10);
}

.vb-storage-nine-stage {
  max-width: 1080px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #0f172a;
  box-shadow: 0 28px 90px rgba(15, 23, 42, 0.30);
}

.vb-storage-nine-page {
  display: grid;
  gap: 16px;
}

.vb-storage-nine-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(14, 165, 233, 0.16);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-nine-page h3 {
  max-width: 760px;
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-nine-page > p {
  max-width: 760px;
  margin: 0 0 8px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-nine-browser {
  position: relative;
  min-height: 390px;
  overflow: hidden;
  border-radius: 28px;
  background: linear-gradient(135deg, #f8fafc, #e0f2fe) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.24);
}

.vb-storage-nine-browser-top {
  display: flex;
  gap: 8px;
  padding: 16px;
  background: #ffffff;
  border-bottom: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-storage-nine-browser-top span {
  width: 12px;
  height: 12px;
  border-radius: 999px;
  background: #f87171;
}

.vb-storage-nine-browser-top span:nth-child(2) {
  background: #fbbf24;
}

.vb-storage-nine-browser-top span:nth-child(3) {
  background: #34d399;
}

.vb-storage-nine-hero {
  display: grid;
  place-items: center;
  align-content: center;
  min-height: 300px;
  padding: 30px;
  text-align: center;
}

.vb-storage-nine-hero strong {
  margin-bottom: 10px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(28px, 5vw, 48px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-storage-nine-hero p {
  max-width: 480px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-storage-nine-banner {
  position: absolute;
  left: 18px;
  right: 18px;
  bottom: 18px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  padding: 16px;
  border-radius: 22px;
  background: #0f172a;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.28);
}

.vb-storage-nine-banner.is-hidden {
  display: none;
}

.vb-storage-nine-banner strong {
  display: block;
  margin-bottom: 5px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 17px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-storage-nine-banner p {
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 13px;
  line-height: 1.45;
  font-weight: 650;
}

.vb-storage-nine-banner button,
.vb-storage-nine-footer button {
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  font-weight: 950;
  white-space: nowrap;
}

.vb-storage-nine-banner button {
  min-height: 42px;
  padding: 10px 14px;
  background: linear-gradient(135deg, #0ea5e9, #f59e0b);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
}

.vb-storage-nine-footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 14px 16px;
  border-radius: 20px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-nine-footer span {
  color: #e2e8f0 !important;
  -webkit-text-fill-color: #e2e8f0 !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-storage-nine-footer button {
  min-height: 40px;
  padding: 9px 13px;
  background: #ffffff;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 12px;
}

@media (max-width: 640px) {
  .vb-storage-nine-page h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }

  .vb-storage-nine-banner {
    align-items: stretch;
    flex-direction: column;
  }

  .vb-storage-nine-banner button,
  .vb-storage-nine-footer button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This dismissible banner localStorage example is useful for cookie notices, announcement bars, promo banners, onboarding messages, discount bars, website update alerts, and custom WordPress notification sections.</p>



<h2 class="wp-block-heading">10. LocalStorage Notes App</h2>



<p class="wp-block-paragraph"><strong>A localStorage notes app</strong> is one of the most useful JavaScript projects because it teaches saving, editing, deleting, rendering, and restoring user-generated content. The same logic can be used for dashboard notes, admin reminders, customer notes, private browser notes, and lightweight project planning widgets.</p>



<p class="wp-block-paragraph">This example lets users create notes, edit existing notes, delete notes, and keep all notes saved after refresh. JavaScript stores an array of note objects in localStorage and rebuilds the note cards when the page loads again.</p>



<ul class="wp-block-list">
<li>Persistent localStorage notes app</li>
<li>Add, edit, and delete notes</li>
<li>Stores notes as a JSON array</li>
<li>Restores notes after page refresh</li>
<li>Useful for dashboards and admin widgets</li>
</ul>



<div class="vb-storage-ten-demo">
  <div class="vb-storage-ten-app" data-vb-storage-ten>
    <div class="vb-storage-ten-left">
      <span class="vb-storage-ten-kicker">Example 10</span>
      <h3>Saved Notes App</h3>
      <p>Create notes, edit them, delete them, and refresh the page. Your notes stay saved in localStorage.</p>

      <form class="vb-storage-ten-form" data-note-form>
        <input type="text" data-note-title placeholder="Note title">
        <textarea data-note-text rows="5" placeholder="Write your note here..."></textarea>
        <button type="submit" data-submit-note>Add Note</button>
      </form>

      <button type="button" class="vb-storage-ten-cancel" data-cancel-edit hidden>Cancel Edit</button>
    </div>

    <div class="vb-storage-ten-board">
      <div class="vb-storage-ten-board-head">
        <strong>Saved Notes</strong>
        <span data-note-count>0 notes</span>
      </div>

      <div class="vb-storage-ten-list" data-note-list>
        <p class="vb-storage-ten-empty">No notes saved yet.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-storage-ten-demo,
.vb-storage-ten-demo * {
  box-sizing: border-box;
}

.vb-storage-ten-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(234, 179, 8, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(59, 130, 246, 0.15), transparent 34%),
    linear-gradient(135deg, #fefce8 0%, #eff6ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(234, 179, 8, 0.22);
  box-shadow: 0 28px 80px rgba(113, 63, 18, 0.10);
}

.vb-storage-ten-app {
  display: grid;
  grid-template-columns: minmax(0, 0.84fr) minmax(0, 1.16fr);
  gap: 22px;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-ten-left,
.vb-storage-ten-board {
  min-width: 0;
}

.vb-storage-ten-left {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 28px;
  background: #111827;
}

.vb-storage-ten-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(250, 204, 21, 0.16);
  color: #fef08a !important;
  -webkit-text-fill-color: #fef08a !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-ten-left h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-ten-left p {
  max-width: 520px;
  margin: 0 0 22px !important;
  color: #d1d5db !important;
  -webkit-text-fill-color: #d1d5db !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-ten-form {
  display: grid;
  gap: 12px;
}

.vb-storage-ten-form input,
.vb-storage-ten-form textarea {
  width: 100%;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 18px;
  background: rgba(255,255,255,0.09);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 700;
  outline: none;
}

.vb-storage-ten-form input {
  min-height: 50px;
  padding: 0 15px;
}

.vb-storage-ten-form textarea {
  resize: vertical;
  padding: 14px 15px;
  line-height: 1.55;
}

.vb-storage-ten-form input::placeholder,
.vb-storage-ten-form textarea::placeholder {
  color: #9ca3af;
  -webkit-text-fill-color: #9ca3af;
}

.vb-storage-ten-form input:focus,
.vb-storage-ten-form textarea:focus {
  border-color: rgba(250, 204, 21, 0.72);
  box-shadow: 0 0 0 4px rgba(250, 204, 21, 0.12);
}

.vb-storage-ten-form button,
.vb-storage-ten-cancel,
.vb-storage-ten-note-actions button {
  border: 0;
  cursor: pointer;
  font-weight: 950;
}

.vb-storage-ten-form button {
  min-height: 50px;
  border-radius: 999px;
  background: linear-gradient(135deg, #eab308, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.22);
}

.vb-storage-ten-cancel {
  align-self: flex-start;
  min-height: 40px;
  margin-top: 10px;
  padding: 0 13px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
}

.vb-storage-ten-board {
  display: grid;
  gap: 14px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 30px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-ten-board-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.vb-storage-ten-board-head strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-storage-ten-board-head span {
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-storage-ten-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  min-height: 330px;
}

.vb-storage-ten-empty {
  grid-column: 1 / -1;
  display: grid;
  place-items: center;
  min-height: 330px;
  margin: 0 !important;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  border-radius: 22px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-ten-note {
  display: grid;
  align-content: start;
  gap: 10px;
  min-height: 190px;
  padding: 16px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 12px 32px rgba(15, 23, 42, 0.07);
}

.vb-storage-ten-note h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 19px !important;
  line-height: 1.18 !important;
  font-weight: 950 !important;
}

.vb-storage-ten-note p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-storage-ten-note small {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 750;
}

.vb-storage-ten-note-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: auto;
}

.vb-storage-ten-note-actions button {
  min-height: 34px;
  padding: 7px 11px;
  border-radius: 999px;
  font-size: 12px;
}

.vb-storage-ten-note-actions button:first-child {
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
}

.vb-storage-ten-note-actions button:last-child {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

@media (max-width: 920px) {
  .vb-storage-ten-app {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-storage-ten-list {
    grid-template-columns: 1fr;
  }

  .vb-storage-ten-left h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-ten]");
  if (!wrapper) return;

  const storageKey = "vbStorageTenNotes";
  const form = wrapper.querySelector("[data-note-form]");
  const titleInput = wrapper.querySelector("[data-note-title]");
  const textInput = wrapper.querySelector("[data-note-text]");
  const submitButton = wrapper.querySelector("[data-submit-note]");
  const cancelEditButton = wrapper.querySelector("[data-cancel-edit]");
  const noteList = wrapper.querySelector("[data-note-list]");
  const noteCount = wrapper.querySelector("[data-note-count]");

  let notes = [];
  let editingId = null;

  function saveNotes() {
    localStorage.setItem(storageKey, JSON.stringify(notes));
  }

  function loadNotes() {
    const savedNotes = localStorage.getItem(storageKey);
    if (!savedNotes) return;

    try {
      const parsedNotes = JSON.parse(savedNotes);
      notes = Array.isArray(parsedNotes) ? parsedNotes : [];
    } catch (error) {
      notes = [];
      localStorage.removeItem(storageKey);
    }
  }

  function resetForm() {
    editingId = null;
    form.reset();
    submitButton.textContent = "Add Note";
    cancelEditButton.hidden = true;
  }

  function renderNotes() {
    noteList.innerHTML = "";

    noteCount.textContent = notes.length === 1 ? "1 note" : notes.length + " notes";

    if (notes.length === 0) {
      noteList.innerHTML = '<p class="vb-storage-ten-empty">No notes saved yet.</p>';
      return;
    }

    notes.forEach(function (note) {
      const card = document.createElement("article");
      card.className = "vb-storage-ten-note";

      card.innerHTML =
        '<h4>' + note.title + '</h4>' +
        '<p>' + note.text + '</p>' +
        '<small>Saved: ' + note.createdAt + '</small>' +
        '<div class="vb-storage-ten-note-actions">' +
          '<button type="button" data-edit-note="' + note.id + '">Edit</button>' +
          '<button type="button" data-delete-note="' + note.id + '">Delete</button>' +
        '</div>';

      noteList.appendChild(card);
    });
  }

  function addOrUpdateNote() {
    const title = titleInput.value.trim();
    const text = textInput.value.trim();

    if (!title || !text) return;

    if (editingId) {
      notes = notes.map(function (note) {
        if (note.id === editingId) {
          return {
            id: note.id,
            title: title,
            text: text,
            createdAt: note.createdAt
          };
        }

        return note;
      });
    } else {
      notes.unshift({
        id: String(Date.now()),
        title: title,
        text: text,
        createdAt: new Date().toLocaleDateString()
      });
    }

    saveNotes();
    renderNotes();
    resetForm();
  }

  function startEditing(noteId) {
    const note = notes.find(function (item) {
      return item.id === noteId;
    });

    if (!note) return;

    editingId = note.id;
    titleInput.value = note.title;
    textInput.value = note.text;
    submitButton.textContent = "Update Note";
    cancelEditButton.hidden = false;
    titleInput.focus();
  }

  function deleteNote(noteId) {
    notes = notes.filter(function (note) {
      return note.id !== noteId;
    });

    if (editingId === noteId) {
      resetForm();
    }

    saveNotes();
    renderNotes();
  }

  form.addEventListener("submit", function (event) {
    event.preventDefault();
    addOrUpdateNote();
  });

  noteList.addEventListener("click", function (event) {
    const editId = event.target.getAttribute("data-edit-note");
    const deleteId = event.target.getAttribute("data-delete-note");

    if (editId) startEditing(editId);
    if (deleteId) deleteNote(deleteId);
  });

  cancelEditButton.addEventListener("click", resetForm);

  loadNotes();
  renderNotes();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-ten]");
  if (!wrapper) return;

  const storageKey = "vbStorageTenNotes";
  const form = wrapper.querySelector("[data-note-form]");
  const titleInput = wrapper.querySelector("[data-note-title]");
  const textInput = wrapper.querySelector("[data-note-text]");
  const submitButton = wrapper.querySelector("[data-submit-note]");
  const cancelEditButton = wrapper.querySelector("[data-cancel-edit]");
  const noteList = wrapper.querySelector("[data-note-list]");
  const noteCount = wrapper.querySelector("[data-note-count]");

  let notes = [];
  let editingId = null;

  function saveNotes() {
    localStorage.setItem(storageKey, JSON.stringify(notes));
  }

  function loadNotes() {
    const savedNotes = localStorage.getItem(storageKey);
    if (!savedNotes) return;

    try {
      const parsedNotes = JSON.parse(savedNotes);
      notes = Array.isArray(parsedNotes) ? parsedNotes : [];
    } catch (error) {
      notes = [];
      localStorage.removeItem(storageKey);
    }
  }

  function resetForm() {
    editingId = null;
    form.reset();
    submitButton.textContent = "Add Note";
    cancelEditButton.hidden = true;
  }

  function renderNotes() {
    noteList.innerHTML = "";

    noteCount.textContent = notes.length === 1 ? "1 note" : notes.length + " notes";

    if (notes.length === 0) {
      noteList.innerHTML = '&lt;p class="vb-storage-ten-empty"&gt;No notes saved yet.&lt;/p&gt;';
      return;
    }

    notes.forEach(function (note) {
      const card = document.createElement("article");
      card.className = "vb-storage-ten-note";

      card.innerHTML =
        '&lt;h4&gt;' + note.title + '&lt;/h4&gt;' +
        '&lt;p&gt;' + note.text + '&lt;/p&gt;' +
        '&lt;small&gt;Saved: ' + note.createdAt + '&lt;/small&gt;' +
        '&lt;div class="vb-storage-ten-note-actions"&gt;' +
          '&lt;button type="button" data-edit-note="' + note.id + '"&gt;Edit&lt;/button&gt;' +
          '&lt;button type="button" data-delete-note="' + note.id + '"&gt;Delete&lt;/button&gt;' +
        '&lt;/div&gt;';

      noteList.appendChild(card);
    });
  }

  function addOrUpdateNote() {
    const title = titleInput.value.trim();
    const text = textInput.value.trim();

    if (!title || !text) return;

    if (editingId) {
      notes = notes.map(function (note) {
        if (note.id === editingId) {
          return {
            id: note.id,
            title: title,
            text: text,
            createdAt: note.createdAt
          };
        }

        return note;
      });
    } else {
      notes.unshift({
        id: String(Date.now()),
        title: title,
        text: text,
        createdAt: new Date().toLocaleDateString()
      });
    }

    saveNotes();
    renderNotes();
    resetForm();
  }

  function startEditing(noteId) {
    const note = notes.find(function (item) {
      return item.id === noteId;
    });

    if (!note) return;

    editingId = note.id;
    titleInput.value = note.title;
    textInput.value = note.text;
    submitButton.textContent = "Update Note";
    cancelEditButton.hidden = false;
    titleInput.focus();
  }

  function deleteNote(noteId) {
    notes = notes.filter(function (note) {
      return note.id !== noteId;
    });

    if (editingId === noteId) {
      resetForm();
    }

    saveNotes();
    renderNotes();
  }

  form.addEventListener("submit", function (event) {
    event.preventDefault();
    addOrUpdateNote();
  });

  noteList.addEventListener("click", function (event) {
    const editId = event.target.getAttribute("data-edit-note");
    const deleteId = event.target.getAttribute("data-delete-note");

    if (editId) startEditing(editId);
    if (deleteId) deleteNote(deleteId);
  });

  cancelEditButton.addEventListener("click", resetForm);

  loadNotes();
  renderNotes();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-ten-demo"&gt;
  &lt;div class="vb-storage-ten-app" data-vb-storage-ten&gt;
    &lt;div class="vb-storage-ten-left"&gt;
      &lt;span class="vb-storage-ten-kicker"&gt;Example 10&lt;/span&gt;
      &lt;h3&gt;Saved Notes App&lt;/h3&gt;
      &lt;p&gt;Create notes, edit them, delete them, and refresh the page. Your notes stay saved in localStorage.&lt;/p&gt;

      &lt;form class="vb-storage-ten-form" data-note-form&gt;
        &lt;input type="text" data-note-title placeholder="Note title"&gt;
        &lt;textarea data-note-text rows="5" placeholder="Write your note here..."&gt;&lt;/textarea&gt;
        &lt;button type="submit" data-submit-note&gt;Add Note&lt;/button&gt;
      &lt;/form&gt;

      &lt;button type="button" class="vb-storage-ten-cancel" data-cancel-edit hidden&gt;Cancel Edit&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-ten-board"&gt;
      &lt;div class="vb-storage-ten-board-head"&gt;
        &lt;strong&gt;Saved Notes&lt;/strong&gt;
        &lt;span data-note-count&gt;0 notes&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-ten-list" data-note-list&gt;
        &lt;p class="vb-storage-ten-empty"&gt;No notes saved yet.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-ten-demo,
.vb-storage-ten-demo * {
  box-sizing: border-box;
}

.vb-storage-ten-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(234, 179, 8, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(59, 130, 246, 0.15), transparent 34%),
    linear-gradient(135deg, #fefce8 0%, #eff6ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(234, 179, 8, 0.22);
  box-shadow: 0 28px 80px rgba(113, 63, 18, 0.10);
}

.vb-storage-ten-app {
  display: grid;
  grid-template-columns: minmax(0, 0.84fr) minmax(0, 1.16fr);
  gap: 22px;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-ten-left,
.vb-storage-ten-board {
  min-width: 0;
}

.vb-storage-ten-left {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 28px;
  background: #111827;
}

.vb-storage-ten-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(250, 204, 21, 0.16);
  color: #fef08a !important;
  -webkit-text-fill-color: #fef08a !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-ten-left h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-ten-left p {
  max-width: 520px;
  margin: 0 0 22px !important;
  color: #d1d5db !important;
  -webkit-text-fill-color: #d1d5db !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-ten-form {
  display: grid;
  gap: 12px;
}

.vb-storage-ten-form input,
.vb-storage-ten-form textarea {
  width: 100%;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 18px;
  background: rgba(255,255,255,0.09);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 700;
  outline: none;
}

.vb-storage-ten-form input {
  min-height: 50px;
  padding: 0 15px;
}

.vb-storage-ten-form textarea {
  resize: vertical;
  padding: 14px 15px;
  line-height: 1.55;
}

.vb-storage-ten-form input::placeholder,
.vb-storage-ten-form textarea::placeholder {
  color: #9ca3af;
  -webkit-text-fill-color: #9ca3af;
}

.vb-storage-ten-form input:focus,
.vb-storage-ten-form textarea:focus {
  border-color: rgba(250, 204, 21, 0.72);
  box-shadow: 0 0 0 4px rgba(250, 204, 21, 0.12);
}

.vb-storage-ten-form button,
.vb-storage-ten-cancel,
.vb-storage-ten-note-actions button {
  border: 0;
  cursor: pointer;
  font-weight: 950;
}

.vb-storage-ten-form button {
  min-height: 50px;
  border-radius: 999px;
  background: linear-gradient(135deg, #eab308, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.22);
}

.vb-storage-ten-cancel {
  align-self: flex-start;
  min-height: 40px;
  margin-top: 10px;
  padding: 0 13px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
}

.vb-storage-ten-board {
  display: grid;
  gap: 14px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 30px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-ten-board-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.vb-storage-ten-board-head strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-storage-ten-board-head span {
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-storage-ten-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  min-height: 330px;
}

.vb-storage-ten-empty {
  grid-column: 1 / -1;
  display: grid;
  place-items: center;
  min-height: 330px;
  margin: 0 !important;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  border-radius: 22px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-ten-note {
  display: grid;
  align-content: start;
  gap: 10px;
  min-height: 190px;
  padding: 16px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 12px 32px rgba(15, 23, 42, 0.07);
}

.vb-storage-ten-note h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 19px !important;
  line-height: 1.18 !important;
  font-weight: 950 !important;
}

.vb-storage-ten-note p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-storage-ten-note small {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 750;
}

.vb-storage-ten-note-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  margin-top: auto;
}

.vb-storage-ten-note-actions button {
  min-height: 34px;
  padding: 7px 11px;
  border-radius: 999px;
  font-size: 12px;
}

.vb-storage-ten-note-actions button:first-child {
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
}

.vb-storage-ten-note-actions button:last-child {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

@media (max-width: 920px) {
  .vb-storage-ten-app {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-storage-ten-list {
    grid-template-columns: 1fr;
  }

  .vb-storage-ten-left h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}</pre>



<p class="wp-block-paragraph">This localStorage notes app example is useful for JavaScript notes projects, dashboard widgets, admin reminders, customer notes, browser-based writing tools, and lightweight project planning interfaces.</p>



<h2 class="wp-block-heading">11. Active Tab Saved with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>Saving the active tab with localStorage</strong> is useful for dashboards, pricing sections, product details, account settings, documentation pages, profile areas, and long content sections. It lets the interface reopen the same tab after refresh instead of always starting from the first tab.</p>



<p class="wp-block-paragraph">This example has three content tabs. JavaScript saves the selected tab key in localStorage, updates the active tab instantly, and restores the same tab when the page loads again.</p>



<ul class="wp-block-list">
<li>Save active tab state</li>
<li>Restores selected tab after refresh</li>
<li>Useful for settings, product details, and dashboards</li>
<li>Uses one localStorage key</li>
<li>Simple and practical UI state example</li>
</ul>



<div class="vb-storage-eleven-demo">
  <div class="vb-storage-eleven-tabs" data-vb-storage-eleven>
    <div class="vb-storage-eleven-header">
      <span class="vb-storage-eleven-kicker">Example 11</span>
      <h3>Saved Active Tab</h3>
      <p>Choose a tab and refresh the page. localStorage restores the same active tab automatically.</p>
    </div>

    <div class="vb-storage-eleven-shell">
      <div class="vb-storage-eleven-nav" role="tablist">
        <button type="button" data-tab-button="overview" class="is-active">Overview</button>
        <button type="button" data-tab-button="features">Features</button>
        <button type="button" data-tab-button="settings">Settings</button>
      </div>

      <div class="vb-storage-eleven-content">
        <section data-tab-panel="overview" class="is-active">
          <span>01</span>
          <h4>Overview Tab</h4>
          <p>This panel could contain product details, account information, dashboard stats, or documentation summary content.</p>
          <ul>
            <li>Good for default content</li>
            <li>Restores after refresh</li>
            <li>Stores only the selected tab key</li>
          </ul>
        </section>

        <section data-tab-panel="features">
          <span>02</span>
          <h4>Features Tab</h4>
          <p>This panel can show feature lists, pricing details, comparison content, or product specifications.</p>
          <ul>
            <li>Great for product pages</li>
            <li>Useful for SaaS sections</li>
            <li>Simple localStorage state</li>
          </ul>
        </section>

        <section data-tab-panel="settings">
          <span>03</span>
          <h4>Settings Tab</h4>
          <p>This panel is useful for user preferences, dashboard controls, display options, and saved interface settings.</p>
          <ul>
            <li>Useful for dashboards</li>
            <li>Works after page reload</li>
            <li>Easy to customize</li>
          </ul>
        </section>
      </div>

      <div class="vb-storage-eleven-status">
        Current saved tab: <strong data-current-tab>overview</strong>
      </div>
    </div>
  </div>
</div>

<style>
.vb-storage-eleven-demo,
.vb-storage-eleven-demo * {
  box-sizing: border-box;
}

.vb-storage-eleven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 18%, rgba(20, 184, 166, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdfa 0%, #eef2ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.18);
  box-shadow: 0 28px 80px rgba(15, 118, 110, 0.10);
}

.vb-storage-eleven-tabs {
  max-width: 1060px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-eleven-header {
  display: grid;
  gap: 12px;
  margin-bottom: 24px;
}

.vb-storage-eleven-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-eleven-header h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-eleven-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-eleven-shell {
  display: grid;
  gap: 16px;
  padding: 18px;
  border-radius: 28px;
  background: #0f172a;
}

.vb-storage-eleven-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.vb-storage-eleven-nav button {
  min-height: 44px;
  padding: 10px 15px;
  border: 0;
  border-radius: 999px;
  background: rgba(255,255,255,0.09);
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-eleven-nav button.is-active {
  background: linear-gradient(135deg, #14b8a6, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 16px 34px rgba(20, 184, 166, 0.22);
}

.vb-storage-eleven-content {
  min-height: 330px;
}

.vb-storage-eleven-content section {
  display: none;
  min-height: 330px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 24px;
  background:
    radial-gradient(circle at 85% 15%, rgba(20, 184, 166, 0.16), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
}

.vb-storage-eleven-content section.is-active {
  display: grid;
  align-content: center;
  gap: 14px;
}

.vb-storage-eleven-content section span {
  display: inline-grid;
  place-items: center;
  width: 58px;
  height: 58px;
  border-radius: 18px;
  background: linear-gradient(135deg, #14b8a6, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-storage-eleven-content section h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(28px, 4vw, 44px) !important;
  line-height: 1.05 !important;
  font-weight: 950 !important;
  letter-spacing: -0.055em;
}

.vb-storage-eleven-content section p {
  max-width: 680px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-eleven-content section ul {
  display: grid;
  gap: 8px;
  margin: 4px 0 0 !important;
  padding-left: 20px !important;
}

.vb-storage-eleven-content section li {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-eleven-status {
  padding: 13px 15px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-storage-eleven-status strong {
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
}

@media (max-width: 640px) {
  .vb-storage-eleven-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }

  .vb-storage-eleven-nav {
    flex-direction: column;
  }

  .vb-storage-eleven-nav button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-eleven]");
  if (!wrapper) return;

  const storageKey = "vbStorageElevenActiveTab";
  const buttons = wrapper.querySelectorAll("[data-tab-button]");
  const panels = wrapper.querySelectorAll("[data-tab-panel]");
  const currentTab = wrapper.querySelector("[data-current-tab]");

  function activateTab(tabKey) {
    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-tab-button") === tabKey);
    });

    panels.forEach(function (panel) {
      panel.classList.toggle("is-active", panel.getAttribute("data-tab-panel") === tabKey);
    });

    currentTab.textContent = tabKey;
    localStorage.setItem(storageKey, tabKey);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activateTab(button.getAttribute("data-tab-button"));
    });
  });

  const savedTab = localStorage.getItem(storageKey) || "overview";
  activateTab(savedTab);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-eleven]");
  if (!wrapper) return;

  const storageKey = "vbStorageElevenActiveTab";
  const buttons = wrapper.querySelectorAll("[data-tab-button]");
  const panels = wrapper.querySelectorAll("[data-tab-panel]");
  const currentTab = wrapper.querySelector("[data-current-tab]");

  function activateTab(tabKey) {
    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-tab-button") === tabKey);
    });

    panels.forEach(function (panel) {
      panel.classList.toggle("is-active", panel.getAttribute("data-tab-panel") === tabKey);
    });

    currentTab.textContent = tabKey;
    localStorage.setItem(storageKey, tabKey);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activateTab(button.getAttribute("data-tab-button"));
    });
  });

  const savedTab = localStorage.getItem(storageKey) || "overview";
  activateTab(savedTab);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-eleven-demo"&gt;
  &lt;div class="vb-storage-eleven-tabs" data-vb-storage-eleven&gt;
    &lt;div class="vb-storage-eleven-header"&gt;
      &lt;span class="vb-storage-eleven-kicker"&gt;Example 11&lt;/span&gt;
      &lt;h3&gt;Saved Active Tab&lt;/h3&gt;
      &lt;p&gt;Choose a tab and refresh the page. localStorage restores the same active tab automatically.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-eleven-shell"&gt;
      &lt;div class="vb-storage-eleven-nav" role="tablist"&gt;
        &lt;button type="button" data-tab-button="overview" class="is-active"&gt;Overview&lt;/button&gt;
        &lt;button type="button" data-tab-button="features"&gt;Features&lt;/button&gt;
        &lt;button type="button" data-tab-button="settings"&gt;Settings&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-eleven-content"&gt;
        &lt;section data-tab-panel="overview" class="is-active"&gt;
          &lt;span&gt;01&lt;/span&gt;
          &lt;h4&gt;Overview Tab&lt;/h4&gt;
          &lt;p&gt;This panel could contain product details, account information, dashboard stats, or documentation summary content.&lt;/p&gt;
          &lt;ul&gt;
            &lt;li&gt;Good for default content&lt;/li&gt;
            &lt;li&gt;Restores after refresh&lt;/li&gt;
            &lt;li&gt;Stores only the selected tab key&lt;/li&gt;
          &lt;/ul&gt;
        &lt;/section&gt;

        &lt;section data-tab-panel="features"&gt;
          &lt;span&gt;02&lt;/span&gt;
          &lt;h4&gt;Features Tab&lt;/h4&gt;
          &lt;p&gt;This panel can show feature lists, pricing details, comparison content, or product specifications.&lt;/p&gt;
          &lt;ul&gt;
            &lt;li&gt;Great for product pages&lt;/li&gt;
            &lt;li&gt;Useful for SaaS sections&lt;/li&gt;
            &lt;li&gt;Simple localStorage state&lt;/li&gt;
          &lt;/ul&gt;
        &lt;/section&gt;

        &lt;section data-tab-panel="settings"&gt;
          &lt;span&gt;03&lt;/span&gt;
          &lt;h4&gt;Settings Tab&lt;/h4&gt;
          &lt;p&gt;This panel is useful for user preferences, dashboard controls, display options, and saved interface settings.&lt;/p&gt;
          &lt;ul&gt;
            &lt;li&gt;Useful for dashboards&lt;/li&gt;
            &lt;li&gt;Works after page reload&lt;/li&gt;
            &lt;li&gt;Easy to customize&lt;/li&gt;
          &lt;/ul&gt;
        &lt;/section&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-eleven-status"&gt;
        Current saved tab: &lt;strong data-current-tab&gt;overview&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-eleven-demo,
.vb-storage-eleven-demo * {
  box-sizing: border-box;
}

.vb-storage-eleven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 18%, rgba(20, 184, 166, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdfa 0%, #eef2ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.18);
  box-shadow: 0 28px 80px rgba(15, 118, 110, 0.10);
}

.vb-storage-eleven-tabs {
  max-width: 1060px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-eleven-header {
  display: grid;
  gap: 12px;
  margin-bottom: 24px;
}

.vb-storage-eleven-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-eleven-header h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-eleven-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-eleven-shell {
  display: grid;
  gap: 16px;
  padding: 18px;
  border-radius: 28px;
  background: #0f172a;
}

.vb-storage-eleven-nav {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.vb-storage-eleven-nav button {
  min-height: 44px;
  padding: 10px 15px;
  border: 0;
  border-radius: 999px;
  background: rgba(255,255,255,0.09);
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-eleven-nav button.is-active {
  background: linear-gradient(135deg, #14b8a6, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 16px 34px rgba(20, 184, 166, 0.22);
}

.vb-storage-eleven-content {
  min-height: 330px;
}

.vb-storage-eleven-content section {
  display: none;
  min-height: 330px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 24px;
  background:
    radial-gradient(circle at 85% 15%, rgba(20, 184, 166, 0.16), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
}

.vb-storage-eleven-content section.is-active {
  display: grid;
  align-content: center;
  gap: 14px;
}

.vb-storage-eleven-content section span {
  display: inline-grid;
  place-items: center;
  width: 58px;
  height: 58px;
  border-radius: 18px;
  background: linear-gradient(135deg, #14b8a6, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-storage-eleven-content section h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(28px, 4vw, 44px) !important;
  line-height: 1.05 !important;
  font-weight: 950 !important;
  letter-spacing: -0.055em;
}

.vb-storage-eleven-content section p {
  max-width: 680px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-eleven-content section ul {
  display: grid;
  gap: 8px;
  margin: 4px 0 0 !important;
  padding-left: 20px !important;
}

.vb-storage-eleven-content section li {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-eleven-status {
  padding: 13px 15px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-storage-eleven-status strong {
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
}

@media (max-width: 640px) {
  .vb-storage-eleven-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }

  .vb-storage-eleven-nav {
    flex-direction: column;
  }

  .vb-storage-eleven-nav button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This active tab localStorage example is useful for product detail tabs, pricing tabs, account settings, dashboard panels, documentation pages, FAQ categories, and custom WordPress content sections.</p>



<h2 class="wp-block-heading">12. Product Comparison List Saved with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>A product comparison list saved with localStorage</strong> is useful for ecommerce stores, affiliate product roundups, SaaS pricing pages, hosting comparison sites, software directories, and product review websites. It lets visitors add items to a comparison table and keep that selection after refresh.</p>



<p class="wp-block-paragraph">This example lets users add and remove products from a comparison table. JavaScript stores selected product IDs in localStorage, updates the table instantly, prevents duplicate items, and restores the comparison list after page reload.</p>



<ul class="wp-block-list">
<li>Save product comparison list</li>
<li>Add and remove products</li>
<li>Prevents duplicate comparison items</li>
<li>Restores selected products after refresh</li>
<li>Useful for ecommerce and affiliate websites</li>
</ul>



<div class="vb-storage-twelve-demo">
  <div class="vb-storage-twelve-compare" data-vb-storage-twelve>
    <div class="vb-storage-twelve-head">
      <span class="vb-storage-twelve-kicker">Example 12</span>
      <h3>Saved Product Compare</h3>
      <p>Add products to the comparison table. Refresh the page and the selected products stay saved in localStorage.</p>
    </div>

    <div class="vb-storage-twelve-grid">
      <div class="vb-storage-twelve-products">
        <article data-product data-id="starter" data-name="Starter Plan" data-price="19€" data-speed="Fast" data-support="Email">
          <span>Starter</span>
          <h4>Starter Plan</h4>
          <p>Good for small sites and simple landing pages.</p>
          <strong>19€</strong>
          <button type="button" data-add-compare>Add to Compare</button>
        </article>

        <article data-product data-id="business" data-name="Business Plan" data-price="49€" data-speed="Very Fast" data-support="Priority">
          <span>Business</span>
          <h4>Business Plan</h4>
          <p>Better for company websites and growing traffic.</p>
          <strong>49€</strong>
          <button type="button" data-add-compare>Add to Compare</button>
        </article>

        <article data-product data-id="pro" data-name="Pro Plan" data-price="99€" data-speed="Ultra Fast" data-support="Premium">
          <span>Pro</span>
          <h4>Pro Plan</h4>
          <p>Best for ecommerce, automation, and advanced features.</p>
          <strong>99€</strong>
          <button type="button" data-add-compare>Add to Compare</button>
        </article>
      </div>

      <div class="vb-storage-twelve-tablebox">
        <div class="vb-storage-twelve-table-head">
          <strong>Compare Products</strong>
          <span data-compare-count>0 selected</span>
        </div>

        <div class="vb-storage-twelve-table" data-compare-table>
          <p class="vb-storage-twelve-empty">No products selected for comparison.</p>
        </div>

        <button type="button" class="vb-storage-twelve-clear" data-clear-compare>Clear Compare</button>
      </div>
    </div>
  </div>
</div>

<style>
.vb-storage-twelve-demo,
.vb-storage-twelve-demo * {
  box-sizing: border-box;
}

.vb-storage-twelve-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(37, 99, 235, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(236, 72, 153, 0.14), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #fdf2f8 55%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.18);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-storage-twelve-compare {
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-twelve-head {
  display: grid;
  gap: 12px;
  margin-bottom: 24px;
}

.vb-storage-twelve-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-twelve-head h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-twelve-head p {
  max-width: 780px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-twelve-grid {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: 20px;
  align-items: start;
}

.vb-storage-twelve-products {
  display: grid;
  gap: 14px;
}

.vb-storage-twelve-products article {
  display: grid;
  gap: 9px;
  padding: 18px;
  border-radius: 24px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-storage-twelve-products article.is-selected {
  border-color: rgba(37, 99, 235, 0.54);
  box-shadow: 0 16px 40px rgba(37, 99, 235, 0.10);
}

.vb-storage-twelve-products article span {
  display: inline-flex;
  justify-self: start;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-storage-twelve-products article h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 23px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
}

.vb-storage-twelve-products article p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-storage-twelve-products article strong {
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 26px;
  font-weight: 950;
}

.vb-storage-twelve-products article button,
.vb-storage-twelve-clear {
  min-height: 42px;
  border: 0;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twelve-products article button {
  justify-self: start;
  padding: 0 14px;
  background: linear-gradient(135deg, #2563eb, #db2777);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-twelve-products article.is-selected button {
  background: #e0e7ff;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
}

.vb-storage-twelve-tablebox {
  display: grid;
  gap: 14px;
  padding: 18px;
  border-radius: 28px;
  background: #111827;
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.24);
}

.vb-storage-twelve-table-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}

.vb-storage-twelve-table-head strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  font-weight: 950;
}

.vb-storage-twelve-table-head span {
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-storage-twelve-table {
  min-height: 270px;
  overflow-x: auto;
}

.vb-storage-twelve-empty {
  display: grid;
  place-items: center;
  min-height: 270px;
  margin: 0 !important;
  border: 1px dashed rgba(255,255,255,0.22);
  border-radius: 20px;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-twelve-table table {
  width: 100%;
  min-width: 520px;
  border-collapse: separate;
  border-spacing: 0 9px;
}

.vb-storage-twelve-table th {
  padding: 10px;
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  text-align: left;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-storage-twelve-table td {
  padding: 12px 10px;
  background: rgba(255,255,255,0.08);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 800;
}

.vb-storage-twelve-table td:first-child {
  border-radius: 14px 0 0 14px;
}

.vb-storage-twelve-table td:last-child {
  border-radius: 0 14px 14px 0;
}

.vb-storage-twelve-table td button {
  width: 30px;
  height: 30px;
  border: 0;
  border-radius: 999px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 16px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twelve-clear {
  background: #ffffff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
}

@media (max-width: 960px) {
  .vb-storage-twelve-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-storage-twelve-head h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-twelve]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwelveCompare";
  const products = Array.from(wrapper.querySelectorAll("[data-product]"));
  const compareTable = wrapper.querySelector("[data-compare-table]");
  const compareCount = wrapper.querySelector("[data-compare-count]");
  const clearButton = wrapper.querySelector("[data-clear-compare]");

  let selectedIds = [];

  function saveCompare() {
    localStorage.setItem(storageKey, JSON.stringify(selectedIds));
  }

  function loadCompare() {
    const savedCompare = localStorage.getItem(storageKey);
    if (!savedCompare) return;

    try {
      const parsedCompare = JSON.parse(savedCompare);
      selectedIds = Array.isArray(parsedCompare) ? parsedCompare : [];
    } catch (error) {
      selectedIds = [];
      localStorage.removeItem(storageKey);
    }
  }

  function getProductData(product) {
    return {
      id: product.getAttribute("data-id"),
      name: product.getAttribute("data-name"),
      price: product.getAttribute("data-price"),
      speed: product.getAttribute("data-speed"),
      support: product.getAttribute("data-support")
    };
  }

  function renderCompare() {
    products.forEach(function (product) {
      const productId = product.getAttribute("data-id");
      const isSelected = selectedIds.includes(productId);

      product.classList.toggle("is-selected", isSelected);
      product.querySelector("[data-add-compare]").textContent = isSelected ? "Added" : "Add to Compare";
    });

    compareCount.textContent = selectedIds.length === 1 ? "1 selected" : selectedIds.length + " selected";

    if (selectedIds.length === 0) {
      compareTable.innerHTML = '<p class="vb-storage-twelve-empty">No products selected for comparison.</p>';
      return;
    }

    const selectedProducts = selectedIds
      .map(function (id) {
        return products.find(function (product) {
          return product.getAttribute("data-id") === id;
        });
      })
      .filter(Boolean)
      .map(getProductData);

    let tableHtml =
      '<table>' +
        '<thead>' +
          '<tr>' +
            '<th>Product</th>' +
            '<th>Price</th>' +
            '<th>Speed</th>' +
            '<th>Support</th>' +
            '<th></th>' +
          '</tr>' +
        '</thead>' +
        '<tbody>';

    selectedProducts.forEach(function (product) {
      tableHtml +=
        '<tr>' +
          '<td>' + product.name + '</td>' +
          '<td>' + product.price + '</td>' +
          '<td>' + product.speed + '</td>' +
          '<td>' + product.support + '</td>' +
          '<td><button type="button" data-remove-compare="' + product.id + '">×</button></td>' +
        '</tr>';
    });

    tableHtml += '</tbody></table>';
    compareTable.innerHTML = tableHtml;
  }

  function toggleCompare(productId) {
    if (selectedIds.includes(productId)) {
      selectedIds = selectedIds.filter(function (id) {
        return id !== productId;
      });
    } else {
      selectedIds.push(productId);
    }

    saveCompare();
    renderCompare();
  }

  products.forEach(function (product) {
    product.querySelector("[data-add-compare]").addEventListener("click", function () {
      toggleCompare(product.getAttribute("data-id"));
    });
  });

  compareTable.addEventListener("click", function (event) {
    const removeId = event.target.getAttribute("data-remove-compare");
    if (!removeId) return;

    selectedIds = selectedIds.filter(function (id) {
      return id !== removeId;
    });

    saveCompare();
    renderCompare();
  });

  clearButton.addEventListener("click", function () {
    selectedIds = [];
    saveCompare();
    renderCompare();
  });

  loadCompare();
  renderCompare();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-twelve]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwelveCompare";
  const products = Array.from(wrapper.querySelectorAll("[data-product]"));
  const compareTable = wrapper.querySelector("[data-compare-table]");
  const compareCount = wrapper.querySelector("[data-compare-count]");
  const clearButton = wrapper.querySelector("[data-clear-compare]");

  let selectedIds = [];

  function saveCompare() {
    localStorage.setItem(storageKey, JSON.stringify(selectedIds));
  }

  function loadCompare() {
    const savedCompare = localStorage.getItem(storageKey);
    if (!savedCompare) return;

    try {
      const parsedCompare = JSON.parse(savedCompare);
      selectedIds = Array.isArray(parsedCompare) ? parsedCompare : [];
    } catch (error) {
      selectedIds = [];
      localStorage.removeItem(storageKey);
    }
  }

  function getProductData(product) {
    return {
      id: product.getAttribute("data-id"),
      name: product.getAttribute("data-name"),
      price: product.getAttribute("data-price"),
      speed: product.getAttribute("data-speed"),
      support: product.getAttribute("data-support")
    };
  }

  function renderCompare() {
    products.forEach(function (product) {
      const productId = product.getAttribute("data-id");
      const isSelected = selectedIds.includes(productId);

      product.classList.toggle("is-selected", isSelected);
      product.querySelector("[data-add-compare]").textContent = isSelected ? "Added" : "Add to Compare";
    });

    compareCount.textContent = selectedIds.length === 1 ? "1 selected" : selectedIds.length + " selected";

    if (selectedIds.length === 0) {
      compareTable.innerHTML = '&lt;p class="vb-storage-twelve-empty"&gt;No products selected for comparison.&lt;/p&gt;';
      return;
    }

    const selectedProducts = selectedIds
      .map(function (id) {
        return products.find(function (product) {
          return product.getAttribute("data-id") === id;
        });
      })
      .filter(Boolean)
      .map(getProductData);

    let tableHtml =
      '&lt;table&gt;' +
        '&lt;thead&gt;' +
          '&lt;tr&gt;' +
            '&lt;th&gt;Product&lt;/th&gt;' +
            '&lt;th&gt;Price&lt;/th&gt;' +
            '&lt;th&gt;Speed&lt;/th&gt;' +
            '&lt;th&gt;Support&lt;/th&gt;' +
            '&lt;th&gt;&lt;/th&gt;' +
          '&lt;/tr&gt;' +
        '&lt;/thead&gt;' +
        '&lt;tbody&gt;';

    selectedProducts.forEach(function (product) {
      tableHtml +=
        '&lt;tr&gt;' +
          '&lt;td&gt;' + product.name + '&lt;/td&gt;' +
          '&lt;td&gt;' + product.price + '&lt;/td&gt;' +
          '&lt;td&gt;' + product.speed + '&lt;/td&gt;' +
          '&lt;td&gt;' + product.support + '&lt;/td&gt;' +
          '&lt;td&gt;&lt;button type="button" data-remove-compare="' + product.id + '"&gt;×&lt;/button&gt;&lt;/td&gt;' +
        '&lt;/tr&gt;';
    });

    tableHtml += '&lt;/tbody&gt;&lt;/table&gt;';
    compareTable.innerHTML = tableHtml;
  }

  function toggleCompare(productId) {
    if (selectedIds.includes(productId)) {
      selectedIds = selectedIds.filter(function (id) {
        return id !== productId;
      });
    } else {
      selectedIds.push(productId);
    }

    saveCompare();
    renderCompare();
  }

  products.forEach(function (product) {
    product.querySelector("[data-add-compare]").addEventListener("click", function () {
      toggleCompare(product.getAttribute("data-id"));
    });
  });

  compareTable.addEventListener("click", function (event) {
    const removeId = event.target.getAttribute("data-remove-compare");
    if (!removeId) return;

    selectedIds = selectedIds.filter(function (id) {
      return id !== removeId;
    });

    saveCompare();
    renderCompare();
  });

  clearButton.addEventListener("click", function () {
    selectedIds = [];
    saveCompare();
    renderCompare();
  });

  loadCompare();
  renderCompare();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-twelve-demo"&gt;
  &lt;div class="vb-storage-twelve-compare" data-vb-storage-twelve&gt;
    &lt;div class="vb-storage-twelve-head"&gt;
      &lt;span class="vb-storage-twelve-kicker"&gt;Example 12&lt;/span&gt;
      &lt;h3&gt;Saved Product Compare&lt;/h3&gt;
      &lt;p&gt;Add products to the comparison table. Refresh the page and the selected products stay saved in localStorage.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-twelve-grid"&gt;
      &lt;div class="vb-storage-twelve-products"&gt;
        &lt;article data-product data-id="starter" data-name="Starter Plan" data-price="19€" data-speed="Fast" data-support="Email"&gt;
          &lt;span&gt;Starter&lt;/span&gt;
          &lt;h4&gt;Starter Plan&lt;/h4&gt;
          &lt;p&gt;Good for small sites and simple landing pages.&lt;/p&gt;
          &lt;strong&gt;19€&lt;/strong&gt;
          &lt;button type="button" data-add-compare&gt;Add to Compare&lt;/button&gt;
        &lt;/article&gt;

        &lt;article data-product data-id="business" data-name="Business Plan" data-price="49€" data-speed="Very Fast" data-support="Priority"&gt;
          &lt;span&gt;Business&lt;/span&gt;
          &lt;h4&gt;Business Plan&lt;/h4&gt;
          &lt;p&gt;Better for company websites and growing traffic.&lt;/p&gt;
          &lt;strong&gt;49€&lt;/strong&gt;
          &lt;button type="button" data-add-compare&gt;Add to Compare&lt;/button&gt;
        &lt;/article&gt;

        &lt;article data-product data-id="pro" data-name="Pro Plan" data-price="99€" data-speed="Ultra Fast" data-support="Premium"&gt;
          &lt;span&gt;Pro&lt;/span&gt;
          &lt;h4&gt;Pro Plan&lt;/h4&gt;
          &lt;p&gt;Best for ecommerce, automation, and advanced features.&lt;/p&gt;
          &lt;strong&gt;99€&lt;/strong&gt;
          &lt;button type="button" data-add-compare&gt;Add to Compare&lt;/button&gt;
        &lt;/article&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-twelve-tablebox"&gt;
        &lt;div class="vb-storage-twelve-table-head"&gt;
          &lt;strong&gt;Compare Products&lt;/strong&gt;
          &lt;span data-compare-count&gt;0 selected&lt;/span&gt;
        &lt;/div&gt;

        &lt;div class="vb-storage-twelve-table" data-compare-table&gt;
          &lt;p class="vb-storage-twelve-empty"&gt;No products selected for comparison.&lt;/p&gt;
        &lt;/div&gt;

        &lt;button type="button" class="vb-storage-twelve-clear" data-clear-compare&gt;Clear Compare&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-twelve-demo,
.vb-storage-twelve-demo * {
  box-sizing: border-box;
}

.vb-storage-twelve-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(37, 99, 235, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(236, 72, 153, 0.14), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #fdf2f8 55%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.18);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-storage-twelve-compare {
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-twelve-head {
  display: grid;
  gap: 12px;
  margin-bottom: 24px;
}

.vb-storage-twelve-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-twelve-head h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-twelve-head p {
  max-width: 780px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-twelve-grid {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: 20px;
  align-items: start;
}

.vb-storage-twelve-products {
  display: grid;
  gap: 14px;
}

.vb-storage-twelve-products article {
  display: grid;
  gap: 9px;
  padding: 18px;
  border-radius: 24px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-storage-twelve-products article.is-selected {
  border-color: rgba(37, 99, 235, 0.54);
  box-shadow: 0 16px 40px rgba(37, 99, 235, 0.10);
}

.vb-storage-twelve-products article span {
  display: inline-flex;
  justify-self: start;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-storage-twelve-products article h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 23px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
}

.vb-storage-twelve-products article p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-storage-twelve-products article strong {
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 26px;
  font-weight: 950;
}

.vb-storage-twelve-products article button,
.vb-storage-twelve-clear {
  min-height: 42px;
  border: 0;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twelve-products article button {
  justify-self: start;
  padding: 0 14px;
  background: linear-gradient(135deg, #2563eb, #db2777);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-twelve-products article.is-selected button {
  background: #e0e7ff;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
}

.vb-storage-twelve-tablebox {
  display: grid;
  gap: 14px;
  padding: 18px;
  border-radius: 28px;
  background: #111827;
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.24);
}

.vb-storage-twelve-table-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}

.vb-storage-twelve-table-head strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  font-weight: 950;
}

.vb-storage-twelve-table-head span {
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-storage-twelve-table {
  min-height: 270px;
  overflow-x: auto;
}

.vb-storage-twelve-empty {
  display: grid;
  place-items: center;
  min-height: 270px;
  margin: 0 !important;
  border: 1px dashed rgba(255,255,255,0.22);
  border-radius: 20px;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-twelve-table table {
  width: 100%;
  min-width: 520px;
  border-collapse: separate;
  border-spacing: 0 9px;
}

.vb-storage-twelve-table th {
  padding: 10px;
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  text-align: left;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-storage-twelve-table td {
  padding: 12px 10px;
  background: rgba(255,255,255,0.08);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 800;
}

.vb-storage-twelve-table td:first-child {
  border-radius: 14px 0 0 14px;
}

.vb-storage-twelve-table td:last-child {
  border-radius: 0 14px 14px 0;
}

.vb-storage-twelve-table td button {
  width: 30px;
  height: 30px;
  border: 0;
  border-radius: 999px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 16px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twelve-clear {
  background: #ffffff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
}

@media (max-width: 960px) {
  .vb-storage-twelve-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-storage-twelve-head h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}</pre>



<p class="wp-block-paragraph">This product comparison localStorage example is useful for ecommerce product tables, affiliate comparison posts, hosting comparison pages, SaaS pricing tables, software directories, product review websites, and WooCommerce-style catalog features.</p>



<div class="vb24-service-cta-box">
  <div class="vb24-service-cta-content">
    <span>Need this on your website?</span>
    <h3>Can’t build it yourself? We can create it for you.</h3>
    <p>If you like these JavaScript localStorage features but want a custom version for your website, landing page, ecommerce store, or WordPress project, contact us and tell us what you need.</p>
  </div>

  <a class="vb24-service-cta-button" href="https://veebilehed24.ee/en/contact-us/">Contact Us</a>
</div>

<style>
.vb24-service-cta-box,
.vb24-service-cta-box * {
  box-sizing: border-box;
}

.vb24-service-cta-box {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 22px;
  margin: 34px 0;
  padding: clamp(20px, 3vw, 28px);
  border: 1px solid rgba(148, 163, 184, 0.24);
  border-radius: 26px;
  background:
    radial-gradient(circle at 10% 20%, rgba(37, 99, 235, 0.10), transparent 32%),
    linear-gradient(135deg, #ffffff 0%, #f8fafc 100%) !important;
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb24-service-cta-content {
  min-width: 0;
}

.vb24-service-cta-content span {
  display: inline-flex;
  margin-bottom: 8px;
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb24-service-cta-content h3 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(22px, 3vw, 32px) !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb24-service-cta-content p {
  max-width: 760px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb24-service-cta-button {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  text-decoration: none !important;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.22);
}

.vb24-service-cta-button:hover {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transform: translateY(-2px);
}

@media (max-width: 720px) {
  .vb24-service-cta-box {
    align-items: stretch;
    flex-direction: column;
  }

  .vb24-service-cta-button {
    width: 100%;
  }
}
</style>



<h2 class="wp-block-heading">13. Quiz Progress Saved with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>Saving quiz progress with localStorage</strong> is useful for online quizzes, course lessons, onboarding tests, product recommendation quizzes, lead generation quizzes, and learning platforms. It helps users continue from the same question after refreshing or returning later.</p>



<p class="wp-block-paragraph">This example saves the current quiz question, selected answers, and score state in localStorage. Visitors can answer questions, move forward, refresh the page, and continue from the saved quiz progress.</p>



<ul class="wp-block-list">
<li>Save quiz progress in localStorage</li>
<li>Restores current question after refresh</li>
<li>Saves selected answers</li>
<li>Shows final score</li>
<li>Useful for quizzes, lessons, and onboarding flows</li>
</ul>



<div class="vb-storage-thirteen-demo">
  <div class="vb-storage-thirteen-quiz" data-vb-storage-thirteen>
    <div class="vb-storage-thirteen-intro">
      <span class="vb-storage-thirteen-kicker">Example 13</span>
      <h3>Saved Quiz Progress</h3>
      <p>Answer the quiz, refresh the page, and localStorage restores your current question and selected answers.</p>
    </div>

    <div class="vb-storage-thirteen-card">
      <div class="vb-storage-thirteen-top">
        <span data-question-count>Question 1 of 3</span>
        <strong data-score-label>Score: 0</strong>
      </div>

      <div class="vb-storage-thirteen-progress">
        <span data-progress-bar></span>
      </div>

      <div class="vb-storage-thirteen-question">
        <h4 data-question-title>Loading question...</h4>
        <div class="vb-storage-thirteen-options" data-options></div>
      </div>

      <div class="vb-storage-thirteen-actions">
        <button type="button" data-prev-question>Back</button>
        <button type="button" data-next-question>Next</button>
      </div>

      <div class="vb-storage-thirteen-result" data-result-box hidden>
        <strong data-result-title>Quiz complete</strong>
        <p data-result-text>Your result will appear here.</p>
      </div>

      <button type="button" class="vb-storage-thirteen-reset" data-reset-quiz>Reset Saved Quiz</button>
    </div>
  </div>
</div>

<style>
.vb-storage-thirteen-demo,
.vb-storage-thirteen-demo * {
  box-sizing: border-box;
}

.vb-storage-thirteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 16%, rgba(99, 102, 241, 0.18), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(16, 185, 129, 0.16), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #ecfdf5 54%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.18);
  box-shadow: 0 28px 80px rgba(67, 56, 202, 0.10);
}

.vb-storage-thirteen-quiz {
  display: grid;
  grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
  gap: 22px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #111827;
  box-shadow: 0 28px 90px rgba(17, 24, 39, 0.28);
}

.vb-storage-thirteen-intro {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
  padding: clamp(18px, 3vw, 26px);
}

.vb-storage-thirteen-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(99, 102, 241, 0.20);
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-thirteen-intro h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-thirteen-intro p {
  max-width: 540px;
  margin: 0 !important;
  color: #d1d5db !important;
  -webkit-text-fill-color: #d1d5db !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-thirteen-card {
  display: grid;
  gap: 16px;
  min-width: 0;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-storage-thirteen-top,
.vb-storage-thirteen-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.vb-storage-thirteen-top span,
.vb-storage-thirteen-top strong {
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-thirteen-top span {
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
}

.vb-storage-thirteen-top strong {
  color: #059669 !important;
  -webkit-text-fill-color: #059669 !important;
}

.vb-storage-thirteen-progress {
  height: 12px;
  overflow: hidden;
  border-radius: 999px;
  background: #e5e7eb;
}

.vb-storage-thirteen-progress span {
  display: block;
  width: 33.33%;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(135deg, #6366f1, #10b981);
  transition: width 0.25s ease;
}

.vb-storage-thirteen-question {
  display: grid;
  gap: 16px;
  min-height: 270px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 24px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-thirteen-question h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(24px, 3vw, 34px) !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-storage-thirteen-options {
  display: grid;
  gap: 10px;
}

.vb-storage-thirteen-option {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  padding: 13px 14px;
  border: 1px solid rgba(148, 163, 184, 0.24);
  border-radius: 16px;
  background: #ffffff;
  cursor: pointer;
}

.vb-storage-thirteen-option.is-selected {
  border-color: rgba(99, 102, 241, 0.70);
  background: #eef2ff;
}

.vb-storage-thirteen-option input {
  width: 18px;
  height: 18px;
  accent-color: #6366f1;
}

.vb-storage-thirteen-option span {
  color: #1f2937 !important;
  -webkit-text-fill-color: #1f2937 !important;
  font-size: 15px;
  line-height: 1.35;
  font-weight: 750;
}

.vb-storage-thirteen-actions button,
.vb-storage-thirteen-reset {
  min-height: 44px;
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-thirteen-actions button {
  padding: 0 16px;
  background: #e0e7ff;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
}

.vb-storage-thirteen-actions button:last-child {
  background: linear-gradient(135deg, #6366f1, #10b981);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-thirteen-actions button:disabled {
  opacity: 0.52;
  cursor: not-allowed;
}

.vb-storage-thirteen-result {
  padding: 16px;
  border-radius: 20px;
  background: #ecfdf5;
  border: 1px solid rgba(16, 185, 129, 0.24);
}

.vb-storage-thirteen-result strong {
  display: block;
  margin-bottom: 6px;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-storage-thirteen-result p {
  margin: 0 !important;
  color: #065f46 !important;
  -webkit-text-fill-color: #065f46 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 750;
}

.vb-storage-thirteen-reset {
  justify-self: start;
  padding: 0 14px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

@media (max-width: 920px) {
  .vb-storage-thirteen-quiz {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-storage-thirteen-intro h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }

  .vb-storage-thirteen-actions {
    flex-direction: column;
  }

  .vb-storage-thirteen-actions button,
  .vb-storage-thirteen-reset {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-thirteen]");
  if (!wrapper) return;

  const storageKey = "vbStorageThirteenQuiz";
  const questionCount = wrapper.querySelector("[data-question-count]");
  const scoreLabel = wrapper.querySelector("[data-score-label]");
  const progressBar = wrapper.querySelector("[data-progress-bar]");
  const questionTitle = wrapper.querySelector("[data-question-title]");
  const optionsBox = wrapper.querySelector("[data-options]");
  const prevButton = wrapper.querySelector("[data-prev-question]");
  const nextButton = wrapper.querySelector("[data-next-question]");
  const resultBox = wrapper.querySelector("[data-result-box]");
  const resultTitle = wrapper.querySelector("[data-result-title]");
  const resultText = wrapper.querySelector("[data-result-text]");
  const resetButton = wrapper.querySelector("[data-reset-quiz]");

  const questions = [
    {
      title: "What does localStorage store values as?",
      options: ["Numbers only", "Strings", "CSS variables"],
      correct: "Strings"
    },
    {
      title: "Which method saves a value in localStorage?",
      options: ["localStorage.setItem()", "localStorage.push()", "localStorage.save()"],
      correct: "localStorage.setItem()"
    },
    {
      title: "What is commonly used to store arrays or objects?",
      options: ["JSON.stringify()", "document.write()", "parseInt()"],
      correct: "JSON.stringify()"
    }
  ];

  let state = {
    currentQuestion: 0,
    answers: {}
  };

  function saveState() {
    localStorage.setItem(storageKey, JSON.stringify(state));
  }

  function loadState() {
    const savedState = localStorage.getItem(storageKey);
    if (!savedState) return;

    try {
      const parsedState = JSON.parse(savedState);
      state.currentQuestion = Number(parsedState.currentQuestion) || 0;
      state.answers = parsedState.answers || {};
    } catch (error) {
      localStorage.removeItem(storageKey);
    }
  }

  function getScore() {
    return questions.reduce(function (score, question, index) {
      return state.answers[index] === question.correct ? score + 1 : score;
    }, 0);
  }

  function renderQuiz() {
    const question = questions[state.currentQuestion];
    const selectedAnswer = state.answers[state.currentQuestion];

    questionCount.textContent = "Question " + (state.currentQuestion + 1) + " of " + questions.length;
    scoreLabel.textContent = "Score: " + getScore();
    progressBar.style.width = ((state.currentQuestion + 1) / questions.length * 100) + "%";
    questionTitle.textContent = question.title;
    optionsBox.innerHTML = "";

    question.options.forEach(function (option) {
      const label = document.createElement("label");
      label.className = "vb-storage-thirteen-option";
      label.classList.toggle("is-selected", selectedAnswer === option);

      label.innerHTML =
        '<input type="radio" name="quizAnswer" value="' + option + '"' + (selectedAnswer === option ? " checked" : "") + '>' +
        '<span>' + option + '</span>';

      optionsBox.appendChild(label);
    });

    prevButton.disabled = state.currentQuestion === 0;
    nextButton.textContent = state.currentQuestion === questions.length - 1 ? "Finish Quiz" : "Next";
    resultBox.hidden = true;

    saveState();
  }

  optionsBox.addEventListener("change", function (event) {
    if (event.target.name !== "quizAnswer") return;

    state.answers[state.currentQuestion] = event.target.value;
    saveState();
    renderQuiz();
  });

  prevButton.addEventListener("click", function () {
    state.currentQuestion = Math.max(0, state.currentQuestion - 1);
    renderQuiz();
  });

  nextButton.addEventListener("click", function () {
    if (state.currentQuestion < questions.length - 1) {
      state.currentQuestion += 1;
      renderQuiz();
      return;
    }

    const score = getScore();
    resultBox.hidden = false;
    resultTitle.textContent = "Quiz complete";
    resultText.textContent = "You scored " + score + " out of " + questions.length + ". Your progress is still saved in localStorage.";
  });

  resetButton.addEventListener("click", function () {
    state = {
      currentQuestion: 0,
      answers: {}
    };

    localStorage.removeItem(storageKey);
    renderQuiz();
  });

  loadState();
  renderQuiz();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-thirteen]");
  if (!wrapper) return;

  const storageKey = "vbStorageThirteenQuiz";
  const questionCount = wrapper.querySelector("[data-question-count]");
  const scoreLabel = wrapper.querySelector("[data-score-label]");
  const progressBar = wrapper.querySelector("[data-progress-bar]");
  const questionTitle = wrapper.querySelector("[data-question-title]");
  const optionsBox = wrapper.querySelector("[data-options]");
  const prevButton = wrapper.querySelector("[data-prev-question]");
  const nextButton = wrapper.querySelector("[data-next-question]");
  const resultBox = wrapper.querySelector("[data-result-box]");
  const resultTitle = wrapper.querySelector("[data-result-title]");
  const resultText = wrapper.querySelector("[data-result-text]");
  const resetButton = wrapper.querySelector("[data-reset-quiz]");

  const questions = [
    {
      title: "What does localStorage store values as?",
      options: ["Numbers only", "Strings", "CSS variables"],
      correct: "Strings"
    },
    {
      title: "Which method saves a value in localStorage?",
      options: ["localStorage.setItem()", "localStorage.push()", "localStorage.save()"],
      correct: "localStorage.setItem()"
    },
    {
      title: "What is commonly used to store arrays or objects?",
      options: ["JSON.stringify()", "document.write()", "parseInt()"],
      correct: "JSON.stringify()"
    }
  ];

  let state = {
    currentQuestion: 0,
    answers: {}
  };

  function saveState() {
    localStorage.setItem(storageKey, JSON.stringify(state));
  }

  function loadState() {
    const savedState = localStorage.getItem(storageKey);
    if (!savedState) return;

    try {
      const parsedState = JSON.parse(savedState);
      state.currentQuestion = Number(parsedState.currentQuestion) || 0;
      state.answers = parsedState.answers || {};
    } catch (error) {
      localStorage.removeItem(storageKey);
    }
  }

  function getScore() {
    return questions.reduce(function (score, question, index) {
      return state.answers[index] === question.correct ? score + 1 : score;
    }, 0);
  }

  function renderQuiz() {
    const question = questions[state.currentQuestion];
    const selectedAnswer = state.answers[state.currentQuestion];

    questionCount.textContent = "Question " + (state.currentQuestion + 1) + " of " + questions.length;
    scoreLabel.textContent = "Score: " + getScore();
    progressBar.style.width = ((state.currentQuestion + 1) / questions.length * 100) + "%";
    questionTitle.textContent = question.title;
    optionsBox.innerHTML = "";

    question.options.forEach(function (option) {
      const label = document.createElement("label");
      label.className = "vb-storage-thirteen-option";
      label.classList.toggle("is-selected", selectedAnswer === option);

      label.innerHTML =
        '&lt;input type="radio" name="quizAnswer" value="' + option + '"' + (selectedAnswer === option ? " checked" : "") + '&gt;' +
        '&lt;span&gt;' + option + '&lt;/span&gt;';

      optionsBox.appendChild(label);
    });

    prevButton.disabled = state.currentQuestion === 0;
    nextButton.textContent = state.currentQuestion === questions.length - 1 ? "Finish Quiz" : "Next";
    resultBox.hidden = true;

    saveState();
  }

  optionsBox.addEventListener("change", function (event) {
    if (event.target.name !== "quizAnswer") return;

    state.answers[state.currentQuestion] = event.target.value;
    saveState();
    renderQuiz();
  });

  prevButton.addEventListener("click", function () {
    state.currentQuestion = Math.max(0, state.currentQuestion - 1);
    renderQuiz();
  });

  nextButton.addEventListener("click", function () {
    if (state.currentQuestion &lt; questions.length - 1) {
      state.currentQuestion += 1;
      renderQuiz();
      return;
    }

    const score = getScore();
    resultBox.hidden = false;
    resultTitle.textContent = "Quiz complete";
    resultText.textContent = "You scored " + score + " out of " + questions.length + ". Your progress is still saved in localStorage.";
  });

  resetButton.addEventListener("click", function () {
    state = {
      currentQuestion: 0,
      answers: {}
    };

    localStorage.removeItem(storageKey);
    renderQuiz();
  });

  loadState();
  renderQuiz();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-thirteen-demo"&gt;
  &lt;div class="vb-storage-thirteen-quiz" data-vb-storage-thirteen&gt;
    &lt;div class="vb-storage-thirteen-intro"&gt;
      &lt;span class="vb-storage-thirteen-kicker"&gt;Example 13&lt;/span&gt;
      &lt;h3&gt;Saved Quiz Progress&lt;/h3&gt;
      &lt;p&gt;Answer the quiz, refresh the page, and localStorage restores your current question and selected answers.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-thirteen-card"&gt;
      &lt;div class="vb-storage-thirteen-top"&gt;
        &lt;span data-question-count&gt;Question 1 of 3&lt;/span&gt;
        &lt;strong data-score-label&gt;Score: 0&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-thirteen-progress"&gt;
        &lt;span data-progress-bar&gt;&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-thirteen-question"&gt;
        &lt;h4 data-question-title&gt;Loading question...&lt;/h4&gt;
        &lt;div class="vb-storage-thirteen-options" data-options&gt;&lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-thirteen-actions"&gt;
        &lt;button type="button" data-prev-question&gt;Back&lt;/button&gt;
        &lt;button type="button" data-next-question&gt;Next&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-thirteen-result" data-result-box hidden&gt;
        &lt;strong data-result-title&gt;Quiz complete&lt;/strong&gt;
        &lt;p data-result-text&gt;Your result will appear here.&lt;/p&gt;
      &lt;/div&gt;

      &lt;button type="button" class="vb-storage-thirteen-reset" data-reset-quiz&gt;Reset Saved Quiz&lt;/button&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-thirteen-demo,
.vb-storage-thirteen-demo * {
  box-sizing: border-box;
}

.vb-storage-thirteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 16%, rgba(99, 102, 241, 0.18), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(16, 185, 129, 0.16), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #ecfdf5 54%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.18);
  box-shadow: 0 28px 80px rgba(67, 56, 202, 0.10);
}

.vb-storage-thirteen-quiz {
  display: grid;
  grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
  gap: 22px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #111827;
  box-shadow: 0 28px 90px rgba(17, 24, 39, 0.28);
}

.vb-storage-thirteen-intro {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
  padding: clamp(18px, 3vw, 26px);
}

.vb-storage-thirteen-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(99, 102, 241, 0.20);
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-thirteen-intro h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-thirteen-intro p {
  max-width: 540px;
  margin: 0 !important;
  color: #d1d5db !important;
  -webkit-text-fill-color: #d1d5db !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-thirteen-card {
  display: grid;
  gap: 16px;
  min-width: 0;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-storage-thirteen-top,
.vb-storage-thirteen-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.vb-storage-thirteen-top span,
.vb-storage-thirteen-top strong {
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-thirteen-top span {
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
}

.vb-storage-thirteen-top strong {
  color: #059669 !important;
  -webkit-text-fill-color: #059669 !important;
}

.vb-storage-thirteen-progress {
  height: 12px;
  overflow: hidden;
  border-radius: 999px;
  background: #e5e7eb;
}

.vb-storage-thirteen-progress span {
  display: block;
  width: 33.33%;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(135deg, #6366f1, #10b981);
  transition: width 0.25s ease;
}

.vb-storage-thirteen-question {
  display: grid;
  gap: 16px;
  min-height: 270px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 24px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-thirteen-question h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(24px, 3vw, 34px) !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-storage-thirteen-options {
  display: grid;
  gap: 10px;
}

.vb-storage-thirteen-option {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  padding: 13px 14px;
  border: 1px solid rgba(148, 163, 184, 0.24);
  border-radius: 16px;
  background: #ffffff;
  cursor: pointer;
}

.vb-storage-thirteen-option.is-selected {
  border-color: rgba(99, 102, 241, 0.70);
  background: #eef2ff;
}

.vb-storage-thirteen-option input {
  width: 18px;
  height: 18px;
  accent-color: #6366f1;
}

.vb-storage-thirteen-option span {
  color: #1f2937 !important;
  -webkit-text-fill-color: #1f2937 !important;
  font-size: 15px;
  line-height: 1.35;
  font-weight: 750;
}

.vb-storage-thirteen-actions button,
.vb-storage-thirteen-reset {
  min-height: 44px;
  border: 0;
  border-radius: 999px;
  cursor: pointer;
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-thirteen-actions button {
  padding: 0 16px;
  background: #e0e7ff;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
}

.vb-storage-thirteen-actions button:last-child {
  background: linear-gradient(135deg, #6366f1, #10b981);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-thirteen-actions button:disabled {
  opacity: 0.52;
  cursor: not-allowed;
}

.vb-storage-thirteen-result {
  padding: 16px;
  border-radius: 20px;
  background: #ecfdf5;
  border: 1px solid rgba(16, 185, 129, 0.24);
}

.vb-storage-thirteen-result strong {
  display: block;
  margin-bottom: 6px;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-storage-thirteen-result p {
  margin: 0 !important;
  color: #065f46 !important;
  -webkit-text-fill-color: #065f46 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 750;
}

.vb-storage-thirteen-reset {
  justify-self: start;
  padding: 0 14px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

@media (max-width: 920px) {
  .vb-storage-thirteen-quiz {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-storage-thirteen-intro h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }

  .vb-storage-thirteen-actions {
    flex-direction: column;
  }

  .vb-storage-thirteen-actions button,
  .vb-storage-thirteen-reset {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This quiz progress localStorage example is useful for JavaScript quiz apps, online course lessons, onboarding questionnaires, product recommendation quizzes, lead generation quizzes, learning platforms, and interactive website assessments.</p>



<h2 class="wp-block-heading">14. Calculator History Saved with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>Saving calculator history with localStorage</strong> is useful for price calculators, loan calculators, quote calculators, discount calculators, BMI calculators, tax calculators, and form-based tools. It helps users compare previous results without needing a backend database.</p>



<p class="wp-block-paragraph">This example calculates a simple project price estimate from hours and hourly rate. JavaScript saves each calculated result into localStorage, displays a history list, and restores previous calculations after page refresh.</p>



<ul class="wp-block-list">
<li>Save calculator history</li>
<li>Stores previous results in localStorage</li>
<li>Calculates price estimates</li>
<li>Supports clear history</li>
<li>Useful for quote and price calculators</li>
</ul>



<div class="vb-storage-fourteen-demo">
  <div class="vb-storage-fourteen-app" data-vb-storage-fourteen>
    <div class="vb-storage-fourteen-calc">
      <span class="vb-storage-fourteen-kicker">Example 14</span>
      <h3>Saved Calculator History</h3>
      <p>Calculate a project estimate and save every result in localStorage for later comparison.</p>

      <form data-calc-form class="vb-storage-fourteen-form">
        <label>
          <span>Project name</span>
          <input type="text" data-project-name placeholder="Landing page build">
        </label>

        <div class="vb-storage-fourteen-fields">
          <label>
            <span>Hours</span>
            <input type="number" data-hours min="1" value="12">
          </label>

          <label>
            <span>Hourly rate (€)</span>
            <input type="number" data-rate min="1" value="45">
          </label>
        </div>

        <button type="submit">Calculate Estimate</button>
      </form>

      <div class="vb-storage-fourteen-total">
        <span>Current estimate</span>
        <strong data-current-total>540€</strong>
      </div>
    </div>

    <div class="vb-storage-fourteen-history">
      <div class="vb-storage-fourteen-history-head">
        <strong>Saved History</strong>
        <button type="button" data-clear-history>Clear</button>
      </div>

      <div class="vb-storage-fourteen-list" data-history-list>
        <p class="vb-storage-fourteen-empty">No saved calculations yet.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-storage-fourteen-demo,
.vb-storage-fourteen-demo * {
  box-sizing: border-box;
}

.vb-storage-fourteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(249, 115, 22, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(37, 99, 235, 0.16), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #eff6ff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(249, 115, 22, 0.18);
  box-shadow: 0 28px 80px rgba(154, 52, 18, 0.10);
}

.vb-storage-fourteen-app {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: 22px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-fourteen-calc,
.vb-storage-fourteen-history {
  min-width: 0;
}

.vb-storage-fourteen-calc {
  display: grid;
  gap: 16px;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 28px;
  background: #111827;
}

.vb-storage-fourteen-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(249, 115, 22, 0.16);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-fourteen-calc h3 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-fourteen-calc p {
  margin: 0 !important;
  color: #d1d5db !important;
  -webkit-text-fill-color: #d1d5db !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-fourteen-form {
  display: grid;
  gap: 12px;
}

.vb-storage-fourteen-form label {
  display: grid;
  gap: 7px;
}

.vb-storage-fourteen-form label span {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-storage-fourteen-fields {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-storage-fourteen-form input {
  width: 100%;
  min-height: 50px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 16px;
  background: rgba(255,255,255,0.09);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-storage-fourteen-form input::placeholder {
  color: #9ca3af;
  -webkit-text-fill-color: #9ca3af;
}

.vb-storage-fourteen-form input:focus {
  border-color: rgba(249, 115, 22, 0.70);
  box-shadow: 0 0 0 4px rgba(249, 115, 22, 0.12);
}

.vb-storage-fourteen-form button {
  min-height: 50px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #f97316, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.22);
}

.vb-storage-fourteen-total {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 16px;
  border-radius: 22px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-fourteen-total span {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-storage-fourteen-total strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px;
  line-height: 1;
  font-weight: 950;
}

.vb-storage-fourteen-history {
  display: grid;
  gap: 14px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 30px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-fourteen-history-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.vb-storage-fourteen-history-head strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-storage-fourteen-history-head button {
  min-height: 38px;
  padding: 0 13px;
  border: 0;
  border-radius: 999px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-fourteen-list {
  display: grid;
  gap: 10px;
  min-height: 340px;
}

.vb-storage-fourteen-empty {
  display: grid;
  place-items: center;
  min-height: 340px;
  margin: 0 !important;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  border-radius: 22px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-fourteen-item {
  display: grid;
  gap: 7px;
  padding: 14px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 12px 32px rgba(15, 23, 42, 0.06);
}

.vb-storage-fourteen-item strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 16px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-storage-fourteen-item span {
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 22px;
  line-height: 1;
  font-weight: 950;
}

.vb-storage-fourteen-item small {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 750;
}

@media (max-width: 920px) {
  .vb-storage-fourteen-app {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-storage-fourteen-fields {
    grid-template-columns: 1fr;
  }

  .vb-storage-fourteen-calc h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }

  .vb-storage-fourteen-total {
    align-items: flex-start;
    flex-direction: column;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-fourteen]");
  if (!wrapper) return;

  const storageKey = "vbStorageFourteenCalculatorHistory";
  const form = wrapper.querySelector("[data-calc-form]");
  const projectInput = wrapper.querySelector("[data-project-name]");
  const hoursInput = wrapper.querySelector("[data-hours]");
  const rateInput = wrapper.querySelector("[data-rate]");
  const currentTotal = wrapper.querySelector("[data-current-total]");
  const historyList = wrapper.querySelector("[data-history-list]");
  const clearButton = wrapper.querySelector("[data-clear-history]");

  let history = [];

  function saveHistory() {
    localStorage.setItem(storageKey, JSON.stringify(history));
  }

  function loadHistory() {
    const savedHistory = localStorage.getItem(storageKey);
    if (!savedHistory) return;

    try {
      const parsedHistory = JSON.parse(savedHistory);
      history = Array.isArray(parsedHistory) ? parsedHistory : [];
    } catch (error) {
      history = [];
      localStorage.removeItem(storageKey);
    }
  }

  function calculateTotal() {
    const hours = Number(hoursInput.value) || 0;
    const rate = Number(rateInput.value) || 0;
    return hours * rate;
  }

  function updateCurrentTotal() {
    currentTotal.textContent = calculateTotal() + "€";
  }

  function renderHistory() {
    historyList.innerHTML = "";

    if (history.length === 0) {
      historyList.innerHTML = '<p class="vb-storage-fourteen-empty">No saved calculations yet.</p>';
      return;
    }

    history.forEach(function (item) {
      const historyItem = document.createElement("div");
      historyItem.className = "vb-storage-fourteen-item";

      historyItem.innerHTML =
        '<strong>' + item.project + '</strong>' +
        '<span>' + item.total + '€</span>' +
        '<small>' + item.hours + ' hours × ' + item.rate + '€/h · ' + item.date + '</small>';

      historyList.appendChild(historyItem);
    });
  }

  form.addEventListener("submit", function (event) {
    event.preventDefault();

    const total = calculateTotal();
    const project = projectInput.value.trim() || "Untitled estimate";

    history.unshift({
      id: String(Date.now()),
      project: project,
      hours: Number(hoursInput.value) || 0,
      rate: Number(rateInput.value) || 0,
      total: total,
      date: new Date().toLocaleDateString()
    });

    history = history.slice(0, 6);
    saveHistory();
    renderHistory();
    updateCurrentTotal();
  });

  hoursInput.addEventListener("input", updateCurrentTotal);
  rateInput.addEventListener("input", updateCurrentTotal);

  clearButton.addEventListener("click", function () {
    history = [];
    localStorage.removeItem(storageKey);
    renderHistory();
  });

  loadHistory();
  renderHistory();
  updateCurrentTotal();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-fourteen]");
  if (!wrapper) return;

  const storageKey = "vbStorageFourteenCalculatorHistory";
  const form = wrapper.querySelector("[data-calc-form]");
  const projectInput = wrapper.querySelector("[data-project-name]");
  const hoursInput = wrapper.querySelector("[data-hours]");
  const rateInput = wrapper.querySelector("[data-rate]");
  const currentTotal = wrapper.querySelector("[data-current-total]");
  const historyList = wrapper.querySelector("[data-history-list]");
  const clearButton = wrapper.querySelector("[data-clear-history]");

  let history = [];

  function saveHistory() {
    localStorage.setItem(storageKey, JSON.stringify(history));
  }

  function loadHistory() {
    const savedHistory = localStorage.getItem(storageKey);
    if (!savedHistory) return;

    try {
      const parsedHistory = JSON.parse(savedHistory);
      history = Array.isArray(parsedHistory) ? parsedHistory : [];
    } catch (error) {
      history = [];
      localStorage.removeItem(storageKey);
    }
  }

  function calculateTotal() {
    const hours = Number(hoursInput.value) || 0;
    const rate = Number(rateInput.value) || 0;
    return hours * rate;
  }

  function updateCurrentTotal() {
    currentTotal.textContent = calculateTotal() + "€";
  }

  function renderHistory() {
    historyList.innerHTML = "";

    if (history.length === 0) {
      historyList.innerHTML = '&lt;p class="vb-storage-fourteen-empty"&gt;No saved calculations yet.&lt;/p&gt;';
      return;
    }

    history.forEach(function (item) {
      const historyItem = document.createElement("div");
      historyItem.className = "vb-storage-fourteen-item";

      historyItem.innerHTML =
        '&lt;strong&gt;' + item.project + '&lt;/strong&gt;' +
        '&lt;span&gt;' + item.total + '€&lt;/span&gt;' +
        '&lt;small&gt;' + item.hours + ' hours × ' + item.rate + '€/h · ' + item.date + '&lt;/small&gt;';

      historyList.appendChild(historyItem);
    });
  }

  form.addEventListener("submit", function (event) {
    event.preventDefault();

    const total = calculateTotal();
    const project = projectInput.value.trim() || "Untitled estimate";

    history.unshift({
      id: String(Date.now()),
      project: project,
      hours: Number(hoursInput.value) || 0,
      rate: Number(rateInput.value) || 0,
      total: total,
      date: new Date().toLocaleDateString()
    });

    history = history.slice(0, 6);
    saveHistory();
    renderHistory();
    updateCurrentTotal();
  });

  hoursInput.addEventListener("input", updateCurrentTotal);
  rateInput.addEventListener("input", updateCurrentTotal);

  clearButton.addEventListener("click", function () {
    history = [];
    localStorage.removeItem(storageKey);
    renderHistory();
  });

  loadHistory();
  renderHistory();
  updateCurrentTotal();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-fourteen-demo"&gt;
  &lt;div class="vb-storage-fourteen-app" data-vb-storage-fourteen&gt;
    &lt;div class="vb-storage-fourteen-calc"&gt;
      &lt;span class="vb-storage-fourteen-kicker"&gt;Example 14&lt;/span&gt;
      &lt;h3&gt;Saved Calculator History&lt;/h3&gt;
      &lt;p&gt;Calculate a project estimate and save every result in localStorage for later comparison.&lt;/p&gt;

      &lt;form data-calc-form class="vb-storage-fourteen-form"&gt;
        &lt;label&gt;
          &lt;span&gt;Project name&lt;/span&gt;
          &lt;input type="text" data-project-name placeholder="Landing page build"&gt;
        &lt;/label&gt;

        &lt;div class="vb-storage-fourteen-fields"&gt;
          &lt;label&gt;
            &lt;span&gt;Hours&lt;/span&gt;
            &lt;input type="number" data-hours min="1" value="12"&gt;
          &lt;/label&gt;

          &lt;label&gt;
            &lt;span&gt;Hourly rate (€)&lt;/span&gt;
            &lt;input type="number" data-rate min="1" value="45"&gt;
          &lt;/label&gt;
        &lt;/div&gt;

        &lt;button type="submit"&gt;Calculate Estimate&lt;/button&gt;
      &lt;/form&gt;

      &lt;div class="vb-storage-fourteen-total"&gt;
        &lt;span&gt;Current estimate&lt;/span&gt;
        &lt;strong data-current-total&gt;540€&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-fourteen-history"&gt;
      &lt;div class="vb-storage-fourteen-history-head"&gt;
        &lt;strong&gt;Saved History&lt;/strong&gt;
        &lt;button type="button" data-clear-history&gt;Clear&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-fourteen-list" data-history-list&gt;
        &lt;p class="vb-storage-fourteen-empty"&gt;No saved calculations yet.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-fourteen-demo,
.vb-storage-fourteen-demo * {
  box-sizing: border-box;
}

.vb-storage-fourteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(249, 115, 22, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(37, 99, 235, 0.16), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #eff6ff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(249, 115, 22, 0.18);
  box-shadow: 0 28px 80px rgba(154, 52, 18, 0.10);
}

.vb-storage-fourteen-app {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: 22px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-fourteen-calc,
.vb-storage-fourteen-history {
  min-width: 0;
}

.vb-storage-fourteen-calc {
  display: grid;
  gap: 16px;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 28px;
  background: #111827;
}

.vb-storage-fourteen-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(249, 115, 22, 0.16);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-fourteen-calc h3 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-fourteen-calc p {
  margin: 0 !important;
  color: #d1d5db !important;
  -webkit-text-fill-color: #d1d5db !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-fourteen-form {
  display: grid;
  gap: 12px;
}

.vb-storage-fourteen-form label {
  display: grid;
  gap: 7px;
}

.vb-storage-fourteen-form label span {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-storage-fourteen-fields {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-storage-fourteen-form input {
  width: 100%;
  min-height: 50px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 16px;
  background: rgba(255,255,255,0.09);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-storage-fourteen-form input::placeholder {
  color: #9ca3af;
  -webkit-text-fill-color: #9ca3af;
}

.vb-storage-fourteen-form input:focus {
  border-color: rgba(249, 115, 22, 0.70);
  box-shadow: 0 0 0 4px rgba(249, 115, 22, 0.12);
}

.vb-storage-fourteen-form button {
  min-height: 50px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #f97316, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.22);
}

.vb-storage-fourteen-total {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 16px;
  border-radius: 22px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-fourteen-total span {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-storage-fourteen-total strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px;
  line-height: 1;
  font-weight: 950;
}

.vb-storage-fourteen-history {
  display: grid;
  gap: 14px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 30px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-fourteen-history-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.vb-storage-fourteen-history-head strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-storage-fourteen-history-head button {
  min-height: 38px;
  padding: 0 13px;
  border: 0;
  border-radius: 999px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-fourteen-list {
  display: grid;
  gap: 10px;
  min-height: 340px;
}

.vb-storage-fourteen-empty {
  display: grid;
  place-items: center;
  min-height: 340px;
  margin: 0 !important;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  border-radius: 22px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-fourteen-item {
  display: grid;
  gap: 7px;
  padding: 14px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 12px 32px rgba(15, 23, 42, 0.06);
}

.vb-storage-fourteen-item strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 16px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-storage-fourteen-item span {
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 22px;
  line-height: 1;
  font-weight: 950;
}

.vb-storage-fourteen-item small {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 750;
}

@media (max-width: 920px) {
  .vb-storage-fourteen-app {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-storage-fourteen-fields {
    grid-template-columns: 1fr;
  }

  .vb-storage-fourteen-calc h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }

  .vb-storage-fourteen-total {
    align-items: flex-start;
    flex-direction: column;
  }
}</pre>



<p class="wp-block-paragraph">This calculator history localStorage example is useful for price calculators, quote estimators, loan calculators, discount calculators, project calculators, service estimate forms, and browser-based calculation tools.</p>



<h2 class="wp-block-heading">15. Continue Reading Progress Saved with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>Saving reading progress with localStorage</strong> is useful for blogs, documentation pages, tutorials, online courses, long-form guides, knowledge bases, and article websites. It helps readers continue from where they left off after returning to a page.</p>



<p class="wp-block-paragraph">This example simulates a long article area with section buttons. JavaScript saves the last selected article section in localStorage, updates the reading progress indicator, and restores the same section after refresh.</p>



<ul class="wp-block-list">
<li>Save reading progress</li>
<li>Restores last active section</li>
<li>Updates progress indicator</li>
<li>Useful for tutorials and long articles</li>
<li>Simple continue reading pattern</li>
</ul>



<div class="vb-storage-fifteen-demo">
  <div class="vb-storage-fifteen-reader" data-vb-storage-fifteen>
    <div class="vb-storage-fifteen-head">
      <span class="vb-storage-fifteen-kicker">Example 15</span>
      <h3>Continue Reading Progress</h3>
      <p>Select article sections and refresh the page. localStorage restores the last section you were reading.</p>
    </div>

    <div class="vb-storage-fifteen-layout">
      <aside class="vb-storage-fifteen-sidebar">
        <strong>Article Sections</strong>
        <button type="button" data-section-button="intro" class="is-active">1. Introduction</button>
        <button type="button" data-section-button="setup">2. Setup</button>
        <button type="button" data-section-button="examples">3. Examples</button>
        <button type="button" data-section-button="summary">4. Summary</button>

        <div class="vb-storage-fifteen-progress">
          <span>Reading progress</span>
          <div><i data-reading-progress></i></div>
          <small data-progress-label>25% complete</small>
        </div>
      </aside>

      <article class="vb-storage-fifteen-content">
        <section data-section-panel="intro" class="is-active">
          <span>Section 01</span>
          <h4>Introduction</h4>
          <p>This section introduces the topic and explains why saving reading progress can improve long-form content experiences.</p>
        </section>

        <section data-section-panel="setup">
          <span>Section 02</span>
          <h4>Setup</h4>
          <p>This section explains how a page can use JavaScript, section buttons, and localStorage to remember the reader’s last position.</p>
        </section>

        <section data-section-panel="examples">
          <span>Section 03</span>
          <h4>Examples</h4>
          <p>This section could contain code examples, screenshots, tutorial steps, videos, or detailed learning material.</p>
        </section>

        <section data-section-panel="summary">
          <span>Section 04</span>
          <h4>Summary</h4>
          <p>This section closes the guide and lets the reader return later without losing where they stopped.</p>
        </section>
      </article>
    </div>

    <button type="button" class="vb-storage-fifteen-reset" data-reset-reading>Reset Reading Progress</button>
  </div>
</div>

<style>
.vb-storage-fifteen-demo,
.vb-storage-fifteen-demo * {
  box-sizing: border-box;
}

.vb-storage-fifteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(6, 182, 212, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(124, 58, 237, 0.14), transparent 34%),
    linear-gradient(135deg, #ecfeff 0%, #f5f3ff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(6, 182, 212, 0.18);
  box-shadow: 0 28px 80px rgba(14, 116, 144, 0.10);
}

.vb-storage-fifteen-reader {
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-fifteen-head {
  display: grid;
  gap: 12px;
  margin-bottom: 24px;
}

.vb-storage-fifteen-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #cffafe;
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-fifteen-head h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-fifteen-head p {
  max-width: 760px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-fifteen-layout {
  display: grid;
  grid-template-columns: 280px minmax(0, 1fr);
  gap: 18px;
  align-items: stretch;
}

.vb-storage-fifteen-sidebar {
  display: grid;
  align-content: start;
  gap: 10px;
  padding: 18px;
  border-radius: 28px;
  background: #0f172a;
}

.vb-storage-fifteen-sidebar strong {
  margin-bottom: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1.15;
  font-weight: 950;
}

.vb-storage-fifteen-sidebar button {
  min-height: 44px;
  padding: 10px 13px;
  border: 0;
  border-radius: 16px;
  background: rgba(255,255,255,0.08);
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 13px;
  font-weight: 850;
  text-align: left;
  cursor: pointer;
}

.vb-storage-fifteen-sidebar button.is-active {
  background: linear-gradient(135deg, #06b6d4, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-fifteen-progress {
  display: grid;
  gap: 8px;
  margin-top: 12px;
  padding: 14px;
  border-radius: 20px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-storage-fifteen-progress span,
.vb-storage-fifteen-progress small {
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-storage-fifteen-progress div {
  height: 10px;
  overflow: hidden;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
}

.vb-storage-fifteen-progress i {
  display: block;
  width: 25%;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(135deg, #06b6d4, #a78bfa);
  transition: width 0.25s ease;
}

.vb-storage-fifteen-content {
  min-height: 420px;
  border-radius: 28px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
  overflow: hidden;
}

.vb-storage-fifteen-content section {
  display: none;
  min-height: 420px;
  padding: clamp(24px, 5vw, 54px);
  background:
    radial-gradient(circle at 90% 12%, rgba(6, 182, 212, 0.16), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
}

.vb-storage-fifteen-content section.is-active {
  display: grid;
  align-content: center;
  gap: 14px;
}

.vb-storage-fifteen-content section span {
  display: inline-flex;
  justify-self: start;
  padding: 8px 11px;
  border-radius: 999px;
  background: #cffafe;
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-storage-fifteen-content section h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-storage-fifteen-content section p {
  max-width: 640px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 17px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-storage-fifteen-reset {
  min-height: 42px;
  margin-top: 16px;
  padding: 0 14px;
  border: 0;
  border-radius: 999px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

@media (max-width: 860px) {
  .vb-storage-fifteen-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-storage-fifteen-head h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }

  .vb-storage-fifteen-reset {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-fifteen]");
  if (!wrapper) return;

  const storageKey = "vbStorageFifteenReadingSection";
  const buttons = Array.from(wrapper.querySelectorAll("[data-section-button]"));
  const panels = Array.from(wrapper.querySelectorAll("[data-section-panel]"));
  const progressBar = wrapper.querySelector("[data-reading-progress]");
  const progressLabel = wrapper.querySelector("[data-progress-label]");
  const resetButton = wrapper.querySelector("[data-reset-reading]");

  function activateSection(sectionKey) {
    const activeIndex = buttons.findIndex(function (button) {
      return button.getAttribute("data-section-button") === sectionKey;
    });

    const safeIndex = activeIndex >= 0 ? activeIndex : 0;
    const safeKey = buttons[safeIndex].getAttribute("data-section-button");
    const percent = Math.round(((safeIndex + 1) / buttons.length) * 100);

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-section-button") === safeKey);
    });

    panels.forEach(function (panel) {
      panel.classList.toggle("is-active", panel.getAttribute("data-section-panel") === safeKey);
    });

    progressBar.style.width = percent + "%";
    progressLabel.textContent = percent + "% complete";
    localStorage.setItem(storageKey, safeKey);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activateSection(button.getAttribute("data-section-button"));
    });
  });

  resetButton.addEventListener("click", function () {
    localStorage.removeItem(storageKey);
    activateSection("intro");
  });

  activateSection(localStorage.getItem(storageKey) || "intro");
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-fifteen]");
  if (!wrapper) return;

  const storageKey = "vbStorageFifteenReadingSection";
  const buttons = Array.from(wrapper.querySelectorAll("[data-section-button]"));
  const panels = Array.from(wrapper.querySelectorAll("[data-section-panel]"));
  const progressBar = wrapper.querySelector("[data-reading-progress]");
  const progressLabel = wrapper.querySelector("[data-progress-label]");
  const resetButton = wrapper.querySelector("[data-reset-reading]");

  function activateSection(sectionKey) {
    const activeIndex = buttons.findIndex(function (button) {
      return button.getAttribute("data-section-button") === sectionKey;
    });

    const safeIndex = activeIndex >= 0 ? activeIndex : 0;
    const safeKey = buttons[safeIndex].getAttribute("data-section-button");
    const percent = Math.round(((safeIndex + 1) / buttons.length) * 100);

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-section-button") === safeKey);
    });

    panels.forEach(function (panel) {
      panel.classList.toggle("is-active", panel.getAttribute("data-section-panel") === safeKey);
    });

    progressBar.style.width = percent + "%";
    progressLabel.textContent = percent + "% complete";
    localStorage.setItem(storageKey, safeKey);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activateSection(button.getAttribute("data-section-button"));
    });
  });

  resetButton.addEventListener("click", function () {
    localStorage.removeItem(storageKey);
    activateSection("intro");
  });

  activateSection(localStorage.getItem(storageKey) || "intro");
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-fifteen-demo"&gt;
  &lt;div class="vb-storage-fifteen-reader" data-vb-storage-fifteen&gt;
    &lt;div class="vb-storage-fifteen-head"&gt;
      &lt;span class="vb-storage-fifteen-kicker"&gt;Example 15&lt;/span&gt;
      &lt;h3&gt;Continue Reading Progress&lt;/h3&gt;
      &lt;p&gt;Select article sections and refresh the page. localStorage restores the last section you were reading.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-fifteen-layout"&gt;
      &lt;aside class="vb-storage-fifteen-sidebar"&gt;
        &lt;strong&gt;Article Sections&lt;/strong&gt;
        &lt;button type="button" data-section-button="intro" class="is-active"&gt;1. Introduction&lt;/button&gt;
        &lt;button type="button" data-section-button="setup"&gt;2. Setup&lt;/button&gt;
        &lt;button type="button" data-section-button="examples"&gt;3. Examples&lt;/button&gt;
        &lt;button type="button" data-section-button="summary"&gt;4. Summary&lt;/button&gt;

        &lt;div class="vb-storage-fifteen-progress"&gt;
          &lt;span&gt;Reading progress&lt;/span&gt;
          &lt;div&gt;&lt;i data-reading-progress&gt;&lt;/i&gt;&lt;/div&gt;
          &lt;small data-progress-label&gt;25% complete&lt;/small&gt;
        &lt;/div&gt;
      &lt;/aside&gt;

      &lt;article class="vb-storage-fifteen-content"&gt;
        &lt;section data-section-panel="intro" class="is-active"&gt;
          &lt;span&gt;Section 01&lt;/span&gt;
          &lt;h4&gt;Introduction&lt;/h4&gt;
          &lt;p&gt;This section introduces the topic and explains why saving reading progress can improve long-form content experiences.&lt;/p&gt;
        &lt;/section&gt;

        &lt;section data-section-panel="setup"&gt;
          &lt;span&gt;Section 02&lt;/span&gt;
          &lt;h4&gt;Setup&lt;/h4&gt;
          &lt;p&gt;This section explains how a page can use JavaScript, section buttons, and localStorage to remember the reader’s last position.&lt;/p&gt;
        &lt;/section&gt;

        &lt;section data-section-panel="examples"&gt;
          &lt;span&gt;Section 03&lt;/span&gt;
          &lt;h4&gt;Examples&lt;/h4&gt;
          &lt;p&gt;This section could contain code examples, screenshots, tutorial steps, videos, or detailed learning material.&lt;/p&gt;
        &lt;/section&gt;

        &lt;section data-section-panel="summary"&gt;
          &lt;span&gt;Section 04&lt;/span&gt;
          &lt;h4&gt;Summary&lt;/h4&gt;
          &lt;p&gt;This section closes the guide and lets the reader return later without losing where they stopped.&lt;/p&gt;
        &lt;/section&gt;
      &lt;/article&gt;
    &lt;/div&gt;

    &lt;button type="button" class="vb-storage-fifteen-reset" data-reset-reading&gt;Reset Reading Progress&lt;/button&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-fifteen-demo,
.vb-storage-fifteen-demo * {
  box-sizing: border-box;
}

.vb-storage-fifteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(6, 182, 212, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(124, 58, 237, 0.14), transparent 34%),
    linear-gradient(135deg, #ecfeff 0%, #f5f3ff 55%, #ffffff 100%) !important;
  border: 1px solid rgba(6, 182, 212, 0.18);
  box-shadow: 0 28px 80px rgba(14, 116, 144, 0.10);
}

.vb-storage-fifteen-reader {
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-fifteen-head {
  display: grid;
  gap: 12px;
  margin-bottom: 24px;
}

.vb-storage-fifteen-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #cffafe;
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-fifteen-head h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-fifteen-head p {
  max-width: 760px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-fifteen-layout {
  display: grid;
  grid-template-columns: 280px minmax(0, 1fr);
  gap: 18px;
  align-items: stretch;
}

.vb-storage-fifteen-sidebar {
  display: grid;
  align-content: start;
  gap: 10px;
  padding: 18px;
  border-radius: 28px;
  background: #0f172a;
}

.vb-storage-fifteen-sidebar strong {
  margin-bottom: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1.15;
  font-weight: 950;
}

.vb-storage-fifteen-sidebar button {
  min-height: 44px;
  padding: 10px 13px;
  border: 0;
  border-radius: 16px;
  background: rgba(255,255,255,0.08);
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 13px;
  font-weight: 850;
  text-align: left;
  cursor: pointer;
}

.vb-storage-fifteen-sidebar button.is-active {
  background: linear-gradient(135deg, #06b6d4, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-fifteen-progress {
  display: grid;
  gap: 8px;
  margin-top: 12px;
  padding: 14px;
  border-radius: 20px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-storage-fifteen-progress span,
.vb-storage-fifteen-progress small {
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-storage-fifteen-progress div {
  height: 10px;
  overflow: hidden;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
}

.vb-storage-fifteen-progress i {
  display: block;
  width: 25%;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(135deg, #06b6d4, #a78bfa);
  transition: width 0.25s ease;
}

.vb-storage-fifteen-content {
  min-height: 420px;
  border-radius: 28px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
  overflow: hidden;
}

.vb-storage-fifteen-content section {
  display: none;
  min-height: 420px;
  padding: clamp(24px, 5vw, 54px);
  background:
    radial-gradient(circle at 90% 12%, rgba(6, 182, 212, 0.16), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
}

.vb-storage-fifteen-content section.is-active {
  display: grid;
  align-content: center;
  gap: 14px;
}

.vb-storage-fifteen-content section span {
  display: inline-flex;
  justify-self: start;
  padding: 8px 11px;
  border-radius: 999px;
  background: #cffafe;
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-storage-fifteen-content section h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-storage-fifteen-content section p {
  max-width: 640px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 17px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-storage-fifteen-reset {
  min-height: 42px;
  margin-top: 16px;
  padding: 0 14px;
  border: 0;
  border-radius: 999px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

@media (max-width: 860px) {
  .vb-storage-fifteen-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-storage-fifteen-head h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }

  .vb-storage-fifteen-reset {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This continue reading localStorage example is useful for long blog posts, documentation pages, online lessons, tutorials, course platforms, knowledge bases, and step-by-step educational content.</p>



<h2 class="wp-block-heading">16. Accordion Open State Saved with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>Saving accordion open state with localStorage</strong> is useful for FAQ sections, product detail panels, support centers, documentation pages, settings panels, and course lessons. When a visitor opens a panel and refreshes the page, the same accordion item can stay open.</p>



<p class="wp-block-paragraph">This example saves the currently open accordion item in localStorage. JavaScript updates the active panel when a button is clicked, stores the selected panel key, and restores the same open panel after refresh.</p>



<ul class="wp-block-list">
<li>Save active accordion panel</li>
<li>Restores open FAQ item after refresh</li>
<li>Useful for FAQ and product detail sections</li>
<li>Uses one localStorage key</li>
<li>Simple UI state pattern</li>
</ul>



<div class="vb-storage-sixteen-demo">
  <div class="vb-storage-sixteen-faq" data-vb-storage-sixteen>
    <div class="vb-storage-sixteen-head">
      <span class="vb-storage-sixteen-kicker">Example 16</span>
      <h3>Saved Accordion State</h3>
      <p>Open an FAQ item and refresh the page. localStorage restores the same open accordion panel.</p>
    </div>

    <div class="vb-storage-sixteen-list">
      <div class="vb-storage-sixteen-item is-active" data-accordion-item="shipping">
        <button type="button" data-accordion-button="shipping">
          <span>How does shipping work?</span>
          <strong>+</strong>
        </button>
        <div class="vb-storage-sixteen-panel">
          <p>Shipping options can be displayed here. This panel stays open after refresh because the active accordion key is saved in localStorage.</p>
        </div>
      </div>

      <div class="vb-storage-sixteen-item" data-accordion-item="payment">
        <button type="button" data-accordion-button="payment">
          <span>Which payment methods are available?</span>
          <strong>+</strong>
        </button>
        <div class="vb-storage-sixteen-panel">
          <p>You can use this panel for payment details, invoice options, card payments, bank links, or custom ecommerce checkout information.</p>
        </div>
      </div>

      <div class="vb-storage-sixteen-item" data-accordion-item="support">
        <button type="button" data-accordion-button="support">
          <span>Do you offer support?</span>
          <strong>+</strong>
        </button>
        <div class="vb-storage-sixteen-panel">
          <p>This panel can include support information, response times, help center links, documentation, or contact details.</p>
        </div>
      </div>

      <div class="vb-storage-sixteen-item" data-accordion-item="custom">
        <button type="button" data-accordion-button="custom">
          <span>Can this be customized?</span>
          <strong>+</strong>
        </button>
        <div class="vb-storage-sixteen-panel">
          <p>Yes. The same localStorage logic can be used for product accordions, settings panels, documentation sections, and FAQ blocks.</p>
        </div>
      </div>
    </div>

    <div class="vb-storage-sixteen-status">
      Saved open panel: <strong data-saved-panel>shipping</strong>
      <button type="button" data-reset-accordion>Reset</button>
    </div>
  </div>
</div>

<style>
.vb-storage-sixteen-demo,
.vb-storage-sixteen-demo * {
  box-sizing: border-box;
}

.vb-storage-sixteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(59, 130, 246, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(16, 185, 129, 0.15), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 56%, #ffffff 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.18);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-storage-sixteen-faq {
  max-width: 960px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-sixteen-head {
  display: grid;
  gap: 12px;
  margin-bottom: 24px;
}

.vb-storage-sixteen-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-sixteen-head h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-sixteen-head p {
  max-width: 760px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-sixteen-list {
  display: grid;
  gap: 12px;
}

.vb-storage-sixteen-item {
  overflow: hidden;
  border: 1px solid rgba(148, 163, 184, 0.24);
  border-radius: 22px;
  background: #f8fafc;
  transition: border-color 0.22s ease, box-shadow 0.22s ease;
}

.vb-storage-sixteen-item.is-active {
  border-color: rgba(37, 99, 235, 0.55);
  box-shadow: 0 16px 40px rgba(37, 99, 235, 0.10);
}

.vb-storage-sixteen-item button {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  width: 100%;
  min-height: 64px;
  padding: 18px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-storage-sixteen-item button span {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
}

.vb-storage-sixteen-item button strong {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 20px;
  line-height: 1;
  font-weight: 950;
}

.vb-storage-sixteen-item.is-active button strong {
  background: linear-gradient(135deg, #2563eb, #10b981);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transform: rotate(45deg);
}

.vb-storage-sixteen-panel {
  display: none;
  padding: 0 18px 18px;
}

.vb-storage-sixteen-item.is-active .vb-storage-sixteen-panel {
  display: block;
}

.vb-storage-sixteen-panel p {
  margin: 0 !important;
  padding: 16px;
  border-radius: 18px;
  background: #ffffff;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-sixteen-status {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-top: 16px;
  padding: 14px 16px;
  border-radius: 20px;
  background: #eff6ff;
  color: #1e3a8a !important;
  -webkit-text-fill-color: #1e3a8a !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-storage-sixteen-status strong {
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
}

.vb-storage-sixteen-status button {
  min-height: 38px;
  padding: 0 13px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

@media (max-width: 560px) {
  .vb-storage-sixteen-head h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }

  .vb-storage-sixteen-status button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-sixteen]");
  if (!wrapper) return;

  const storageKey = "vbStorageSixteenAccordion";
  const items = wrapper.querySelectorAll("[data-accordion-item]");
  const buttons = wrapper.querySelectorAll("[data-accordion-button]");
  const savedPanelLabel = wrapper.querySelector("[data-saved-panel]");
  const resetButton = wrapper.querySelector("[data-reset-accordion]");

  function openPanel(panelKey) {
    items.forEach(function (item) {
      item.classList.toggle("is-active", item.getAttribute("data-accordion-item") === panelKey);
    });

    savedPanelLabel.textContent = panelKey;
    localStorage.setItem(storageKey, panelKey);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      openPanel(button.getAttribute("data-accordion-button"));
    });
  });

  resetButton.addEventListener("click", function () {
    localStorage.removeItem(storageKey);
    openPanel("shipping");
  });

  openPanel(localStorage.getItem(storageKey) || "shipping");
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-sixteen]");
  if (!wrapper) return;

  const storageKey = "vbStorageSixteenAccordion";
  const items = wrapper.querySelectorAll("[data-accordion-item]");
  const buttons = wrapper.querySelectorAll("[data-accordion-button]");
  const savedPanelLabel = wrapper.querySelector("[data-saved-panel]");
  const resetButton = wrapper.querySelector("[data-reset-accordion]");

  function openPanel(panelKey) {
    items.forEach(function (item) {
      item.classList.toggle("is-active", item.getAttribute("data-accordion-item") === panelKey);
    });

    savedPanelLabel.textContent = panelKey;
    localStorage.setItem(storageKey, panelKey);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      openPanel(button.getAttribute("data-accordion-button"));
    });
  });

  resetButton.addEventListener("click", function () {
    localStorage.removeItem(storageKey);
    openPanel("shipping");
  });

  openPanel(localStorage.getItem(storageKey) || "shipping");
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-sixteen-demo"&gt;
  &lt;div class="vb-storage-sixteen-faq" data-vb-storage-sixteen&gt;
    &lt;div class="vb-storage-sixteen-head"&gt;
      &lt;span class="vb-storage-sixteen-kicker"&gt;Example 16&lt;/span&gt;
      &lt;h3&gt;Saved Accordion State&lt;/h3&gt;
      &lt;p&gt;Open an FAQ item and refresh the page. localStorage restores the same open accordion panel.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-sixteen-list"&gt;
      &lt;div class="vb-storage-sixteen-item is-active" data-accordion-item="shipping"&gt;
        &lt;button type="button" data-accordion-button="shipping"&gt;
          &lt;span&gt;How does shipping work?&lt;/span&gt;
          &lt;strong&gt;+&lt;/strong&gt;
        &lt;/button&gt;
        &lt;div class="vb-storage-sixteen-panel"&gt;
          &lt;p&gt;Shipping options can be displayed here. This panel stays open after refresh because the active accordion key is saved in localStorage.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-sixteen-item" data-accordion-item="payment"&gt;
        &lt;button type="button" data-accordion-button="payment"&gt;
          &lt;span&gt;Which payment methods are available?&lt;/span&gt;
          &lt;strong&gt;+&lt;/strong&gt;
        &lt;/button&gt;
        &lt;div class="vb-storage-sixteen-panel"&gt;
          &lt;p&gt;You can use this panel for payment details, invoice options, card payments, bank links, or custom ecommerce checkout information.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-sixteen-item" data-accordion-item="support"&gt;
        &lt;button type="button" data-accordion-button="support"&gt;
          &lt;span&gt;Do you offer support?&lt;/span&gt;
          &lt;strong&gt;+&lt;/strong&gt;
        &lt;/button&gt;
        &lt;div class="vb-storage-sixteen-panel"&gt;
          &lt;p&gt;This panel can include support information, response times, help center links, documentation, or contact details.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-sixteen-item" data-accordion-item="custom"&gt;
        &lt;button type="button" data-accordion-button="custom"&gt;
          &lt;span&gt;Can this be customized?&lt;/span&gt;
          &lt;strong&gt;+&lt;/strong&gt;
        &lt;/button&gt;
        &lt;div class="vb-storage-sixteen-panel"&gt;
          &lt;p&gt;Yes. The same localStorage logic can be used for product accordions, settings panels, documentation sections, and FAQ blocks.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-sixteen-status"&gt;
      Saved open panel: &lt;strong data-saved-panel&gt;shipping&lt;/strong&gt;
      &lt;button type="button" data-reset-accordion&gt;Reset&lt;/button&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-sixteen-demo,
.vb-storage-sixteen-demo * {
  box-sizing: border-box;
}

.vb-storage-sixteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(59, 130, 246, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(16, 185, 129, 0.15), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 56%, #ffffff 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.18);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-storage-sixteen-faq {
  max-width: 960px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-sixteen-head {
  display: grid;
  gap: 12px;
  margin-bottom: 24px;
}

.vb-storage-sixteen-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-sixteen-head h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-sixteen-head p {
  max-width: 760px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-sixteen-list {
  display: grid;
  gap: 12px;
}

.vb-storage-sixteen-item {
  overflow: hidden;
  border: 1px solid rgba(148, 163, 184, 0.24);
  border-radius: 22px;
  background: #f8fafc;
  transition: border-color 0.22s ease, box-shadow 0.22s ease;
}

.vb-storage-sixteen-item.is-active {
  border-color: rgba(37, 99, 235, 0.55);
  box-shadow: 0 16px 40px rgba(37, 99, 235, 0.10);
}

.vb-storage-sixteen-item button {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  width: 100%;
  min-height: 64px;
  padding: 18px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-storage-sixteen-item button span {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
}

.vb-storage-sixteen-item button strong {
  display: grid;
  place-items: center;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 20px;
  line-height: 1;
  font-weight: 950;
}

.vb-storage-sixteen-item.is-active button strong {
  background: linear-gradient(135deg, #2563eb, #10b981);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transform: rotate(45deg);
}

.vb-storage-sixteen-panel {
  display: none;
  padding: 0 18px 18px;
}

.vb-storage-sixteen-item.is-active .vb-storage-sixteen-panel {
  display: block;
}

.vb-storage-sixteen-panel p {
  margin: 0 !important;
  padding: 16px;
  border-radius: 18px;
  background: #ffffff;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-sixteen-status {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  margin-top: 16px;
  padding: 14px 16px;
  border-radius: 20px;
  background: #eff6ff;
  color: #1e3a8a !important;
  -webkit-text-fill-color: #1e3a8a !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-storage-sixteen-status strong {
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
}

.vb-storage-sixteen-status button {
  min-height: 38px;
  padding: 0 13px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

@media (max-width: 560px) {
  .vb-storage-sixteen-head h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }

  .vb-storage-sixteen-status button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This saved accordion state localStorage example is useful for FAQ sections, product information panels, checkout help blocks, documentation pages, support center categories, and dashboard settings panels.</p>



<h2 class="wp-block-heading">17. User Preferences Saved with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>Saving user preferences with localStorage</strong> is useful for dashboards, admin panels, SaaS apps, documentation websites, blog layouts, accessibility widgets, and custom website settings. It lets visitors keep interface choices such as font size, layout density, and accent style.</p>



<p class="wp-block-paragraph">This example saves three interface preferences: text size, layout density, and accent color. JavaScript stores the settings object in localStorage, applies the choices instantly, and restores the same preferences after refresh.</p>



<ul class="wp-block-list">
<li>Save multiple user preferences</li>
<li>Stores settings as a JSON object</li>
<li>Restores font size, density, and accent</li>
<li>Useful for dashboards and accessibility panels</li>
<li>Includes reset settings button</li>
</ul>



<div class="vb-storage-seventeen-demo">
  <div class="vb-storage-seventeen-app" data-vb-storage-seventeen data-size="medium" data-density="comfortable" data-accent="blue">
    <aside class="vb-storage-seventeen-settings">
      <span class="vb-storage-seventeen-kicker">Example 17</span>
      <h3>Saved User Preferences</h3>
      <p>Change the settings and refresh the page. localStorage restores your preferred interface style.</p>

      <label>
        <span>Text size</span>
        <select data-preference="size">
          <option value="small">Small</option>
          <option value="medium">Medium</option>
          <option value="large">Large</option>
        </select>
      </label>

      <label>
        <span>Layout density</span>
        <select data-preference="density">
          <option value="compact">Compact</option>
          <option value="comfortable">Comfortable</option>
          <option value="spacious">Spacious</option>
        </select>
      </label>

      <label>
        <span>Accent color</span>
        <select data-preference="accent">
          <option value="blue">Blue</option>
          <option value="green">Green</option>
          <option value="purple">Purple</option>
        </select>
      </label>

      <button type="button" data-reset-preferences>Reset Preferences</button>
    </aside>

    <section class="vb-storage-seventeen-preview">
      <div class="vb-storage-seventeen-preview-top">
        <span>Dashboard Preview</span>
        <strong data-preference-summary>medium · comfortable · blue</strong>
      </div>

      <div class="vb-storage-seventeen-card">
        <h4>Saved Interface Settings</h4>
        <p>This preview changes based on your saved localStorage preferences. It can be used for dashboard settings, accessibility controls, user accounts, or blog reading options.</p>
      </div>

      <div class="vb-storage-seventeen-grid">
        <div>
          <span>Preference</span>
          <strong>Text size</strong>
        </div>
        <div>
          <span>Preference</span>
          <strong>Density</strong>
        </div>
        <div>
          <span>Preference</span>
          <strong>Accent</strong>
        </div>
      </div>
    </section>
  </div>
</div>

<style>
.vb-storage-seventeen-demo,
.vb-storage-seventeen-demo * {
  box-sizing: border-box;
}

.vb-storage-seventeen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(37, 99, 235, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(168, 85, 247, 0.14), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #faf5ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.18);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-storage-seventeen-app {
  display: grid;
  grid-template-columns: minmax(280px, 360px) minmax(0, 1fr);
  gap: 22px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-seventeen-settings,
.vb-storage-seventeen-preview {
  min-width: 0;
}

.vb-storage-seventeen-settings {
  display: grid;
  align-content: start;
  gap: 13px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 28px;
  background: #0f172a;
}

.vb-storage-seventeen-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(96, 165, 250, 0.18);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-seventeen-settings h3 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 58px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-storage-seventeen-settings p {
  margin: 0 0 8px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-storage-seventeen-settings label {
  display: grid;
  gap: 7px;
}

.vb-storage-seventeen-settings label span {
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-storage-seventeen-settings select {
  width: 100%;
  min-height: 46px;
  padding: 0 13px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 15px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 750;
  outline: none;
}

.vb-storage-seventeen-settings button {
  min-height: 44px;
  margin-top: 4px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-seventeen-preview {
  display: grid;
  gap: 16px;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 28px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-seventeen-preview-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}

.vb-storage-seventeen-preview-top span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-storage-seventeen-preview-top strong {
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-seventeen-card {
  padding: clamp(20px, 4vw, 34px);
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.08);
}

.vb-storage-seventeen-card h4 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 34px !important;
  line-height: 1.05 !important;
  font-weight: 950 !important;
  letter-spacing: -0.055em;
}

.vb-storage-seventeen-card p {
  max-width: 650px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-seventeen-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-storage-seventeen-grid div {
  padding: 16px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-seventeen-grid span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-storage-seventeen-grid strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-storage-seventeen-app[data-size="small"] .vb-storage-seventeen-card p {
  font-size: 14px;
}

.vb-storage-seventeen-app[data-size="medium"] .vb-storage-seventeen-card p {
  font-size: 16px;
}

.vb-storage-seventeen-app[data-size="large"] .vb-storage-seventeen-card p {
  font-size: 19px;
}

.vb-storage-seventeen-app[data-density="compact"] .vb-storage-seventeen-card,
.vb-storage-seventeen-app[data-density="compact"] .vb-storage-seventeen-grid div {
  padding: 14px;
}

.vb-storage-seventeen-app[data-density="comfortable"] .vb-storage-seventeen-card {
  padding: 28px;
}

.vb-storage-seventeen-app[data-density="spacious"] .vb-storage-seventeen-card,
.vb-storage-seventeen-app[data-density="spacious"] .vb-storage-seventeen-grid div {
  padding: 34px;
}

.vb-storage-seventeen-app[data-accent="blue"] .vb-storage-seventeen-preview-top strong,
.vb-storage-seventeen-app[data-accent="blue"] .vb-storage-seventeen-grid strong {
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
}

.vb-storage-seventeen-app[data-accent="green"] .vb-storage-seventeen-preview-top strong,
.vb-storage-seventeen-app[data-accent="green"] .vb-storage-seventeen-grid strong {
  color: #059669 !important;
  -webkit-text-fill-color: #059669 !important;
}

.vb-storage-seventeen-app[data-accent="purple"] .vb-storage-seventeen-preview-top strong,
.vb-storage-seventeen-app[data-accent="purple"] .vb-storage-seventeen-grid strong {
  color: #7c3aed !important;
  -webkit-text-fill-color: #7c3aed !important;
}

@media (max-width: 920px) {
  .vb-storage-seventeen-app {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-storage-seventeen-grid {
    grid-template-columns: 1fr;
  }

  .vb-storage-seventeen-settings h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-seventeen]");
  if (!wrapper) return;

  const storageKey = "vbStorageSeventeenPreferences";
  const selects = wrapper.querySelectorAll("[data-preference]");
  const resetButton = wrapper.querySelector("[data-reset-preferences]");
  const summary = wrapper.querySelector("[data-preference-summary]");

  const defaultPreferences = {
    size: "medium",
    density: "comfortable",
    accent: "blue"
  };

  let preferences = Object.assign({}, defaultPreferences);

  function savePreferences() {
    localStorage.setItem(storageKey, JSON.stringify(preferences));
  }

  function loadPreferences() {
    const savedPreferences = localStorage.getItem(storageKey);
    if (!savedPreferences) return;

    try {
      const parsedPreferences = JSON.parse(savedPreferences);
      preferences = Object.assign({}, defaultPreferences, parsedPreferences);
    } catch (error) {
      preferences = Object.assign({}, defaultPreferences);
      localStorage.removeItem(storageKey);
    }
  }

  function applyPreferences() {
    wrapper.setAttribute("data-size", preferences.size);
    wrapper.setAttribute("data-density", preferences.density);
    wrapper.setAttribute("data-accent", preferences.accent);

    selects.forEach(function (select) {
      const key = select.getAttribute("data-preference");
      select.value = preferences[key];
    });

    summary.textContent = preferences.size + " · " + preferences.density + " · " + preferences.accent;
    savePreferences();
  }

  selects.forEach(function (select) {
    select.addEventListener("change", function () {
      const key = select.getAttribute("data-preference");
      preferences[key] = select.value;
      applyPreferences();
    });
  });

  resetButton.addEventListener("click", function () {
    preferences = Object.assign({}, defaultPreferences);
    localStorage.removeItem(storageKey);
    applyPreferences();
  });

  loadPreferences();
  applyPreferences();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-seventeen]");
  if (!wrapper) return;

  const storageKey = "vbStorageSeventeenPreferences";
  const selects = wrapper.querySelectorAll("[data-preference]");
  const resetButton = wrapper.querySelector("[data-reset-preferences]");
  const summary = wrapper.querySelector("[data-preference-summary]");

  const defaultPreferences = {
    size: "medium",
    density: "comfortable",
    accent: "blue"
  };

  let preferences = Object.assign({}, defaultPreferences);

  function savePreferences() {
    localStorage.setItem(storageKey, JSON.stringify(preferences));
  }

  function loadPreferences() {
    const savedPreferences = localStorage.getItem(storageKey);
    if (!savedPreferences) return;

    try {
      const parsedPreferences = JSON.parse(savedPreferences);
      preferences = Object.assign({}, defaultPreferences, parsedPreferences);
    } catch (error) {
      preferences = Object.assign({}, defaultPreferences);
      localStorage.removeItem(storageKey);
    }
  }

  function applyPreferences() {
    wrapper.setAttribute("data-size", preferences.size);
    wrapper.setAttribute("data-density", preferences.density);
    wrapper.setAttribute("data-accent", preferences.accent);

    selects.forEach(function (select) {
      const key = select.getAttribute("data-preference");
      select.value = preferences[key];
    });

    summary.textContent = preferences.size + " · " + preferences.density + " · " + preferences.accent;
    savePreferences();
  }

  selects.forEach(function (select) {
    select.addEventListener("change", function () {
      const key = select.getAttribute("data-preference");
      preferences[key] = select.value;
      applyPreferences();
    });
  });

  resetButton.addEventListener("click", function () {
    preferences = Object.assign({}, defaultPreferences);
    localStorage.removeItem(storageKey);
    applyPreferences();
  });

  loadPreferences();
  applyPreferences();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-seventeen-demo"&gt;
  &lt;div class="vb-storage-seventeen-app" data-vb-storage-seventeen data-size="medium" data-density="comfortable" data-accent="blue"&gt;
    &lt;aside class="vb-storage-seventeen-settings"&gt;
      &lt;span class="vb-storage-seventeen-kicker"&gt;Example 17&lt;/span&gt;
      &lt;h3&gt;Saved User Preferences&lt;/h3&gt;
      &lt;p&gt;Change the settings and refresh the page. localStorage restores your preferred interface style.&lt;/p&gt;

      &lt;label&gt;
        &lt;span&gt;Text size&lt;/span&gt;
        &lt;select data-preference="size"&gt;
          &lt;option value="small"&gt;Small&lt;/option&gt;
          &lt;option value="medium"&gt;Medium&lt;/option&gt;
          &lt;option value="large"&gt;Large&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;

      &lt;label&gt;
        &lt;span&gt;Layout density&lt;/span&gt;
        &lt;select data-preference="density"&gt;
          &lt;option value="compact"&gt;Compact&lt;/option&gt;
          &lt;option value="comfortable"&gt;Comfortable&lt;/option&gt;
          &lt;option value="spacious"&gt;Spacious&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;

      &lt;label&gt;
        &lt;span&gt;Accent color&lt;/span&gt;
        &lt;select data-preference="accent"&gt;
          &lt;option value="blue"&gt;Blue&lt;/option&gt;
          &lt;option value="green"&gt;Green&lt;/option&gt;
          &lt;option value="purple"&gt;Purple&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;

      &lt;button type="button" data-reset-preferences&gt;Reset Preferences&lt;/button&gt;
    &lt;/aside&gt;

    &lt;section class="vb-storage-seventeen-preview"&gt;
      &lt;div class="vb-storage-seventeen-preview-top"&gt;
        &lt;span&gt;Dashboard Preview&lt;/span&gt;
        &lt;strong data-preference-summary&gt;medium · comfortable · blue&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-seventeen-card"&gt;
        &lt;h4&gt;Saved Interface Settings&lt;/h4&gt;
        &lt;p&gt;This preview changes based on your saved localStorage preferences. It can be used for dashboard settings, accessibility controls, user accounts, or blog reading options.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-seventeen-grid"&gt;
        &lt;div&gt;
          &lt;span&gt;Preference&lt;/span&gt;
          &lt;strong&gt;Text size&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Preference&lt;/span&gt;
          &lt;strong&gt;Density&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Preference&lt;/span&gt;
          &lt;strong&gt;Accent&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/section&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-seventeen-demo,
.vb-storage-seventeen-demo * {
  box-sizing: border-box;
}

.vb-storage-seventeen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(37, 99, 235, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(168, 85, 247, 0.14), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #faf5ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.18);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-storage-seventeen-app {
  display: grid;
  grid-template-columns: minmax(280px, 360px) minmax(0, 1fr);
  gap: 22px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-seventeen-settings,
.vb-storage-seventeen-preview {
  min-width: 0;
}

.vb-storage-seventeen-settings {
  display: grid;
  align-content: start;
  gap: 13px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 28px;
  background: #0f172a;
}

.vb-storage-seventeen-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(96, 165, 250, 0.18);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-seventeen-settings h3 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 58px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-storage-seventeen-settings p {
  margin: 0 0 8px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-storage-seventeen-settings label {
  display: grid;
  gap: 7px;
}

.vb-storage-seventeen-settings label span {
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-storage-seventeen-settings select {
  width: 100%;
  min-height: 46px;
  padding: 0 13px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 15px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 750;
  outline: none;
}

.vb-storage-seventeen-settings button {
  min-height: 44px;
  margin-top: 4px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-seventeen-preview {
  display: grid;
  gap: 16px;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 28px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-seventeen-preview-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}

.vb-storage-seventeen-preview-top span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-storage-seventeen-preview-top strong {
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-seventeen-card {
  padding: clamp(20px, 4vw, 34px);
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.08);
}

.vb-storage-seventeen-card h4 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 34px !important;
  line-height: 1.05 !important;
  font-weight: 950 !important;
  letter-spacing: -0.055em;
}

.vb-storage-seventeen-card p {
  max-width: 650px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-seventeen-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-storage-seventeen-grid div {
  padding: 16px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-seventeen-grid span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-storage-seventeen-grid strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-storage-seventeen-app[data-size="small"] .vb-storage-seventeen-card p {
  font-size: 14px;
}

.vb-storage-seventeen-app[data-size="medium"] .vb-storage-seventeen-card p {
  font-size: 16px;
}

.vb-storage-seventeen-app[data-size="large"] .vb-storage-seventeen-card p {
  font-size: 19px;
}

.vb-storage-seventeen-app[data-density="compact"] .vb-storage-seventeen-card,
.vb-storage-seventeen-app[data-density="compact"] .vb-storage-seventeen-grid div {
  padding: 14px;
}

.vb-storage-seventeen-app[data-density="comfortable"] .vb-storage-seventeen-card {
  padding: 28px;
}

.vb-storage-seventeen-app[data-density="spacious"] .vb-storage-seventeen-card,
.vb-storage-seventeen-app[data-density="spacious"] .vb-storage-seventeen-grid div {
  padding: 34px;
}

.vb-storage-seventeen-app[data-accent="blue"] .vb-storage-seventeen-preview-top strong,
.vb-storage-seventeen-app[data-accent="blue"] .vb-storage-seventeen-grid strong {
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
}

.vb-storage-seventeen-app[data-accent="green"] .vb-storage-seventeen-preview-top strong,
.vb-storage-seventeen-app[data-accent="green"] .vb-storage-seventeen-grid strong {
  color: #059669 !important;
  -webkit-text-fill-color: #059669 !important;
}

.vb-storage-seventeen-app[data-accent="purple"] .vb-storage-seventeen-preview-top strong,
.vb-storage-seventeen-app[data-accent="purple"] .vb-storage-seventeen-grid strong {
  color: #7c3aed !important;
  -webkit-text-fill-color: #7c3aed !important;
}

@media (max-width: 920px) {
  .vb-storage-seventeen-app {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-storage-seventeen-grid {
    grid-template-columns: 1fr;
  }

  .vb-storage-seventeen-settings h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}</pre>



<p class="wp-block-paragraph">This user preferences localStorage example is useful for dashboards, admin panels, user account settings, accessibility widgets, SaaS interfaces, documentation pages, and blog reading preference controls.</p>



<h2 class="wp-block-heading">18. Discount Code Saved with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>Saving a discount code with localStorage</strong> is useful for ecommerce landing pages, product checkout demos, pricing sections, cart pages, coupon banners, and sales campaigns. It lets a visitor apply a coupon and keep that discount visible after refreshing the page.</p>



<p class="wp-block-paragraph">This example applies a discount code to a simple order summary. JavaScript saves the applied coupon in localStorage, recalculates the total, shows discount feedback, and restores the coupon after refresh.</p>



<ul class="wp-block-list">
<li>Save applied discount code</li>
<li>Restores coupon after refresh</li>
<li>Calculates discounted total</li>
<li>Includes remove coupon button</li>
<li>Useful for ecommerce and checkout pages</li>
</ul>



<div class="vb-storage-eighteen-demo">
  <div class="vb-storage-eighteen-checkout" data-vb-storage-eighteen>
    <div class="vb-storage-eighteen-info">
      <span class="vb-storage-eighteen-kicker">Example 18</span>
      <h3>Saved Discount Code</h3>
      <p>Apply the code <strong>SAVE20</strong>, refresh the page, and localStorage keeps the discount active.</p>

      <form class="vb-storage-eighteen-form" data-coupon-form>
        <input type="text" data-coupon-input placeholder="Enter coupon code">
        <button type="submit">Apply Code</button>
      </form>

      <div class="vb-storage-eighteen-message" data-coupon-message>
        Coupon status: no code applied.
      </div>
    </div>

    <div class="vb-storage-eighteen-summary">
      <div class="vb-storage-eighteen-summary-head">
        <strong>Order Summary</strong>
        <span data-coupon-badge>No coupon</span>
      </div>

      <div class="vb-storage-eighteen-line">
        <span>Website template</span>
        <strong>120€</strong>
      </div>

      <div class="vb-storage-eighteen-line">
        <span>Setup service</span>
        <strong>80€</strong>
      </div>

      <div class="vb-storage-eighteen-line vb-storage-eighteen-discount">
        <span>Discount</span>
        <strong data-discount-value>0€</strong>
      </div>

      <div class="vb-storage-eighteen-total">
        <span>Total</span>
        <strong data-order-total>200€</strong>
      </div>

      <button type="button" data-remove-coupon>Remove Saved Coupon</button>
    </div>
  </div>
</div>

<style>
.vb-storage-eighteen-demo,
.vb-storage-eighteen-demo * {
  box-sizing: border-box;
}

.vb-storage-eighteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(16, 185, 129, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(245, 158, 11, 0.16), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #fffbeb 56%, #ffffff 100%) !important;
  border: 1px solid rgba(16, 185, 129, 0.18);
  box-shadow: 0 28px 80px rgba(6, 95, 70, 0.10);
}

.vb-storage-eighteen-checkout {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(320px, 420px);
  gap: 22px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-eighteen-info,
.vb-storage-eighteen-summary {
  min-width: 0;
}

.vb-storage-eighteen-info {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 28px;
  background: #0f172a;
}

.vb-storage-eighteen-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(16, 185, 129, 0.16);
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-eighteen-info h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-eighteen-info p {
  max-width: 560px;
  margin: 0 0 22px !important;
  color: #d1d5db !important;
  -webkit-text-fill-color: #d1d5db !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-eighteen-info p strong {
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
}

.vb-storage-eighteen-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  margin-bottom: 14px;
}

.vb-storage-eighteen-form input {
  min-width: 0;
  min-height: 50px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 750;
  outline: none;
}

.vb-storage-eighteen-form input::placeholder {
  color: #9ca3af;
  -webkit-text-fill-color: #9ca3af;
}

.vb-storage-eighteen-form input:focus {
  border-color: rgba(16, 185, 129, 0.70);
  box-shadow: 0 0 0 4px rgba(16, 185, 129, 0.12);
}

.vb-storage-eighteen-form button {
  min-height: 50px;
  padding: 0 16px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #10b981, #f59e0b);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-eighteen-message {
  padding: 13px 15px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-storage-eighteen-summary {
  display: grid;
  gap: 14px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 30px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-eighteen-summary-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.vb-storage-eighteen-summary-head strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-storage-eighteen-summary-head span {
  padding: 7px 10px;
  border-radius: 999px;
  background: #e5e7eb;
  color: #374151 !important;
  -webkit-text-fill-color: #374151 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-storage-eighteen-summary-head span.is-active {
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
}

.vb-storage-eighteen-line,
.vb-storage-eighteen-total {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 14px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.18);
}

.vb-storage-eighteen-line span,
.vb-storage-eighteen-line strong {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-storage-eighteen-discount span,
.vb-storage-eighteen-discount strong {
  color: #059669 !important;
  -webkit-text-fill-color: #059669 !important;
}

.vb-storage-eighteen-total {
  background: #0f172a;
}

.vb-storage-eighteen-total span {
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-storage-eighteen-total strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px;
  line-height: 1;
  font-weight: 950;
}

.vb-storage-eighteen-summary > button {
  min-height: 44px;
  border: 0;
  border-radius: 999px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

@media (max-width: 900px) {
  .vb-storage-eighteen-checkout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-storage-eighteen-form {
    grid-template-columns: 1fr;
  }

  .vb-storage-eighteen-info h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-eighteen]");
  if (!wrapper) return;

  const storageKey = "vbStorageEighteenCoupon";
  const form = wrapper.querySelector("[data-coupon-form]");
  const input = wrapper.querySelector("[data-coupon-input]");
  const message = wrapper.querySelector("[data-coupon-message]");
  const badge = wrapper.querySelector("[data-coupon-badge]");
  const discountValue = wrapper.querySelector("[data-discount-value]");
  const orderTotal = wrapper.querySelector("[data-order-total]");
  const removeButton = wrapper.querySelector("[data-remove-coupon]");

  const baseTotal = 200;
  const validCoupon = "SAVE20";
  const discountPercent = 20;

  function applyCoupon(code) {
    const normalizedCode = (code || "").trim().toUpperCase();
    const isValid = normalizedCode === validCoupon;
    const discount = isValid ? Math.round(baseTotal * discountPercent / 100) : 0;
    const total = baseTotal - discount;

    input.value = normalizedCode;
    discountValue.textContent = "-" + discount + "€";
    orderTotal.textContent = total + "€";

    if (isValid) {
      localStorage.setItem(storageKey, normalizedCode);
      message.textContent = "Coupon status: SAVE20 applied and saved in localStorage.";
      badge.textContent = "SAVE20 active";
      badge.classList.add("is-active");
    } else {
      localStorage.removeItem(storageKey);
      message.textContent = normalizedCode ? "Coupon status: invalid code." : "Coupon status: no code applied.";
      badge.textContent = "No coupon";
      badge.classList.remove("is-active");
    }
  }

  form.addEventListener("submit", function (event) {
    event.preventDefault();
    applyCoupon(input.value);
  });

  removeButton.addEventListener("click", function () {
    localStorage.removeItem(storageKey);
    input.value = "";
    applyCoupon("");
  });

  applyCoupon(localStorage.getItem(storageKey) || "");
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-eighteen]");
  if (!wrapper) return;

  const storageKey = "vbStorageEighteenCoupon";
  const form = wrapper.querySelector("[data-coupon-form]");
  const input = wrapper.querySelector("[data-coupon-input]");
  const message = wrapper.querySelector("[data-coupon-message]");
  const badge = wrapper.querySelector("[data-coupon-badge]");
  const discountValue = wrapper.querySelector("[data-discount-value]");
  const orderTotal = wrapper.querySelector("[data-order-total]");
  const removeButton = wrapper.querySelector("[data-remove-coupon]");

  const baseTotal = 200;
  const validCoupon = "SAVE20";
  const discountPercent = 20;

  function applyCoupon(code) {
    const normalizedCode = (code || "").trim().toUpperCase();
    const isValid = normalizedCode === validCoupon;
    const discount = isValid ? Math.round(baseTotal * discountPercent / 100) : 0;
    const total = baseTotal - discount;

    input.value = normalizedCode;
    discountValue.textContent = "-" + discount + "€";
    orderTotal.textContent = total + "€";

    if (isValid) {
      localStorage.setItem(storageKey, normalizedCode);
      message.textContent = "Coupon status: SAVE20 applied and saved in localStorage.";
      badge.textContent = "SAVE20 active";
      badge.classList.add("is-active");
    } else {
      localStorage.removeItem(storageKey);
      message.textContent = normalizedCode ? "Coupon status: invalid code." : "Coupon status: no code applied.";
      badge.textContent = "No coupon";
      badge.classList.remove("is-active");
    }
  }

  form.addEventListener("submit", function (event) {
    event.preventDefault();
    applyCoupon(input.value);
  });

  removeButton.addEventListener("click", function () {
    localStorage.removeItem(storageKey);
    input.value = "";
    applyCoupon("");
  });

  applyCoupon(localStorage.getItem(storageKey) || "");
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-eighteen-demo"&gt;
  &lt;div class="vb-storage-eighteen-checkout" data-vb-storage-eighteen&gt;
    &lt;div class="vb-storage-eighteen-info"&gt;
      &lt;span class="vb-storage-eighteen-kicker"&gt;Example 18&lt;/span&gt;
      &lt;h3&gt;Saved Discount Code&lt;/h3&gt;
      &lt;p&gt;Apply the code &lt;strong&gt;SAVE20&lt;/strong&gt;, refresh the page, and localStorage keeps the discount active.&lt;/p&gt;

      &lt;form class="vb-storage-eighteen-form" data-coupon-form&gt;
        &lt;input type="text" data-coupon-input placeholder="Enter coupon code"&gt;
        &lt;button type="submit"&gt;Apply Code&lt;/button&gt;
      &lt;/form&gt;

      &lt;div class="vb-storage-eighteen-message" data-coupon-message&gt;
        Coupon status: no code applied.
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-eighteen-summary"&gt;
      &lt;div class="vb-storage-eighteen-summary-head"&gt;
        &lt;strong&gt;Order Summary&lt;/strong&gt;
        &lt;span data-coupon-badge&gt;No coupon&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-eighteen-line"&gt;
        &lt;span&gt;Website template&lt;/span&gt;
        &lt;strong&gt;120€&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-eighteen-line"&gt;
        &lt;span&gt;Setup service&lt;/span&gt;
        &lt;strong&gt;80€&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-eighteen-line vb-storage-eighteen-discount"&gt;
        &lt;span&gt;Discount&lt;/span&gt;
        &lt;strong data-discount-value&gt;0€&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-eighteen-total"&gt;
        &lt;span&gt;Total&lt;/span&gt;
        &lt;strong data-order-total&gt;200€&lt;/strong&gt;
      &lt;/div&gt;

      &lt;button type="button" data-remove-coupon&gt;Remove Saved Coupon&lt;/button&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-eighteen-demo,
.vb-storage-eighteen-demo * {
  box-sizing: border-box;
}

.vb-storage-eighteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(16, 185, 129, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(245, 158, 11, 0.16), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #fffbeb 56%, #ffffff 100%) !important;
  border: 1px solid rgba(16, 185, 129, 0.18);
  box-shadow: 0 28px 80px rgba(6, 95, 70, 0.10);
}

.vb-storage-eighteen-checkout {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(320px, 420px);
  gap: 22px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-eighteen-info,
.vb-storage-eighteen-summary {
  min-width: 0;
}

.vb-storage-eighteen-info {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 28px;
  background: #0f172a;
}

.vb-storage-eighteen-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(16, 185, 129, 0.16);
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-eighteen-info h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-eighteen-info p {
  max-width: 560px;
  margin: 0 0 22px !important;
  color: #d1d5db !important;
  -webkit-text-fill-color: #d1d5db !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-eighteen-info p strong {
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
}

.vb-storage-eighteen-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  margin-bottom: 14px;
}

.vb-storage-eighteen-form input {
  min-width: 0;
  min-height: 50px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 750;
  outline: none;
}

.vb-storage-eighteen-form input::placeholder {
  color: #9ca3af;
  -webkit-text-fill-color: #9ca3af;
}

.vb-storage-eighteen-form input:focus {
  border-color: rgba(16, 185, 129, 0.70);
  box-shadow: 0 0 0 4px rgba(16, 185, 129, 0.12);
}

.vb-storage-eighteen-form button {
  min-height: 50px;
  padding: 0 16px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #10b981, #f59e0b);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-eighteen-message {
  padding: 13px 15px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

.vb-storage-eighteen-summary {
  display: grid;
  gap: 14px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 30px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-eighteen-summary-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.vb-storage-eighteen-summary-head strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-storage-eighteen-summary-head span {
  padding: 7px 10px;
  border-radius: 999px;
  background: #e5e7eb;
  color: #374151 !important;
  -webkit-text-fill-color: #374151 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-storage-eighteen-summary-head span.is-active {
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
}

.vb-storage-eighteen-line,
.vb-storage-eighteen-total {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 14px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.18);
}

.vb-storage-eighteen-line span,
.vb-storage-eighteen-line strong {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-storage-eighteen-discount span,
.vb-storage-eighteen-discount strong {
  color: #059669 !important;
  -webkit-text-fill-color: #059669 !important;
}

.vb-storage-eighteen-total {
  background: #0f172a;
}

.vb-storage-eighteen-total span {
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-storage-eighteen-total strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px;
  line-height: 1;
  font-weight: 950;
}

.vb-storage-eighteen-summary > button {
  min-height: 44px;
  border: 0;
  border-radius: 999px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

@media (max-width: 900px) {
  .vb-storage-eighteen-checkout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-storage-eighteen-form {
    grid-template-columns: 1fr;
  }

  .vb-storage-eighteen-info h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}</pre>



<p class="wp-block-paragraph">This discount code localStorage example is useful for ecommerce checkout pages, coupon banners, landing page offers, pricing tables, cart demos, product sales pages, and WooCommerce-style promotional features.</p>



<div class="vb24-service-cta-box">
  <div class="vb24-service-cta-content">
    <span>Need this on your website?</span>
    <h3>Can’t build it yourself? We can create it for you.</h3>
    <p>If you like these JavaScript localStorage features but want a custom version for your website, landing page, ecommerce store, or WordPress project, contact us and tell us what you need.</p>
  </div>

  <a class="vb24-service-cta-button" href="https://veebilehed24.ee/en/contact-us/">Contact Us</a>
</div>

<style>
.vb24-service-cta-box,
.vb24-service-cta-box * {
  box-sizing: border-box;
}

.vb24-service-cta-box {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 22px;
  margin: 34px 0;
  padding: clamp(20px, 3vw, 28px);
  border: 1px solid rgba(148, 163, 184, 0.24);
  border-radius: 26px;
  background:
    radial-gradient(circle at 10% 20%, rgba(37, 99, 235, 0.10), transparent 32%),
    linear-gradient(135deg, #ffffff 0%, #f8fafc 100%) !important;
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb24-service-cta-content {
  min-width: 0;
}

.vb24-service-cta-content span {
  display: inline-flex;
  margin-bottom: 8px;
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb24-service-cta-content h3 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(22px, 3vw, 32px) !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb24-service-cta-content p {
  max-width: 760px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb24-service-cta-button {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  text-decoration: none !important;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.22);
}

.vb24-service-cta-button:hover {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transform: translateY(-2px);
}

@media (max-width: 720px) {
  .vb24-service-cta-box {
    align-items: stretch;
    flex-direction: column;
  }

  .vb24-service-cta-button {
    width: 100%;
  }
}
</style>



<h2 class="wp-block-heading">19. Remember Me Login Form with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>A remember me login form with localStorage</strong> is a very common JavaScript example for login pages, account forms, dashboard prototypes, and membership websites. In real projects, passwords should never be stored in localStorage, but saving a harmless email or username preference is a practical UI pattern.</p>



<p class="wp-block-paragraph">This example saves only the email address when the “Remember me” checkbox is enabled. JavaScript restores the email after refresh, updates the saved status, and clears the stored email when the checkbox is turned off.</p>



<ul class="wp-block-list">
<li>Remember email address</li>
<li>Does not save password</li>
<li>Restores saved email after refresh</li>
<li>Uses checkbox state with localStorage</li>
<li>Useful for login and account forms</li>
</ul>



<div class="vb-storage-nineteen-demo">
  <div class="vb-storage-nineteen-login" data-vb-storage-nineteen>
    <div class="vb-storage-nineteen-info">
      <span class="vb-storage-nineteen-kicker">Example 19</span>
      <h3>Remember Me Login</h3>
      <p>Save only the email address in localStorage. Passwords are never stored in this demo.</p>
      <div class="vb-storage-nineteen-status" data-login-status>Email not saved yet.</div>
    </div>

    <form class="vb-storage-nineteen-form" data-login-form>
      <label>
        <span>Email address</span>
        <input type="email" data-login-email placeholder="alex@example.com">
      </label>

      <label>
        <span>Password</span>
        <input type="password" data-login-password placeholder="Password is not saved">
      </label>

      <label class="vb-storage-nineteen-check">
        <input type="checkbox" data-remember-email>
        <span>Remember my email on this device</span>
      </label>

      <button type="submit">Demo Login</button>
      <button type="button" class="vb-storage-nineteen-clear" data-clear-login>Clear Saved Email</button>

      <p class="vb-storage-nineteen-note">Security note: this demo saves only the email address, never the password.</p>
    </form>
  </div>
</div>

<style>
.vb-storage-nineteen-demo,
.vb-storage-nineteen-demo * {
  box-sizing: border-box;
}

.vb-storage-nineteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(37, 99, 235, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfeff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.18);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-storage-nineteen-login {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(320px, 430px);
  gap: 22px;
  max-width: 1100px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #0f172a;
  box-shadow: 0 28px 90px rgba(15, 23, 42, 0.30);
}

.vb-storage-nineteen-info,
.vb-storage-nineteen-form {
  min-width: 0;
}

.vb-storage-nineteen-info {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(18px, 3vw, 26px);
}

.vb-storage-nineteen-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(59, 130, 246, 0.18);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-nineteen-info h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-nineteen-info p {
  max-width: 560px;
  margin: 0 0 22px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-nineteen-status {
  display: inline-flex;
  align-self: flex-start;
  padding: 13px 15px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 850;
}

.vb-storage-nineteen-form {
  display: grid;
  gap: 14px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-nineteen-form label {
  display: grid;
  gap: 7px;
}

.vb-storage-nineteen-form label > span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-storage-nineteen-form input[type="email"],
.vb-storage-nineteen-form input[type="password"] {
  width: 100%;
  min-height: 50px;
  padding: 0 15px;
  border: 1px solid rgba(148, 163, 184, 0.34);
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 700;
  outline: none;
}

.vb-storage-nineteen-form input:focus {
  border-color: rgba(37, 99, 235, 0.74);
  box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.10);
}

.vb-storage-nineteen-check {
  display: grid !important;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 10px !important;
  padding: 12px;
  border-radius: 16px;
  background: #eff6ff;
}

.vb-storage-nineteen-check input {
  width: 18px;
  height: 18px;
  accent-color: #2563eb;
}

.vb-storage-nineteen-form button {
  min-height: 48px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #0ea5e9);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-nineteen-clear {
  background: #fee2e2 !important;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-storage-nineteen-note {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-storage-nineteen-login {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-storage-nineteen-info h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-nineteen]");
  if (!wrapper) return;

  const storageKey = "vbStorageNineteenRememberEmail";
  const form = wrapper.querySelector("[data-login-form]");
  const emailInput = wrapper.querySelector("[data-login-email]");
  const passwordInput = wrapper.querySelector("[data-login-password]");
  const rememberCheckbox = wrapper.querySelector("[data-remember-email]");
  const status = wrapper.querySelector("[data-login-status]");
  const clearButton = wrapper.querySelector("[data-clear-login]");

  function updateStatus() {
    const savedEmail = localStorage.getItem(storageKey);

    if (savedEmail) {
      status.textContent = "Saved email: " + savedEmail;
      emailInput.value = savedEmail;
      rememberCheckbox.checked = true;
    } else {
      status.textContent = "Email not saved yet.";
      rememberCheckbox.checked = false;
    }
  }

  function saveEmailIfAllowed() {
    const email = emailInput.value.trim();

    if (rememberCheckbox.checked && email) {
      localStorage.setItem(storageKey, email);
    }

    if (!rememberCheckbox.checked) {
      localStorage.removeItem(storageKey);
    }

    updateStatus();
  }

  rememberCheckbox.addEventListener("change", saveEmailIfAllowed);
  emailInput.addEventListener("input", function () {
    if (rememberCheckbox.checked) {
      saveEmailIfAllowed();
    }
  });

  form.addEventListener("submit", function (event) {
    event.preventDefault();
    saveEmailIfAllowed();
    passwordInput.value = "";
    status.textContent = rememberCheckbox.checked
      ? "Demo login complete. Email preference is saved."
      : "Demo login complete. Email was not saved.";
  });

  clearButton.addEventListener("click", function () {
    localStorage.removeItem(storageKey);
    emailInput.value = "";
    passwordInput.value = "";
    updateStatus();
  });

  updateStatus();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-nineteen]");
  if (!wrapper) return;

  const storageKey = "vbStorageNineteenRememberEmail";
  const form = wrapper.querySelector("[data-login-form]");
  const emailInput = wrapper.querySelector("[data-login-email]");
  const passwordInput = wrapper.querySelector("[data-login-password]");
  const rememberCheckbox = wrapper.querySelector("[data-remember-email]");
  const status = wrapper.querySelector("[data-login-status]");
  const clearButton = wrapper.querySelector("[data-clear-login]");

  function updateStatus() {
    const savedEmail = localStorage.getItem(storageKey);

    if (savedEmail) {
      status.textContent = "Saved email: " + savedEmail;
      emailInput.value = savedEmail;
      rememberCheckbox.checked = true;
    } else {
      status.textContent = "Email not saved yet.";
      rememberCheckbox.checked = false;
    }
  }

  function saveEmailIfAllowed() {
    const email = emailInput.value.trim();

    if (rememberCheckbox.checked &amp;&amp; email) {
      localStorage.setItem(storageKey, email);
    }

    if (!rememberCheckbox.checked) {
      localStorage.removeItem(storageKey);
    }

    updateStatus();
  }

  rememberCheckbox.addEventListener("change", saveEmailIfAllowed);
  emailInput.addEventListener("input", function () {
    if (rememberCheckbox.checked) {
      saveEmailIfAllowed();
    }
  });

  form.addEventListener("submit", function (event) {
    event.preventDefault();
    saveEmailIfAllowed();
    passwordInput.value = "";
    status.textContent = rememberCheckbox.checked
      ? "Demo login complete. Email preference is saved."
      : "Demo login complete. Email was not saved.";
  });

  clearButton.addEventListener("click", function () {
    localStorage.removeItem(storageKey);
    emailInput.value = "";
    passwordInput.value = "";
    updateStatus();
  });

  updateStatus();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-nineteen-demo"&gt;
  &lt;div class="vb-storage-nineteen-login" data-vb-storage-nineteen&gt;
    &lt;div class="vb-storage-nineteen-info"&gt;
      &lt;span class="vb-storage-nineteen-kicker"&gt;Example 19&lt;/span&gt;
      &lt;h3&gt;Remember Me Login&lt;/h3&gt;
      &lt;p&gt;Save only the email address in localStorage. Passwords are never stored in this demo.&lt;/p&gt;
      &lt;div class="vb-storage-nineteen-status" data-login-status&gt;Email not saved yet.&lt;/div&gt;
    &lt;/div&gt;

    &lt;form class="vb-storage-nineteen-form" data-login-form&gt;
      &lt;label&gt;
        &lt;span&gt;Email address&lt;/span&gt;
        &lt;input type="email" data-login-email placeholder="alex@example.com"&gt;
      &lt;/label&gt;

      &lt;label&gt;
        &lt;span&gt;Password&lt;/span&gt;
        &lt;input type="password" data-login-password placeholder="Password is not saved"&gt;
      &lt;/label&gt;

      &lt;label class="vb-storage-nineteen-check"&gt;
        &lt;input type="checkbox" data-remember-email&gt;
        &lt;span&gt;Remember my email on this device&lt;/span&gt;
      &lt;/label&gt;

      &lt;button type="submit"&gt;Demo Login&lt;/button&gt;
      &lt;button type="button" class="vb-storage-nineteen-clear" data-clear-login&gt;Clear Saved Email&lt;/button&gt;

      &lt;p class="vb-storage-nineteen-note"&gt;Security note: this demo saves only the email address, never the password.&lt;/p&gt;
    &lt;/form&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-nineteen-demo,
.vb-storage-nineteen-demo * {
  box-sizing: border-box;
}

.vb-storage-nineteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(37, 99, 235, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfeff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.18);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-storage-nineteen-login {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(320px, 430px);
  gap: 22px;
  max-width: 1100px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #0f172a;
  box-shadow: 0 28px 90px rgba(15, 23, 42, 0.30);
}

.vb-storage-nineteen-info,
.vb-storage-nineteen-form {
  min-width: 0;
}

.vb-storage-nineteen-info {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(18px, 3vw, 26px);
}

.vb-storage-nineteen-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(59, 130, 246, 0.18);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-nineteen-info h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-nineteen-info p {
  max-width: 560px;
  margin: 0 0 22px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-nineteen-status {
  display: inline-flex;
  align-self: flex-start;
  padding: 13px 15px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 850;
}

.vb-storage-nineteen-form {
  display: grid;
  gap: 14px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-nineteen-form label {
  display: grid;
  gap: 7px;
}

.vb-storage-nineteen-form label &gt; span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-storage-nineteen-form input[type="email"],
.vb-storage-nineteen-form input[type="password"] {
  width: 100%;
  min-height: 50px;
  padding: 0 15px;
  border: 1px solid rgba(148, 163, 184, 0.34);
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 700;
  outline: none;
}

.vb-storage-nineteen-form input:focus {
  border-color: rgba(37, 99, 235, 0.74);
  box-shadow: 0 0 0 4px rgba(37, 99, 235, 0.10);
}

.vb-storage-nineteen-check {
  display: grid !important;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 10px !important;
  padding: 12px;
  border-radius: 16px;
  background: #eff6ff;
}

.vb-storage-nineteen-check input {
  width: 18px;
  height: 18px;
  accent-color: #2563eb;
}

.vb-storage-nineteen-form button {
  min-height: 48px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #0ea5e9);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-nineteen-clear {
  background: #fee2e2 !important;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-storage-nineteen-note {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-storage-nineteen-login {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-storage-nineteen-info h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}</pre>



<p class="wp-block-paragraph">This remember me localStorage example is useful for login pages, account forms, dashboard prototypes, membership websites, app interfaces, and JavaScript form preference demos. In production, only harmless preferences should be saved in localStorage.</p>



<h2 class="wp-block-heading">20. Dashboard Layout Saved with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>Saving a dashboard layout with localStorage</strong> is useful for admin panels, SaaS dashboards, analytics pages, project management tools, ecommerce back offices, and user portals. It lets users choose which widgets are visible and keeps that layout after refresh.</p>



<p class="wp-block-paragraph">This example lets users toggle dashboard widgets on or off. JavaScript saves the visible widget list in localStorage, updates the dashboard instantly, and restores the selected layout after page reload.</p>



<ul class="wp-block-list">
<li>Save dashboard widget visibility</li>
<li>Show and hide dashboard cards</li>
<li>Stores layout preferences as JSON</li>
<li>Restores layout after refresh</li>
<li>Useful for admin panels and SaaS apps</li>
</ul>



<div class="vb-storage-twenty-demo">
  <div class="vb-storage-twenty-dashboard" data-vb-storage-twenty>
    <aside class="vb-storage-twenty-controls">
      <span class="vb-storage-twenty-kicker">Example 20</span>
      <h3>Saved Dashboard Layout</h3>
      <p>Choose which widgets should be visible. localStorage saves the dashboard layout after refresh.</p>

      <label><input type="checkbox" data-widget-toggle="sales" checked> Sales widget</label>
      <label><input type="checkbox" data-widget-toggle="traffic" checked> Traffic widget</label>
      <label><input type="checkbox" data-widget-toggle="tasks" checked> Tasks widget</label>
      <label><input type="checkbox" data-widget-toggle="messages" checked> Messages widget</label>

      <button type="button" data-reset-layout>Reset Layout</button>
    </aside>

    <section class="vb-storage-twenty-preview">
      <div class="vb-storage-twenty-preview-head">
        <strong>Dashboard Preview</strong>
        <span data-layout-status>4 widgets visible</span>
      </div>

      <div class="vb-storage-twenty-grid">
        <article data-dashboard-widget="sales">
          <span>Sales</span>
          <strong>€12.4k</strong>
          <p>Monthly revenue overview</p>
        </article>

        <article data-dashboard-widget="traffic">
          <span>Traffic</span>
          <strong>48.2k</strong>
          <p>Website visits this month</p>
        </article>

        <article data-dashboard-widget="tasks">
          <span>Tasks</span>
          <strong>17</strong>
          <p>Open project tasks</p>
        </article>

        <article data-dashboard-widget="messages">
          <span>Messages</span>
          <strong>9</strong>
          <p>Unread client messages</p>
        </article>
      </div>
    </section>
  </div>
</div>

<style>
.vb-storage-twenty-demo,
.vb-storage-twenty-demo * {
  box-sizing: border-box;
}

.vb-storage-twenty-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(99, 102, 241, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(20, 184, 166, 0.14), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #f0fdfa 56%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.18);
  box-shadow: 0 28px 80px rgba(67, 56, 202, 0.10);
}

.vb-storage-twenty-dashboard {
  display: grid;
  grid-template-columns: minmax(280px, 360px) minmax(0, 1fr);
  gap: 22px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-twenty-controls {
  display: grid;
  align-content: start;
  gap: 12px;
  min-width: 0;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 28px;
  background: #111827;
}

.vb-storage-twenty-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(129, 140, 248, 0.18);
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-twenty-controls h3 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 58px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-storage-twenty-controls p {
  margin: 0 0 8px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-storage-twenty-controls label {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  min-height: 44px;
  padding: 10px 12px;
  border-radius: 16px;
  background: rgba(255,255,255,0.08);
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-storage-twenty-controls input {
  width: 18px;
  height: 18px;
  accent-color: #6366f1;
}

.vb-storage-twenty-controls button {
  min-height: 44px;
  margin-top: 4px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twenty-preview {
  display: grid;
  gap: 16px;
  min-width: 0;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 28px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-twenty-preview-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}

.vb-storage-twenty-preview-head strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-storage-twenty-preview-head span {
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-twenty-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-height: 390px;
}

.vb-storage-twenty-grid article {
  display: grid;
  align-content: space-between;
  min-height: 180px;
  padding: 18px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.07);
}

.vb-storage-twenty-grid article.is-hidden {
  display: none;
}

.vb-storage-twenty-grid article span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.vb-storage-twenty-grid article strong {
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: clamp(34px, 5vw, 54px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vb-storage-twenty-grid article p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

@media (max-width: 920px) {
  .vb-storage-twenty-dashboard {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-storage-twenty-grid {
    grid-template-columns: 1fr;
  }

  .vb-storage-twenty-controls h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-twenty]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwentyDashboardLayout";
  const toggles = wrapper.querySelectorAll("[data-widget-toggle]");
  const widgets = wrapper.querySelectorAll("[data-dashboard-widget]");
  const status = wrapper.querySelector("[data-layout-status]");
  const resetButton = wrapper.querySelector("[data-reset-layout]");

  const defaultVisibleWidgets = ["sales", "traffic", "tasks", "messages"];
  let visibleWidgets = defaultVisibleWidgets.slice();

  function saveLayout() {
    localStorage.setItem(storageKey, JSON.stringify(visibleWidgets));
  }

  function loadLayout() {
    const savedLayout = localStorage.getItem(storageKey);
    if (!savedLayout) return;

    try {
      const parsedLayout = JSON.parse(savedLayout);
      visibleWidgets = Array.isArray(parsedLayout) ? parsedLayout : defaultVisibleWidgets.slice();
    } catch (error) {
      visibleWidgets = defaultVisibleWidgets.slice();
      localStorage.removeItem(storageKey);
    }
  }

  function applyLayout() {
    toggles.forEach(function (toggle) {
      const key = toggle.getAttribute("data-widget-toggle");
      toggle.checked = visibleWidgets.includes(key);
    });

    widgets.forEach(function (widget) {
      const key = widget.getAttribute("data-dashboard-widget");
      widget.classList.toggle("is-hidden", !visibleWidgets.includes(key));
    });

    status.textContent = visibleWidgets.length === 1
      ? "1 widget visible"
      : visibleWidgets.length + " widgets visible";

    saveLayout();
  }

  toggles.forEach(function (toggle) {
    toggle.addEventListener("change", function () {
      const key = toggle.getAttribute("data-widget-toggle");

      if (toggle.checked && !visibleWidgets.includes(key)) {
        visibleWidgets.push(key);
      }

      if (!toggle.checked) {
        visibleWidgets = visibleWidgets.filter(function (item) {
          return item !== key;
        });
      }

      applyLayout();
    });
  });

  resetButton.addEventListener("click", function () {
    visibleWidgets = defaultVisibleWidgets.slice();
    localStorage.removeItem(storageKey);
    applyLayout();
  });

  loadLayout();
  applyLayout();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-twenty]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwentyDashboardLayout";
  const toggles = wrapper.querySelectorAll("[data-widget-toggle]");
  const widgets = wrapper.querySelectorAll("[data-dashboard-widget]");
  const status = wrapper.querySelector("[data-layout-status]");
  const resetButton = wrapper.querySelector("[data-reset-layout]");

  const defaultVisibleWidgets = ["sales", "traffic", "tasks", "messages"];
  let visibleWidgets = defaultVisibleWidgets.slice();

  function saveLayout() {
    localStorage.setItem(storageKey, JSON.stringify(visibleWidgets));
  }

  function loadLayout() {
    const savedLayout = localStorage.getItem(storageKey);
    if (!savedLayout) return;

    try {
      const parsedLayout = JSON.parse(savedLayout);
      visibleWidgets = Array.isArray(parsedLayout) ? parsedLayout : defaultVisibleWidgets.slice();
    } catch (error) {
      visibleWidgets = defaultVisibleWidgets.slice();
      localStorage.removeItem(storageKey);
    }
  }

  function applyLayout() {
    toggles.forEach(function (toggle) {
      const key = toggle.getAttribute("data-widget-toggle");
      toggle.checked = visibleWidgets.includes(key);
    });

    widgets.forEach(function (widget) {
      const key = widget.getAttribute("data-dashboard-widget");
      widget.classList.toggle("is-hidden", !visibleWidgets.includes(key));
    });

    status.textContent = visibleWidgets.length === 1
      ? "1 widget visible"
      : visibleWidgets.length + " widgets visible";

    saveLayout();
  }

  toggles.forEach(function (toggle) {
    toggle.addEventListener("change", function () {
      const key = toggle.getAttribute("data-widget-toggle");

      if (toggle.checked &amp;&amp; !visibleWidgets.includes(key)) {
        visibleWidgets.push(key);
      }

      if (!toggle.checked) {
        visibleWidgets = visibleWidgets.filter(function (item) {
          return item !== key;
        });
      }

      applyLayout();
    });
  });

  resetButton.addEventListener("click", function () {
    visibleWidgets = defaultVisibleWidgets.slice();
    localStorage.removeItem(storageKey);
    applyLayout();
  });

  loadLayout();
  applyLayout();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-twenty-demo"&gt;
  &lt;div class="vb-storage-twenty-dashboard" data-vb-storage-twenty&gt;
    &lt;aside class="vb-storage-twenty-controls"&gt;
      &lt;span class="vb-storage-twenty-kicker"&gt;Example 20&lt;/span&gt;
      &lt;h3&gt;Saved Dashboard Layout&lt;/h3&gt;
      &lt;p&gt;Choose which widgets should be visible. localStorage saves the dashboard layout after refresh.&lt;/p&gt;

      &lt;label&gt;&lt;input type="checkbox" data-widget-toggle="sales" checked&gt; Sales widget&lt;/label&gt;
      &lt;label&gt;&lt;input type="checkbox" data-widget-toggle="traffic" checked&gt; Traffic widget&lt;/label&gt;
      &lt;label&gt;&lt;input type="checkbox" data-widget-toggle="tasks" checked&gt; Tasks widget&lt;/label&gt;
      &lt;label&gt;&lt;input type="checkbox" data-widget-toggle="messages" checked&gt; Messages widget&lt;/label&gt;

      &lt;button type="button" data-reset-layout&gt;Reset Layout&lt;/button&gt;
    &lt;/aside&gt;

    &lt;section class="vb-storage-twenty-preview"&gt;
      &lt;div class="vb-storage-twenty-preview-head"&gt;
        &lt;strong&gt;Dashboard Preview&lt;/strong&gt;
        &lt;span data-layout-status&gt;4 widgets visible&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-twenty-grid"&gt;
        &lt;article data-dashboard-widget="sales"&gt;
          &lt;span&gt;Sales&lt;/span&gt;
          &lt;strong&gt;€12.4k&lt;/strong&gt;
          &lt;p&gt;Monthly revenue overview&lt;/p&gt;
        &lt;/article&gt;

        &lt;article data-dashboard-widget="traffic"&gt;
          &lt;span&gt;Traffic&lt;/span&gt;
          &lt;strong&gt;48.2k&lt;/strong&gt;
          &lt;p&gt;Website visits this month&lt;/p&gt;
        &lt;/article&gt;

        &lt;article data-dashboard-widget="tasks"&gt;
          &lt;span&gt;Tasks&lt;/span&gt;
          &lt;strong&gt;17&lt;/strong&gt;
          &lt;p&gt;Open project tasks&lt;/p&gt;
        &lt;/article&gt;

        &lt;article data-dashboard-widget="messages"&gt;
          &lt;span&gt;Messages&lt;/span&gt;
          &lt;strong&gt;9&lt;/strong&gt;
          &lt;p&gt;Unread client messages&lt;/p&gt;
        &lt;/article&gt;
      &lt;/div&gt;
    &lt;/section&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-twenty-demo,
.vb-storage-twenty-demo * {
  box-sizing: border-box;
}

.vb-storage-twenty-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(99, 102, 241, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(20, 184, 166, 0.14), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #f0fdfa 56%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.18);
  box-shadow: 0 28px 80px rgba(67, 56, 202, 0.10);
}

.vb-storage-twenty-dashboard {
  display: grid;
  grid-template-columns: minmax(280px, 360px) minmax(0, 1fr);
  gap: 22px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-twenty-controls {
  display: grid;
  align-content: start;
  gap: 12px;
  min-width: 0;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 28px;
  background: #111827;
}

.vb-storage-twenty-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(129, 140, 248, 0.18);
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-twenty-controls h3 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 58px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-storage-twenty-controls p {
  margin: 0 0 8px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-storage-twenty-controls label {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  min-height: 44px;
  padding: 10px 12px;
  border-radius: 16px;
  background: rgba(255,255,255,0.08);
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-storage-twenty-controls input {
  width: 18px;
  height: 18px;
  accent-color: #6366f1;
}

.vb-storage-twenty-controls button {
  min-height: 44px;
  margin-top: 4px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twenty-preview {
  display: grid;
  gap: 16px;
  min-width: 0;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 28px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-twenty-preview-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}

.vb-storage-twenty-preview-head strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-storage-twenty-preview-head span {
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-twenty-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-height: 390px;
}

.vb-storage-twenty-grid article {
  display: grid;
  align-content: space-between;
  min-height: 180px;
  padding: 18px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.07);
}

.vb-storage-twenty-grid article.is-hidden {
  display: none;
}

.vb-storage-twenty-grid article span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.vb-storage-twenty-grid article strong {
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: clamp(34px, 5vw, 54px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vb-storage-twenty-grid article p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

@media (max-width: 920px) {
  .vb-storage-twenty-dashboard {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-storage-twenty-grid {
    grid-template-columns: 1fr;
  }

  .vb-storage-twenty-controls h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}</pre>



<p class="wp-block-paragraph">This dashboard layout localStorage example is useful for admin panels, analytics dashboards, SaaS apps, ecommerce back offices, CRM interfaces, project management tools, and customizable user portals.</p>



<h2 class="wp-block-heading">21. Kanban Board Saved with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>A Kanban board saved with localStorage</strong> is a practical JavaScript project for task management apps, project dashboards, content planning boards, CRM pipelines, and personal productivity tools. It teaches how to save grouped data and move items between columns.</p>



<p class="wp-block-paragraph">This example lets users add a task, move tasks between To Do, Doing, and Done columns, delete tasks, and restore the full board after refresh. JavaScript stores the board data as a JSON object in localStorage.</p>



<ul class="wp-block-list">
<li>Save Kanban board columns</li>
<li>Add tasks to localStorage</li>
<li>Move tasks between columns</li>
<li>Delete tasks from the board</li>
<li>Useful for task apps and project dashboards</li>
</ul>



<div class="vb-storage-twentyone-demo">
  <div class="vb-storage-twentyone-board" data-vb-storage-twentyone>
    <div class="vb-storage-twentyone-head">
      <span class="vb-storage-twentyone-kicker">Example 21</span>
      <h3>Saved Kanban Board</h3>
      <p>Add tasks and move them between columns. localStorage restores the whole board after refresh.</p>
    </div>

    <form class="vb-storage-twentyone-form" data-kanban-form>
      <input type="text" data-kanban-input placeholder="Add a new task...">
      <button type="submit">Add Task</button>
      <button type="button" data-clear-board>Clear Board</button>
    </form>

    <div class="vb-storage-twentyone-columns">
      <section data-column="todo">
        <h4>To Do <span data-count="todo">0</span></h4>
        <div data-task-column="todo"></div>
      </section>

      <section data-column="doing">
        <h4>Doing <span data-count="doing">0</span></h4>
        <div data-task-column="doing"></div>
      </section>

      <section data-column="done">
        <h4>Done <span data-count="done">0</span></h4>
        <div data-task-column="done"></div>
      </section>
    </div>
  </div>
</div>

<style>
.vb-storage-twentyone-demo,
.vb-storage-twentyone-demo * {
  box-sizing: border-box;
}

.vb-storage-twentyone-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(14, 165, 233, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #faf5ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  box-shadow: 0 28px 80px rgba(12, 74, 110, 0.10);
}

.vb-storage-twentyone-board {
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #0f172a;
  box-shadow: 0 28px 90px rgba(15, 23, 42, 0.30);
}

.vb-storage-twentyone-head {
  display: grid;
  gap: 12px;
  margin-bottom: 20px;
}

.vb-storage-twentyone-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(14, 165, 233, 0.16);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-twentyone-head h3 {
  max-width: 820px;
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-twentyone-head p {
  max-width: 760px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-twentyone-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: 10px;
  margin-bottom: 18px;
  padding: 14px;
  border-radius: 24px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-twentyone-form input {
  min-width: 0;
  min-height: 48px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 750;
  outline: none;
}

.vb-storage-twentyone-form input::placeholder {
  color: #9ca3af;
  -webkit-text-fill-color: #9ca3af;
}

.vb-storage-twentyone-form button {
  min-height: 48px;
  padding: 0 15px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #0ea5e9, #9333ea);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentyone-form button:last-child {
  background: rgba(255,255,255,0.12);
}

.vb-storage-twentyone-columns {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.vb-storage-twentyone-columns section {
  display: grid;
  align-content: start;
  gap: 12px;
  min-height: 390px;
  padding: 14px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-storage-twentyone-columns h4 {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
}

.vb-storage-twentyone-columns h4 span {
  display: grid;
  place-items: center;
  min-width: 34px;
  height: 34px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-twentyone-columns [data-task-column] {
  display: grid;
  gap: 10px;
}

.vb-storage-twentyone-task {
  display: grid;
  gap: 10px;
  padding: 13px;
  border-radius: 18px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 10px 26px rgba(15, 23, 42, 0.06);
}

.vb-storage-twentyone-task strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  line-height: 1.35;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-storage-twentyone-actions {
  display: flex;
  gap: 7px;
  flex-wrap: wrap;
}

.vb-storage-twentyone-actions button {
  min-height: 32px;
  padding: 6px 9px;
  border: 0;
  border-radius: 999px;
  background: #e0e7ff;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: 11px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentyone-actions button:last-child {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

@media (max-width: 940px) {
  .vb-storage-twentyone-columns {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-storage-twentyone-form {
    grid-template-columns: 1fr;
  }

  .vb-storage-twentyone-head h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-twentyone]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwentyoneKanban";
  const form = wrapper.querySelector("[data-kanban-form]");
  const input = wrapper.querySelector("[data-kanban-input]");
  const clearButton = wrapper.querySelector("[data-clear-board]");
  const columns = {
    todo: wrapper.querySelector('[data-task-column="todo"]'),
    doing: wrapper.querySelector('[data-task-column="doing"]'),
    done: wrapper.querySelector('[data-task-column="done"]')
  };
  const counts = {
    todo: wrapper.querySelector('[data-count="todo"]'),
    doing: wrapper.querySelector('[data-count="doing"]'),
    done: wrapper.querySelector('[data-count="done"]')
  };

  let board = {
    todo: [],
    doing: [],
    done: []
  };

  function saveBoard() {
    localStorage.setItem(storageKey, JSON.stringify(board));
  }

  function loadBoard() {
    const savedBoard = localStorage.getItem(storageKey);
    if (!savedBoard) return;

    try {
      const parsedBoard = JSON.parse(savedBoard);
      board = {
        todo: Array.isArray(parsedBoard.todo) ? parsedBoard.todo : [],
        doing: Array.isArray(parsedBoard.doing) ? parsedBoard.doing : [],
        done: Array.isArray(parsedBoard.done) ? parsedBoard.done : []
      };
    } catch (error) {
      localStorage.removeItem(storageKey);
    }
  }

  function findTask(taskId) {
    for (const columnName in board) {
      const task = board[columnName].find(function (item) {
        return item.id === taskId;
      });

      if (task) {
        return {
          task: task,
          columnName: columnName
        };
      }
    }

    return null;
  }

  function renderBoard() {
    Object.keys(columns).forEach(function (columnName) {
      columns[columnName].innerHTML = "";
      counts[columnName].textContent = board[columnName].length;

      board[columnName].forEach(function (task) {
        const card = document.createElement("div");
        card.className = "vb-storage-twentyone-task";

        card.innerHTML =
          '<strong>' + task.text + '</strong>' +
          '<div class="vb-storage-twentyone-actions">' +
            '<button type="button" data-move-task="' + task.id + '" data-target-column="todo">To Do</button>' +
            '<button type="button" data-move-task="' + task.id + '" data-target-column="doing">Doing</button>' +
            '<button type="button" data-move-task="' + task.id + '" data-target-column="done">Done</button>' +
            '<button type="button" data-delete-task="' + task.id + '">Delete</button>' +
          '</div>';

        columns[columnName].appendChild(card);
      });
    });

    saveBoard();
  }

  function addTask(text) {
    board.todo.unshift({
      id: String(Date.now()),
      text: text
    });

    renderBoard();
  }

  function moveTask(taskId, targetColumn) {
    const found = findTask(taskId);
    if (!found || found.columnName === targetColumn) return;

    board[found.columnName] = board[found.columnName].filter(function (task) {
      return task.id !== taskId;
    });

    board[targetColumn].unshift(found.task);
    renderBoard();
  }

  function deleteTask(taskId) {
    Object.keys(board).forEach(function (columnName) {
      board[columnName] = board[columnName].filter(function (task) {
        return task.id !== taskId;
      });
    });

    renderBoard();
  }

  form.addEventListener("submit", function (event) {
    event.preventDefault();

    const text = input.value.trim();
    if (!text) return;

    addTask(text);
    input.value = "";
    input.focus();
  });

  wrapper.addEventListener("click", function (event) {
    const moveId = event.target.getAttribute("data-move-task");
    const targetColumn = event.target.getAttribute("data-target-column");
    const deleteId = event.target.getAttribute("data-delete-task");

    if (moveId && targetColumn) {
      moveTask(moveId, targetColumn);
    }

    if (deleteId) {
      deleteTask(deleteId);
    }
  });

  clearButton.addEventListener("click", function () {
    board = {
      todo: [],
      doing: [],
      done: []
    };

    localStorage.removeItem(storageKey);
    renderBoard();
  });

  loadBoard();
  renderBoard();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-twentyone]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwentyoneKanban";
  const form = wrapper.querySelector("[data-kanban-form]");
  const input = wrapper.querySelector("[data-kanban-input]");
  const clearButton = wrapper.querySelector("[data-clear-board]");
  const columns = {
    todo: wrapper.querySelector('[data-task-column="todo"]'),
    doing: wrapper.querySelector('[data-task-column="doing"]'),
    done: wrapper.querySelector('[data-task-column="done"]')
  };
  const counts = {
    todo: wrapper.querySelector('[data-count="todo"]'),
    doing: wrapper.querySelector('[data-count="doing"]'),
    done: wrapper.querySelector('[data-count="done"]')
  };

  let board = {
    todo: [],
    doing: [],
    done: []
  };

  function saveBoard() {
    localStorage.setItem(storageKey, JSON.stringify(board));
  }

  function loadBoard() {
    const savedBoard = localStorage.getItem(storageKey);
    if (!savedBoard) return;

    try {
      const parsedBoard = JSON.parse(savedBoard);
      board = {
        todo: Array.isArray(parsedBoard.todo) ? parsedBoard.todo : [],
        doing: Array.isArray(parsedBoard.doing) ? parsedBoard.doing : [],
        done: Array.isArray(parsedBoard.done) ? parsedBoard.done : []
      };
    } catch (error) {
      localStorage.removeItem(storageKey);
    }
  }

  function findTask(taskId) {
    for (const columnName in board) {
      const task = board[columnName].find(function (item) {
        return item.id === taskId;
      });

      if (task) {
        return {
          task: task,
          columnName: columnName
        };
      }
    }

    return null;
  }

  function renderBoard() {
    Object.keys(columns).forEach(function (columnName) {
      columns[columnName].innerHTML = "";
      counts[columnName].textContent = board[columnName].length;

      board[columnName].forEach(function (task) {
        const card = document.createElement("div");
        card.className = "vb-storage-twentyone-task";

        card.innerHTML =
          '&lt;strong&gt;' + task.text + '&lt;/strong&gt;' +
          '&lt;div class="vb-storage-twentyone-actions"&gt;' +
            '&lt;button type="button" data-move-task="' + task.id + '" data-target-column="todo"&gt;To Do&lt;/button&gt;' +
            '&lt;button type="button" data-move-task="' + task.id + '" data-target-column="doing"&gt;Doing&lt;/button&gt;' +
            '&lt;button type="button" data-move-task="' + task.id + '" data-target-column="done"&gt;Done&lt;/button&gt;' +
            '&lt;button type="button" data-delete-task="' + task.id + '"&gt;Delete&lt;/button&gt;' +
          '&lt;/div&gt;';

        columns[columnName].appendChild(card);
      });
    });

    saveBoard();
  }

  function addTask(text) {
    board.todo.unshift({
      id: String(Date.now()),
      text: text
    });

    renderBoard();
  }

  function moveTask(taskId, targetColumn) {
    const found = findTask(taskId);
    if (!found || found.columnName === targetColumn) return;

    board[found.columnName] = board[found.columnName].filter(function (task) {
      return task.id !== taskId;
    });

    board[targetColumn].unshift(found.task);
    renderBoard();
  }

  function deleteTask(taskId) {
    Object.keys(board).forEach(function (columnName) {
      board[columnName] = board[columnName].filter(function (task) {
        return task.id !== taskId;
      });
    });

    renderBoard();
  }

  form.addEventListener("submit", function (event) {
    event.preventDefault();

    const text = input.value.trim();
    if (!text) return;

    addTask(text);
    input.value = "";
    input.focus();
  });

  wrapper.addEventListener("click", function (event) {
    const moveId = event.target.getAttribute("data-move-task");
    const targetColumn = event.target.getAttribute("data-target-column");
    const deleteId = event.target.getAttribute("data-delete-task");

    if (moveId &amp;&amp; targetColumn) {
      moveTask(moveId, targetColumn);
    }

    if (deleteId) {
      deleteTask(deleteId);
    }
  });

  clearButton.addEventListener("click", function () {
    board = {
      todo: [],
      doing: [],
      done: []
    };

    localStorage.removeItem(storageKey);
    renderBoard();
  });

  loadBoard();
  renderBoard();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-twentyone-demo"&gt;
  &lt;div class="vb-storage-twentyone-board" data-vb-storage-twentyone&gt;
    &lt;div class="vb-storage-twentyone-head"&gt;
      &lt;span class="vb-storage-twentyone-kicker"&gt;Example 21&lt;/span&gt;
      &lt;h3&gt;Saved Kanban Board&lt;/h3&gt;
      &lt;p&gt;Add tasks and move them between columns. localStorage restores the whole board after refresh.&lt;/p&gt;
    &lt;/div&gt;

    &lt;form class="vb-storage-twentyone-form" data-kanban-form&gt;
      &lt;input type="text" data-kanban-input placeholder="Add a new task..."&gt;
      &lt;button type="submit"&gt;Add Task&lt;/button&gt;
      &lt;button type="button" data-clear-board&gt;Clear Board&lt;/button&gt;
    &lt;/form&gt;

    &lt;div class="vb-storage-twentyone-columns"&gt;
      &lt;section data-column="todo"&gt;
        &lt;h4&gt;To Do &lt;span data-count="todo"&gt;0&lt;/span&gt;&lt;/h4&gt;
        &lt;div data-task-column="todo"&gt;&lt;/div&gt;
      &lt;/section&gt;

      &lt;section data-column="doing"&gt;
        &lt;h4&gt;Doing &lt;span data-count="doing"&gt;0&lt;/span&gt;&lt;/h4&gt;
        &lt;div data-task-column="doing"&gt;&lt;/div&gt;
      &lt;/section&gt;

      &lt;section data-column="done"&gt;
        &lt;h4&gt;Done &lt;span data-count="done"&gt;0&lt;/span&gt;&lt;/h4&gt;
        &lt;div data-task-column="done"&gt;&lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-twentyone-demo,
.vb-storage-twentyone-demo * {
  box-sizing: border-box;
}

.vb-storage-twentyone-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(14, 165, 233, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #faf5ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  box-shadow: 0 28px 80px rgba(12, 74, 110, 0.10);
}

.vb-storage-twentyone-board {
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #0f172a;
  box-shadow: 0 28px 90px rgba(15, 23, 42, 0.30);
}

.vb-storage-twentyone-head {
  display: grid;
  gap: 12px;
  margin-bottom: 20px;
}

.vb-storage-twentyone-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(14, 165, 233, 0.16);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-twentyone-head h3 {
  max-width: 820px;
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-twentyone-head p {
  max-width: 760px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-twentyone-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: 10px;
  margin-bottom: 18px;
  padding: 14px;
  border-radius: 24px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-twentyone-form input {
  min-width: 0;
  min-height: 48px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 750;
  outline: none;
}

.vb-storage-twentyone-form input::placeholder {
  color: #9ca3af;
  -webkit-text-fill-color: #9ca3af;
}

.vb-storage-twentyone-form button {
  min-height: 48px;
  padding: 0 15px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #0ea5e9, #9333ea);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentyone-form button:last-child {
  background: rgba(255,255,255,0.12);
}

.vb-storage-twentyone-columns {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.vb-storage-twentyone-columns section {
  display: grid;
  align-content: start;
  gap: 12px;
  min-height: 390px;
  padding: 14px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-storage-twentyone-columns h4 {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
}

.vb-storage-twentyone-columns h4 span {
  display: grid;
  place-items: center;
  min-width: 34px;
  height: 34px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-twentyone-columns [data-task-column] {
  display: grid;
  gap: 10px;
}

.vb-storage-twentyone-task {
  display: grid;
  gap: 10px;
  padding: 13px;
  border-radius: 18px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 10px 26px rgba(15, 23, 42, 0.06);
}

.vb-storage-twentyone-task strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  line-height: 1.35;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-storage-twentyone-actions {
  display: flex;
  gap: 7px;
  flex-wrap: wrap;
}

.vb-storage-twentyone-actions button {
  min-height: 32px;
  padding: 6px 9px;
  border: 0;
  border-radius: 999px;
  background: #e0e7ff;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: 11px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentyone-actions button:last-child {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

@media (max-width: 940px) {
  .vb-storage-twentyone-columns {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-storage-twentyone-form {
    grid-template-columns: 1fr;
  }

  .vb-storage-twentyone-head h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}</pre>



<p class="wp-block-paragraph">This Kanban board localStorage example is useful for task managers, project dashboards, content planning boards, CRM pipeline demos, productivity apps, and JavaScript portfolio projects that need persistent grouped data.</p>



<h2 class="wp-block-heading">22. Shopping Cart Saved with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>A shopping cart saved with localStorage</strong> is one of the most practical JavaScript localStorage examples for ecommerce websites, product landing pages, digital product shops, affiliate demos, and cart UI prototypes. It lets visitors add products to a cart and keep the cart after refresh.</p>



<p class="wp-block-paragraph">This example lets users add products, increase or decrease quantity, remove items, clear the cart, and restore the cart from localStorage after page reload. JavaScript stores the cart as a JSON array and recalculates the total every time the cart changes.</p>



<ul class="wp-block-list">
<li>Save shopping cart items in localStorage</li>
<li>Add, remove, increase, and decrease quantities</li>
<li>Calculates cart subtotal automatically</li>
<li>Restores cart after refresh</li>
<li>Useful for ecommerce and product page demos</li>
</ul>



<div class="vb-storage-twentytwo-demo">
  <div class="vb-storage-twentytwo-shop" data-vb-storage-twentytwo>
    <div class="vb-storage-twentytwo-head">
      <span class="vb-storage-twentytwo-kicker">Example 22</span>
      <h3>Saved Shopping Cart</h3>
      <p>Add products to the cart, refresh the page, and localStorage restores the full cart with quantities.</p>
    </div>

    <div class="vb-storage-twentytwo-layout">
      <div class="vb-storage-twentytwo-products">
        <article data-product-id="template" data-product-name="Website Template" data-product-price="49">
          <span>WEB</span>
          <h4>Website Template</h4>
          <p>Responsive landing page template for a modern website.</p>
          <strong>49€</strong>
          <button type="button" data-add-cart>Add to Cart</button>
        </article>

        <article data-product-id="plugin" data-product-name="JavaScript Plugin" data-product-price="29">
          <span>JS</span>
          <h4>JavaScript Plugin</h4>
          <p>Small browser feature that saves user actions locally.</p>
          <strong>29€</strong>
          <button type="button" data-add-cart>Add to Cart</button>
        </article>

        <article data-product-id="audit" data-product-name="SEO Audit" data-product-price="99">
          <span>SEO</span>
          <h4>SEO Audit</h4>
          <p>Technical SEO review for structure, speed, and content.</p>
          <strong>99€</strong>
          <button type="button" data-add-cart>Add to Cart</button>
        </article>
      </div>

      <aside class="vb-storage-twentytwo-cart">
        <div class="vb-storage-twentytwo-cart-head">
          <strong>Your Cart</strong>
          <span data-cart-count>0 items</span>
        </div>

        <div class="vb-storage-twentytwo-cart-list" data-cart-list>
          <p class="vb-storage-twentytwo-empty">Your cart is empty.</p>
        </div>

        <div class="vb-storage-twentytwo-total">
          <span>Subtotal</span>
          <strong data-cart-total>0€</strong>
        </div>

        <button type="button" data-clear-cart>Clear Cart</button>
      </aside>
    </div>
  </div>
</div>

<style>
.vb-storage-twentytwo-demo,
.vb-storage-twentytwo-demo * {
  box-sizing: border-box;
}

.vb-storage-twentytwo-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(16, 185, 129, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #eff6ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(16, 185, 129, 0.18);
  box-shadow: 0 28px 80px rgba(6, 95, 70, 0.10);
}

.vb-storage-twentytwo-shop {
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-twentytwo-head {
  display: grid;
  gap: 12px;
  margin-bottom: 24px;
}

.vb-storage-twentytwo-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-twentytwo-head h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-twentytwo-head p {
  max-width: 780px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-twentytwo-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(320px, 410px);
  gap: 20px;
  align-items: start;
}

.vb-storage-twentytwo-products {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.vb-storage-twentytwo-products article {
  display: grid;
  align-content: start;
  gap: 11px;
  min-height: 280px;
  padding: 18px;
  border-radius: 26px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-storage-twentytwo-products article > span {
  display: grid;
  place-items: center;
  width: 64px;
  height: 64px;
  border-radius: 22px;
  background: linear-gradient(135deg, #10b981, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-storage-twentytwo-products h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 22px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
}

.vb-storage-twentytwo-products p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-storage-twentytwo-products strong {
  margin-top: auto;
  color: #059669 !important;
  -webkit-text-fill-color: #059669 !important;
  font-size: 26px;
  line-height: 1;
  font-weight: 950;
}

.vb-storage-twentytwo-products button,
.vb-storage-twentytwo-cart > button {
  min-height: 44px;
  border: 0;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentytwo-products button {
  background: linear-gradient(135deg, #10b981, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-twentytwo-cart {
  display: grid;
  gap: 14px;
  padding: 18px;
  border-radius: 28px;
  background: #0f172a;
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.24);
}

.vb-storage-twentytwo-cart-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.vb-storage-twentytwo-cart-head strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-storage-twentytwo-cart-head span {
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-storage-twentytwo-cart-list {
  display: grid;
  gap: 10px;
  min-height: 280px;
}

.vb-storage-twentytwo-empty {
  display: grid;
  place-items: center;
  min-height: 280px;
  margin: 0 !important;
  border: 1px dashed rgba(255,255,255,0.22);
  border-radius: 20px;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-twentytwo-cart-item {
  display: grid;
  gap: 10px;
  padding: 12px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-twentytwo-cart-item-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.vb-storage-twentytwo-cart-item strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.25;
  font-weight: 900;
}

.vb-storage-twentytwo-cart-item span {
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-storage-twentytwo-qty {
  display: flex;
  align-items: center;
  gap: 7px;
}

.vb-storage-twentytwo-qty button {
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentytwo-qty small {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-twentytwo-total {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 16px;
  border-radius: 20px;
  background: rgba(255,255,255,0.10);
}

.vb-storage-twentytwo-total span {
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-storage-twentytwo-total strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px;
  line-height: 1;
  font-weight: 950;
}

.vb-storage-twentytwo-cart > button {
  background: #ffffff;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
}

@media (max-width: 980px) {
  .vb-storage-twentytwo-layout {
    grid-template-columns: 1fr;
  }

  .vb-storage-twentytwo-products {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-storage-twentytwo-products {
    grid-template-columns: 1fr;
  }

  .vb-storage-twentytwo-head h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-twentytwo]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwentytwoCart";
  const products = wrapper.querySelectorAll("[data-product-id]");
  const cartList = wrapper.querySelector("[data-cart-list]");
  const cartCount = wrapper.querySelector("[data-cart-count]");
  const cartTotal = wrapper.querySelector("[data-cart-total]");
  const clearButton = wrapper.querySelector("[data-clear-cart]");

  let cart = [];

  function saveCart() {
    localStorage.setItem(storageKey, JSON.stringify(cart));
  }

  function loadCart() {
    const savedCart = localStorage.getItem(storageKey);
    if (!savedCart) return;

    try {
      const parsedCart = JSON.parse(savedCart);
      cart = Array.isArray(parsedCart) ? parsedCart : [];
    } catch (error) {
      cart = [];
      localStorage.removeItem(storageKey);
    }
  }

  function renderCart() {
    cartList.innerHTML = "";

    const totalItems = cart.reduce(function (sum, item) {
      return sum + item.quantity;
    }, 0);

    const subtotal = cart.reduce(function (sum, item) {
      return sum + item.price * item.quantity;
    }, 0);

    cartCount.textContent = totalItems === 1 ? "1 item" : totalItems + " items";
    cartTotal.textContent = subtotal + "€";

    if (cart.length === 0) {
      cartList.innerHTML = '<p class="vb-storage-twentytwo-empty">Your cart is empty.</p>';
      saveCart();
      return;
    }

    cart.forEach(function (item) {
      const row = document.createElement("div");
      row.className = "vb-storage-twentytwo-cart-item";

      row.innerHTML =
        '<div class="vb-storage-twentytwo-cart-item-top">' +
          '<strong>' + item.name + '</strong>' +
          '<span>' + item.price + '€</span>' +
        '</div>' +
        '<div class="vb-storage-twentytwo-qty">' +
          '<button type="button" data-decrease="' + item.id + '">−</button>' +
          '<small>Qty ' + item.quantity + '</small>' +
          '<button type="button" data-increase="' + item.id + '">+</button>' +
          '<button type="button" data-remove="' + item.id + '">×</button>' +
        '</div>';

      cartList.appendChild(row);
    });

    saveCart();
  }

  function addToCart(product) {
    const productId = product.getAttribute("data-product-id");
    const existingItem = cart.find(function (item) {
      return item.id === productId;
    });

    if (existingItem) {
      existingItem.quantity += 1;
    } else {
      cart.push({
        id: productId,
        name: product.getAttribute("data-product-name"),
        price: Number(product.getAttribute("data-product-price")),
        quantity: 1
      });
    }

    renderCart();
  }

  function changeQuantity(productId, amount) {
    cart = cart.map(function (item) {
      if (item.id === productId) {
        item.quantity += amount;
      }

      return item;
    }).filter(function (item) {
      return item.quantity > 0;
    });

    renderCart();
  }

  function removeItem(productId) {
    cart = cart.filter(function (item) {
      return item.id !== productId;
    });

    renderCart();
  }

  products.forEach(function (product) {
    product.querySelector("[data-add-cart]").addEventListener("click", function () {
      addToCart(product);
    });
  });

  cartList.addEventListener("click", function (event) {
    const increaseId = event.target.getAttribute("data-increase");
    const decreaseId = event.target.getAttribute("data-decrease");
    const removeId = event.target.getAttribute("data-remove");

    if (increaseId) changeQuantity(increaseId, 1);
    if (decreaseId) changeQuantity(decreaseId, -1);
    if (removeId) removeItem(removeId);
  });

  clearButton.addEventListener("click", function () {
    cart = [];
    localStorage.removeItem(storageKey);
    renderCart();
  });

  loadCart();
  renderCart();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-twentytwo]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwentytwoCart";
  const products = wrapper.querySelectorAll("[data-product-id]");
  const cartList = wrapper.querySelector("[data-cart-list]");
  const cartCount = wrapper.querySelector("[data-cart-count]");
  const cartTotal = wrapper.querySelector("[data-cart-total]");
  const clearButton = wrapper.querySelector("[data-clear-cart]");

  let cart = [];

  function saveCart() {
    localStorage.setItem(storageKey, JSON.stringify(cart));
  }

  function loadCart() {
    const savedCart = localStorage.getItem(storageKey);
    if (!savedCart) return;

    try {
      const parsedCart = JSON.parse(savedCart);
      cart = Array.isArray(parsedCart) ? parsedCart : [];
    } catch (error) {
      cart = [];
      localStorage.removeItem(storageKey);
    }
  }

  function renderCart() {
    cartList.innerHTML = "";

    const totalItems = cart.reduce(function (sum, item) {
      return sum + item.quantity;
    }, 0);

    const subtotal = cart.reduce(function (sum, item) {
      return sum + item.price * item.quantity;
    }, 0);

    cartCount.textContent = totalItems === 1 ? "1 item" : totalItems + " items";
    cartTotal.textContent = subtotal + "€";

    if (cart.length === 0) {
      cartList.innerHTML = '&lt;p class="vb-storage-twentytwo-empty"&gt;Your cart is empty.&lt;/p&gt;';
      saveCart();
      return;
    }

    cart.forEach(function (item) {
      const row = document.createElement("div");
      row.className = "vb-storage-twentytwo-cart-item";

      row.innerHTML =
        '&lt;div class="vb-storage-twentytwo-cart-item-top"&gt;' +
          '&lt;strong&gt;' + item.name + '&lt;/strong&gt;' +
          '&lt;span&gt;' + item.price + '€&lt;/span&gt;' +
        '&lt;/div&gt;' +
        '&lt;div class="vb-storage-twentytwo-qty"&gt;' +
          '&lt;button type="button" data-decrease="' + item.id + '"&gt;−&lt;/button&gt;' +
          '&lt;small&gt;Qty ' + item.quantity + '&lt;/small&gt;' +
          '&lt;button type="button" data-increase="' + item.id + '"&gt;+&lt;/button&gt;' +
          '&lt;button type="button" data-remove="' + item.id + '"&gt;×&lt;/button&gt;' +
        '&lt;/div&gt;';

      cartList.appendChild(row);
    });

    saveCart();
  }

  function addToCart(product) {
    const productId = product.getAttribute("data-product-id");
    const existingItem = cart.find(function (item) {
      return item.id === productId;
    });

    if (existingItem) {
      existingItem.quantity += 1;
    } else {
      cart.push({
        id: productId,
        name: product.getAttribute("data-product-name"),
        price: Number(product.getAttribute("data-product-price")),
        quantity: 1
      });
    }

    renderCart();
  }

  function changeQuantity(productId, amount) {
    cart = cart.map(function (item) {
      if (item.id === productId) {
        item.quantity += amount;
      }

      return item;
    }).filter(function (item) {
      return item.quantity &gt; 0;
    });

    renderCart();
  }

  function removeItem(productId) {
    cart = cart.filter(function (item) {
      return item.id !== productId;
    });

    renderCart();
  }

  products.forEach(function (product) {
    product.querySelector("[data-add-cart]").addEventListener("click", function () {
      addToCart(product);
    });
  });

  cartList.addEventListener("click", function (event) {
    const increaseId = event.target.getAttribute("data-increase");
    const decreaseId = event.target.getAttribute("data-decrease");
    const removeId = event.target.getAttribute("data-remove");

    if (increaseId) changeQuantity(increaseId, 1);
    if (decreaseId) changeQuantity(decreaseId, -1);
    if (removeId) removeItem(removeId);
  });

  clearButton.addEventListener("click", function () {
    cart = [];
    localStorage.removeItem(storageKey);
    renderCart();
  });

  loadCart();
  renderCart();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-twentytwo-demo"&gt;
  &lt;div class="vb-storage-twentytwo-shop" data-vb-storage-twentytwo&gt;
    &lt;div class="vb-storage-twentytwo-head"&gt;
      &lt;span class="vb-storage-twentytwo-kicker"&gt;Example 22&lt;/span&gt;
      &lt;h3&gt;Saved Shopping Cart&lt;/h3&gt;
      &lt;p&gt;Add products to the cart, refresh the page, and localStorage restores the full cart with quantities.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-twentytwo-layout"&gt;
      &lt;div class="vb-storage-twentytwo-products"&gt;
        &lt;article data-product-id="template" data-product-name="Website Template" data-product-price="49"&gt;
          &lt;span&gt;WEB&lt;/span&gt;
          &lt;h4&gt;Website Template&lt;/h4&gt;
          &lt;p&gt;Responsive landing page template for a modern website.&lt;/p&gt;
          &lt;strong&gt;49€&lt;/strong&gt;
          &lt;button type="button" data-add-cart&gt;Add to Cart&lt;/button&gt;
        &lt;/article&gt;

        &lt;article data-product-id="plugin" data-product-name="JavaScript Plugin" data-product-price="29"&gt;
          &lt;span&gt;JS&lt;/span&gt;
          &lt;h4&gt;JavaScript Plugin&lt;/h4&gt;
          &lt;p&gt;Small browser feature that saves user actions locally.&lt;/p&gt;
          &lt;strong&gt;29€&lt;/strong&gt;
          &lt;button type="button" data-add-cart&gt;Add to Cart&lt;/button&gt;
        &lt;/article&gt;

        &lt;article data-product-id="audit" data-product-name="SEO Audit" data-product-price="99"&gt;
          &lt;span&gt;SEO&lt;/span&gt;
          &lt;h4&gt;SEO Audit&lt;/h4&gt;
          &lt;p&gt;Technical SEO review for structure, speed, and content.&lt;/p&gt;
          &lt;strong&gt;99€&lt;/strong&gt;
          &lt;button type="button" data-add-cart&gt;Add to Cart&lt;/button&gt;
        &lt;/article&gt;
      &lt;/div&gt;

      &lt;aside class="vb-storage-twentytwo-cart"&gt;
        &lt;div class="vb-storage-twentytwo-cart-head"&gt;
          &lt;strong&gt;Your Cart&lt;/strong&gt;
          &lt;span data-cart-count&gt;0 items&lt;/span&gt;
        &lt;/div&gt;

        &lt;div class="vb-storage-twentytwo-cart-list" data-cart-list&gt;
          &lt;p class="vb-storage-twentytwo-empty"&gt;Your cart is empty.&lt;/p&gt;
        &lt;/div&gt;

        &lt;div class="vb-storage-twentytwo-total"&gt;
          &lt;span&gt;Subtotal&lt;/span&gt;
          &lt;strong data-cart-total&gt;0€&lt;/strong&gt;
        &lt;/div&gt;

        &lt;button type="button" data-clear-cart&gt;Clear Cart&lt;/button&gt;
      &lt;/aside&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-twentytwo-demo,
.vb-storage-twentytwo-demo * {
  box-sizing: border-box;
}

.vb-storage-twentytwo-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(16, 185, 129, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #eff6ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(16, 185, 129, 0.18);
  box-shadow: 0 28px 80px rgba(6, 95, 70, 0.10);
}

.vb-storage-twentytwo-shop {
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-twentytwo-head {
  display: grid;
  gap: 12px;
  margin-bottom: 24px;
}

.vb-storage-twentytwo-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-twentytwo-head h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-twentytwo-head p {
  max-width: 780px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-twentytwo-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(320px, 410px);
  gap: 20px;
  align-items: start;
}

.vb-storage-twentytwo-products {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.vb-storage-twentytwo-products article {
  display: grid;
  align-content: start;
  gap: 11px;
  min-height: 280px;
  padding: 18px;
  border-radius: 26px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-storage-twentytwo-products article &gt; span {
  display: grid;
  place-items: center;
  width: 64px;
  height: 64px;
  border-radius: 22px;
  background: linear-gradient(135deg, #10b981, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-storage-twentytwo-products h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 22px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
}

.vb-storage-twentytwo-products p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-storage-twentytwo-products strong {
  margin-top: auto;
  color: #059669 !important;
  -webkit-text-fill-color: #059669 !important;
  font-size: 26px;
  line-height: 1;
  font-weight: 950;
}

.vb-storage-twentytwo-products button,
.vb-storage-twentytwo-cart &gt; button {
  min-height: 44px;
  border: 0;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentytwo-products button {
  background: linear-gradient(135deg, #10b981, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-twentytwo-cart {
  display: grid;
  gap: 14px;
  padding: 18px;
  border-radius: 28px;
  background: #0f172a;
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.24);
}

.vb-storage-twentytwo-cart-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.vb-storage-twentytwo-cart-head strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-storage-twentytwo-cart-head span {
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-storage-twentytwo-cart-list {
  display: grid;
  gap: 10px;
  min-height: 280px;
}

.vb-storage-twentytwo-empty {
  display: grid;
  place-items: center;
  min-height: 280px;
  margin: 0 !important;
  border: 1px dashed rgba(255,255,255,0.22);
  border-radius: 20px;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-twentytwo-cart-item {
  display: grid;
  gap: 10px;
  padding: 12px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-twentytwo-cart-item-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.vb-storage-twentytwo-cart-item strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.25;
  font-weight: 900;
}

.vb-storage-twentytwo-cart-item span {
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-storage-twentytwo-qty {
  display: flex;
  align-items: center;
  gap: 7px;
}

.vb-storage-twentytwo-qty button {
  width: 32px;
  height: 32px;
  border: 0;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentytwo-qty small {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-twentytwo-total {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 16px;
  border-radius: 20px;
  background: rgba(255,255,255,0.10);
}

.vb-storage-twentytwo-total span {
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-storage-twentytwo-total strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px;
  line-height: 1;
  font-weight: 950;
}

.vb-storage-twentytwo-cart &gt; button {
  background: #ffffff;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
}

@media (max-width: 980px) {
  .vb-storage-twentytwo-layout {
    grid-template-columns: 1fr;
  }

  .vb-storage-twentytwo-products {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-storage-twentytwo-products {
    grid-template-columns: 1fr;
  }

  .vb-storage-twentytwo-head h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}</pre>



<p class="wp-block-paragraph">This shopping cart localStorage example is useful for ecommerce demos, WooCommerce-style product pages, digital product shops, checkout prototypes, mini cart features, and JavaScript portfolio projects.</p>



<h2 class="wp-block-heading">23. Form Autosave with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>Form autosave with localStorage</strong> is useful for contact forms, quote request forms, application forms, booking forms, support tickets, long surveys, and checkout flows. It prevents users from losing typed content if they accidentally refresh the page.</p>



<p class="wp-block-paragraph">This example automatically saves form fields while the user types. JavaScript restores the draft from localStorage after refresh, shows a saved status message, and lets the user clear the saved draft when needed.</p>



<ul class="wp-block-list">
<li>Autosave form fields while typing</li>
<li>Restores draft data after refresh</li>
<li>Saves text inputs, select fields, and textarea</li>
<li>Includes clear saved draft button</li>
<li>Useful for contact and quote forms</li>
</ul>



<div class="vb-storage-twentythree-demo">
  <div class="vb-storage-twentythree-formwrap" data-vb-storage-twentythree>
    <div class="vb-storage-twentythree-intro">
      <span class="vb-storage-twentythree-kicker">Example 23</span>
      <h3>Form Autosave Draft</h3>
      <p>Type into the form and refresh the page. localStorage restores the saved draft automatically.</p>

      <div class="vb-storage-twentythree-status" data-draft-status>
        Draft status: ready.
      </div>
    </div>

    <form class="vb-storage-twentythree-form" data-autosave-form>
      <label>
        <span>Your name</span>
        <input type="text" name="name" placeholder="Your name">
      </label>

      <label>
        <span>Email address</span>
        <input type="email" name="email" placeholder="you@example.com">
      </label>

      <label>
        <span>Project type</span>
        <select name="projectType">
          <option value="">Choose project type</option>
          <option value="Website">Website</option>
          <option value="Ecommerce">Ecommerce</option>
          <option value="WordPress Plugin">WordPress Plugin</option>
          <option value="JavaScript Feature">JavaScript Feature</option>
        </select>
      </label>

      <label>
        <span>Project message</span>
        <textarea name="message" rows="6" placeholder="Describe what you need..."></textarea>
      </label>

      <div class="vb-storage-twentythree-actions">
        <button type="submit">Submit Demo</button>
        <button type="button" data-clear-draft>Clear Saved Draft</button>
      </div>
    </form>
  </div>
</div>

<style>
.vb-storage-twentythree-demo,
.vb-storage-twentythree-demo * {
  box-sizing: border-box;
}

.vb-storage-twentythree-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(236, 72, 153, 0.15), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #eef2ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(236, 72, 153, 0.18);
  box-shadow: 0 28px 80px rgba(157, 23, 77, 0.10);
}

.vb-storage-twentythree-formwrap {
  display: grid;
  grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
  gap: 22px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-twentythree-intro,
.vb-storage-twentythree-form {
  min-width: 0;
}

.vb-storage-twentythree-intro {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 28px;
  background: #111827;
}

.vb-storage-twentythree-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(236, 72, 153, 0.16);
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-twentythree-intro h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-twentythree-intro p {
  max-width: 560px;
  margin: 0 0 22px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-twentythree-status {
  padding: 13px 15px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 850;
}

.vb-storage-twentythree-form {
  display: grid;
  gap: 14px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 30px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-twentythree-form label {
  display: grid;
  gap: 7px;
}

.vb-storage-twentythree-form label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-storage-twentythree-form input,
.vb-storage-twentythree-form select,
.vb-storage-twentythree-form textarea {
  width: 100%;
  border: 1px solid rgba(148, 163, 184, 0.34);
  border-radius: 16px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 700;
  outline: none;
}

.vb-storage-twentythree-form input,
.vb-storage-twentythree-form select {
  min-height: 50px;
  padding: 0 15px;
}

.vb-storage-twentythree-form textarea {
  resize: vertical;
  padding: 14px 15px;
  line-height: 1.55;
}

.vb-storage-twentythree-form input:focus,
.vb-storage-twentythree-form select:focus,
.vb-storage-twentythree-form textarea:focus {
  border-color: rgba(236, 72, 153, 0.70);
  box-shadow: 0 0 0 4px rgba(236, 72, 153, 0.10);
}

.vb-storage-twentythree-actions {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 10px;
}

.vb-storage-twentythree-actions button {
  min-height: 48px;
  padding: 0 16px;
  border: 0;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentythree-actions button:first-child {
  background: linear-gradient(135deg, #ec4899, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-twentythree-actions button:last-child {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

@media (max-width: 900px) {
  .vb-storage-twentythree-formwrap {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 580px) {
  .vb-storage-twentythree-actions {
    grid-template-columns: 1fr;
  }

  .vb-storage-twentythree-intro h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-twentythree]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwentythreeFormDraft";
  const form = wrapper.querySelector("[data-autosave-form]");
  const fields = Array.from(form.querySelectorAll("input, select, textarea"));
  const status = wrapper.querySelector("[data-draft-status]");
  const clearButton = wrapper.querySelector("[data-clear-draft]");
  let saveTimer;

  function getDraftData() {
    const data = {};

    fields.forEach(function (field) {
      data[field.name] = field.value;
    });

    return data;
  }

  function saveDraft() {
    localStorage.setItem(storageKey, JSON.stringify(getDraftData()));
    status.textContent = "Draft status: saved at " + new Date().toLocaleTimeString();
  }

  function loadDraft() {
    const savedDraft = localStorage.getItem(storageKey);
    if (!savedDraft) return;

    try {
      const data = JSON.parse(savedDraft);

      fields.forEach(function (field) {
        field.value = data[field.name] || "";
      });

      status.textContent = "Draft status: restored from localStorage.";
    } catch (error) {
      localStorage.removeItem(storageKey);
      status.textContent = "Draft status: saved draft could not be loaded.";
    }
  }

  function scheduleSave() {
    status.textContent = "Draft status: saving...";
    clearTimeout(saveTimer);
    saveTimer = setTimeout(saveDraft, 350);
  }

  fields.forEach(function (field) {
    field.addEventListener("input", scheduleSave);
    field.addEventListener("change", scheduleSave);
  });

  form.addEventListener("submit", function (event) {
    event.preventDefault();
    localStorage.removeItem(storageKey);
    status.textContent = "Demo submitted. Saved draft has been cleared.";
    form.reset();
  });

  clearButton.addEventListener("click", function () {
    localStorage.removeItem(storageKey);
    form.reset();
    status.textContent = "Draft status: cleared.";
  });

  loadDraft();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-twentythree]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwentythreeFormDraft";
  const form = wrapper.querySelector("[data-autosave-form]");
  const fields = Array.from(form.querySelectorAll("input, select, textarea"));
  const status = wrapper.querySelector("[data-draft-status]");
  const clearButton = wrapper.querySelector("[data-clear-draft]");
  let saveTimer;

  function getDraftData() {
    const data = {};

    fields.forEach(function (field) {
      data[field.name] = field.value;
    });

    return data;
  }

  function saveDraft() {
    localStorage.setItem(storageKey, JSON.stringify(getDraftData()));
    status.textContent = "Draft status: saved at " + new Date().toLocaleTimeString();
  }

  function loadDraft() {
    const savedDraft = localStorage.getItem(storageKey);
    if (!savedDraft) return;

    try {
      const data = JSON.parse(savedDraft);

      fields.forEach(function (field) {
        field.value = data[field.name] || "";
      });

      status.textContent = "Draft status: restored from localStorage.";
    } catch (error) {
      localStorage.removeItem(storageKey);
      status.textContent = "Draft status: saved draft could not be loaded.";
    }
  }

  function scheduleSave() {
    status.textContent = "Draft status: saving...";
    clearTimeout(saveTimer);
    saveTimer = setTimeout(saveDraft, 350);
  }

  fields.forEach(function (field) {
    field.addEventListener("input", scheduleSave);
    field.addEventListener("change", scheduleSave);
  });

  form.addEventListener("submit", function (event) {
    event.preventDefault();
    localStorage.removeItem(storageKey);
    status.textContent = "Demo submitted. Saved draft has been cleared.";
    form.reset();
  });

  clearButton.addEventListener("click", function () {
    localStorage.removeItem(storageKey);
    form.reset();
    status.textContent = "Draft status: cleared.";
  });

  loadDraft();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-twentythree-demo"&gt;
  &lt;div class="vb-storage-twentythree-formwrap" data-vb-storage-twentythree&gt;
    &lt;div class="vb-storage-twentythree-intro"&gt;
      &lt;span class="vb-storage-twentythree-kicker"&gt;Example 23&lt;/span&gt;
      &lt;h3&gt;Form Autosave Draft&lt;/h3&gt;
      &lt;p&gt;Type into the form and refresh the page. localStorage restores the saved draft automatically.&lt;/p&gt;

      &lt;div class="vb-storage-twentythree-status" data-draft-status&gt;
        Draft status: ready.
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;form class="vb-storage-twentythree-form" data-autosave-form&gt;
      &lt;label&gt;
        &lt;span&gt;Your name&lt;/span&gt;
        &lt;input type="text" name="name" placeholder="Your name"&gt;
      &lt;/label&gt;

      &lt;label&gt;
        &lt;span&gt;Email address&lt;/span&gt;
        &lt;input type="email" name="email" placeholder="you@example.com"&gt;
      &lt;/label&gt;

      &lt;label&gt;
        &lt;span&gt;Project type&lt;/span&gt;
        &lt;select name="projectType"&gt;
          &lt;option value=""&gt;Choose project type&lt;/option&gt;
          &lt;option value="Website"&gt;Website&lt;/option&gt;
          &lt;option value="Ecommerce"&gt;Ecommerce&lt;/option&gt;
          &lt;option value="WordPress Plugin"&gt;WordPress Plugin&lt;/option&gt;
          &lt;option value="JavaScript Feature"&gt;JavaScript Feature&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;

      &lt;label&gt;
        &lt;span&gt;Project message&lt;/span&gt;
        &lt;textarea name="message" rows="6" placeholder="Describe what you need..."&gt;&lt;/textarea&gt;
      &lt;/label&gt;

      &lt;div class="vb-storage-twentythree-actions"&gt;
        &lt;button type="submit"&gt;Submit Demo&lt;/button&gt;
        &lt;button type="button" data-clear-draft&gt;Clear Saved Draft&lt;/button&gt;
      &lt;/div&gt;
    &lt;/form&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-twentythree-demo,
.vb-storage-twentythree-demo * {
  box-sizing: border-box;
}

.vb-storage-twentythree-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(236, 72, 153, 0.15), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #eef2ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(236, 72, 153, 0.18);
  box-shadow: 0 28px 80px rgba(157, 23, 77, 0.10);
}

.vb-storage-twentythree-formwrap {
  display: grid;
  grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
  gap: 22px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-twentythree-intro,
.vb-storage-twentythree-form {
  min-width: 0;
}

.vb-storage-twentythree-intro {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 28px;
  background: #111827;
}

.vb-storage-twentythree-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(236, 72, 153, 0.16);
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-twentythree-intro h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-twentythree-intro p {
  max-width: 560px;
  margin: 0 0 22px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-twentythree-status {
  padding: 13px 15px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 850;
}

.vb-storage-twentythree-form {
  display: grid;
  gap: 14px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 30px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-twentythree-form label {
  display: grid;
  gap: 7px;
}

.vb-storage-twentythree-form label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-storage-twentythree-form input,
.vb-storage-twentythree-form select,
.vb-storage-twentythree-form textarea {
  width: 100%;
  border: 1px solid rgba(148, 163, 184, 0.34);
  border-radius: 16px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 700;
  outline: none;
}

.vb-storage-twentythree-form input,
.vb-storage-twentythree-form select {
  min-height: 50px;
  padding: 0 15px;
}

.vb-storage-twentythree-form textarea {
  resize: vertical;
  padding: 14px 15px;
  line-height: 1.55;
}

.vb-storage-twentythree-form input:focus,
.vb-storage-twentythree-form select:focus,
.vb-storage-twentythree-form textarea:focus {
  border-color: rgba(236, 72, 153, 0.70);
  box-shadow: 0 0 0 4px rgba(236, 72, 153, 0.10);
}

.vb-storage-twentythree-actions {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 10px;
}

.vb-storage-twentythree-actions button {
  min-height: 48px;
  padding: 0 16px;
  border: 0;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentythree-actions button:first-child {
  background: linear-gradient(135deg, #ec4899, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-twentythree-actions button:last-child {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

@media (max-width: 900px) {
  .vb-storage-twentythree-formwrap {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 580px) {
  .vb-storage-twentythree-actions {
    grid-template-columns: 1fr;
  }

  .vb-storage-twentythree-intro h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}</pre>



<p class="wp-block-paragraph">This form autosave localStorage example is useful for contact forms, quote request forms, application forms, checkout forms, booking forms, support tickets, survey forms, and long lead generation forms.</p>



<h2 class="wp-block-heading">24. Dark Mode Theme Saved with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>Saving dark mode with localStorage</strong> is one of the most searched JavaScript localStorage examples. It is useful for blogs, dashboards, documentation websites, SaaS interfaces, portfolios, admin panels, and modern landing pages.</p>



<p class="wp-block-paragraph">This example toggles between light mode and dark mode. JavaScript saves the selected theme in localStorage, applies the theme instantly with a data attribute, and restores the same theme after refresh.</p>



<ul class="wp-block-list">
<li>Save dark mode preference</li>
<li>Restore theme after refresh</li>
<li>Uses localStorage and data attributes</li>
<li>Includes live UI preview</li>
<li>Useful for blogs, dashboards, and SaaS websites</li>
</ul>



<div class="vb-storage-twentyfour-demo">
  <div class="vb-storage-twentyfour-theme" data-vb-storage-twentyfour data-theme="light">
    <div class="vb-storage-twentyfour-panel">
      <span class="vb-storage-twentyfour-kicker">Example 24</span>
      <h3>Saved Dark Mode Theme</h3>
      <p>Switch between light and dark mode. localStorage remembers your selected theme after refresh.</p>

      <button type="button" data-theme-toggle>
        Toggle Dark Mode
      </button>

      <div class="vb-storage-twentyfour-status" data-theme-status>
        Current theme: light
      </div>
    </div>

    <div class="vb-storage-twentyfour-preview">
      <div class="vb-storage-twentyfour-window">
        <div class="vb-storage-twentyfour-window-top">
          <span></span>
          <span></span>
          <span></span>
        </div>

        <div class="vb-storage-twentyfour-content">
          <strong>Theme Preview</strong>
          <p>This preview changes between light and dark mode using one saved localStorage value.</p>

          <div class="vb-storage-twentyfour-cards">
            <div>
              <span>Readability</span>
              <strong>High</strong>
            </div>
            <div>
              <span>Saved</span>
              <strong>Yes</strong>
            </div>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-storage-twentyfour-demo,
.vb-storage-twentyfour-demo * {
  box-sizing: border-box;
}

.vb-storage-twentyfour-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(15, 23, 42, 0.14), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #eef2ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(15, 23, 42, 0.12);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-storage-twentyfour-theme {
  display: grid;
  grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
  gap: 22px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
  transition: background 0.25s ease, border-color 0.25s ease;
}

.vb-storage-twentyfour-theme[data-theme="dark"] {
  background: #020617;
  border-color: rgba(255,255,255,0.10);
}

.vb-storage-twentyfour-panel,
.vb-storage-twentyfour-preview {
  min-width: 0;
}

.vb-storage-twentyfour-panel {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 28px;
  background: #0f172a;
}

.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-panel {
  background: #111827;
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-storage-twentyfour-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(129, 140, 248, 0.18);
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-twentyfour-panel h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-twentyfour-panel p {
  max-width: 560px;
  margin: 0 0 22px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-twentyfour-panel button {
  align-self: flex-start;
  min-height: 50px;
  padding: 0 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #6366f1, #0ea5e9);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentyfour-status {
  align-self: flex-start;
  margin-top: 14px;
  padding: 12px 14px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-storage-twentyfour-preview {
  display: grid;
  place-items: center;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 28px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
  transition: background 0.25s ease, border-color 0.25s ease;
}

.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-preview {
  background: #0f172a;
  border-color: rgba(255,255,255,0.10);
}

.vb-storage-twentyfour-window {
  width: 100%;
  max-width: 560px;
  overflow: hidden;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 22px 60px rgba(15, 23, 42, 0.12);
  transition: background 0.25s ease, border-color 0.25s ease;
}

.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-window {
  background: #020617;
  border-color: rgba(255,255,255,0.12);
}

.vb-storage-twentyfour-window-top {
  display: flex;
  gap: 8px;
  padding: 16px;
  background: #f1f5f9;
  border-bottom: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-window-top {
  background: #111827;
  border-bottom-color: rgba(255,255,255,0.10);
}

.vb-storage-twentyfour-window-top span {
  width: 12px;
  height: 12px;
  border-radius: 999px;
  background: #f87171;
}

.vb-storage-twentyfour-window-top span:nth-child(2) {
  background: #fbbf24;
}

.vb-storage-twentyfour-window-top span:nth-child(3) {
  background: #34d399;
}

.vb-storage-twentyfour-content {
  display: grid;
  gap: 16px;
  padding: clamp(24px, 5vw, 46px);
}

.vb-storage-twentyfour-content > strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 54px);
  line-height: 0.96;
  font-weight: 950;
  letter-spacing: -0.07em;
}

.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-content > strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-twentyfour-content p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-content p {
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
}

.vb-storage-twentyfour-cards {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-storage-twentyfour-cards div {
  padding: 16px;
  border-radius: 20px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-cards div {
  background: #111827;
  border-color: rgba(255,255,255,0.10);
}

.vb-storage-twentyfour-cards span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-cards span {
  color: #94a3b8 !important;
  -webkit-text-fill-color: #94a3b8 !important;
}

.vb-storage-twentyfour-cards strong {
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 22px;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vb-storage-twentyfour-theme {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-storage-twentyfour-panel h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }

  .vb-storage-twentyfour-panel button {
    width: 100%;
  }

  .vb-storage-twentyfour-cards {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-twentyfour]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwentyfourTheme";
  const toggleButton = wrapper.querySelector("[data-theme-toggle]");
  const status = wrapper.querySelector("[data-theme-status]");

  function applyTheme(theme) {
    wrapper.setAttribute("data-theme", theme);
    localStorage.setItem(storageKey, theme);
    status.textContent = "Current theme: " + theme;
    toggleButton.textContent = theme === "dark" ? "Switch to Light Mode" : "Switch to Dark Mode";
  }

  toggleButton.addEventListener("click", function () {
    const currentTheme = wrapper.getAttribute("data-theme");
    applyTheme(currentTheme === "dark" ? "light" : "dark");
  });

  applyTheme(localStorage.getItem(storageKey) || "light");
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-twentyfour]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwentyfourTheme";
  const toggleButton = wrapper.querySelector("[data-theme-toggle]");
  const status = wrapper.querySelector("[data-theme-status]");

  function applyTheme(theme) {
    wrapper.setAttribute("data-theme", theme);
    localStorage.setItem(storageKey, theme);
    status.textContent = "Current theme: " + theme;
    toggleButton.textContent = theme === "dark" ? "Switch to Light Mode" : "Switch to Dark Mode";
  }

  toggleButton.addEventListener("click", function () {
    const currentTheme = wrapper.getAttribute("data-theme");
    applyTheme(currentTheme === "dark" ? "light" : "dark");
  });

  applyTheme(localStorage.getItem(storageKey) || "light");
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-twentyfour-demo"&gt;
  &lt;div class="vb-storage-twentyfour-theme" data-vb-storage-twentyfour data-theme="light"&gt;
    &lt;div class="vb-storage-twentyfour-panel"&gt;
      &lt;span class="vb-storage-twentyfour-kicker"&gt;Example 24&lt;/span&gt;
      &lt;h3&gt;Saved Dark Mode Theme&lt;/h3&gt;
      &lt;p&gt;Switch between light and dark mode. localStorage remembers your selected theme after refresh.&lt;/p&gt;

      &lt;button type="button" data-theme-toggle&gt;
        Toggle Dark Mode
      &lt;/button&gt;

      &lt;div class="vb-storage-twentyfour-status" data-theme-status&gt;
        Current theme: light
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-twentyfour-preview"&gt;
      &lt;div class="vb-storage-twentyfour-window"&gt;
        &lt;div class="vb-storage-twentyfour-window-top"&gt;
          &lt;span&gt;&lt;/span&gt;
          &lt;span&gt;&lt;/span&gt;
          &lt;span&gt;&lt;/span&gt;
        &lt;/div&gt;

        &lt;div class="vb-storage-twentyfour-content"&gt;
          &lt;strong&gt;Theme Preview&lt;/strong&gt;
          &lt;p&gt;This preview changes between light and dark mode using one saved localStorage value.&lt;/p&gt;

          &lt;div class="vb-storage-twentyfour-cards"&gt;
            &lt;div&gt;
              &lt;span&gt;Readability&lt;/span&gt;
              &lt;strong&gt;High&lt;/strong&gt;
            &lt;/div&gt;
            &lt;div&gt;
              &lt;span&gt;Saved&lt;/span&gt;
              &lt;strong&gt;Yes&lt;/strong&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-twentyfour-demo,
.vb-storage-twentyfour-demo * {
  box-sizing: border-box;
}

.vb-storage-twentyfour-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(15, 23, 42, 0.14), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #eef2ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(15, 23, 42, 0.12);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-storage-twentyfour-theme {
  display: grid;
  grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
  gap: 22px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
  transition: background 0.25s ease, border-color 0.25s ease;
}

.vb-storage-twentyfour-theme[data-theme="dark"] {
  background: #020617;
  border-color: rgba(255,255,255,0.10);
}

.vb-storage-twentyfour-panel,
.vb-storage-twentyfour-preview {
  min-width: 0;
}

.vb-storage-twentyfour-panel {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 28px;
  background: #0f172a;
}

.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-panel {
  background: #111827;
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-storage-twentyfour-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(129, 140, 248, 0.18);
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-twentyfour-panel h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-twentyfour-panel p {
  max-width: 560px;
  margin: 0 0 22px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-twentyfour-panel button {
  align-self: flex-start;
  min-height: 50px;
  padding: 0 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #6366f1, #0ea5e9);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentyfour-status {
  align-self: flex-start;
  margin-top: 14px;
  padding: 12px 14px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-storage-twentyfour-preview {
  display: grid;
  place-items: center;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 28px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
  transition: background 0.25s ease, border-color 0.25s ease;
}

.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-preview {
  background: #0f172a;
  border-color: rgba(255,255,255,0.10);
}

.vb-storage-twentyfour-window {
  width: 100%;
  max-width: 560px;
  overflow: hidden;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 22px 60px rgba(15, 23, 42, 0.12);
  transition: background 0.25s ease, border-color 0.25s ease;
}

.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-window {
  background: #020617;
  border-color: rgba(255,255,255,0.12);
}

.vb-storage-twentyfour-window-top {
  display: flex;
  gap: 8px;
  padding: 16px;
  background: #f1f5f9;
  border-bottom: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-window-top {
  background: #111827;
  border-bottom-color: rgba(255,255,255,0.10);
}

.vb-storage-twentyfour-window-top span {
  width: 12px;
  height: 12px;
  border-radius: 999px;
  background: #f87171;
}

.vb-storage-twentyfour-window-top span:nth-child(2) {
  background: #fbbf24;
}

.vb-storage-twentyfour-window-top span:nth-child(3) {
  background: #34d399;
}

.vb-storage-twentyfour-content {
  display: grid;
  gap: 16px;
  padding: clamp(24px, 5vw, 46px);
}

.vb-storage-twentyfour-content &gt; strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 54px);
  line-height: 0.96;
  font-weight: 950;
  letter-spacing: -0.07em;
}

.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-content &gt; strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-twentyfour-content p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-content p {
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
}

.vb-storage-twentyfour-cards {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-storage-twentyfour-cards div {
  padding: 16px;
  border-radius: 20px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-cards div {
  background: #111827;
  border-color: rgba(255,255,255,0.10);
}

.vb-storage-twentyfour-cards span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-storage-twentyfour-theme[data-theme="dark"] .vb-storage-twentyfour-cards span {
  color: #94a3b8 !important;
  -webkit-text-fill-color: #94a3b8 !important;
}

.vb-storage-twentyfour-cards strong {
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 22px;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vb-storage-twentyfour-theme {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-storage-twentyfour-panel h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }

  .vb-storage-twentyfour-panel button {
    width: 100%;
  }

  .vb-storage-twentyfour-cards {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This dark mode localStorage example is useful for blogs, dashboards, SaaS interfaces, documentation websites, admin panels, user portals, portfolio websites, and modern JavaScript UI preference features.</p>



<div class="vb24-service-cta-box">
  <div class="vb24-service-cta-content">
    <span>Need this on your website?</span>
    <h3>Can’t build it yourself? We can create it for you.</h3>
    <p>If you like these JavaScript localStorage features but want a custom version for your website, landing page, ecommerce store, or WordPress project, contact us and tell us what you need.</p>
  </div>

  <a class="vb24-service-cta-button" href="https://veebilehed24.ee/en/contact-us/">Contact Us</a>
</div>

<style>
.vb24-service-cta-box,
.vb24-service-cta-box * {
  box-sizing: border-box;
}

.vb24-service-cta-box {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 22px;
  margin: 34px 0;
  padding: clamp(20px, 3vw, 28px);
  border: 1px solid rgba(148, 163, 184, 0.24);
  border-radius: 26px;
  background:
    radial-gradient(circle at 10% 20%, rgba(37, 99, 235, 0.10), transparent 32%),
    linear-gradient(135deg, #ffffff 0%, #f8fafc 100%) !important;
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb24-service-cta-content {
  min-width: 0;
}

.vb24-service-cta-content span {
  display: inline-flex;
  margin-bottom: 8px;
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb24-service-cta-content h3 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(22px, 3vw, 32px) !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb24-service-cta-content p {
  max-width: 760px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb24-service-cta-button {
  display: inline-flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  text-decoration: none !important;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.22);
}

.vb24-service-cta-button:hover {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transform: translateY(-2px);
}

@media (max-width: 720px) {
  .vb24-service-cta-box {
    align-items: stretch;
    flex-direction: column;
  }

  .vb24-service-cta-button {
    width: 100%;
  }
}
</style>



<h2 class="wp-block-heading">25. Recent Searches Saved with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>Recent searches saved with localStorage</strong> are useful for search bars, ecommerce stores, documentation websites, blog search pages, SaaS dashboards, help centers, and directory websites. It helps users quickly repeat previous searches without needing a backend account system.</p>



<p class="wp-block-paragraph">This example saves submitted search terms into localStorage, displays the latest searches as clickable chips, restores them after refresh, and allows users to remove individual searches or clear the full history.</p>



<ul class="wp-block-list">
<li>Save recent search terms</li>
<li>Restore search history after refresh</li>
<li>Click recent searches to reuse them</li>
<li>Remove single search terms</li>
<li>Useful for ecommerce, blogs, and help centers</li>
</ul>



<div class="vb-storage-twentyfive-demo">
  <div class="vb-storage-twentyfive-search" data-vb-storage-twentyfive>
    <div class="vb-storage-twentyfive-head">
      <span class="vb-storage-twentyfive-kicker">Example 25</span>
      <h3>Saved Recent Searches</h3>
      <p>Search for something, refresh the page, and localStorage keeps your recent search history.</p>
    </div>

    <form class="vb-storage-twentyfive-form" data-search-form>
      <input type="search" data-search-input placeholder="Search tutorials, products, docs...">
      <button type="submit">Search</button>
    </form>

    <div class="vb-storage-twentyfive-current">
      <span>Current search</span>
      <strong data-current-search>No search yet</strong>
    </div>

    <div class="vb-storage-twentyfive-history">
      <div class="vb-storage-twentyfive-history-head">
        <strong>Recent Searches</strong>
        <button type="button" data-clear-searches>Clear All</button>
      </div>

      <div class="vb-storage-twentyfive-list" data-search-list>
        <p class="vb-storage-twentyfive-empty">No recent searches saved yet.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-storage-twentyfive-demo,
.vb-storage-twentyfive-demo * {
  box-sizing: border-box;
}

.vb-storage-twentyfive-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(14, 165, 233, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(34, 197, 94, 0.14), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #f0fdf4 56%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  box-shadow: 0 28px 80px rgba(12, 74, 110, 0.10);
}

.vb-storage-twentyfive-search {
  max-width: 980px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #0f172a;
  box-shadow: 0 28px 90px rgba(15, 23, 42, 0.30);
}

.vb-storage-twentyfive-head {
  display: grid;
  gap: 12px;
  margin-bottom: 22px;
}

.vb-storage-twentyfive-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(14, 165, 233, 0.16);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-twentyfive-head h3 {
  max-width: 780px;
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-twentyfive-head p {
  max-width: 760px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-twentyfive-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  margin-bottom: 16px;
  padding: 14px;
  border-radius: 24px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-twentyfive-form input {
  min-width: 0;
  min-height: 52px;
  padding: 0 16px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-storage-twentyfive-form input::placeholder {
  color: #9ca3af;
  -webkit-text-fill-color: #9ca3af;
}

.vb-storage-twentyfive-form input:focus {
  border-color: rgba(14, 165, 233, 0.72);
  box-shadow: 0 0 0 4px rgba(14, 165, 233, 0.12);
}

.vb-storage-twentyfive-form button {
  min-height: 52px;
  padding: 0 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #0ea5e9, #22c55e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentyfive-current {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  margin-bottom: 16px;
  padding: 15px;
  border-radius: 20px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-twentyfive-current span {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-storage-twentyfive-current strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-storage-twentyfive-history {
  display: grid;
  gap: 14px;
  padding: 18px;
  border-radius: 28px;
  background: #ffffff;
}

.vb-storage-twentyfive-history-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}

.vb-storage-twentyfive-history-head strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-storage-twentyfive-history-head button {
  min-height: 38px;
  padding: 0 13px;
  border: 0;
  border-radius: 999px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentyfive-list {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  min-height: 150px;
  align-content: flex-start;
}

.vb-storage-twentyfive-empty {
  display: grid;
  place-items: center;
  width: 100%;
  min-height: 150px;
  margin: 0 !important;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  border-radius: 20px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-twentyfive-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 42px;
  padding: 8px 10px 8px 14px;
  border-radius: 999px;
  background: #f0f9ff;
  border: 1px solid rgba(14, 165, 233, 0.20);
}

.vb-storage-twentyfive-chip button:first-child {
  border: 0;
  background: transparent;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 13px;
  font-weight: 900;
  cursor: pointer;
}

.vb-storage-twentyfive-chip button:last-child {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border: 0;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

@media (max-width: 640px) {
  .vb-storage-twentyfive-form {
    grid-template-columns: 1fr;
  }

  .vb-storage-twentyfive-head h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-twentyfive]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwentyfiveRecentSearches";
  const form = wrapper.querySelector("[data-search-form]");
  const input = wrapper.querySelector("[data-search-input]");
  const searchList = wrapper.querySelector("[data-search-list]");
  const currentSearch = wrapper.querySelector("[data-current-search]");
  const clearButton = wrapper.querySelector("[data-clear-searches]");

  let searches = [];

  function saveSearches() {
    localStorage.setItem(storageKey, JSON.stringify(searches));
  }

  function loadSearches() {
    const savedSearches = localStorage.getItem(storageKey);
    if (!savedSearches) return;

    try {
      const parsedSearches = JSON.parse(savedSearches);
      searches = Array.isArray(parsedSearches) ? parsedSearches : [];
    } catch (error) {
      searches = [];
      localStorage.removeItem(storageKey);
    }
  }

  function renderSearches() {
    searchList.innerHTML = "";

    if (searches.length === 0) {
      searchList.innerHTML = '<p class="vb-storage-twentyfive-empty">No recent searches saved yet.</p>';
      return;
    }

    searches.forEach(function (term) {
      const chip = document.createElement("div");
      chip.className = "vb-storage-twentyfive-chip";

      chip.innerHTML =
        '<button type="button" data-use-search="' + term + '">' + term + '</button>' +
        '<button type="button" data-remove-search="' + term + '">×</button>';

      searchList.appendChild(chip);
    });
  }

  function addSearch(term) {
    const cleanTerm = term.trim();
    if (!cleanTerm) return;

    searches = searches.filter(function (item) {
      return item.toLowerCase() !== cleanTerm.toLowerCase();
    });

    searches.unshift(cleanTerm);
    searches = searches.slice(0, 8);
    currentSearch.textContent = cleanTerm;
    input.value = cleanTerm;

    saveSearches();
    renderSearches();
  }

  form.addEventListener("submit", function (event) {
    event.preventDefault();
    addSearch(input.value);
  });

  searchList.addEventListener("click", function (event) {
    const useSearch = event.target.getAttribute("data-use-search");
    const removeSearch = event.target.getAttribute("data-remove-search");

    if (useSearch) {
      currentSearch.textContent = useSearch;
      input.value = useSearch;
    }

    if (removeSearch) {
      searches = searches.filter(function (item) {
        return item !== removeSearch;
      });

      saveSearches();
      renderSearches();
    }
  });

  clearButton.addEventListener("click", function () {
    searches = [];
    localStorage.removeItem(storageKey);
    currentSearch.textContent = "No search yet";
    input.value = "";
    renderSearches();
  });

  loadSearches();
  renderSearches();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-twentyfive]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwentyfiveRecentSearches";
  const form = wrapper.querySelector("[data-search-form]");
  const input = wrapper.querySelector("[data-search-input]");
  const searchList = wrapper.querySelector("[data-search-list]");
  const currentSearch = wrapper.querySelector("[data-current-search]");
  const clearButton = wrapper.querySelector("[data-clear-searches]");

  let searches = [];

  function saveSearches() {
    localStorage.setItem(storageKey, JSON.stringify(searches));
  }

  function loadSearches() {
    const savedSearches = localStorage.getItem(storageKey);
    if (!savedSearches) return;

    try {
      const parsedSearches = JSON.parse(savedSearches);
      searches = Array.isArray(parsedSearches) ? parsedSearches : [];
    } catch (error) {
      searches = [];
      localStorage.removeItem(storageKey);
    }
  }

  function renderSearches() {
    searchList.innerHTML = "";

    if (searches.length === 0) {
      searchList.innerHTML = '&lt;p class="vb-storage-twentyfive-empty"&gt;No recent searches saved yet.&lt;/p&gt;';
      return;
    }

    searches.forEach(function (term) {
      const chip = document.createElement("div");
      chip.className = "vb-storage-twentyfive-chip";

      chip.innerHTML =
        '&lt;button type="button" data-use-search="' + term + '"&gt;' + term + '&lt;/button&gt;' +
        '&lt;button type="button" data-remove-search="' + term + '"&gt;×&lt;/button&gt;';

      searchList.appendChild(chip);
    });
  }

  function addSearch(term) {
    const cleanTerm = term.trim();
    if (!cleanTerm) return;

    searches = searches.filter(function (item) {
      return item.toLowerCase() !== cleanTerm.toLowerCase();
    });

    searches.unshift(cleanTerm);
    searches = searches.slice(0, 8);
    currentSearch.textContent = cleanTerm;
    input.value = cleanTerm;

    saveSearches();
    renderSearches();
  }

  form.addEventListener("submit", function (event) {
    event.preventDefault();
    addSearch(input.value);
  });

  searchList.addEventListener("click", function (event) {
    const useSearch = event.target.getAttribute("data-use-search");
    const removeSearch = event.target.getAttribute("data-remove-search");

    if (useSearch) {
      currentSearch.textContent = useSearch;
      input.value = useSearch;
    }

    if (removeSearch) {
      searches = searches.filter(function (item) {
        return item !== removeSearch;
      });

      saveSearches();
      renderSearches();
    }
  });

  clearButton.addEventListener("click", function () {
    searches = [];
    localStorage.removeItem(storageKey);
    currentSearch.textContent = "No search yet";
    input.value = "";
    renderSearches();
  });

  loadSearches();
  renderSearches();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-twentyfive-demo"&gt;
  &lt;div class="vb-storage-twentyfive-search" data-vb-storage-twentyfive&gt;
    &lt;div class="vb-storage-twentyfive-head"&gt;
      &lt;span class="vb-storage-twentyfive-kicker"&gt;Example 25&lt;/span&gt;
      &lt;h3&gt;Saved Recent Searches&lt;/h3&gt;
      &lt;p&gt;Search for something, refresh the page, and localStorage keeps your recent search history.&lt;/p&gt;
    &lt;/div&gt;

    &lt;form class="vb-storage-twentyfive-form" data-search-form&gt;
      &lt;input type="search" data-search-input placeholder="Search tutorials, products, docs..."&gt;
      &lt;button type="submit"&gt;Search&lt;/button&gt;
    &lt;/form&gt;

    &lt;div class="vb-storage-twentyfive-current"&gt;
      &lt;span&gt;Current search&lt;/span&gt;
      &lt;strong data-current-search&gt;No search yet&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-twentyfive-history"&gt;
      &lt;div class="vb-storage-twentyfive-history-head"&gt;
        &lt;strong&gt;Recent Searches&lt;/strong&gt;
        &lt;button type="button" data-clear-searches&gt;Clear All&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-twentyfive-list" data-search-list&gt;
        &lt;p class="vb-storage-twentyfive-empty"&gt;No recent searches saved yet.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-twentyfive-demo,
.vb-storage-twentyfive-demo * {
  box-sizing: border-box;
}

.vb-storage-twentyfive-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(14, 165, 233, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(34, 197, 94, 0.14), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #f0fdf4 56%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  box-shadow: 0 28px 80px rgba(12, 74, 110, 0.10);
}

.vb-storage-twentyfive-search {
  max-width: 980px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #0f172a;
  box-shadow: 0 28px 90px rgba(15, 23, 42, 0.30);
}

.vb-storage-twentyfive-head {
  display: grid;
  gap: 12px;
  margin-bottom: 22px;
}

.vb-storage-twentyfive-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(14, 165, 233, 0.16);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-twentyfive-head h3 {
  max-width: 780px;
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-twentyfive-head p {
  max-width: 760px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-twentyfive-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  margin-bottom: 16px;
  padding: 14px;
  border-radius: 24px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-twentyfive-form input {
  min-width: 0;
  min-height: 52px;
  padding: 0 16px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-storage-twentyfive-form input::placeholder {
  color: #9ca3af;
  -webkit-text-fill-color: #9ca3af;
}

.vb-storage-twentyfive-form input:focus {
  border-color: rgba(14, 165, 233, 0.72);
  box-shadow: 0 0 0 4px rgba(14, 165, 233, 0.12);
}

.vb-storage-twentyfive-form button {
  min-height: 52px;
  padding: 0 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #0ea5e9, #22c55e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentyfive-current {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
  margin-bottom: 16px;
  padding: 15px;
  border-radius: 20px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-twentyfive-current span {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-storage-twentyfive-current strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-storage-twentyfive-history {
  display: grid;
  gap: 14px;
  padding: 18px;
  border-radius: 28px;
  background: #ffffff;
}

.vb-storage-twentyfive-history-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}

.vb-storage-twentyfive-history-head strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-storage-twentyfive-history-head button {
  min-height: 38px;
  padding: 0 13px;
  border: 0;
  border-radius: 999px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentyfive-list {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  min-height: 150px;
  align-content: flex-start;
}

.vb-storage-twentyfive-empty {
  display: grid;
  place-items: center;
  width: 100%;
  min-height: 150px;
  margin: 0 !important;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  border-radius: 20px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-twentyfive-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 42px;
  padding: 8px 10px 8px 14px;
  border-radius: 999px;
  background: #f0f9ff;
  border: 1px solid rgba(14, 165, 233, 0.20);
}

.vb-storage-twentyfive-chip button:first-child {
  border: 0;
  background: transparent;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 13px;
  font-weight: 900;
  cursor: pointer;
}

.vb-storage-twentyfive-chip button:last-child {
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border: 0;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

@media (max-width: 640px) {
  .vb-storage-twentyfive-form {
    grid-template-columns: 1fr;
  }

  .vb-storage-twentyfive-head h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}</pre>



<p class="wp-block-paragraph">This recent searches localStorage example is useful for ecommerce search bars, blog search pages, documentation websites, SaaS dashboards, help centers, directory websites, and product finder interfaces.</p>



<h2 class="wp-block-heading">26. Recently Viewed Products Saved with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>Recently viewed products saved with localStorage</strong> are useful for ecommerce stores, WooCommerce product pages, affiliate websites, marketplaces, real estate listings, booking platforms, and product recommendation sections. It helps visitors return to items they already explored.</p>



<p class="wp-block-paragraph">This example lets users click product cards to mark them as viewed. JavaScript saves recently viewed products in localStorage, displays them in a separate panel, avoids duplicates, and restores the same list after refresh.</p>



<ul class="wp-block-list">
<li>Save recently viewed products</li>
<li>Restore product history after refresh</li>
<li>Avoid duplicate viewed items</li>
<li>Show latest viewed items first</li>
<li>Useful for ecommerce and affiliate websites</li>
</ul>



<div class="vb-storage-twentysix-demo">
  <div class="vb-storage-twentysix-wrap" data-vb-storage-twentysix>
    <div class="vb-storage-twentysix-head">
      <span class="vb-storage-twentysix-kicker">Example 26</span>
      <h3>Recently Viewed Products</h3>
      <p>Click product cards to add them to the viewed list. Refresh the page and your viewed products stay saved.</p>
    </div>

    <div class="vb-storage-twentysix-layout">
      <div class="vb-storage-twentysix-products">
        <article data-product data-id="hosting" data-name="Cloud Hosting" data-price="29€" data-icon="CH">
          <span>CH</span>
          <h4>Cloud Hosting</h4>
          <p>Fast hosting package for business websites.</p>
          <strong>29€</strong>
          <button type="button" data-view-product>View Product</button>
        </article>

        <article data-product data-id="audit" data-name="SEO Audit" data-price="99€" data-icon="SEO">
          <span>SEO</span>
          <h4>SEO Audit</h4>
          <p>Technical review for rankings and structure.</p>
          <strong>99€</strong>
          <button type="button" data-view-product>View Product</button>
        </article>

        <article data-product data-id="plugin" data-name="Custom Plugin" data-price="399€" data-icon="WP">
          <span>WP</span>
          <h4>Custom Plugin</h4>
          <p>WordPress plugin built for custom workflows.</p>
          <strong>399€</strong>
          <button type="button" data-view-product>View Product</button>
        </article>

        <article data-product data-id="landing" data-name="Landing Page" data-price="249€" data-icon="UI">
          <span>UI</span>
          <h4>Landing Page</h4>
          <p>Modern responsive sales page section.</p>
          <strong>249€</strong>
          <button type="button" data-view-product>View Product</button>
        </article>
      </div>

      <aside class="vb-storage-twentysix-panel">
        <div class="vb-storage-twentysix-panel-head">
          <strong>Viewed Products</strong>
          <button type="button" data-clear-viewed>Clear</button>
        </div>

        <div class="vb-storage-twentysix-list" data-viewed-list>
          <p class="vb-storage-twentysix-empty">No viewed products yet.</p>
        </div>
      </aside>
    </div>
  </div>
</div>

<style>
.vb-storage-twentysix-demo,
.vb-storage-twentysix-demo * {
  box-sizing: border-box;
}

.vb-storage-twentysix-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(168, 85, 247, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(236, 72, 153, 0.14), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #fdf2f8 56%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.18);
  box-shadow: 0 28px 80px rgba(88, 28, 135, 0.10);
}

.vb-storage-twentysix-wrap {
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-twentysix-head {
  display: grid;
  gap: 12px;
  margin-bottom: 24px;
}

.vb-storage-twentysix-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-twentysix-head h3 {
  max-width: 820px;
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-twentysix-head p {
  max-width: 780px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-twentysix-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(320px, 390px);
  gap: 20px;
  align-items: start;
}

.vb-storage-twentysix-products {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-storage-twentysix-products article {
  display: grid;
  align-content: start;
  gap: 11px;
  min-height: 260px;
  padding: 18px;
  border-radius: 26px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-storage-twentysix-products article.is-viewed {
  border-color: rgba(168, 85, 247, 0.55);
  background: linear-gradient(135deg, #faf5ff, #ffffff) !important;
}

.vb-storage-twentysix-products article > span {
  display: grid;
  place-items: center;
  width: 66px;
  height: 66px;
  border-radius: 22px;
  background: linear-gradient(135deg, #a855f7, #ec4899);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-storage-twentysix-products h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 23px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
}

.vb-storage-twentysix-products p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-storage-twentysix-products strong {
  margin-top: auto;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 26px;
  line-height: 1;
  font-weight: 950;
}

.vb-storage-twentysix-products button {
  min-height: 44px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #a855f7, #ec4899);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentysix-panel {
  display: grid;
  gap: 14px;
  padding: 18px;
  border-radius: 28px;
  background: #111827;
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.24);
}

.vb-storage-twentysix-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.vb-storage-twentysix-panel-head strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-storage-twentysix-panel-head button {
  min-height: 38px;
  padding: 0 13px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentysix-list {
  display: grid;
  gap: 10px;
  min-height: 320px;
}

.vb-storage-twentysix-empty {
  display: grid;
  place-items: center;
  min-height: 320px;
  margin: 0 !important;
  border: 1px dashed rgba(255,255,255,0.22);
  border-radius: 20px;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-twentysix-viewed {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 12px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-twentysix-viewed span {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border-radius: 16px;
  background: linear-gradient(135deg, #a855f7, #ec4899);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-twentysix-viewed strong {
  display: block;
  margin-bottom: 4px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.25;
  font-weight: 900;
}

.vb-storage-twentysix-viewed small {
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 12px;
  font-weight: 850;
}

@media (max-width: 940px) {
  .vb-storage-twentysix-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-storage-twentysix-products {
    grid-template-columns: 1fr;
  }

  .vb-storage-twentysix-head h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-twentysix]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwentysixViewedProducts";
  const products = Array.from(wrapper.querySelectorAll("[data-product]"));
  const viewedList = wrapper.querySelector("[data-viewed-list]");
  const clearButton = wrapper.querySelector("[data-clear-viewed]");

  let viewedProducts = [];

  function saveViewedProducts() {
    localStorage.setItem(storageKey, JSON.stringify(viewedProducts));
  }

  function loadViewedProducts() {
    const savedProducts = localStorage.getItem(storageKey);
    if (!savedProducts) return;

    try {
      const parsedProducts = JSON.parse(savedProducts);
      viewedProducts = Array.isArray(parsedProducts) ? parsedProducts : [];
    } catch (error) {
      viewedProducts = [];
      localStorage.removeItem(storageKey);
    }
  }

  function getProductData(product) {
    return {
      id: product.getAttribute("data-id"),
      name: product.getAttribute("data-name"),
      price: product.getAttribute("data-price"),
      icon: product.getAttribute("data-icon")
    };
  }

  function renderViewedProducts() {
    viewedList.innerHTML = "";

    products.forEach(function (product) {
      const productId = product.getAttribute("data-id");
      const isViewed = viewedProducts.some(function (item) {
        return item.id === productId;
      });

      product.classList.toggle("is-viewed", isViewed);
    });

    if (viewedProducts.length === 0) {
      viewedList.innerHTML = '<p class="vb-storage-twentysix-empty">No viewed products yet.</p>';
      return;
    }

    viewedProducts.forEach(function (product) {
      const item = document.createElement("div");
      item.className = "vb-storage-twentysix-viewed";

      item.innerHTML =
        '<span>' + product.icon + '</span>' +
        '<div>' +
          '<strong>' + product.name + '</strong>' +
          '<small>' + product.price + '</small>' +
        '</div>';

      viewedList.appendChild(item);
    });
  }

  function addViewedProduct(product) {
    const productData = getProductData(product);

    viewedProducts = viewedProducts.filter(function (item) {
      return item.id !== productData.id;
    });

    viewedProducts.unshift(productData);
    viewedProducts = viewedProducts.slice(0, 5);

    saveViewedProducts();
    renderViewedProducts();
  }

  products.forEach(function (product) {
    product.querySelector("[data-view-product]").addEventListener("click", function () {
      addViewedProduct(product);
    });
  });

  clearButton.addEventListener("click", function () {
    viewedProducts = [];
    localStorage.removeItem(storageKey);
    renderViewedProducts();
  });

  loadViewedProducts();
  renderViewedProducts();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-twentysix]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwentysixViewedProducts";
  const products = Array.from(wrapper.querySelectorAll("[data-product]"));
  const viewedList = wrapper.querySelector("[data-viewed-list]");
  const clearButton = wrapper.querySelector("[data-clear-viewed]");

  let viewedProducts = [];

  function saveViewedProducts() {
    localStorage.setItem(storageKey, JSON.stringify(viewedProducts));
  }

  function loadViewedProducts() {
    const savedProducts = localStorage.getItem(storageKey);
    if (!savedProducts) return;

    try {
      const parsedProducts = JSON.parse(savedProducts);
      viewedProducts = Array.isArray(parsedProducts) ? parsedProducts : [];
    } catch (error) {
      viewedProducts = [];
      localStorage.removeItem(storageKey);
    }
  }

  function getProductData(product) {
    return {
      id: product.getAttribute("data-id"),
      name: product.getAttribute("data-name"),
      price: product.getAttribute("data-price"),
      icon: product.getAttribute("data-icon")
    };
  }

  function renderViewedProducts() {
    viewedList.innerHTML = "";

    products.forEach(function (product) {
      const productId = product.getAttribute("data-id");
      const isViewed = viewedProducts.some(function (item) {
        return item.id === productId;
      });

      product.classList.toggle("is-viewed", isViewed);
    });

    if (viewedProducts.length === 0) {
      viewedList.innerHTML = '&lt;p class="vb-storage-twentysix-empty"&gt;No viewed products yet.&lt;/p&gt;';
      return;
    }

    viewedProducts.forEach(function (product) {
      const item = document.createElement("div");
      item.className = "vb-storage-twentysix-viewed";

      item.innerHTML =
        '&lt;span&gt;' + product.icon + '&lt;/span&gt;' +
        '&lt;div&gt;' +
          '&lt;strong&gt;' + product.name + '&lt;/strong&gt;' +
          '&lt;small&gt;' + product.price + '&lt;/small&gt;' +
        '&lt;/div&gt;';

      viewedList.appendChild(item);
    });
  }

  function addViewedProduct(product) {
    const productData = getProductData(product);

    viewedProducts = viewedProducts.filter(function (item) {
      return item.id !== productData.id;
    });

    viewedProducts.unshift(productData);
    viewedProducts = viewedProducts.slice(0, 5);

    saveViewedProducts();
    renderViewedProducts();
  }

  products.forEach(function (product) {
    product.querySelector("[data-view-product]").addEventListener("click", function () {
      addViewedProduct(product);
    });
  });

  clearButton.addEventListener("click", function () {
    viewedProducts = [];
    localStorage.removeItem(storageKey);
    renderViewedProducts();
  });

  loadViewedProducts();
  renderViewedProducts();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-twentysix-demo"&gt;
  &lt;div class="vb-storage-twentysix-wrap" data-vb-storage-twentysix&gt;
    &lt;div class="vb-storage-twentysix-head"&gt;
      &lt;span class="vb-storage-twentysix-kicker"&gt;Example 26&lt;/span&gt;
      &lt;h3&gt;Recently Viewed Products&lt;/h3&gt;
      &lt;p&gt;Click product cards to add them to the viewed list. Refresh the page and your viewed products stay saved.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-twentysix-layout"&gt;
      &lt;div class="vb-storage-twentysix-products"&gt;
        &lt;article data-product data-id="hosting" data-name="Cloud Hosting" data-price="29€" data-icon="CH"&gt;
          &lt;span&gt;CH&lt;/span&gt;
          &lt;h4&gt;Cloud Hosting&lt;/h4&gt;
          &lt;p&gt;Fast hosting package for business websites.&lt;/p&gt;
          &lt;strong&gt;29€&lt;/strong&gt;
          &lt;button type="button" data-view-product&gt;View Product&lt;/button&gt;
        &lt;/article&gt;

        &lt;article data-product data-id="audit" data-name="SEO Audit" data-price="99€" data-icon="SEO"&gt;
          &lt;span&gt;SEO&lt;/span&gt;
          &lt;h4&gt;SEO Audit&lt;/h4&gt;
          &lt;p&gt;Technical review for rankings and structure.&lt;/p&gt;
          &lt;strong&gt;99€&lt;/strong&gt;
          &lt;button type="button" data-view-product&gt;View Product&lt;/button&gt;
        &lt;/article&gt;

        &lt;article data-product data-id="plugin" data-name="Custom Plugin" data-price="399€" data-icon="WP"&gt;
          &lt;span&gt;WP&lt;/span&gt;
          &lt;h4&gt;Custom Plugin&lt;/h4&gt;
          &lt;p&gt;WordPress plugin built for custom workflows.&lt;/p&gt;
          &lt;strong&gt;399€&lt;/strong&gt;
          &lt;button type="button" data-view-product&gt;View Product&lt;/button&gt;
        &lt;/article&gt;

        &lt;article data-product data-id="landing" data-name="Landing Page" data-price="249€" data-icon="UI"&gt;
          &lt;span&gt;UI&lt;/span&gt;
          &lt;h4&gt;Landing Page&lt;/h4&gt;
          &lt;p&gt;Modern responsive sales page section.&lt;/p&gt;
          &lt;strong&gt;249€&lt;/strong&gt;
          &lt;button type="button" data-view-product&gt;View Product&lt;/button&gt;
        &lt;/article&gt;
      &lt;/div&gt;

      &lt;aside class="vb-storage-twentysix-panel"&gt;
        &lt;div class="vb-storage-twentysix-panel-head"&gt;
          &lt;strong&gt;Viewed Products&lt;/strong&gt;
          &lt;button type="button" data-clear-viewed&gt;Clear&lt;/button&gt;
        &lt;/div&gt;

        &lt;div class="vb-storage-twentysix-list" data-viewed-list&gt;
          &lt;p class="vb-storage-twentysix-empty"&gt;No viewed products yet.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/aside&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-twentysix-demo,
.vb-storage-twentysix-demo * {
  box-sizing: border-box;
}

.vb-storage-twentysix-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(168, 85, 247, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(236, 72, 153, 0.14), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #fdf2f8 56%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.18);
  box-shadow: 0 28px 80px rgba(88, 28, 135, 0.10);
}

.vb-storage-twentysix-wrap {
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-twentysix-head {
  display: grid;
  gap: 12px;
  margin-bottom: 24px;
}

.vb-storage-twentysix-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-twentysix-head h3 {
  max-width: 820px;
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-twentysix-head p {
  max-width: 780px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-twentysix-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(320px, 390px);
  gap: 20px;
  align-items: start;
}

.vb-storage-twentysix-products {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-storage-twentysix-products article {
  display: grid;
  align-content: start;
  gap: 11px;
  min-height: 260px;
  padding: 18px;
  border-radius: 26px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-storage-twentysix-products article.is-viewed {
  border-color: rgba(168, 85, 247, 0.55);
  background: linear-gradient(135deg, #faf5ff, #ffffff) !important;
}

.vb-storage-twentysix-products article &gt; span {
  display: grid;
  place-items: center;
  width: 66px;
  height: 66px;
  border-radius: 22px;
  background: linear-gradient(135deg, #a855f7, #ec4899);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-storage-twentysix-products h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 23px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
}

.vb-storage-twentysix-products p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-storage-twentysix-products strong {
  margin-top: auto;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 26px;
  line-height: 1;
  font-weight: 950;
}

.vb-storage-twentysix-products button {
  min-height: 44px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #a855f7, #ec4899);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentysix-panel {
  display: grid;
  gap: 14px;
  padding: 18px;
  border-radius: 28px;
  background: #111827;
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.24);
}

.vb-storage-twentysix-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.vb-storage-twentysix-panel-head strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-storage-twentysix-panel-head button {
  min-height: 38px;
  padding: 0 13px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentysix-list {
  display: grid;
  gap: 10px;
  min-height: 320px;
}

.vb-storage-twentysix-empty {
  display: grid;
  place-items: center;
  min-height: 320px;
  margin: 0 !important;
  border: 1px dashed rgba(255,255,255,0.22);
  border-radius: 20px;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-twentysix-viewed {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 12px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-twentysix-viewed span {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  border-radius: 16px;
  background: linear-gradient(135deg, #a855f7, #ec4899);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-twentysix-viewed strong {
  display: block;
  margin-bottom: 4px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.25;
  font-weight: 900;
}

.vb-storage-twentysix-viewed small {
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 12px;
  font-weight: 850;
}

@media (max-width: 940px) {
  .vb-storage-twentysix-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-storage-twentysix-products {
    grid-template-columns: 1fr;
  }

  .vb-storage-twentysix-head h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}</pre>



<p class="wp-block-paragraph">This recently viewed products localStorage example is useful for ecommerce stores, WooCommerce layouts, product detail pages, affiliate product roundups, marketplace listings, booking pages, and product recommendation widgets.</p>



<h2 class="wp-block-heading">27. Product Filters Saved with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>Product filters saved with localStorage</strong> are useful for ecommerce category pages, real estate listings, job boards, directories, blog archives, product catalogs, and comparison websites. It keeps filter choices active after refresh, so users do not lose their selected view.</p>



<p class="wp-block-paragraph">This example filters product cards by category, price range, and availability. JavaScript saves the selected filters in localStorage, restores them after refresh, and updates the visible product count instantly.</p>



<ul class="wp-block-list">
<li>Save selected filters in localStorage</li>
<li>Filter by category, price, and availability</li>
<li>Restore filters after refresh</li>
<li>Show live result count</li>
<li>Useful for ecommerce and directory pages</li>
</ul>



<div class="vb-storage-twentyseven-demo">
  <div class="vb-storage-twentyseven-filter" data-vb-storage-twentyseven>
    <aside class="vb-storage-twentyseven-sidebar">
      <span class="vb-storage-twentyseven-kicker">Example 27</span>
      <h3>Saved Product Filters</h3>
      <p>Choose filters and refresh the page. localStorage restores the same product filter state.</p>

      <label>
        <span>Category</span>
        <select data-filter="category">
          <option value="all">All categories</option>
          <option value="website">Website</option>
          <option value="plugin">Plugin</option>
          <option value="seo">SEO</option>
        </select>
      </label>

      <label>
        <span>Max price</span>
        <select data-filter="price">
          <option value="9999">Any price</option>
          <option value="100">Up to 100€</option>
          <option value="300">Up to 300€</option>
          <option value="500">Up to 500€</option>
        </select>
      </label>

      <label class="vb-storage-twentyseven-check">
        <input type="checkbox" data-filter="available">
        <span>Available only</span>
      </label>

      <button type="button" data-reset-filters>Reset Filters</button>
    </aside>

    <section class="vb-storage-twentyseven-results">
      <div class="vb-storage-twentyseven-results-head">
        <strong>Product Results</strong>
        <span data-result-count>6 products</span>
      </div>

      <div class="vb-storage-twentyseven-grid">
        <article data-product-card data-category="website" data-price="249" data-available="true">
          <span>Website</span>
          <h4>Landing Page</h4>
          <p>Modern responsive landing page section.</p>
          <strong>249€</strong>
        </article>

        <article data-product-card data-category="plugin" data-price="399" data-available="true">
          <span>Plugin</span>
          <h4>Quote Form Plugin</h4>
          <p>Custom WordPress quote request system.</p>
          <strong>399€</strong>
        </article>

        <article data-product-card data-category="seo" data-price="99" data-available="true">
          <span>SEO</span>
          <h4>SEO Audit</h4>
          <p>Technical SEO and content review.</p>
          <strong>99€</strong>
        </article>

        <article data-product-card data-category="website" data-price="499" data-available="false">
          <span>Website</span>
          <h4>Ecommerce Setup</h4>
          <p>WooCommerce style product page setup.</p>
          <strong>499€</strong>
        </article>

        <article data-product-card data-category="plugin" data-price="89" data-available="true">
          <span>Plugin</span>
          <h4>Dark Mode Widget</h4>
          <p>Saved theme preference component.</p>
          <strong>89€</strong>
        </article>

        <article data-product-card data-category="seo" data-price="299" data-available="false">
          <span>SEO</span>
          <h4>Content SEO Plan</h4>
          <p>SEO structure for long-form articles.</p>
          <strong>299€</strong>
        </article>
      </div>
    </section>
  </div>
</div>

<style>
.vb-storage-twentyseven-demo,
.vb-storage-twentyseven-demo * {
  box-sizing: border-box;
}

.vb-storage-twentyseven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(37, 99, 235, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(245, 158, 11, 0.15), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #fffbeb 56%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.18);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-storage-twentyseven-filter {
  display: grid;
  grid-template-columns: minmax(280px, 360px) minmax(0, 1fr);
  gap: 22px;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-twentyseven-sidebar,
.vb-storage-twentyseven-results {
  min-width: 0;
}

.vb-storage-twentyseven-sidebar {
  display: grid;
  align-content: start;
  gap: 13px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 28px;
  background: #0f172a;
}

.vb-storage-twentyseven-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(245, 158, 11, 0.16);
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-twentyseven-sidebar h3 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 58px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-storage-twentyseven-sidebar p {
  margin: 0 0 8px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-storage-twentyseven-sidebar label {
  display: grid;
  gap: 7px;
}

.vb-storage-twentyseven-sidebar label span {
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-storage-twentyseven-sidebar select {
  width: 100%;
  min-height: 46px;
  padding: 0 13px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 15px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 750;
  outline: none;
}

.vb-storage-twentyseven-check {
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 10px !important;
  min-height: 46px;
  padding: 10px 12px;
  border-radius: 16px;
  background: rgba(255,255,255,0.08);
}

.vb-storage-twentyseven-check input {
  width: 18px;
  height: 18px;
  accent-color: #f59e0b;
}

.vb-storage-twentyseven-sidebar button {
  min-height: 44px;
  margin-top: 4px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentyseven-results {
  display: grid;
  gap: 16px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 28px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-twentyseven-results-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}

.vb-storage-twentyseven-results-head strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-storage-twentyseven-results-head span {
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-twentyseven-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-height: 480px;
}

.vb-storage-twentyseven-grid article {
  display: grid;
  align-content: start;
  gap: 10px;
  min-height: 210px;
  padding: 16px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 12px 32px rgba(15, 23, 42, 0.06);
}

.vb-storage-twentyseven-grid article.is-hidden {
  display: none;
}

.vb-storage-twentyseven-grid article span {
  display: inline-flex;
  justify-self: start;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-storage-twentyseven-grid article h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 21px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
}

.vb-storage-twentyseven-grid article p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-storage-twentyseven-grid article strong {
  margin-top: auto;
  color: #d97706 !important;
  -webkit-text-fill-color: #d97706 !important;
  font-size: 24px;
  line-height: 1;
  font-weight: 950;
}

@media (max-width: 920px) {
  .vb-storage-twentyseven-filter {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-storage-twentyseven-grid {
    grid-template-columns: 1fr;
  }

  .vb-storage-twentyseven-sidebar h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-twentyseven]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwentysevenFilters";
  const filterFields = wrapper.querySelectorAll("[data-filter]");
  const productCards = Array.from(wrapper.querySelectorAll("[data-product-card]"));
  const resultCount = wrapper.querySelector("[data-result-count]");
  const resetButton = wrapper.querySelector("[data-reset-filters]");

  const defaultFilters = {
    category: "all",
    price: "9999",
    available: false
  };

  let filters = Object.assign({}, defaultFilters);

  function saveFilters() {
    localStorage.setItem(storageKey, JSON.stringify(filters));
  }

  function loadFilters() {
    const savedFilters = localStorage.getItem(storageKey);
    if (!savedFilters) return;

    try {
      filters = Object.assign({}, defaultFilters, JSON.parse(savedFilters));
    } catch (error) {
      filters = Object.assign({}, defaultFilters);
      localStorage.removeItem(storageKey);
    }
  }

  function syncFields() {
    filterFields.forEach(function (field) {
      const key = field.getAttribute("data-filter");

      if (field.type === "checkbox") {
        field.checked = Boolean(filters[key]);
      } else {
        field.value = filters[key];
      }
    });
  }

  function applyFilters() {
    let visibleCount = 0;

    productCards.forEach(function (card) {
      const category = card.getAttribute("data-category");
      const price = Number(card.getAttribute("data-price"));
      const available = card.getAttribute("data-available") === "true";

      const matchesCategory = filters.category === "all" || filters.category === category;
      const matchesPrice = price <= Number(filters.price);
      const matchesAvailability = !filters.available || available;
      const isVisible = matchesCategory &#038;&#038; matchesPrice &#038;&#038; matchesAvailability;

      card.classList.toggle("is-hidden", !isVisible);

      if (isVisible) {
        visibleCount += 1;
      }
    });

    resultCount.textContent = visibleCount === 1 ? "1 product" : visibleCount + " products";
    saveFilters();
  }

  filterFields.forEach(function (field) {
    field.addEventListener("change", function () {
      const key = field.getAttribute("data-filter");
      filters[key] = field.type === "checkbox" ? field.checked : field.value;
      applyFilters();
    });
  });

  resetButton.addEventListener("click", function () {
    filters = Object.assign({}, defaultFilters);
    localStorage.removeItem(storageKey);
    syncFields();
    applyFilters();
  });

  loadFilters();
  syncFields();
  applyFilters();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-twentyseven]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwentysevenFilters";
  const filterFields = wrapper.querySelectorAll("[data-filter]");
  const productCards = Array.from(wrapper.querySelectorAll("[data-product-card]"));
  const resultCount = wrapper.querySelector("[data-result-count]");
  const resetButton = wrapper.querySelector("[data-reset-filters]");

  const defaultFilters = {
    category: "all",
    price: "9999",
    available: false
  };

  let filters = Object.assign({}, defaultFilters);

  function saveFilters() {
    localStorage.setItem(storageKey, JSON.stringify(filters));
  }

  function loadFilters() {
    const savedFilters = localStorage.getItem(storageKey);
    if (!savedFilters) return;

    try {
      filters = Object.assign({}, defaultFilters, JSON.parse(savedFilters));
    } catch (error) {
      filters = Object.assign({}, defaultFilters);
      localStorage.removeItem(storageKey);
    }
  }

  function syncFields() {
    filterFields.forEach(function (field) {
      const key = field.getAttribute("data-filter");

      if (field.type === "checkbox") {
        field.checked = Boolean(filters[key]);
      } else {
        field.value = filters[key];
      }
    });
  }

  function applyFilters() {
    let visibleCount = 0;

    productCards.forEach(function (card) {
      const category = card.getAttribute("data-category");
      const price = Number(card.getAttribute("data-price"));
      const available = card.getAttribute("data-available") === "true";

      const matchesCategory = filters.category === "all" || filters.category === category;
      const matchesPrice = price &lt;= Number(filters.price);
      const matchesAvailability = !filters.available || available;
      const isVisible = matchesCategory &amp;&amp; matchesPrice &amp;&amp; matchesAvailability;

      card.classList.toggle("is-hidden", !isVisible);

      if (isVisible) {
        visibleCount += 1;
      }
    });

    resultCount.textContent = visibleCount === 1 ? "1 product" : visibleCount + " products";
    saveFilters();
  }

  filterFields.forEach(function (field) {
    field.addEventListener("change", function () {
      const key = field.getAttribute("data-filter");
      filters[key] = field.type === "checkbox" ? field.checked : field.value;
      applyFilters();
    });
  });

  resetButton.addEventListener("click", function () {
    filters = Object.assign({}, defaultFilters);
    localStorage.removeItem(storageKey);
    syncFields();
    applyFilters();
  });

  loadFilters();
  syncFields();
  applyFilters();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-twentyseven-demo"&gt;
  &lt;div class="vb-storage-twentyseven-filter" data-vb-storage-twentyseven&gt;
    &lt;aside class="vb-storage-twentyseven-sidebar"&gt;
      &lt;span class="vb-storage-twentyseven-kicker"&gt;Example 27&lt;/span&gt;
      &lt;h3&gt;Saved Product Filters&lt;/h3&gt;
      &lt;p&gt;Choose filters and refresh the page. localStorage restores the same product filter state.&lt;/p&gt;

      &lt;label&gt;
        &lt;span&gt;Category&lt;/span&gt;
        &lt;select data-filter="category"&gt;
          &lt;option value="all"&gt;All categories&lt;/option&gt;
          &lt;option value="website"&gt;Website&lt;/option&gt;
          &lt;option value="plugin"&gt;Plugin&lt;/option&gt;
          &lt;option value="seo"&gt;SEO&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;

      &lt;label&gt;
        &lt;span&gt;Max price&lt;/span&gt;
        &lt;select data-filter="price"&gt;
          &lt;option value="9999"&gt;Any price&lt;/option&gt;
          &lt;option value="100"&gt;Up to 100€&lt;/option&gt;
          &lt;option value="300"&gt;Up to 300€&lt;/option&gt;
          &lt;option value="500"&gt;Up to 500€&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;

      &lt;label class="vb-storage-twentyseven-check"&gt;
        &lt;input type="checkbox" data-filter="available"&gt;
        &lt;span&gt;Available only&lt;/span&gt;
      &lt;/label&gt;

      &lt;button type="button" data-reset-filters&gt;Reset Filters&lt;/button&gt;
    &lt;/aside&gt;

    &lt;section class="vb-storage-twentyseven-results"&gt;
      &lt;div class="vb-storage-twentyseven-results-head"&gt;
        &lt;strong&gt;Product Results&lt;/strong&gt;
        &lt;span data-result-count&gt;6 products&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-storage-twentyseven-grid"&gt;
        &lt;article data-product-card data-category="website" data-price="249" data-available="true"&gt;
          &lt;span&gt;Website&lt;/span&gt;
          &lt;h4&gt;Landing Page&lt;/h4&gt;
          &lt;p&gt;Modern responsive landing page section.&lt;/p&gt;
          &lt;strong&gt;249€&lt;/strong&gt;
        &lt;/article&gt;

        &lt;article data-product-card data-category="plugin" data-price="399" data-available="true"&gt;
          &lt;span&gt;Plugin&lt;/span&gt;
          &lt;h4&gt;Quote Form Plugin&lt;/h4&gt;
          &lt;p&gt;Custom WordPress quote request system.&lt;/p&gt;
          &lt;strong&gt;399€&lt;/strong&gt;
        &lt;/article&gt;

        &lt;article data-product-card data-category="seo" data-price="99" data-available="true"&gt;
          &lt;span&gt;SEO&lt;/span&gt;
          &lt;h4&gt;SEO Audit&lt;/h4&gt;
          &lt;p&gt;Technical SEO and content review.&lt;/p&gt;
          &lt;strong&gt;99€&lt;/strong&gt;
        &lt;/article&gt;

        &lt;article data-product-card data-category="website" data-price="499" data-available="false"&gt;
          &lt;span&gt;Website&lt;/span&gt;
          &lt;h4&gt;Ecommerce Setup&lt;/h4&gt;
          &lt;p&gt;WooCommerce style product page setup.&lt;/p&gt;
          &lt;strong&gt;499€&lt;/strong&gt;
        &lt;/article&gt;

        &lt;article data-product-card data-category="plugin" data-price="89" data-available="true"&gt;
          &lt;span&gt;Plugin&lt;/span&gt;
          &lt;h4&gt;Dark Mode Widget&lt;/h4&gt;
          &lt;p&gt;Saved theme preference component.&lt;/p&gt;
          &lt;strong&gt;89€&lt;/strong&gt;
        &lt;/article&gt;

        &lt;article data-product-card data-category="seo" data-price="299" data-available="false"&gt;
          &lt;span&gt;SEO&lt;/span&gt;
          &lt;h4&gt;Content SEO Plan&lt;/h4&gt;
          &lt;p&gt;SEO structure for long-form articles.&lt;/p&gt;
          &lt;strong&gt;299€&lt;/strong&gt;
        &lt;/article&gt;
      &lt;/div&gt;
    &lt;/section&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-twentyseven-demo,
.vb-storage-twentyseven-demo * {
  box-sizing: border-box;
}

.vb-storage-twentyseven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(37, 99, 235, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(245, 158, 11, 0.15), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #fffbeb 56%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.18);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-storage-twentyseven-filter {
  display: grid;
  grid-template-columns: minmax(280px, 360px) minmax(0, 1fr);
  gap: 22px;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-twentyseven-sidebar,
.vb-storage-twentyseven-results {
  min-width: 0;
}

.vb-storage-twentyseven-sidebar {
  display: grid;
  align-content: start;
  gap: 13px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 28px;
  background: #0f172a;
}

.vb-storage-twentyseven-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(245, 158, 11, 0.16);
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-twentyseven-sidebar h3 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 58px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-storage-twentyseven-sidebar p {
  margin: 0 0 8px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-storage-twentyseven-sidebar label {
  display: grid;
  gap: 7px;
}

.vb-storage-twentyseven-sidebar label span {
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-storage-twentyseven-sidebar select {
  width: 100%;
  min-height: 46px;
  padding: 0 13px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 15px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 750;
  outline: none;
}

.vb-storage-twentyseven-check {
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 10px !important;
  min-height: 46px;
  padding: 10px 12px;
  border-radius: 16px;
  background: rgba(255,255,255,0.08);
}

.vb-storage-twentyseven-check input {
  width: 18px;
  height: 18px;
  accent-color: #f59e0b;
}

.vb-storage-twentyseven-sidebar button {
  min-height: 44px;
  margin-top: 4px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentyseven-results {
  display: grid;
  gap: 16px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 28px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-twentyseven-results-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  flex-wrap: wrap;
}

.vb-storage-twentyseven-results-head strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-storage-twentyseven-results-head span {
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-twentyseven-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-height: 480px;
}

.vb-storage-twentyseven-grid article {
  display: grid;
  align-content: start;
  gap: 10px;
  min-height: 210px;
  padding: 16px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 12px 32px rgba(15, 23, 42, 0.06);
}

.vb-storage-twentyseven-grid article.is-hidden {
  display: none;
}

.vb-storage-twentyseven-grid article span {
  display: inline-flex;
  justify-self: start;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-storage-twentyseven-grid article h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 21px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
}

.vb-storage-twentyseven-grid article p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-storage-twentyseven-grid article strong {
  margin-top: auto;
  color: #d97706 !important;
  -webkit-text-fill-color: #d97706 !important;
  font-size: 24px;
  line-height: 1;
  font-weight: 950;
}

@media (max-width: 920px) {
  .vb-storage-twentyseven-filter {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-storage-twentyseven-grid {
    grid-template-columns: 1fr;
  }

  .vb-storage-twentyseven-sidebar h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}</pre>



<p class="wp-block-paragraph">This saved filters localStorage example is useful for ecommerce category pages, WooCommerce product filters, real estate listings, job boards, directories, comparison websites, blog archives, and searchable catalog interfaces.</p>



<h2 class="wp-block-heading">28. Wishlist Saved with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>A wishlist saved with localStorage</strong> is useful for ecommerce stores, affiliate websites, product catalogs, marketplaces, course websites, booking platforms, and comparison pages. It lets visitors save favorite items without needing an account or backend database.</p>



<p class="wp-block-paragraph">This example lets users add products to a wishlist, remove products, clear the wishlist, and keep saved items after refreshing the page. JavaScript stores the wishlist as a JSON array in localStorage and updates the UI instantly.</p>



<ul class="wp-block-list">
<li>Save wishlist items in localStorage</li>
<li>Add and remove favorite products</li>
<li>Avoid duplicate wishlist items</li>
<li>Restore wishlist after refresh</li>
<li>Useful for ecommerce and affiliate websites</li>
</ul>



<div class="vb-storage-twentyeight-demo">
  <div class="vb-storage-twentyeight-wishlist" data-vb-storage-twentyeight>
    <div class="vb-storage-twentyeight-head">
      <span class="vb-storage-twentyeight-kicker">Example 28</span>
      <h3>Saved Wishlist</h3>
      <p>Add items to the wishlist, refresh the page, and localStorage restores your saved favorites.</p>
    </div>

    <div class="vb-storage-twentyeight-layout">
      <section class="vb-storage-twentyeight-products">
        <article data-product data-id="starter-site" data-name="Starter Website" data-price="299€" data-tag="Website">
          <span>Website</span>
          <h4>Starter Website</h4>
          <p>A clean website package for small businesses and service pages.</p>
          <strong>299€</strong>
          <button type="button" data-wishlist-button>Add to Wishlist</button>
        </article>

        <article data-product data-id="booking-form" data-name="Booking Form" data-price="149€" data-tag="Form">
          <span>Form</span>
          <h4>Booking Form</h4>
          <p>A custom booking form with saved form fields and smooth UI.</p>
          <strong>149€</strong>
          <button type="button" data-wishlist-button>Add to Wishlist</button>
        </article>

        <article data-product data-id="seo-setup" data-name="SEO Setup" data-price="199€" data-tag="SEO">
          <span>SEO</span>
          <h4>SEO Setup</h4>
          <p>Technical SEO setup for structure, metadata, and internal links.</p>
          <strong>199€</strong>
          <button type="button" data-wishlist-button>Add to Wishlist</button>
        </article>

        <article data-product data-id="custom-widget" data-name="Custom JS Widget" data-price="249€" data-tag="JavaScript">
          <span>JavaScript</span>
          <h4>Custom JS Widget</h4>
          <p>A lightweight browser feature built with custom JavaScript.</p>
          <strong>249€</strong>
          <button type="button" data-wishlist-button>Add to Wishlist</button>
        </article>
      </section>

      <aside class="vb-storage-twentyeight-panel">
        <div class="vb-storage-twentyeight-panel-head">
          <strong>Wishlist</strong>
          <span data-wishlist-count>0 saved</span>
        </div>

        <div class="vb-storage-twentyeight-list" data-wishlist-list>
          <p class="vb-storage-twentyeight-empty">No wishlist items saved yet.</p>
        </div>

        <button type="button" data-clear-wishlist>Clear Wishlist</button>
      </aside>
    </div>
  </div>
</div>

<style>
.vb-storage-twentyeight-demo,
.vb-storage-twentyeight-demo * {
  box-sizing: border-box;
}

.vb-storage-twentyeight-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(244, 63, 94, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(168, 85, 247, 0.15), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #faf5ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(244, 63, 94, 0.18);
  box-shadow: 0 28px 80px rgba(159, 18, 57, 0.10);
}

.vb-storage-twentyeight-wishlist {
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-twentyeight-head {
  display: grid;
  gap: 12px;
  margin-bottom: 24px;
}

.vb-storage-twentyeight-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-twentyeight-head h3 {
  max-width: 820px;
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-twentyeight-head p {
  max-width: 780px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-twentyeight-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(320px, 390px);
  gap: 20px;
  align-items: start;
}

.vb-storage-twentyeight-products {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-storage-twentyeight-products article {
  display: grid;
  align-content: start;
  gap: 10px;
  min-height: 250px;
  padding: 18px;
  border-radius: 26px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-storage-twentyeight-products article.is-saved {
  border-color: rgba(244, 63, 94, 0.56);
  background: linear-gradient(135deg, #fff1f2, #ffffff) !important;
}

.vb-storage-twentyeight-products article span {
  display: inline-flex;
  justify-self: start;
  padding: 7px 10px;
  border-radius: 999px;
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-storage-twentyeight-products h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 23px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
}

.vb-storage-twentyeight-products p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-storage-twentyeight-products strong {
  margin-top: auto;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 26px;
  line-height: 1;
  font-weight: 950;
}

.vb-storage-twentyeight-products button,
.vb-storage-twentyeight-panel > button,
.vb-storage-twentyeight-remove {
  min-height: 44px;
  border: 0;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentyeight-products button {
  background: linear-gradient(135deg, #f43f5e, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-twentyeight-products article.is-saved button {
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
}

.vb-storage-twentyeight-panel {
  display: grid;
  gap: 14px;
  padding: 18px;
  border-radius: 28px;
  background: #111827;
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.24);
}

.vb-storage-twentyeight-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.vb-storage-twentyeight-panel-head strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-storage-twentyeight-panel-head span {
  color: #fecdd3 !important;
  -webkit-text-fill-color: #fecdd3 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-twentyeight-list {
  display: grid;
  gap: 10px;
  min-height: 320px;
}

.vb-storage-twentyeight-empty {
  display: grid;
  place-items: center;
  min-height: 320px;
  margin: 0 !important;
  border: 1px dashed rgba(255,255,255,0.22);
  border-radius: 20px;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-twentyeight-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  padding: 12px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-twentyeight-item strong {
  display: block;
  margin-bottom: 4px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.25;
  font-weight: 900;
}

.vb-storage-twentyeight-item span {
  color: #fecdd3 !important;
  -webkit-text-fill-color: #fecdd3 !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-storage-twentyeight-remove {
  width: 34px;
  height: 34px;
  min-height: 34px;
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 16px;
}

.vb-storage-twentyeight-panel > button {
  background: #ffffff;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
}

@media (max-width: 940px) {
  .vb-storage-twentyeight-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-storage-twentyeight-products {
    grid-template-columns: 1fr;
  }

  .vb-storage-twentyeight-head h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-twentyeight]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwentyeightWishlist";
  const products = Array.from(wrapper.querySelectorAll("[data-product]"));
  const wishlistList = wrapper.querySelector("[data-wishlist-list]");
  const wishlistCount = wrapper.querySelector("[data-wishlist-count]");
  const clearButton = wrapper.querySelector("[data-clear-wishlist]");

  let wishlist = [];

  function saveWishlist() {
    localStorage.setItem(storageKey, JSON.stringify(wishlist));
  }

  function loadWishlist() {
    const savedWishlist = localStorage.getItem(storageKey);
    if (!savedWishlist) return;

    try {
      const parsedWishlist = JSON.parse(savedWishlist);
      wishlist = Array.isArray(parsedWishlist) ? parsedWishlist : [];
    } catch (error) {
      wishlist = [];
      localStorage.removeItem(storageKey);
    }
  }

  function getProductData(product) {
    return {
      id: product.getAttribute("data-id"),
      name: product.getAttribute("data-name"),
      price: product.getAttribute("data-price"),
      tag: product.getAttribute("data-tag")
    };
  }

  function renderWishlist() {
    wishlistList.innerHTML = "";

    products.forEach(function (product) {
      const productId = product.getAttribute("data-id");
      const isSaved = wishlist.some(function (item) {
        return item.id === productId;
      });

      product.classList.toggle("is-saved", isSaved);
      product.querySelector("[data-wishlist-button]").textContent = isSaved ? "Saved" : "Add to Wishlist";
    });

    wishlistCount.textContent = wishlist.length === 1 ? "1 saved" : wishlist.length + " saved";

    if (wishlist.length === 0) {
      wishlistList.innerHTML = '<p class="vb-storage-twentyeight-empty">No wishlist items saved yet.</p>';
      saveWishlist();
      return;
    }

    wishlist.forEach(function (item) {
      const row = document.createElement("div");
      row.className = "vb-storage-twentyeight-item";

      row.innerHTML =
        '<div>' +
          '<strong>' + item.name + '</strong>' +
          '<span>' + item.tag + ' · ' + item.price + '</span>' +
        '</div>' +
        '<button type="button" class="vb-storage-twentyeight-remove" data-remove-wishlist="' + item.id + '">×</button>';

      wishlistList.appendChild(row);
    });

    saveWishlist();
  }

  function toggleWishlist(product) {
    const productData = getProductData(product);
    const alreadySaved = wishlist.some(function (item) {
      return item.id === productData.id;
    });

    if (alreadySaved) {
      wishlist = wishlist.filter(function (item) {
        return item.id !== productData.id;
      });
    } else {
      wishlist.unshift(productData);
    }

    renderWishlist();
  }

  products.forEach(function (product) {
    product.querySelector("[data-wishlist-button]").addEventListener("click", function () {
      toggleWishlist(product);
    });
  });

  wishlistList.addEventListener("click", function (event) {
    const removeId = event.target.getAttribute("data-remove-wishlist");
    if (!removeId) return;

    wishlist = wishlist.filter(function (item) {
      return item.id !== removeId;
    });

    renderWishlist();
  });

  clearButton.addEventListener("click", function () {
    wishlist = [];
    localStorage.removeItem(storageKey);
    renderWishlist();
  });

  loadWishlist();
  renderWishlist();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-twentyeight]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwentyeightWishlist";
  const products = Array.from(wrapper.querySelectorAll("[data-product]"));
  const wishlistList = wrapper.querySelector("[data-wishlist-list]");
  const wishlistCount = wrapper.querySelector("[data-wishlist-count]");
  const clearButton = wrapper.querySelector("[data-clear-wishlist]");

  let wishlist = [];

  function saveWishlist() {
    localStorage.setItem(storageKey, JSON.stringify(wishlist));
  }

  function loadWishlist() {
    const savedWishlist = localStorage.getItem(storageKey);
    if (!savedWishlist) return;

    try {
      const parsedWishlist = JSON.parse(savedWishlist);
      wishlist = Array.isArray(parsedWishlist) ? parsedWishlist : [];
    } catch (error) {
      wishlist = [];
      localStorage.removeItem(storageKey);
    }
  }

  function getProductData(product) {
    return {
      id: product.getAttribute("data-id"),
      name: product.getAttribute("data-name"),
      price: product.getAttribute("data-price"),
      tag: product.getAttribute("data-tag")
    };
  }

  function renderWishlist() {
    wishlistList.innerHTML = "";

    products.forEach(function (product) {
      const productId = product.getAttribute("data-id");
      const isSaved = wishlist.some(function (item) {
        return item.id === productId;
      });

      product.classList.toggle("is-saved", isSaved);
      product.querySelector("[data-wishlist-button]").textContent = isSaved ? "Saved" : "Add to Wishlist";
    });

    wishlistCount.textContent = wishlist.length === 1 ? "1 saved" : wishlist.length + " saved";

    if (wishlist.length === 0) {
      wishlistList.innerHTML = '&lt;p class="vb-storage-twentyeight-empty"&gt;No wishlist items saved yet.&lt;/p&gt;';
      saveWishlist();
      return;
    }

    wishlist.forEach(function (item) {
      const row = document.createElement("div");
      row.className = "vb-storage-twentyeight-item";

      row.innerHTML =
        '&lt;div&gt;' +
          '&lt;strong&gt;' + item.name + '&lt;/strong&gt;' +
          '&lt;span&gt;' + item.tag + ' · ' + item.price + '&lt;/span&gt;' +
        '&lt;/div&gt;' +
        '&lt;button type="button" class="vb-storage-twentyeight-remove" data-remove-wishlist="' + item.id + '"&gt;×&lt;/button&gt;';

      wishlistList.appendChild(row);
    });

    saveWishlist();
  }

  function toggleWishlist(product) {
    const productData = getProductData(product);
    const alreadySaved = wishlist.some(function (item) {
      return item.id === productData.id;
    });

    if (alreadySaved) {
      wishlist = wishlist.filter(function (item) {
        return item.id !== productData.id;
      });
    } else {
      wishlist.unshift(productData);
    }

    renderWishlist();
  }

  products.forEach(function (product) {
    product.querySelector("[data-wishlist-button]").addEventListener("click", function () {
      toggleWishlist(product);
    });
  });

  wishlistList.addEventListener("click", function (event) {
    const removeId = event.target.getAttribute("data-remove-wishlist");
    if (!removeId) return;

    wishlist = wishlist.filter(function (item) {
      return item.id !== removeId;
    });

    renderWishlist();
  });

  clearButton.addEventListener("click", function () {
    wishlist = [];
    localStorage.removeItem(storageKey);
    renderWishlist();
  });

  loadWishlist();
  renderWishlist();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-twentyeight-demo"&gt;
  &lt;div class="vb-storage-twentyeight-wishlist" data-vb-storage-twentyeight&gt;
    &lt;div class="vb-storage-twentyeight-head"&gt;
      &lt;span class="vb-storage-twentyeight-kicker"&gt;Example 28&lt;/span&gt;
      &lt;h3&gt;Saved Wishlist&lt;/h3&gt;
      &lt;p&gt;Add items to the wishlist, refresh the page, and localStorage restores your saved favorites.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-twentyeight-layout"&gt;
      &lt;section class="vb-storage-twentyeight-products"&gt;
        &lt;article data-product data-id="starter-site" data-name="Starter Website" data-price="299€" data-tag="Website"&gt;
          &lt;span&gt;Website&lt;/span&gt;
          &lt;h4&gt;Starter Website&lt;/h4&gt;
          &lt;p&gt;A clean website package for small businesses and service pages.&lt;/p&gt;
          &lt;strong&gt;299€&lt;/strong&gt;
          &lt;button type="button" data-wishlist-button&gt;Add to Wishlist&lt;/button&gt;
        &lt;/article&gt;

        &lt;article data-product data-id="booking-form" data-name="Booking Form" data-price="149€" data-tag="Form"&gt;
          &lt;span&gt;Form&lt;/span&gt;
          &lt;h4&gt;Booking Form&lt;/h4&gt;
          &lt;p&gt;A custom booking form with saved form fields and smooth UI.&lt;/p&gt;
          &lt;strong&gt;149€&lt;/strong&gt;
          &lt;button type="button" data-wishlist-button&gt;Add to Wishlist&lt;/button&gt;
        &lt;/article&gt;

        &lt;article data-product data-id="seo-setup" data-name="SEO Setup" data-price="199€" data-tag="SEO"&gt;
          &lt;span&gt;SEO&lt;/span&gt;
          &lt;h4&gt;SEO Setup&lt;/h4&gt;
          &lt;p&gt;Technical SEO setup for structure, metadata, and internal links.&lt;/p&gt;
          &lt;strong&gt;199€&lt;/strong&gt;
          &lt;button type="button" data-wishlist-button&gt;Add to Wishlist&lt;/button&gt;
        &lt;/article&gt;

        &lt;article data-product data-id="custom-widget" data-name="Custom JS Widget" data-price="249€" data-tag="JavaScript"&gt;
          &lt;span&gt;JavaScript&lt;/span&gt;
          &lt;h4&gt;Custom JS Widget&lt;/h4&gt;
          &lt;p&gt;A lightweight browser feature built with custom JavaScript.&lt;/p&gt;
          &lt;strong&gt;249€&lt;/strong&gt;
          &lt;button type="button" data-wishlist-button&gt;Add to Wishlist&lt;/button&gt;
        &lt;/article&gt;
      &lt;/section&gt;

      &lt;aside class="vb-storage-twentyeight-panel"&gt;
        &lt;div class="vb-storage-twentyeight-panel-head"&gt;
          &lt;strong&gt;Wishlist&lt;/strong&gt;
          &lt;span data-wishlist-count&gt;0 saved&lt;/span&gt;
        &lt;/div&gt;

        &lt;div class="vb-storage-twentyeight-list" data-wishlist-list&gt;
          &lt;p class="vb-storage-twentyeight-empty"&gt;No wishlist items saved yet.&lt;/p&gt;
        &lt;/div&gt;

        &lt;button type="button" data-clear-wishlist&gt;Clear Wishlist&lt;/button&gt;
      &lt;/aside&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-twentyeight-demo,
.vb-storage-twentyeight-demo * {
  box-sizing: border-box;
}

.vb-storage-twentyeight-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(244, 63, 94, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(168, 85, 247, 0.15), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #faf5ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(244, 63, 94, 0.18);
  box-shadow: 0 28px 80px rgba(159, 18, 57, 0.10);
}

.vb-storage-twentyeight-wishlist {
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-twentyeight-head {
  display: grid;
  gap: 12px;
  margin-bottom: 24px;
}

.vb-storage-twentyeight-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-twentyeight-head h3 {
  max-width: 820px;
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-twentyeight-head p {
  max-width: 780px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-twentyeight-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(320px, 390px);
  gap: 20px;
  align-items: start;
}

.vb-storage-twentyeight-products {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-storage-twentyeight-products article {
  display: grid;
  align-content: start;
  gap: 10px;
  min-height: 250px;
  padding: 18px;
  border-radius: 26px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-storage-twentyeight-products article.is-saved {
  border-color: rgba(244, 63, 94, 0.56);
  background: linear-gradient(135deg, #fff1f2, #ffffff) !important;
}

.vb-storage-twentyeight-products article span {
  display: inline-flex;
  justify-self: start;
  padding: 7px 10px;
  border-radius: 999px;
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-storage-twentyeight-products h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 23px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
}

.vb-storage-twentyeight-products p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-storage-twentyeight-products strong {
  margin-top: auto;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 26px;
  line-height: 1;
  font-weight: 950;
}

.vb-storage-twentyeight-products button,
.vb-storage-twentyeight-panel &gt; button,
.vb-storage-twentyeight-remove {
  min-height: 44px;
  border: 0;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentyeight-products button {
  background: linear-gradient(135deg, #f43f5e, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-twentyeight-products article.is-saved button {
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
}

.vb-storage-twentyeight-panel {
  display: grid;
  gap: 14px;
  padding: 18px;
  border-radius: 28px;
  background: #111827;
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.24);
}

.vb-storage-twentyeight-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.vb-storage-twentyeight-panel-head strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-storage-twentyeight-panel-head span {
  color: #fecdd3 !important;
  -webkit-text-fill-color: #fecdd3 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-twentyeight-list {
  display: grid;
  gap: 10px;
  min-height: 320px;
}

.vb-storage-twentyeight-empty {
  display: grid;
  place-items: center;
  min-height: 320px;
  margin: 0 !important;
  border: 1px dashed rgba(255,255,255,0.22);
  border-radius: 20px;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-twentyeight-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  padding: 12px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-twentyeight-item strong {
  display: block;
  margin-bottom: 4px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.25;
  font-weight: 900;
}

.vb-storage-twentyeight-item span {
  color: #fecdd3 !important;
  -webkit-text-fill-color: #fecdd3 !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-storage-twentyeight-remove {
  width: 34px;
  height: 34px;
  min-height: 34px;
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 16px;
}

.vb-storage-twentyeight-panel &gt; button {
  background: #ffffff;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
}

@media (max-width: 940px) {
  .vb-storage-twentyeight-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-storage-twentyeight-products {
    grid-template-columns: 1fr;
  }

  .vb-storage-twentyeight-head h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}</pre>



<p class="wp-block-paragraph">This wishlist localStorage example is useful for ecommerce stores, affiliate product lists, marketplace cards, booking platforms, course catalogs, digital product shops, and WooCommerce-style favorite product features.</p>



<h2 class="wp-block-heading">29. Multi-Step Form Progress Saved with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>Saving multi-step form progress with localStorage</strong> is useful for quote request forms, checkout flows, onboarding forms, application forms, booking forms, surveys, and lead generation funnels. It prevents users from losing progress when they refresh or return later.</p>



<p class="wp-block-paragraph">This example saves the current form step and entered field values. JavaScript restores the same step after refresh, keeps the typed data, updates the progress bar, and lets users reset the saved progress.</p>



<ul class="wp-block-list">
<li>Save current form step</li>
<li>Save entered form data</li>
<li>Restore progress after refresh</li>
<li>Includes next, back, and reset buttons</li>
<li>Useful for quote forms and onboarding flows</li>
</ul>



<div class="vb-storage-twentynine-demo">
  <div class="vb-storage-twentynine-formapp" data-vb-storage-twentynine>
    <div class="vb-storage-twentynine-intro">
      <span class="vb-storage-twentynine-kicker">Example 29</span>
      <h3>Saved Multi-Step Form</h3>
      <p>Fill the steps, refresh the page, and localStorage restores your current step and field values.</p>

      <div class="vb-storage-twentynine-progress">
        <span data-step-label>Step 1 of 3</span>
        <div><i data-step-progress></i></div>
      </div>
    </div>

    <form class="vb-storage-twentynine-form" data-multistep-form>
      <section data-step-panel="0" class="is-active">
        <h4>Contact Details</h4>
        <label>
          <span>Name</span>
          <input type="text" name="name" placeholder="Your name">
        </label>
        <label>
          <span>Email</span>
          <input type="email" name="email" placeholder="you@example.com">
        </label>
      </section>

      <section data-step-panel="1">
        <h4>Project Type</h4>
        <label>
          <span>What do you need?</span>
          <select name="project">
            <option value="">Choose project</option>
            <option value="Website">Website</option>
            <option value="Ecommerce">Ecommerce</option>
            <option value="WordPress Plugin">WordPress Plugin</option>
            <option value="JavaScript Feature">JavaScript Feature</option>
          </select>
        </label>
        <label>
          <span>Budget</span>
          <select name="budget">
            <option value="">Choose budget</option>
            <option value="Under 500€">Under 500€</option>
            <option value="500€ - 1500€">500€ - 1500€</option>
            <option value="1500€+">1500€+</option>
          </select>
        </label>
      </section>

      <section data-step-panel="2">
        <h4>Project Message</h4>
        <label>
          <span>Message</span>
          <textarea name="message" rows="7" placeholder="Describe your project..."></textarea>
        </label>
        <div class="vb-storage-twentynine-summary" data-form-summary>
          Your saved form summary will appear here.
        </div>
      </section>

      <div class="vb-storage-twentynine-actions">
        <button type="button" data-prev-step>Back</button>
        <button type="button" data-next-step>Next</button>
        <button type="button" data-reset-progress>Reset</button>
      </div>
    </form>
  </div>
</div>

<style>
.vb-storage-twentynine-demo,
.vb-storage-twentynine-demo * {
  box-sizing: border-box;
}

.vb-storage-twentynine-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(14, 165, 233, 0.17), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #eef2ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  box-shadow: 0 28px 80px rgba(12, 74, 110, 0.10);
}

.vb-storage-twentynine-formapp {
  display: grid;
  grid-template-columns: minmax(0, 0.88fr) minmax(0, 1.12fr);
  gap: 22px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-twentynine-intro,
.vb-storage-twentynine-form {
  min-width: 0;
}

.vb-storage-twentynine-intro {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 28px;
  background: #0f172a;
}

.vb-storage-twentynine-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(14, 165, 233, 0.16);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-twentynine-intro h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-twentynine-intro p {
  max-width: 560px;
  margin: 0 0 22px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-twentynine-progress {
  display: grid;
  gap: 9px;
  padding: 15px;
  border-radius: 20px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-twentynine-progress span {
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-storage-twentynine-progress div {
  height: 11px;
  overflow: hidden;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
}

.vb-storage-twentynine-progress i {
  display: block;
  width: 33.33%;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(135deg, #0ea5e9, #6366f1);
  transition: width 0.25s ease;
}

.vb-storage-twentynine-form {
  display: grid;
  gap: 16px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 30px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-twentynine-form section {
  display: none;
  min-height: 340px;
  align-content: start;
  gap: 14px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 12px 32px rgba(15, 23, 42, 0.06);
}

.vb-storage-twentynine-form section.is-active {
  display: grid;
}

.vb-storage-twentynine-form h4 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(28px, 4vw, 42px) !important;
  line-height: 1.05 !important;
  font-weight: 950 !important;
  letter-spacing: -0.055em;
}

.vb-storage-twentynine-form label {
  display: grid;
  gap: 7px;
}

.vb-storage-twentynine-form label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-storage-twentynine-form input,
.vb-storage-twentynine-form select,
.vb-storage-twentynine-form textarea {
  width: 100%;
  border: 1px solid rgba(148, 163, 184, 0.34);
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 700;
  outline: none;
}

.vb-storage-twentynine-form input,
.vb-storage-twentynine-form select {
  min-height: 50px;
  padding: 0 15px;
}

.vb-storage-twentynine-form textarea {
  resize: vertical;
  padding: 14px 15px;
  line-height: 1.55;
}

.vb-storage-twentynine-form input:focus,
.vb-storage-twentynine-form select:focus,
.vb-storage-twentynine-form textarea:focus {
  border-color: rgba(14, 165, 233, 0.72);
  box-shadow: 0 0 0 4px rgba(14, 165, 233, 0.10);
}

.vb-storage-twentynine-summary {
  padding: 14px;
  border-radius: 18px;
  background: #eff6ff;
  color: #1e3a8a !important;
  -webkit-text-fill-color: #1e3a8a !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 750;
}

.vb-storage-twentynine-actions {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 10px;
}

.vb-storage-twentynine-actions button {
  min-height: 46px;
  padding: 0 16px;
  border: 0;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentynine-actions button:first-child {
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
}

.vb-storage-twentynine-actions button:nth-child(2) {
  background: linear-gradient(135deg, #0ea5e9, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-twentynine-actions button:last-child {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-storage-twentynine-actions button:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

@media (max-width: 900px) {
  .vb-storage-twentynine-formapp {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 580px) {
  .vb-storage-twentynine-actions {
    grid-template-columns: 1fr;
  }

  .vb-storage-twentynine-intro h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-twentynine]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwentynineMultiStep";
  const form = wrapper.querySelector("[data-multistep-form]");
  const panels = Array.from(wrapper.querySelectorAll("[data-step-panel]"));
  const fields = Array.from(form.querySelectorAll("input, select, textarea"));
  const prevButton = wrapper.querySelector("[data-prev-step]");
  const nextButton = wrapper.querySelector("[data-next-step]");
  const resetButton = wrapper.querySelector("[data-reset-progress]");
  const stepLabel = wrapper.querySelector("[data-step-label]");
  const stepProgress = wrapper.querySelector("[data-step-progress]");
  const summary = wrapper.querySelector("[data-form-summary]");

  let state = {
    step: 0,
    data: {}
  };

  function saveState() {
    localStorage.setItem(storageKey, JSON.stringify(state));
  }

  function loadState() {
    const savedState = localStorage.getItem(storageKey);
    if (!savedState) return;

    try {
      const parsedState = JSON.parse(savedState);
      state.step = Number(parsedState.step) || 0;
      state.data = parsedState.data || {};
    } catch (error) {
      localStorage.removeItem(storageKey);
    }
  }

  function collectData() {
    fields.forEach(function (field) {
      state.data[field.name] = field.value;
    });
  }

  function applyData() {
    fields.forEach(function (field) {
      field.value = state.data[field.name] || "";
    });
  }

  function updateSummary() {
    summary.textContent =
      "Name: " + (state.data.name || "Not added") +
      " · Project: " + (state.data.project || "Not selected") +
      " · Budget: " + (state.data.budget || "Not selected");
  }

  function renderStep() {
    panels.forEach(function (panel, index) {
      panel.classList.toggle("is-active", index === state.step);
    });

    stepLabel.textContent = "Step " + (state.step + 1) + " of " + panels.length;
    stepProgress.style.width = ((state.step + 1) / panels.length * 100) + "%";

    prevButton.disabled = state.step === 0;
    nextButton.textContent = state.step === panels.length - 1 ? "Finish Demo" : "Next";

    updateSummary();
    saveState();
  }

  fields.forEach(function (field) {
    field.addEventListener("input", function () {
      collectData();
      updateSummary();
      saveState();
    });

    field.addEventListener("change", function () {
      collectData();
      updateSummary();
      saveState();
    });
  });

  prevButton.addEventListener("click", function () {
    collectData();
    state.step = Math.max(0, state.step - 1);
    renderStep();
  });

  nextButton.addEventListener("click", function () {
    collectData();

    if (state.step < panels.length - 1) {
      state.step += 1;
      renderStep();
      return;
    }

    summary.textContent = "Demo finished. Your progress is still saved until you reset it.";
    saveState();
  });

  resetButton.addEventListener("click", function () {
    state = {
      step: 0,
      data: {}
    };

    localStorage.removeItem(storageKey);
    form.reset();
    renderStep();
  });

  loadState();
  applyData();
  renderStep();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-twentynine]");
  if (!wrapper) return;

  const storageKey = "vbStorageTwentynineMultiStep";
  const form = wrapper.querySelector("[data-multistep-form]");
  const panels = Array.from(wrapper.querySelectorAll("[data-step-panel]"));
  const fields = Array.from(form.querySelectorAll("input, select, textarea"));
  const prevButton = wrapper.querySelector("[data-prev-step]");
  const nextButton = wrapper.querySelector("[data-next-step]");
  const resetButton = wrapper.querySelector("[data-reset-progress]");
  const stepLabel = wrapper.querySelector("[data-step-label]");
  const stepProgress = wrapper.querySelector("[data-step-progress]");
  const summary = wrapper.querySelector("[data-form-summary]");

  let state = {
    step: 0,
    data: {}
  };

  function saveState() {
    localStorage.setItem(storageKey, JSON.stringify(state));
  }

  function loadState() {
    const savedState = localStorage.getItem(storageKey);
    if (!savedState) return;

    try {
      const parsedState = JSON.parse(savedState);
      state.step = Number(parsedState.step) || 0;
      state.data = parsedState.data || {};
    } catch (error) {
      localStorage.removeItem(storageKey);
    }
  }

  function collectData() {
    fields.forEach(function (field) {
      state.data[field.name] = field.value;
    });
  }

  function applyData() {
    fields.forEach(function (field) {
      field.value = state.data[field.name] || "";
    });
  }

  function updateSummary() {
    summary.textContent =
      "Name: " + (state.data.name || "Not added") +
      " · Project: " + (state.data.project || "Not selected") +
      " · Budget: " + (state.data.budget || "Not selected");
  }

  function renderStep() {
    panels.forEach(function (panel, index) {
      panel.classList.toggle("is-active", index === state.step);
    });

    stepLabel.textContent = "Step " + (state.step + 1) + " of " + panels.length;
    stepProgress.style.width = ((state.step + 1) / panels.length * 100) + "%";

    prevButton.disabled = state.step === 0;
    nextButton.textContent = state.step === panels.length - 1 ? "Finish Demo" : "Next";

    updateSummary();
    saveState();
  }

  fields.forEach(function (field) {
    field.addEventListener("input", function () {
      collectData();
      updateSummary();
      saveState();
    });

    field.addEventListener("change", function () {
      collectData();
      updateSummary();
      saveState();
    });
  });

  prevButton.addEventListener("click", function () {
    collectData();
    state.step = Math.max(0, state.step - 1);
    renderStep();
  });

  nextButton.addEventListener("click", function () {
    collectData();

    if (state.step &lt; panels.length - 1) {
      state.step += 1;
      renderStep();
      return;
    }

    summary.textContent = "Demo finished. Your progress is still saved until you reset it.";
    saveState();
  });

  resetButton.addEventListener("click", function () {
    state = {
      step: 0,
      data: {}
    };

    localStorage.removeItem(storageKey);
    form.reset();
    renderStep();
  });

  loadState();
  applyData();
  renderStep();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-twentynine-demo"&gt;
  &lt;div class="vb-storage-twentynine-formapp" data-vb-storage-twentynine&gt;
    &lt;div class="vb-storage-twentynine-intro"&gt;
      &lt;span class="vb-storage-twentynine-kicker"&gt;Example 29&lt;/span&gt;
      &lt;h3&gt;Saved Multi-Step Form&lt;/h3&gt;
      &lt;p&gt;Fill the steps, refresh the page, and localStorage restores your current step and field values.&lt;/p&gt;

      &lt;div class="vb-storage-twentynine-progress"&gt;
        &lt;span data-step-label&gt;Step 1 of 3&lt;/span&gt;
        &lt;div&gt;&lt;i data-step-progress&gt;&lt;/i&gt;&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;form class="vb-storage-twentynine-form" data-multistep-form&gt;
      &lt;section data-step-panel="0" class="is-active"&gt;
        &lt;h4&gt;Contact Details&lt;/h4&gt;
        &lt;label&gt;
          &lt;span&gt;Name&lt;/span&gt;
          &lt;input type="text" name="name" placeholder="Your name"&gt;
        &lt;/label&gt;
        &lt;label&gt;
          &lt;span&gt;Email&lt;/span&gt;
          &lt;input type="email" name="email" placeholder="you@example.com"&gt;
        &lt;/label&gt;
      &lt;/section&gt;

      &lt;section data-step-panel="1"&gt;
        &lt;h4&gt;Project Type&lt;/h4&gt;
        &lt;label&gt;
          &lt;span&gt;What do you need?&lt;/span&gt;
          &lt;select name="project"&gt;
            &lt;option value=""&gt;Choose project&lt;/option&gt;
            &lt;option value="Website"&gt;Website&lt;/option&gt;
            &lt;option value="Ecommerce"&gt;Ecommerce&lt;/option&gt;
            &lt;option value="WordPress Plugin"&gt;WordPress Plugin&lt;/option&gt;
            &lt;option value="JavaScript Feature"&gt;JavaScript Feature&lt;/option&gt;
          &lt;/select&gt;
        &lt;/label&gt;
        &lt;label&gt;
          &lt;span&gt;Budget&lt;/span&gt;
          &lt;select name="budget"&gt;
            &lt;option value=""&gt;Choose budget&lt;/option&gt;
            &lt;option value="Under 500€"&gt;Under 500€&lt;/option&gt;
            &lt;option value="500€ - 1500€"&gt;500€ - 1500€&lt;/option&gt;
            &lt;option value="1500€+"&gt;1500€+&lt;/option&gt;
          &lt;/select&gt;
        &lt;/label&gt;
      &lt;/section&gt;

      &lt;section data-step-panel="2"&gt;
        &lt;h4&gt;Project Message&lt;/h4&gt;
        &lt;label&gt;
          &lt;span&gt;Message&lt;/span&gt;
          &lt;textarea name="message" rows="7" placeholder="Describe your project..."&gt;&lt;/textarea&gt;
        &lt;/label&gt;
        &lt;div class="vb-storage-twentynine-summary" data-form-summary&gt;
          Your saved form summary will appear here.
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;div class="vb-storage-twentynine-actions"&gt;
        &lt;button type="button" data-prev-step&gt;Back&lt;/button&gt;
        &lt;button type="button" data-next-step&gt;Next&lt;/button&gt;
        &lt;button type="button" data-reset-progress&gt;Reset&lt;/button&gt;
      &lt;/div&gt;
    &lt;/form&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-twentynine-demo,
.vb-storage-twentynine-demo * {
  box-sizing: border-box;
}

.vb-storage-twentynine-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(14, 165, 233, 0.17), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #eef2ff 56%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  box-shadow: 0 28px 80px rgba(12, 74, 110, 0.10);
}

.vb-storage-twentynine-formapp {
  display: grid;
  grid-template-columns: minmax(0, 0.88fr) minmax(0, 1.12fr);
  gap: 22px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-storage-twentynine-intro,
.vb-storage-twentynine-form {
  min-width: 0;
}

.vb-storage-twentynine-intro {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 28px;
  background: #0f172a;
}

.vb-storage-twentynine-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(14, 165, 233, 0.16);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-twentynine-intro h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-twentynine-intro p {
  max-width: 560px;
  margin: 0 0 22px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-twentynine-progress {
  display: grid;
  gap: 9px;
  padding: 15px;
  border-radius: 20px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-storage-twentynine-progress span {
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-storage-twentynine-progress div {
  height: 11px;
  overflow: hidden;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
}

.vb-storage-twentynine-progress i {
  display: block;
  width: 33.33%;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(135deg, #0ea5e9, #6366f1);
  transition: width 0.25s ease;
}

.vb-storage-twentynine-form {
  display: grid;
  gap: 16px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 30px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-storage-twentynine-form section {
  display: none;
  min-height: 340px;
  align-content: start;
  gap: 14px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 12px 32px rgba(15, 23, 42, 0.06);
}

.vb-storage-twentynine-form section.is-active {
  display: grid;
}

.vb-storage-twentynine-form h4 {
  margin: 0 0 4px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(28px, 4vw, 42px) !important;
  line-height: 1.05 !important;
  font-weight: 950 !important;
  letter-spacing: -0.055em;
}

.vb-storage-twentynine-form label {
  display: grid;
  gap: 7px;
}

.vb-storage-twentynine-form label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-storage-twentynine-form input,
.vb-storage-twentynine-form select,
.vb-storage-twentynine-form textarea {
  width: 100%;
  border: 1px solid rgba(148, 163, 184, 0.34);
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 700;
  outline: none;
}

.vb-storage-twentynine-form input,
.vb-storage-twentynine-form select {
  min-height: 50px;
  padding: 0 15px;
}

.vb-storage-twentynine-form textarea {
  resize: vertical;
  padding: 14px 15px;
  line-height: 1.55;
}

.vb-storage-twentynine-form input:focus,
.vb-storage-twentynine-form select:focus,
.vb-storage-twentynine-form textarea:focus {
  border-color: rgba(14, 165, 233, 0.72);
  box-shadow: 0 0 0 4px rgba(14, 165, 233, 0.10);
}

.vb-storage-twentynine-summary {
  padding: 14px;
  border-radius: 18px;
  background: #eff6ff;
  color: #1e3a8a !important;
  -webkit-text-fill-color: #1e3a8a !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 750;
}

.vb-storage-twentynine-actions {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: 10px;
}

.vb-storage-twentynine-actions button {
  min-height: 46px;
  padding: 0 16px;
  border: 0;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-twentynine-actions button:first-child {
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
}

.vb-storage-twentynine-actions button:nth-child(2) {
  background: linear-gradient(135deg, #0ea5e9, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-twentynine-actions button:last-child {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-storage-twentynine-actions button:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

@media (max-width: 900px) {
  .vb-storage-twentynine-formapp {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 580px) {
  .vb-storage-twentynine-actions {
    grid-template-columns: 1fr;
  }

  .vb-storage-twentynine-intro h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}</pre>



<p class="wp-block-paragraph">This multi-step form progress localStorage example is useful for quote request forms, onboarding flows, checkout forms, booking forms, application forms, surveys, lead generation funnels, and long contact forms.</p>



<h2 class="wp-block-heading">30. LocalStorage CRUD App</h2>



<p class="wp-block-paragraph"><strong>A localStorage CRUD app</strong> is one of the best JavaScript localStorage examples because it combines the most important browser storage patterns: create, read, update, and delete. It is useful for task managers, admin demos, dashboards, small browser apps, saved lists, and JavaScript portfolio projects.</p>



<p class="wp-block-paragraph">This example lets users create records, edit existing records, delete records, search saved records, and restore everything after refresh. JavaScript stores the records as a JSON array in localStorage and rebuilds the interface whenever the data changes.</p>



<ul class="wp-block-list">
<li>Create records in localStorage</li>
<li>Read and render saved records</li>
<li>Update existing records</li>
<li>Delete records from localStorage</li>
<li>Includes simple search filtering</li>
</ul>



<div class="vb-storage-thirty-demo">
  <div class="vb-storage-thirty-app" data-vb-storage-thirty>
    <div class="vb-storage-thirty-head">
      <span class="vb-storage-thirty-kicker">Example 30</span>
      <h3>LocalStorage CRUD App</h3>
      <p>Create, edit, delete, search, and restore saved records using localStorage.</p>
    </div>

    <div class="vb-storage-thirty-layout">
      <form class="vb-storage-thirty-form" data-crud-form>
        <h4 data-form-title>Add New Record</h4>

        <label>
          <span>Title</span>
          <input type="text" data-record-title placeholder="Project title">
        </label>

        <label>
          <span>Category</span>
          <select data-record-category>
            <option value="Website">Website</option>
            <option value="JavaScript">JavaScript</option>
            <option value="SEO">SEO</option>
            <option value="WordPress">WordPress</option>
          </select>
        </label>

        <label>
          <span>Description</span>
          <textarea data-record-description rows="5" placeholder="Short description..."></textarea>
        </label>

        <button type="submit" data-save-record>Save Record</button>
        <button type="button" class="vb-storage-thirty-cancel" data-cancel-edit hidden>Cancel Edit</button>
      </form>

      <section class="vb-storage-thirty-records">
        <div class="vb-storage-thirty-toolbar">
          <input type="search" data-record-search placeholder="Search saved records...">
          <button type="button" data-clear-records>Clear All</button>
        </div>

        <div class="vb-storage-thirty-count" data-record-count>0 records saved</div>

        <div class="vb-storage-thirty-list" data-record-list>
          <p class="vb-storage-thirty-empty">No records saved yet.</p>
        </div>
      </section>
    </div>
  </div>
</div>

<style>
.vb-storage-thirty-demo,
.vb-storage-thirty-demo * {
  box-sizing: border-box;
}

.vb-storage-thirty-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(37, 99, 235, 0.17), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(20, 184, 166, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #f0fdfa 56%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.18);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-storage-thirty-app {
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #0f172a;
  box-shadow: 0 28px 90px rgba(15, 23, 42, 0.30);
}

.vb-storage-thirty-head {
  display: grid;
  gap: 12px;
  margin-bottom: 22px;
}

.vb-storage-thirty-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(45, 212, 191, 0.16);
  color: #99f6e4 !important;
  -webkit-text-fill-color: #99f6e4 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-thirty-head h3 {
  max-width: 850px;
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-thirty-head p {
  max-width: 760px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-thirty-layout {
  display: grid;
  grid-template-columns: minmax(300px, 390px) minmax(0, 1fr);
  gap: 18px;
  align-items: start;
}

.vb-storage-thirty-form,
.vb-storage-thirty-records {
  min-width: 0;
}

.vb-storage-thirty-form {
  display: grid;
  gap: 13px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 28px;
  background: #ffffff;
}

.vb-storage-thirty-form h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 28px !important;
  line-height: 1.08 !important;
  font-weight: 950 !important;
  letter-spacing: -0.05em;
}

.vb-storage-thirty-form label {
  display: grid;
  gap: 7px;
}

.vb-storage-thirty-form label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-storage-thirty-form input,
.vb-storage-thirty-form select,
.vb-storage-thirty-form textarea,
.vb-storage-thirty-toolbar input {
  width: 100%;
  border: 1px solid rgba(148, 163, 184, 0.34);
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 700;
  outline: none;
}

.vb-storage-thirty-form input,
.vb-storage-thirty-form select,
.vb-storage-thirty-toolbar input {
  min-height: 50px;
  padding: 0 15px;
}

.vb-storage-thirty-form textarea {
  resize: vertical;
  padding: 14px 15px;
  line-height: 1.55;
}

.vb-storage-thirty-form input:focus,
.vb-storage-thirty-form select:focus,
.vb-storage-thirty-form textarea:focus,
.vb-storage-thirty-toolbar input:focus {
  border-color: rgba(20, 184, 166, 0.72);
  box-shadow: 0 0 0 4px rgba(20, 184, 166, 0.10);
}

.vb-storage-thirty-form button,
.vb-storage-thirty-toolbar button,
.vb-storage-thirty-actions button {
  min-height: 44px;
  border: 0;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-thirty-form button[type="submit"] {
  background: linear-gradient(135deg, #2563eb, #14b8a6);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-thirty-cancel,
.vb-storage-thirty-toolbar button,
.vb-storage-thirty-actions button:last-child {
  background: #fee2e2 !important;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-storage-thirty-records {
  display: grid;
  gap: 12px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 28px;
  background: #ffffff;
}

.vb-storage-thirty-toolbar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
}

.vb-storage-thirty-toolbar button {
  padding: 0 14px;
}

.vb-storage-thirty-count {
  padding: 12px 14px;
  border-radius: 18px;
  background: #eff6ff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-thirty-list {
  display: grid;
  gap: 10px;
  min-height: 430px;
}

.vb-storage-thirty-empty {
  display: grid;
  place-items: center;
  min-height: 430px;
  margin: 0 !important;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  border-radius: 20px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-thirty-record {
  display: grid;
  gap: 10px;
  padding: 14px;
  border-radius: 20px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 10px 26px rgba(15, 23, 42, 0.06);
}

.vb-storage-thirty-record-top {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: start;
}

.vb-storage-thirty-record h5 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 19px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
}

.vb-storage-thirty-record span {
  flex: 0 0 auto;
  padding: 7px 10px;
  border-radius: 999px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 11px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-storage-thirty-record p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-storage-thirty-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-storage-thirty-actions button {
  min-height: 36px;
  padding: 0 12px;
}

.vb-storage-thirty-actions button:first-child {
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
}

@media (max-width: 940px) {
  .vb-storage-thirty-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-storage-thirty-toolbar {
    grid-template-columns: 1fr;
  }

  .vb-storage-thirty-head h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}
</style>

<script>
(function () {
  const wrapper = document.querySelector("[data-vb-storage-thirty]");
  if (!wrapper) return;

  const storageKey = "vbStorageThirtyCrudRecords";
  const form = wrapper.querySelector("[data-crud-form]");
  const formTitle = wrapper.querySelector("[data-form-title]");
  const titleInput = wrapper.querySelector("[data-record-title]");
  const categoryInput = wrapper.querySelector("[data-record-category]");
  const descriptionInput = wrapper.querySelector("[data-record-description]");
  const saveButton = wrapper.querySelector("[data-save-record]");
  const cancelButton = wrapper.querySelector("[data-cancel-edit]");
  const searchInput = wrapper.querySelector("[data-record-search]");
  const clearButton = wrapper.querySelector("[data-clear-records]");
  const recordCount = wrapper.querySelector("[data-record-count]");
  const recordList = wrapper.querySelector("[data-record-list]");

  let records = [];
  let editingId = null;

  function saveRecords() {
    localStorage.setItem(storageKey, JSON.stringify(records));
  }

  function loadRecords() {
    const savedRecords = localStorage.getItem(storageKey);
    if (!savedRecords) return;

    try {
      const parsedRecords = JSON.parse(savedRecords);
      records = Array.isArray(parsedRecords) ? parsedRecords : [];
    } catch (error) {
      records = [];
      localStorage.removeItem(storageKey);
    }
  }

  function resetForm() {
    editingId = null;
    form.reset();
    formTitle.textContent = "Add New Record";
    saveButton.textContent = "Save Record";
    cancelButton.hidden = true;
  }

  function getFilteredRecords() {
    const search = searchInput.value.trim().toLowerCase();

    if (!search) {
      return records;
    }

    return records.filter(function (record) {
      return (
        record.title.toLowerCase().includes(search) ||
        record.category.toLowerCase().includes(search) ||
        record.description.toLowerCase().includes(search)
      );
    });
  }

  function renderRecords() {
    const filteredRecords = getFilteredRecords();
    recordList.innerHTML = "";

    recordCount.textContent = records.length === 1
      ? "1 record saved"
      : records.length + " records saved";

    if (filteredRecords.length === 0) {
      recordList.innerHTML = '<p class="vb-storage-thirty-empty">No records found.</p>';
      return;
    }

    filteredRecords.forEach(function (record) {
      const card = document.createElement("article");
      card.className = "vb-storage-thirty-record";

      card.innerHTML =
        '<div class="vb-storage-thirty-record-top">' +
          '<h5>' + record.title + '</h5>' +
          '<span>' + record.category + '</span>' +
        '</div>' +
        '<p>' + record.description + '</p>' +
        '<div class="vb-storage-thirty-actions">' +
          '<button type="button" data-edit-record="' + record.id + '">Edit</button>' +
          '<button type="button" data-delete-record="' + record.id + '">Delete</button>' +
        '</div>';

      recordList.appendChild(card);
    });
  }

  function saveRecord() {
    const title = titleInput.value.trim();
    const category = categoryInput.value;
    const description = descriptionInput.value.trim();

    if (!title || !description) return;

    if (editingId) {
      records = records.map(function (record) {
        if (record.id === editingId) {
          return {
            id: record.id,
            title: title,
            category: category,
            description: description
          };
        }

        return record;
      });
    } else {
      records.unshift({
        id: String(Date.now()),
        title: title,
        category: category,
        description: description
      });
    }

    saveRecords();
    renderRecords();
    resetForm();
  }

  function editRecord(recordId) {
    const record = records.find(function (item) {
      return item.id === recordId;
    });

    if (!record) return;

    editingId = record.id;
    titleInput.value = record.title;
    categoryInput.value = record.category;
    descriptionInput.value = record.description;
    formTitle.textContent = "Edit Record";
    saveButton.textContent = "Update Record";
    cancelButton.hidden = false;
    titleInput.focus();
  }

  function deleteRecord(recordId) {
    records = records.filter(function (record) {
      return record.id !== recordId;
    });

    if (editingId === recordId) {
      resetForm();
    }

    saveRecords();
    renderRecords();
  }

  form.addEventListener("submit", function (event) {
    event.preventDefault();
    saveRecord();
  });

  recordList.addEventListener("click", function (event) {
    const editId = event.target.getAttribute("data-edit-record");
    const deleteId = event.target.getAttribute("data-delete-record");

    if (editId) editRecord(editId);
    if (deleteId) deleteRecord(deleteId);
  });

  searchInput.addEventListener("input", renderRecords);

  cancelButton.addEventListener("click", resetForm);

  clearButton.addEventListener("click", function () {
    records = [];
    localStorage.removeItem(storageKey);
    resetForm();
    renderRecords();
  });

  loadRecords();
  renderRecords();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const wrapper = document.querySelector("[data-vb-storage-thirty]");
  if (!wrapper) return;

  const storageKey = "vbStorageThirtyCrudRecords";
  const form = wrapper.querySelector("[data-crud-form]");
  const formTitle = wrapper.querySelector("[data-form-title]");
  const titleInput = wrapper.querySelector("[data-record-title]");
  const categoryInput = wrapper.querySelector("[data-record-category]");
  const descriptionInput = wrapper.querySelector("[data-record-description]");
  const saveButton = wrapper.querySelector("[data-save-record]");
  const cancelButton = wrapper.querySelector("[data-cancel-edit]");
  const searchInput = wrapper.querySelector("[data-record-search]");
  const clearButton = wrapper.querySelector("[data-clear-records]");
  const recordCount = wrapper.querySelector("[data-record-count]");
  const recordList = wrapper.querySelector("[data-record-list]");

  let records = [];
  let editingId = null;

  function saveRecords() {
    localStorage.setItem(storageKey, JSON.stringify(records));
  }

  function loadRecords() {
    const savedRecords = localStorage.getItem(storageKey);
    if (!savedRecords) return;

    try {
      const parsedRecords = JSON.parse(savedRecords);
      records = Array.isArray(parsedRecords) ? parsedRecords : [];
    } catch (error) {
      records = [];
      localStorage.removeItem(storageKey);
    }
  }

  function resetForm() {
    editingId = null;
    form.reset();
    formTitle.textContent = "Add New Record";
    saveButton.textContent = "Save Record";
    cancelButton.hidden = true;
  }

  function getFilteredRecords() {
    const search = searchInput.value.trim().toLowerCase();

    if (!search) {
      return records;
    }

    return records.filter(function (record) {
      return (
        record.title.toLowerCase().includes(search) ||
        record.category.toLowerCase().includes(search) ||
        record.description.toLowerCase().includes(search)
      );
    });
  }

  function renderRecords() {
    const filteredRecords = getFilteredRecords();
    recordList.innerHTML = "";

    recordCount.textContent = records.length === 1
      ? "1 record saved"
      : records.length + " records saved";

    if (filteredRecords.length === 0) {
      recordList.innerHTML = '&lt;p class="vb-storage-thirty-empty"&gt;No records found.&lt;/p&gt;';
      return;
    }

    filteredRecords.forEach(function (record) {
      const card = document.createElement("article");
      card.className = "vb-storage-thirty-record";

      card.innerHTML =
        '&lt;div class="vb-storage-thirty-record-top"&gt;' +
          '&lt;h5&gt;' + record.title + '&lt;/h5&gt;' +
          '&lt;span&gt;' + record.category + '&lt;/span&gt;' +
        '&lt;/div&gt;' +
        '&lt;p&gt;' + record.description + '&lt;/p&gt;' +
        '&lt;div class="vb-storage-thirty-actions"&gt;' +
          '&lt;button type="button" data-edit-record="' + record.id + '"&gt;Edit&lt;/button&gt;' +
          '&lt;button type="button" data-delete-record="' + record.id + '"&gt;Delete&lt;/button&gt;' +
        '&lt;/div&gt;';

      recordList.appendChild(card);
    });
  }

  function saveRecord() {
    const title = titleInput.value.trim();
    const category = categoryInput.value;
    const description = descriptionInput.value.trim();

    if (!title || !description) return;

    if (editingId) {
      records = records.map(function (record) {
        if (record.id === editingId) {
          return {
            id: record.id,
            title: title,
            category: category,
            description: description
          };
        }

        return record;
      });
    } else {
      records.unshift({
        id: String(Date.now()),
        title: title,
        category: category,
        description: description
      });
    }

    saveRecords();
    renderRecords();
    resetForm();
  }

  function editRecord(recordId) {
    const record = records.find(function (item) {
      return item.id === recordId;
    });

    if (!record) return;

    editingId = record.id;
    titleInput.value = record.title;
    categoryInput.value = record.category;
    descriptionInput.value = record.description;
    formTitle.textContent = "Edit Record";
    saveButton.textContent = "Update Record";
    cancelButton.hidden = false;
    titleInput.focus();
  }

  function deleteRecord(recordId) {
    records = records.filter(function (record) {
      return record.id !== recordId;
    });

    if (editingId === recordId) {
      resetForm();
    }

    saveRecords();
    renderRecords();
  }

  form.addEventListener("submit", function (event) {
    event.preventDefault();
    saveRecord();
  });

  recordList.addEventListener("click", function (event) {
    const editId = event.target.getAttribute("data-edit-record");
    const deleteId = event.target.getAttribute("data-delete-record");

    if (editId) editRecord(editId);
    if (deleteId) deleteRecord(deleteId);
  });

  searchInput.addEventListener("input", renderRecords);

  cancelButton.addEventListener("click", resetForm);

  clearButton.addEventListener("click", function () {
    records = [];
    localStorage.removeItem(storageKey);
    resetForm();
    renderRecords();
  });

  loadRecords();
  renderRecords();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-storage-thirty-demo"&gt;
  &lt;div class="vb-storage-thirty-app" data-vb-storage-thirty&gt;
    &lt;div class="vb-storage-thirty-head"&gt;
      &lt;span class="vb-storage-thirty-kicker"&gt;Example 30&lt;/span&gt;
      &lt;h3&gt;LocalStorage CRUD App&lt;/h3&gt;
      &lt;p&gt;Create, edit, delete, search, and restore saved records using localStorage.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-storage-thirty-layout"&gt;
      &lt;form class="vb-storage-thirty-form" data-crud-form&gt;
        &lt;h4 data-form-title&gt;Add New Record&lt;/h4&gt;

        &lt;label&gt;
          &lt;span&gt;Title&lt;/span&gt;
          &lt;input type="text" data-record-title placeholder="Project title"&gt;
        &lt;/label&gt;

        &lt;label&gt;
          &lt;span&gt;Category&lt;/span&gt;
          &lt;select data-record-category&gt;
            &lt;option value="Website"&gt;Website&lt;/option&gt;
            &lt;option value="JavaScript"&gt;JavaScript&lt;/option&gt;
            &lt;option value="SEO"&gt;SEO&lt;/option&gt;
            &lt;option value="WordPress"&gt;WordPress&lt;/option&gt;
          &lt;/select&gt;
        &lt;/label&gt;

        &lt;label&gt;
          &lt;span&gt;Description&lt;/span&gt;
          &lt;textarea data-record-description rows="5" placeholder="Short description..."&gt;&lt;/textarea&gt;
        &lt;/label&gt;

        &lt;button type="submit" data-save-record&gt;Save Record&lt;/button&gt;
        &lt;button type="button" class="vb-storage-thirty-cancel" data-cancel-edit hidden&gt;Cancel Edit&lt;/button&gt;
      &lt;/form&gt;

      &lt;section class="vb-storage-thirty-records"&gt;
        &lt;div class="vb-storage-thirty-toolbar"&gt;
          &lt;input type="search" data-record-search placeholder="Search saved records..."&gt;
          &lt;button type="button" data-clear-records&gt;Clear All&lt;/button&gt;
        &lt;/div&gt;

        &lt;div class="vb-storage-thirty-count" data-record-count&gt;0 records saved&lt;/div&gt;

        &lt;div class="vb-storage-thirty-list" data-record-list&gt;
          &lt;p class="vb-storage-thirty-empty"&gt;No records saved yet.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-storage-thirty-demo,
.vb-storage-thirty-demo * {
  box-sizing: border-box;
}

.vb-storage-thirty-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px;
  background:
    radial-gradient(circle at 14% 18%, rgba(37, 99, 235, 0.17), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(20, 184, 166, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #f0fdfa 56%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.18);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-storage-thirty-app {
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 34px;
  background: #0f172a;
  box-shadow: 0 28px 90px rgba(15, 23, 42, 0.30);
}

.vb-storage-thirty-head {
  display: grid;
  gap: 12px;
  margin-bottom: 22px;
}

.vb-storage-thirty-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(45, 212, 191, 0.16);
  color: #99f6e4 !important;
  -webkit-text-fill-color: #99f6e4 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-storage-thirty-head h3 {
  max-width: 850px;
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-storage-thirty-head p {
  max-width: 760px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-storage-thirty-layout {
  display: grid;
  grid-template-columns: minmax(300px, 390px) minmax(0, 1fr);
  gap: 18px;
  align-items: start;
}

.vb-storage-thirty-form,
.vb-storage-thirty-records {
  min-width: 0;
}

.vb-storage-thirty-form {
  display: grid;
  gap: 13px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 28px;
  background: #ffffff;
}

.vb-storage-thirty-form h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 28px !important;
  line-height: 1.08 !important;
  font-weight: 950 !important;
  letter-spacing: -0.05em;
}

.vb-storage-thirty-form label {
  display: grid;
  gap: 7px;
}

.vb-storage-thirty-form label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-storage-thirty-form input,
.vb-storage-thirty-form select,
.vb-storage-thirty-form textarea,
.vb-storage-thirty-toolbar input {
  width: 100%;
  border: 1px solid rgba(148, 163, 184, 0.34);
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 700;
  outline: none;
}

.vb-storage-thirty-form input,
.vb-storage-thirty-form select,
.vb-storage-thirty-toolbar input {
  min-height: 50px;
  padding: 0 15px;
}

.vb-storage-thirty-form textarea {
  resize: vertical;
  padding: 14px 15px;
  line-height: 1.55;
}

.vb-storage-thirty-form input:focus,
.vb-storage-thirty-form select:focus,
.vb-storage-thirty-form textarea:focus,
.vb-storage-thirty-toolbar input:focus {
  border-color: rgba(20, 184, 166, 0.72);
  box-shadow: 0 0 0 4px rgba(20, 184, 166, 0.10);
}

.vb-storage-thirty-form button,
.vb-storage-thirty-toolbar button,
.vb-storage-thirty-actions button {
  min-height: 44px;
  border: 0;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-storage-thirty-form button[type="submit"] {
  background: linear-gradient(135deg, #2563eb, #14b8a6);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-storage-thirty-cancel,
.vb-storage-thirty-toolbar button,
.vb-storage-thirty-actions button:last-child {
  background: #fee2e2 !important;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-storage-thirty-records {
  display: grid;
  gap: 12px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 28px;
  background: #ffffff;
}

.vb-storage-thirty-toolbar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
}

.vb-storage-thirty-toolbar button {
  padding: 0 14px;
}

.vb-storage-thirty-count {
  padding: 12px 14px;
  border-radius: 18px;
  background: #eff6ff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-storage-thirty-list {
  display: grid;
  gap: 10px;
  min-height: 430px;
}

.vb-storage-thirty-empty {
  display: grid;
  place-items: center;
  min-height: 430px;
  margin: 0 !important;
  border: 1px dashed rgba(148, 163, 184, 0.55);
  border-radius: 20px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-storage-thirty-record {
  display: grid;
  gap: 10px;
  padding: 14px;
  border-radius: 20px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 10px 26px rgba(15, 23, 42, 0.06);
}

.vb-storage-thirty-record-top {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: start;
}

.vb-storage-thirty-record h5 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 19px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
}

.vb-storage-thirty-record span {
  flex: 0 0 auto;
  padding: 7px 10px;
  border-radius: 999px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 11px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-storage-thirty-record p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-storage-thirty-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-storage-thirty-actions button {
  min-height: 36px;
  padding: 0 12px;
}

.vb-storage-thirty-actions button:first-child {
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
}

@media (max-width: 940px) {
  .vb-storage-thirty-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 620px) {
  .vb-storage-thirty-toolbar {
    grid-template-columns: 1fr;
  }

  .vb-storage-thirty-head h3 {
    font-size: 38px !important;
    letter-spacing: -0.055em;
  }
}</pre>



<p class="wp-block-paragraph">This localStorage CRUD app example is useful for task managers, saved lists, admin demos, browser-based apps, JavaScript portfolio projects, lightweight dashboards, and learning how to create, read, update, and delete data in localStorage.</p>



<div class="vb24-js-storage-bottom-ad">
  <a class="vb24-js-storage-bottom-ad-card" href="https://veebilehed24.ee/en/shop/entityschema-pro/" target="_blank" rel="sponsored noopener">
    <div class="vb24-js-storage-bottom-ad-media">
      <img decoding="async" src="https://veebilehed24.ee/wp-content/uploads/2026/03/entityschema-cover-600x400.webp" width="600" height="400" alt="EntitySchema Pro WordPress structured data and entity SEO plugin" loading="lazy">
    </div>

    <div class="vb24-js-storage-bottom-ad-content">
      <span>WordPress SEO Plugin</span>
      <h3>Build AI-readable structured data with EntitySchema Pro</h3>
      <p>Improve your WordPress SEO with entity-based schema markup, structured content signals, and modern AI-readable website data.</p>

      <div class="vb24-js-storage-bottom-ad-price">
        <strong>29€</strong>
        <em>Regular price 89€</em>
        <b>Save 60€</b>
      </div>

      <i>View Plugin</i>
    </div>
  </a>
</div>

<style>
.vb24-js-storage-bottom-ad,
.vb24-js-storage-bottom-ad * {
  box-sizing: border-box;
}

.vb24-js-storage-bottom-ad {
  margin: 42px 0 46px;
}

.vb24-js-storage-bottom-ad-card {
  display: grid;
  grid-template-columns: minmax(260px, 420px) minmax(0, 1fr);
  gap: clamp(18px, 4vw, 34px);
  align-items: center;
  padding: clamp(18px, 4vw, 34px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 18%, rgba(34, 211, 238, 0.22), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(16, 185, 129, 0.20), transparent 36%),
    linear-gradient(135deg, #0f172a 0%, #1e3a8a 48%, #065f46 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  text-decoration: none !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.24);
  overflow: hidden;
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-js-storage-bottom-ad-card:hover {
  transform: translateY(-3px);
  filter: saturate(1.08);
  box-shadow: 0 36px 104px rgba(15, 23, 42, 0.30);
}

.vb24-js-storage-bottom-ad-media {
  overflow: hidden;
  border-radius: 24px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.16);
}

.vb24-js-storage-bottom-ad-media img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 24px;
}

.vb24-js-storage-bottom-ad-content {
  min-width: 0;
}

.vb24-js-storage-bottom-ad-content span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(34, 211, 238, 0.16);
  border: 1px solid rgba(34, 211, 238, 0.24);
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb24-js-storage-bottom-ad-content h3 {
  max-width: 680px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 5vw, 54px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.065em;
}

.vb24-js-storage-bottom-ad-content p {
  max-width: 700px;
  margin: 0 0 20px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb24-js-storage-bottom-ad-price {
  display: flex;
  align-items: center;
  gap: 13px;
  flex-wrap: wrap;
  margin-bottom: 18px;
}

.vb24-js-storage-bottom-ad-price strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 38px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb24-js-storage-bottom-ad-price em {
  color: rgba(255,255,255,0.64) !important;
  -webkit-text-fill-color: rgba(255,255,255,0.64) !important;
  font-size: 15px;
  font-style: normal;
  font-weight: 850;
  text-decoration: line-through;
  text-decoration-thickness: 2px;
  text-decoration-color: rgba(248, 113, 113, 0.95);
}

.vb24-js-storage-bottom-ad-price b {
  display: inline-flex;
  padding: 8px 10px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.18);
  border: 1px solid rgba(74, 222, 128, 0.34);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb24-js-storage-bottom-ad-content i {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 46px;
  padding: 12px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22d3ee, #2563eb 55%, #10b981);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-style: normal;
  font-weight: 950;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.30);
}

@media (max-width: 820px) {
  .vb24-js-storage-bottom-ad-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb24-js-storage-bottom-ad-card {
    border-radius: 26px;
  }

  .vb24-js-storage-bottom-ad-content h3 {
    font-size: 34px !important;
    letter-spacing: -0.055em;
  }

  .vb24-js-storage-bottom-ad-content i {
    width: 100%;
  }
}
</style>



<h2 class="wp-block-heading" id="javascript-localstorage-best-practices">JavaScript LocalStorage Best Practices</h2>



<p class="wp-block-paragraph">JavaScript localStorage is simple to use, but the best localStorage features are planned carefully. A good implementation should store only useful data, keep the interface in sync with the saved value, handle invalid stored data safely, and give users a clear way to remove or reset saved information.</p>



<p class="wp-block-paragraph">For SEO-focused websites, ecommerce pages, WordPress landing pages, SaaS dashboards, and interactive blog examples, localStorage works best when it improves usability without hiding important content from search engines. It should remember user actions, not replace meaningful HTML content that should be visible on the page.</p>



<div class="vb24-js-storage-practice-grid">
  <article>
    <span>01</span>
    <strong>Use clear storage keys</strong>
    <p>Use unique localStorage keys for every feature, plugin, component, or demo so one saved value does not overwrite another.</p>
  </article>

  <article>
    <span>02</span>
    <strong>Store non-sensitive data only</strong>
    <p>Use localStorage for preferences, carts, drafts, filters, and UI state. Do not store passwords, private tokens, payment data, or confidential information.</p>
  </article>

  <article>
    <span>03</span>
    <strong>Use JSON for complex data</strong>
    <p>Arrays and objects must be saved with JSON.stringify() and restored with JSON.parse(), because localStorage stores values as strings.</p>
  </article>

  <article>
    <span>04</span>
    <strong>Always update the UI after storage changes</strong>
    <p>When data is added, edited, removed, or reset, update both localStorage and the visible interface at the same time.</p>
  </article>
</div>

<style>
.vb24-js-storage-practice-grid,
.vb24-js-storage-practice-grid * {
  box-sizing: border-box;
}

.vb24-js-storage-practice-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 30px;
}

.vb24-js-storage-practice-grid article {
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 18% 10%, rgba(37, 99, 235, 0.10), transparent 32%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb24-js-storage-practice-grid span {
  display: grid;
  place-items: center;
  width: 38px;
  height: 38px;
  margin-bottom: 14px;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #06b6d4, #10b981);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb24-js-storage-practice-grid strong {
  display: block;
  margin-bottom: 8px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
}

.vb24-js-storage-practice-grid p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

@media (max-width: 980px) {
  .vb24-js-storage-practice-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-js-storage-practice-grid {
    grid-template-columns: 1fr;
  }
}
</style>



<ul class="wp-block-list">
  <li><strong>Use localStorage for interface memory</strong>, such as saved filters, carts, favorites, form drafts, theme settings, recent searches, notes, and progress states.</li>
  <li><strong>Do not use localStorage as a secure database</strong>. It is browser-side storage and should not contain confidential or security-critical data.</li>
  <li><strong>Wrap JSON.parse() in try/catch</strong> so broken or manually edited browser storage does not break your whole script.</li>
  <li><strong>Keep saved data small</strong>. localStorage is designed for small browser data, not large files, images, or complete databases.</li>
  <li><strong>Add reset, remove, or clear buttons</strong> when the stored data affects the visible user experience.</li>
  <li><strong>Use scoped selectors</strong> so multiple examples, widgets, or WordPress blocks can run on the same page without conflicts.</li>
  <li><strong>Update the interface on page load</strong> so the saved state is visible immediately after refresh.</li>
  <li><strong>Use semantic HTML first</strong>, then enhance the experience with JavaScript and localStorage.</li>
  <li><strong>Keep storage logic separate from styling</strong> so the feature is easier to customize and reuse.</li>
  <li><strong>Test in private browsing and different browsers</strong>, because users may clear storage or use privacy settings that affect persistence.</li>
</ul>



<p class="wp-block-paragraph">When localStorage is used correctly, it can make small website features feel much more polished. A saved form draft, persistent cart, remembered dark mode setting, or restored filter state can reduce friction and make a website feel more useful without requiring a login system or database for every small interaction.</p>



<h2 class="wp-block-heading" id="responsive-localstorage-ui-tips">Responsive LocalStorage UI Tips</h2>



<p class="wp-block-paragraph">Many localStorage examples involve forms, product cards, dashboards, carts, lists, filters, tabs, and settings panels. These components often look fine on desktop but become hard to use on mobile if spacing, button size, scroll behavior, and layout changes are not planned.</p>



<p class="wp-block-paragraph">A responsive localStorage UI should make saved data easy to understand on every screen size. Users should be able to add, remove, reset, edit, or restore saved items just as easily on a phone as they can on a desktop screen.</p>



<div class="vb24-js-storage-responsive-box">
  <div>
    <strong>Mobile-first controls</strong>
    <p>Use full-width buttons, readable labels, and enough spacing between action buttons such as save, remove, reset, next, back, and clear.</p>
  </div>

  <div>
    <strong>Readable saved states</strong>
    <p>Saved status messages, restored draft notices, cart totals, and active filter labels should stay visible and easy to scan on small screens.</p>
  </div>

  <div>
    <strong>Flexible layouts</strong>
    <p>Use CSS grid or flexbox to move sidebars below content, stack product cards, and keep settings panels usable on mobile devices.</p>
  </div>
</div>

<style>
.vb24-js-storage-responsive-box,
.vb24-js-storage-responsive-box * {
  box-sizing: border-box;
}

.vb24-js-storage-responsive-box {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 30px;
  padding: clamp(18px, 4vw, 28px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 14% 16%, rgba(6, 182, 212, 0.14), transparent 34%),
    linear-gradient(135deg, #f0f9ff, #ecfdf5) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.08);
}

.vb24-js-storage-responsive-box div {
  padding: 20px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb24-js-storage-responsive-box strong {
  display: block;
  margin-bottom: 8px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
}

.vb24-js-storage-responsive-box p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

@media (max-width: 860px) {
  .vb24-js-storage-responsive-box {
    grid-template-columns: 1fr;
  }
}
</style>



<ul class="wp-block-list">
  <li><strong>Stack complex layouts on mobile</strong>, especially dashboards, carts, filters, settings sidebars, and CRUD apps.</li>
  <li><strong>Keep action buttons large enough</strong> for touch screens, especially remove, edit, clear, add, save, and reset buttons.</li>
  <li><strong>Show saved status clearly</strong> so users know when a draft, cart, preference, or progress state has been stored.</li>
  <li><strong>Avoid tiny localStorage controls</strong> inside product cards or forms, because they are difficult to use on mobile.</li>
  <li><strong>Test long saved content</strong>, including long notes, long product names, long search terms, and long form messages.</li>
  <li><strong>Use scroll-friendly sections</strong> when a saved list, cart, or dashboard could become too long for the viewport.</li>
</ul>



<p class="wp-block-paragraph">Responsive design is especially important for localStorage features because saved data often grows over time. A cart can get more items, a notes app can get longer text, a recent search list can expand, and a CRUD app can contain many records. The layout should stay usable even when the saved browser data is not empty.</p>



<h2 class="wp-block-heading" id="common-javascript-localstorage-mistakes">Common JavaScript LocalStorage Mistakes</h2>



<p class="wp-block-paragraph">LocalStorage is easy to start with, but there are common mistakes that can make a browser-based feature unreliable, insecure, or frustrating. Most problems happen when developers store the wrong data, forget to parse JSON safely, do not update the UI after changes, or use the same storage key in multiple places.</p>



<div class="vb24-js-storage-mistakes">
  <article>
    <strong>Storing sensitive information</strong>
    <p>Passwords, private tokens, payment details, and confidential customer data should never be stored in localStorage.</p>
  </article>

  <article>
    <strong>Forgetting JSON.parse() error handling</strong>
    <p>Stored JSON can become invalid. Use try/catch before using parsed browser data in your interface.</p>
  </article>

  <article>
    <strong>Using the same storage key everywhere</strong>
    <p>Repeated keys can overwrite carts, forms, filters, or demo data. Every component should use its own unique key.</p>
  </article>

  <article>
    <strong>Not giving users a reset option</strong>
    <p>If a website remembers data, users should have a simple way to clear it, remove items, or reset the saved state.</p>
  </article>
</div>

<style>
.vb24-js-storage-mistakes,
.vb24-js-storage-mistakes * {
  box-sizing: border-box;
}

.vb24-js-storage-mistakes {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 30px;
}

.vb24-js-storage-mistakes article {
  position: relative;
  padding: 22px 22px 22px 58px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 12% 10%, rgba(239, 68, 68, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(248, 113, 113, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb24-js-storage-mistakes article::before {
  content: "!";
  position: absolute;
  left: 18px;
  top: 21px;
  display: grid;
  place-items: center;
  width: 26px;
  height: 26px;
  border-radius: 999px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 15px;
  font-weight: 950;
}

.vb24-js-storage-mistakes strong {
  display: block;
  margin-bottom: 7px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
}

.vb24-js-storage-mistakes p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 720px) {
  .vb24-js-storage-mistakes {
    grid-template-columns: 1fr;
  }
}
</style>



<ul class="wp-block-list">
  <li><strong>Do not store private data</strong> such as passwords, tokens, payment details, personal ID data, or confidential business information.</li>
  <li><strong>Do not assume localStorage always exists</strong> in every privacy mode, browser setting, or restricted environment.</li>
  <li><strong>Do not forget to stringify arrays and objects</strong> before saving them to localStorage.</li>
  <li><strong>Do not parse JSON without error handling</strong> if the data might be missing, broken, or manually changed.</li>
  <li><strong>Do not save huge data</strong> such as base64 images, large files, or thousands of records.</li>
  <li><strong>Do not hide important SEO content only inside JavaScript</strong>. Keep meaningful content in HTML and use localStorage for enhancement.</li>
  <li><strong>Do not create UI states that users cannot reset</strong>, especially for saved forms, carts, filters, and preferences.</li>
  <li><strong>Do not use localStorage instead of server-side storage</strong> when data must be shared across devices or accounts.</li>
</ul>



<p class="wp-block-paragraph">The safest approach is to treat localStorage as a browser-based helper for user experience. It is excellent for saved interface state, but it should not be treated like a protected backend system. When the data is important, private, shared between devices, or connected to payments and accounts, use server-side storage instead.</p>



<h2 class="wp-block-heading" id="javascript-localstorage-faq">JavaScript LocalStorage FAQ</h2>



<p class="wp-block-paragraph">Here are common questions about JavaScript localStorage examples, browser storage, saved form data, shopping carts, dark mode preferences, saved filters, recently viewed products, CRUD apps, and responsive UI components.</p>



<div class="vb24-js-storage-faq-section" data-vb24-js-storage-faq>
  <section class="vb24-js-storage-faq-item is-open">
    <button class="vb24-js-storage-faq-trigger" type="button" aria-expanded="true">
      <span>What is JavaScript localStorage?</span>
      <em></em>
    </button>
    <div class="vb24-js-storage-faq-panel">
      <div class="vb24-js-storage-faq-content">
        <p>JavaScript localStorage is a browser storage feature that lets websites save small pieces of data on the visitor’s device. The data can remain available after refresh, after closing the tab, and after returning to the page later.</p>
      </div>
    </div>
  </section>

  <section class="vb24-js-storage-faq-item">
    <button class="vb24-js-storage-faq-trigger" type="button" aria-expanded="false">
      <span>What can localStorage be used for?</span>
      <em></em>
    </button>
    <div class="vb24-js-storage-faq-panel">
      <div class="vb24-js-storage-faq-content">
        <p>LocalStorage can be used for form drafts, shopping carts, dark mode preferences, saved filters, recent searches, recently viewed products, wishlists, notes, dashboard settings, quiz progress, tab state, accordion state, and small browser-based tools.</p>
      </div>
    </div>
  </section>

  <section class="vb24-js-storage-faq-item">
    <button class="vb24-js-storage-faq-trigger" type="button" aria-expanded="false">
      <span>Is localStorage safe for passwords?</span>
      <em></em>
    </button>
    <div class="vb24-js-storage-faq-panel">
      <div class="vb24-js-storage-faq-content">
        <p>No. Passwords, private tokens, payment details, personal identity data, and confidential information should not be stored in localStorage. Use secure server-side storage and proper authentication systems for sensitive data.</p>
      </div>
    </div>
  </section>

  <section class="vb24-js-storage-faq-item">
    <button class="vb24-js-storage-faq-trigger" type="button" aria-expanded="false">
      <span>How do you save objects and arrays in localStorage?</span>
      <em></em>
    </button>
    <div class="vb24-js-storage-faq-panel">
      <div class="vb24-js-storage-faq-content">
        <p>Objects and arrays should be converted to strings with JSON.stringify() before saving. When reading the value back, use JSON.parse() to turn the string back into an object or array. It is best to wrap JSON.parse() in try/catch.</p>
      </div>
    </div>
  </section>

  <section class="vb24-js-storage-faq-item">
    <button class="vb24-js-storage-faq-trigger" type="button" aria-expanded="false">
      <span>Does localStorage work after page refresh?</span>
      <em></em>
    </button>
    <div class="vb24-js-storage-faq-panel">
      <div class="vb24-js-storage-faq-content">
        <p>Yes. That is one of the main reasons localStorage is useful. It can keep data after a page refresh, so features like saved form drafts, carts, filters, and theme preferences can be restored when the page loads again.</p>
      </div>
    </div>
  </section>

  <section class="vb24-js-storage-faq-item">
    <button class="vb24-js-storage-faq-trigger" type="button" aria-expanded="false">
      <span>When should I use localStorage instead of a database?</span>
      <em></em>
    </button>
    <div class="vb24-js-storage-faq-panel">
      <div class="vb24-js-storage-faq-content">
        <p>Use localStorage for small, non-sensitive browser features that only need to exist on one device. Use a database when the data must be secure, shared between devices, connected to user accounts, used by other visitors, or stored permanently on the server.</p>
      </div>
    </div>
  </section>
</div>

<style>
.vb24-js-storage-faq-section,
.vb24-js-storage-faq-section * {
  box-sizing: border-box;
}

.vb24-js-storage-faq-section {
  display: grid;
  gap: 12px;
  margin: 24px 0 38px;
}

.vb24-js-storage-faq-item {
  overflow: hidden;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb24-js-storage-faq-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  width: 100%;
  min-height: 64px;
  padding: 18px 20px;
  border: 0;
  background: linear-gradient(135deg, #ffffff, #f8fafc);
  cursor: pointer;
  text-align: left;
}

.vb24-js-storage-faq-trigger span {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
}

.vb24-js-storage-faq-trigger em {
  position: relative;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: #dbeafe;
}

.vb24-js-storage-faq-trigger em::before,
.vb24-js-storage-faq-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 14px;
  height: 3px;
  border-radius: 999px;
  background: #2563eb;
  transform: translate(-50%, -50%);
}

.vb24-js-storage-faq-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
  transition: transform 0.22s ease;
}

.vb24-js-storage-faq-item.is-open .vb24-js-storage-faq-trigger em {
  background: linear-gradient(135deg, #2563eb, #06b6d4, #10b981);
}

.vb24-js-storage-faq-item.is-open .vb24-js-storage-faq-trigger em::before,
.vb24-js-storage-faq-item.is-open .vb24-js-storage-faq-trigger em::after {
  background: #ffffff;
}

.vb24-js-storage-faq-item.is-open .vb24-js-storage-faq-trigger em::after {
  transform: translate(-50%, -50%) rotate(0deg);
}

.vb24-js-storage-faq-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.26s ease;
}

.vb24-js-storage-faq-content {
  padding: 0 20px 20px;
}

.vb24-js-storage-faq-content p {
  margin: 0 !important;
  padding: 16px;
  border-radius: 18px;
  background: #f8fafc;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

@media (max-width: 640px) {
  .vb24-js-storage-faq-trigger {
    padding: 16px;
  }

  .vb24-js-storage-faq-trigger span {
    font-size: 16px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb24-js-storage-faq]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb24-js-storage-faq-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb24-js-storage-faq-trigger");
    const panel = item.querySelector(".vb24-js-storage-faq-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb24-js-storage-faq-trigger");
    const panel = item.querySelector(".vb24-js-storage-faq-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb24-js-storage-faq-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  items.forEach(function (item) {
    if (item.classList.contains("is-open")) {
      openItem(item);
    } else {
      closeItem(item);
    }
  });

  window.addEventListener("resize", function () {
    items.forEach(function (item) {
      if (item.classList.contains("is-open")) {
        const panel = item.querySelector(".vb24-js-storage-faq-panel");
        panel.style.maxHeight = panel.scrollHeight + "px";
      }
    });
  });
})();
</script>



<h2 class="wp-block-heading" id="javascript-localstorage-conclusion">Conclusion</h2>



<p class="wp-block-paragraph">JavaScript localStorage is one of the most practical browser features for building interactive website components that remember user actions. It can improve contact forms, quote request forms, ecommerce carts, dark mode toggles, saved filters, wishlists, recently viewed products, dashboard settings, CRUD apps, notes, quizzes, calculators, onboarding flows, and many other front-end UI patterns.</p>



<p class="wp-block-paragraph">The best localStorage examples do more than save a value. They restore the interface after refresh, update the UI when data changes, use clear storage keys, support reset actions, handle JSON safely, and avoid storing sensitive information. That combination makes localStorage useful for real projects instead of only simple tutorials.</p>



<p class="wp-block-paragraph">You can use the examples in this guide as starting points for WordPress pages, ecommerce websites, SaaS dashboards, landing pages, portfolios, learning projects, admin panels, and browser-based JavaScript tools. Customize the storage keys, layout, copy, colors, form fields, product data, and reset logic to match your own website or client project.</p>



<p class="wp-block-paragraph">For production websites, remember the most important rule: localStorage is excellent for non-sensitive browser data, but secure data belongs on the server. Use it for user experience improvements, saved UI state, and practical front-end features — not for passwords, tokens, payments, or confidential customer details.</p>



<h2 class="wp-block-heading" id="related-javascript-and-css-guides">Related JavaScript and CSS Guides</h2>



<p class="wp-block-paragraph">Continue building better website sections and interactive UI components with these related JavaScript and CSS guides. These posts work well together when building full landing pages, product pages, dashboards, ecommerce interfaces, forms, filters, menus, and responsive website layouts.</p>



<div class="vb24-js-storage-related">
  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-form-validation-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Form Validation Examples</strong>
    <p>Input validation, signup validation, checkout validation, password checks, and user-friendly form feedback.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-search-filter-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Search Filter Examples</strong>
    <p>Live search, card filters, product filters, FAQ search, dashboard filters, and responsive filtering UI examples.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-dropdown-menu-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Dropdown Menu Examples</strong>
    <p>Custom selects, navigation dropdowns, profile menus, category dropdowns, and responsive menu components.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-countdown-timer-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Countdown Timer Examples</strong>
    <p>Sale timers, event timers, product launches, checkout urgency blocks, and responsive countdown UI components.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-accordion-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Accordion Examples</strong>
    <p>FAQ accordions, product toggles, dashboard panels, nested accordions, and responsive content expanders.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-modal-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Modal Examples</strong>
    <p>Popup windows, dialog boxes, overlay components, confirmation modals, and responsive modal UI patterns.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-forms/">
    <span>CSS</span>
    <strong>30 Modern CSS Forms</strong>
    <p>Contact forms, login forms, checkout forms, quote forms, and responsive form UI examples.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-layouts/">
    <span>CSS</span>
    <strong>25 Modern CSS Layouts</strong>
    <p>Grid layouts, flexbox sections, container query cards, dashboards, bento grids, and landing page structures.</p>
  </a>
</div>

<style>
.vb24-js-storage-related,
.vb24-js-storage-related * {
  box-sizing: border-box;
}

.vb24-js-storage-related {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin: 26px 0 38px;
}

.vb24-js-storage-related a {
  display: flex;
  flex-direction: column;
  min-height: 100%;
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 16% 12%, rgba(37, 99, 235, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  text-decoration: none !important;
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
  transition: transform 0.22s ease, box-shadow 0.22s ease, border-color 0.22s ease;
}

.vb24-js-storage-related a:hover {
  transform: translateY(-3px);
  border-color: rgba(16, 185, 129, 0.45);
  box-shadow: 0 22px 56px rgba(15, 23, 42, 0.12);
}

.vb24-js-storage-related span {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 12px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb24-js-storage-related strong {
  display: block;
  margin-bottom: 8px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
}

.vb24-js-storage-related p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 1080px) {
  .vb24-js-storage-related {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-js-storage-related {
    grid-template-columns: 1fr;
  }
}
</style>
]]></content:encoded>
					
					<wfw:commentRss>https://veebilehed24.ee/en/blog/javascript/javascript-localstorage-examples/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>30 JavaScript Countdown Timer Examples – Sale Timers, Event Timers &#038; UI Components</title>
		<link>https://veebilehed24.ee/en/blog/javascript/javascript-countdown-timer-examples/</link>
					<comments>https://veebilehed24.ee/en/blog/javascript/javascript-countdown-timer-examples/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Mon, 15 Jun 2026 10:59:51 +0000</pubDate>
				<category><![CDATA[Javascript]]></category>
		<guid isPermaLink="false">https://veebilehed24.ee/?p=1648</guid>

					<description><![CDATA[JavaScript countdown timers are useful interactive UI components for sale pages, ecommerce campaigns, product launches, event landing pages, webinar registrations, coming soon pages, limited-time offers, checkout urgency blocks, and dashboard widgets. They help show how much time is left before an offer ends, an event starts, a launch goes live, or an important deadline expires. [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">JavaScript countdown timers are useful interactive UI components for sale pages, ecommerce campaigns, product launches, event landing pages, webinar registrations, coming soon pages, limited-time offers, checkout urgency blocks, and dashboard widgets. They help show how much time is left before an offer ends, an event starts, a launch goes live, or an important deadline expires.</p>



<p class="wp-block-paragraph">In this guide, you will find 30 JavaScript countdown timer examples for real website projects, including sale countdown timers, event countdown timers, product launch timers, webinar timers, daily deal timers, checkout timers, coming soon timers, circular countdowns, flip clock timers, progress countdowns, card-based timers, sticky countdown bars, dashboard timers, responsive countdown sections, and reusable vanilla JavaScript timer components.</p>



<p class="wp-block-paragraph">This post focuses on JavaScript countdown timer logic, date calculations, time remaining updates, days, hours, minutes and seconds formatting, interval handling, expired states, responsive timer layouts, sale timer UI design, and copy-paste-ready HTML, CSS, and JavaScript examples. For related UI components, you can also explore our <a href="https://veebilehed24.ee/en/blog/javascript/javascript-accordion-examples/">JavaScript accordion examples</a>, <a href="https://veebilehed24.ee/en/blog/javascript/javascript-search-filter-examples/">JavaScript search filter examples</a>, <a href="https://veebilehed24.ee/en/blog/javascript/javascript-dropdown-menu-examples/">JavaScript dropdown menu examples</a>, and <a href="https://veebilehed24.ee/en/blog/javascript/javascript-slider-examples/">JavaScript slider examples</a>.</p>



<div class="vb24-js-countdown-jump-box">
  <a class="vb24-js-countdown-jump-button" href="#javascript-countdown-timer-examples">View All 30 JavaScript Countdown Timer Examples</a>
</div>

<style>
.vb24-js-countdown-jump-box {
  margin: 28px 0 36px;
}

.vb24-js-countdown-jump-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 14px 22px;
  border-radius: 999px;
  background: linear-gradient(135deg, #f97316, #ec4899 52%, #8b5cf6);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 850;
  line-height: 1.2;
  text-decoration: none !important;
  box-shadow: 0 16px 38px rgba(236, 72, 153, 0.30);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-js-countdown-jump-button::after {
  content: "↓";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.18);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  line-height: 1;
}

.vb24-js-countdown-jump-button:hover {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transform: translateY(-2px);
  filter: saturate(1.08);
  box-shadow: 0 20px 46px rgba(236, 72, 153, 0.38);
}

@media (max-width: 640px) {
  .vb24-js-countdown-jump-button {
    width: 100%;
    padding: 14px 16px;
    font-size: 14px;
  }
}
</style>



<div class="toc-affiliate-wrap vb24-js-countdown-toc-wrap">

  <div class="toc-left vb24-js-countdown-toc-left">

    <div class="vb24-js-countdown-toc-kicker">On this page</div>

    <h2>Table of Contents</h2>

    <ul class="vl24-toc vb24-js-countdown-toc">
      <li><a href="#what-is-a-javascript-countdown-timer">What Is a JavaScript Countdown Timer?</a></li>
      <li><a href="#why-countdown-timers-matter">Why Countdown Timers Matter</a></li>
      <li><a href="#javascript-countdown-timer-types">JavaScript Countdown Timer Types</a></li>
      <li><a href="#what-should-a-good-countdown-timer-include">What Should a Good Countdown Timer Include?</a></li>
      <li><a class="vb24-featured-toc-link" href="#javascript-countdown-timer-examples">30 JavaScript Countdown Timer Examples</a></li>
      <li><a href="#javascript-countdown-timer-best-practices">JavaScript Countdown Timer Best Practices</a></li>
      <li><a href="#responsive-countdown-timer-design-tips">Responsive Countdown Timer Design Tips</a></li>
      <li><a href="#common-javascript-countdown-timer-mistakes">Common JavaScript Countdown Timer Mistakes</a></li>
      <li><a href="#javascript-countdown-timer-faq">JavaScript Countdown Timer FAQ</a></li>
      <li><a href="#javascript-countdown-timer-conclusion">Conclusion</a></li>
      <li><a href="#related-javascript-and-css-guides">Related JavaScript and CSS Guides</a></li>
    </ul>

  </div>

  <div class="toc-right vb24-js-countdown-toc-right">

    <a class="vb24-entityschema-ad-card" href="https://veebilehed24.ee/en/shop/entityschema-pro/" target="_blank" rel="sponsored noopener">
      <span class="vb24-entityschema-ad-badge">WordPress SEO Plugin</span>

      <div class="vb24-entityschema-ad-image">
        <img decoding="async" src="https://veebilehed24.ee/wp-content/uploads/2026/03/entityschema-cover-600x400.webp" width="300" height="200" alt="EntitySchema Pro WordPress structured data and entity SEO plugin" loading="lazy">
      </div>

      <div class="vb24-entityschema-ad-content">
        <h3>EntitySchema Pro</h3>
        <p>Build a real entity-based structured data system for WordPress, modern SEO, and AI-readable websites.</p>

        <div class="vb24-entityschema-ad-price">
          <div class="vb24-entityschema-ad-price-left">
            <span class="vb24-entityschema-ad-price-label">Sale price</span>
            <span class="vb24-entityschema-ad-old-price">89€</span>
          </div>

          <strong class="vb24-entityschema-ad-sale-price">29€</strong>

          <span class="vb24-entityschema-ad-save">Save 60€</span>
        </div>

        <span class="vb24-entityschema-ad-button">View Plugin</span>
      </div>
    </a>

  </div>

</div>

<style>
.vb24-js-countdown-toc-wrap {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 26px;
  align-items: stretch;
  margin: 34px 0 44px;
}

.vb24-js-countdown-toc-left,
.vb24-js-countdown-toc-right {
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 28px;
  background: linear-gradient(135deg, #111827 0%, #7c2d12 48%, #4c1d95 100%);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.18);
}

.vb24-js-countdown-toc-left {
  padding: 28px 30px 30px;
}

.vb24-js-countdown-toc-kicker {
  margin-bottom: 10px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 13px;
  font-weight: 850;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb24-js-countdown-toc-left h2 {
  margin: 0 0 22px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px !important;
  line-height: 1.15 !important;
  font-weight: 850 !important;
}

.vb24-js-countdown-toc {
  display: grid !important;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px !important;
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb24-js-countdown-toc li {
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb24-js-countdown-toc li::before {
  display: none !important;
  content: none !important;
}

.vb24-js-countdown-toc a {
  display: flex;
  align-items: center;
  min-height: 54px;
  padding: 13px 15px;
  border: 1px solid rgba(148, 163, 184, 0.18);
  border-radius: 15px;
  background: rgba(255, 255, 255, 0.065);
  color: #f3f4f6 !important;
  -webkit-text-fill-color: #f3f4f6 !important;
  font-size: 15px;
  font-weight: 750;
  line-height: 1.35;
  text-decoration: none !important;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.05);
  transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease;
}

.vb24-js-countdown-toc a:hover {
  transform: translateY(-2px);
  border-color: rgba(249, 115, 22, 0.68);
  background: rgba(249, 115, 22, 0.16);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb24-js-countdown-toc .vb24-featured-toc-link {
  border-color: rgba(249, 115, 22, 0.78);
  background: linear-gradient(135deg, rgba(249, 115, 22, 0.34), rgba(236, 72, 153, 0.28), rgba(139, 92, 246, 0.26));
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb24-js-countdown-toc-right {
  display: flex;
  align-items: stretch;
  justify-content: center;
  padding: 16px;
  overflow: hidden;
}

.vb24-entityschema-ad-card,
.vb24-entityschema-ad-card * {
  box-sizing: border-box;
}

.vb24-entityschema-ad-card {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  min-height: 100%;
  padding: 12px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(34, 211, 238, 0.28), transparent 34%),
    radial-gradient(circle at 86% 14%, rgba(236, 72, 153, 0.24), transparent 36%),
    linear-gradient(135deg, #111827 0%, #312e81 52%, #701a75 100%) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  overflow: hidden;
  box-shadow: 0 20px 56px rgba(2, 6, 23, 0.32);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-entityschema-ad-card:hover {
  transform: translateY(-3px);
  filter: saturate(1.08);
  box-shadow: 0 26px 70px rgba(2, 6, 23, 0.42);
}

.vb24-entityschema-ad-badge {
  position: absolute;
  z-index: 3;
  top: 18px;
  left: 18px;
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.70);
  border: 1px solid rgba(255,255,255,0.22);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb24-entityschema-ad-image {
  overflow: hidden;
  border-radius: 17px;
  border: 1px solid rgba(255,255,255,0.16);
  background: rgba(255,255,255,0.08);
}

.vb24-entityschema-ad-image img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 17px;
}

.vb24-entityschema-ad-content {
  padding: 15px 8px 4px;
}

.vb24-entityschema-ad-content h3 {
  margin: 0 0 8px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 23px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb24-entityschema-ad-content p {
  margin: 0 0 14px !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 13px;
  line-height: 1.5;
  font-weight: 650;
}

.vb24-entityschema-ad-price {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin: 0 0 12px;
  padding: 11px 12px;
  border-radius: 16px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.16);
}

.vb24-entityschema-ad-price-left {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.vb24-entityschema-ad-price-label {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 11px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb24-entityschema-ad-old-price {
  color: rgba(255,255,255,0.62) !important;
  -webkit-text-fill-color: rgba(255,255,255,0.62) !important;
  font-size: 15px;
  line-height: 1;
  font-weight: 850;
  text-decoration: line-through;
  text-decoration-thickness: 2px;
  text-decoration-color: rgba(248, 113, 113, 0.95);
}

.vb24-entityschema-ad-sale-price {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 31px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb24-entityschema-ad-save {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 28px;
  padding: 6px 9px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.18);
  border: 1px solid rgba(74, 222, 128, 0.34);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 11px;
  font-weight: 950;
  white-space: nowrap;
}

.vb24-entityschema-ad-button {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 43px;
  padding: 12px 14px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22d3ee, #2563eb 55%, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
  box-shadow: 0 14px 34px rgba(37, 99, 235, 0.30);
}

@media (max-width: 900px) {
  .vb24-js-countdown-toc-wrap {
    grid-template-columns: 1fr;
  }

  .vb24-js-countdown-toc-right {
    justify-content: flex-start;
    max-width: 360px;
  }
}

@media (max-width: 640px) {
  .vb24-js-countdown-toc-left {
    padding: 22px 18px;
    border-radius: 22px;
  }

  .vb24-js-countdown-toc-left h2 {
    font-size: 26px !important;
  }

  .vb24-js-countdown-toc {
    grid-template-columns: 1fr;
  }

  .vb24-js-countdown-toc a {
    min-height: 48px;
    font-size: 14px;
  }

  .vb24-js-countdown-toc-right {
    max-width: 100%;
    border-radius: 22px;
  }
}
</style>



<h2 class="wp-block-heading" id="what-is-a-javascript-countdown-timer">What Is a JavaScript Countdown Timer?</h2>



<p class="wp-block-paragraph">A JavaScript countdown timer is an interactive component that calculates the time remaining until a specific date, time, offer deadline, product launch, event start, webinar, sale end, or campaign expiry. It usually displays days, hours, minutes, and seconds, then updates automatically while the visitor stays on the page.</p>



<p class="wp-block-paragraph">The main purpose of a countdown timer is to make time-sensitive information clear. Instead of writing “Sale ends soon” or “Event starts next week,” a countdown timer shows the exact remaining time in a visual format that is easy to understand at a glance.</p>



<p class="wp-block-paragraph">A JavaScript countdown timer can be very simple or highly advanced. A basic version may count down to one fixed date. A more advanced version may include recurring daily timers, limited-time offers, timezone-aware deadlines, animated digits, flip clock effects, circular progress, expired states, reset logic, local storage, dynamic labels, or multiple timers on the same page.</p>



<h2 class="wp-block-heading" id="why-countdown-timers-matter">Why Countdown Timers Matter</h2>



<p class="wp-block-paragraph">Countdown timers matter because many website visitors need clear timing information before they take action. If a sale, registration, product launch, event, limited offer, or booking window has a deadline, a countdown timer can make that deadline more visible and easier to understand.</p>



<ul class="wp-block-list">
  <li><strong>They highlight urgency</strong> by showing exactly how much time is left before an offer or event ends.</li>
  <li><strong>They improve campaign pages</strong> by making sale deadlines, launch dates, webinar times, and event registrations more visible.</li>
  <li><strong>They support ecommerce pages</strong> by showing flash sales, daily deals, cart reservation timers, checkout timers, and limited stock campaigns.</li>
  <li><strong>They improve landing page clarity</strong> by turning abstract deadlines into a clear visual UI element.</li>
  <li><strong>They help users make decisions</strong> when a deadline, booking window, or special offer is important to the next step.</li>
</ul>



<p class="wp-block-paragraph">Countdown timers should be used carefully. They work best when the deadline is real and useful. A timer should support the page message, not feel fake or manipulative. A good JavaScript countdown timer gives visitors clear information, improves the visual hierarchy, and makes the page easier to understand.</p>



<h2 class="wp-block-heading" id="javascript-countdown-timer-types">JavaScript Countdown Timer Types</h2>



<p class="wp-block-paragraph">There are many different types of JavaScript countdown timers. Some are simple text-based timers, while others are designed as full sale banners, checkout urgency blocks, event hero sections, product launch cards, dashboard widgets, or animated visual components.</p>



<p class="wp-block-paragraph">The right countdown timer depends on the goal of the page. A sale timer should be highly visible and conversion-focused. An event timer should clearly show the event date and registration action. A dashboard timer may be compact and functional. A coming soon timer can be more visual, atmospheric, and brand-focused.</p>



<ul class="wp-block-list">
  <li><strong>Sale countdown timers</strong> are used for flash sales, discount campaigns, limited-time promotions, and seasonal offers.</li>
  <li><strong>Event countdown timers</strong> show the time left before webinars, conferences, launches, workshops, and live events.</li>
  <li><strong>Checkout countdown timers</strong> can show cart reservation time, payment deadlines, or limited checkout offers.</li>
  <li><strong>Coming soon countdown timers</strong> are useful for new websites, app launches, product releases, and landing pages.</li>
  <li><strong>Recurring countdown timers</strong> reset daily, weekly, or monthly for repeated campaigns or scheduled availability.</li>
  <li><strong>Animated countdown timers</strong> use flip cards, circles, progress bars, number transitions, or motion effects to make the timer more visual.</li>
</ul>



<p class="wp-block-paragraph">This guide focuses on JavaScript countdown timer examples, so every demo will include visible JavaScript, HTML, and CSS code. The examples are designed to be copy-paste friendly, easy to customize, and different in layout, purpose, visual style, timer logic, and responsive behavior.</p>



<h2 class="wp-block-heading" id="what-should-a-good-countdown-timer-include">What Should a Good Countdown Timer Include?</h2>



<p class="wp-block-paragraph">A good JavaScript countdown timer should be accurate, readable, responsive, and visually connected to the page goal. Users should quickly understand what the timer is counting down to, how much time is left, and what action they can take before the deadline ends.</p>



<div class="vb24-js-countdown-checklist">
  <div class="vb24-js-countdown-check-item">
    <h3>Clear deadline context</h3>
    <p>The timer should explain what happens when the countdown reaches zero, such as a sale ending, event starting, launch opening, or offer expiring.</p>
  </div>

  <div class="vb24-js-countdown-check-item">
    <h3>Readable time units</h3>
    <p>Days, hours, minutes, and seconds should be easy to scan, with labels that stay readable on desktop, tablet, and mobile screens.</p>
  </div>

  <div class="vb24-js-countdown-check-item">
    <h3>Automatic updates</h3>
    <p>JavaScript should update the remaining time regularly and handle expired states when the countdown reaches zero.</p>
  </div>

  <div class="vb24-js-countdown-check-item">
    <h3>Strong visual hierarchy</h3>
    <p>The countdown should stand out enough to support the campaign, but it should not make the page feel messy or hard to read.</p>
  </div>
</div>

<style>
.vb24-js-countdown-checklist {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 30px;
}

.vb24-js-countdown-check-item {
  padding: 20px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 22px;
  background:
    radial-gradient(circle at 18% 10%, rgba(249, 115, 22, 0.10), transparent 32%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb24-js-countdown-check-item h3 {
  margin: 0 0 10px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 850;
}

.vb24-js-countdown-check-item p {
  margin: 0;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb24-js-countdown-checklist {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-js-countdown-checklist {
    grid-template-columns: 1fr;
  }

  .vb24-js-countdown-check-item {
    padding: 18px;
    border-radius: 20px;
  }
}
</style>



<p class="wp-block-paragraph">Before building a countdown timer, decide what the timer should do after it reaches zero. Should it show an expired message, hide the offer, disable a button, change the call-to-action, reset automatically, or show a new deadline? This behavior is important because a countdown timer is not only a visual element — it is part of the page logic.</p>



<ul class="wp-block-list">
  <li><strong>Use a real deadline</strong> so the countdown feels trustworthy and useful.</li>
  <li><strong>Show clear labels</strong> for days, hours, minutes, and seconds.</li>
  <li><strong>Handle expired states</strong> when the countdown reaches zero.</li>
  <li><strong>Keep the timer readable</strong> with enough contrast, spacing, and font size.</li>
  <li><strong>Use responsive layout rules</strong> so the timer works on phones and tablets.</li>
  <li><strong>Keep JavaScript scoped</strong> so multiple timers can work on the same page.</li>
  <li><strong>Avoid fake urgency</strong> because misleading timers can damage trust.</li>
  <li><strong>Test timezone behavior</strong> if the deadline is important across different regions.</li>
  <li><strong>Use clear call-to-action text</strong> near the timer when users should take action.</li>
  <li><strong>Keep animation purposeful</strong> so the timer looks polished without becoming distracting.</li>
</ul>



<p class="wp-block-paragraph">You can combine JavaScript countdown timers with many other website UI patterns. Sale timers work well with <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-pricing-tables/">modern CSS pricing tables</a>, event timers can be placed inside <a href="https://veebilehed24.ee/en/blog/css-effects/modern-website-hero-sections/">modern website hero sections</a>, checkout urgency timers can pair with <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-forms/">modern CSS forms</a>, and campaign sections can use layouts from our <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-layouts/">modern CSS layouts</a> guide.</p>



<h2 class="wp-block-heading" id="javascript-countdown-timer-examples">30 JavaScript Countdown Timer Examples</h2>



<p class="wp-block-paragraph">Now let’s look at 30 JavaScript countdown timer examples for real website projects. Each example uses a different timer layout, visual style, countdown purpose, sale campaign design, event UI, product launch pattern, checkout urgency block, dashboard widget, animated number style, expired state, or responsive countdown approach, so you can build professional time-based UI components with visible JavaScript, HTML, and CSS code.</p>



<h2 class="wp-block-heading">1. Flash Sale Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A flash sale countdown timer</strong> is useful for ecommerce campaigns, landing pages, seasonal discounts, product promotions, and limited-time offers. It gives visitors a clear visual deadline and helps highlight when a sale period is ending.</p>



<p class="wp-block-paragraph">This example uses a bold ecommerce sale banner with a strong discount badge, large countdown cards, campaign text, and a clear call-to-action button. The JavaScript uses a rolling weekly campaign cycle, so the demo keeps working in the future without showing an expired old date.</p>



<ul class="wp-block-list">
<li>Flash sale countdown timer</li>
<li>Days, hours, minutes, and seconds</li>
<li>Future-proof rolling campaign logic</li>
<li>Responsive ecommerce sale banner</li>
<li>Large numbers that stay inside the cards</li>
</ul>



<div class="vb-countdown-one-demo">
  <div class="vb-countdown-one-sale" data-vb-countdown-one data-cycle-days="7">
    <div class="vb-countdown-one-copy">
      <span class="vb-countdown-one-kicker">Example 01</span>
      <h3>Flash Sale Countdown Timer</h3>
      <p>Show the remaining time for a weekly flash sale, limited product offer, seasonal campaign, or ecommerce promotion.</p>

      <div class="vb-countdown-one-offer">
        <strong>40% OFF</strong>
        <span>Limited-time ecommerce campaign</span>
      </div>
    </div>

    <div class="vb-countdown-one-panel">
      <div class="vb-countdown-one-panel-head">
        <span>Flash Sale</span>
        <strong data-cycle-label>Sale active</strong>
      </div>

      <div class="vb-countdown-one-timer" aria-label="Flash sale countdown timer">
        <div class="vb-countdown-one-unit">
          <strong data-days>00</strong>
          <span>Days</span>
        </div>

        <div class="vb-countdown-one-unit">
          <strong data-hours>00</strong>
          <span>Hours</span>
        </div>

        <div class="vb-countdown-one-unit">
          <strong data-minutes>00</strong>
          <span>Minutes</span>
        </div>

        <div class="vb-countdown-one-unit">
          <strong data-seconds>00</strong>
          <span>Seconds</span>
        </div>
      </div>

      <p class="vb-countdown-one-status" data-status>Offer ends soon. Grab the deal before the timer reaches zero.</p>

      <a class="vb-countdown-one-button" href="#shop-sale">Shop the Sale</a>
    </div>
  </div>
</div>

<style>
.vb-countdown-one-demo,
.vb-countdown-one-demo * {
  box-sizing: border-box;
}

.vb-countdown-one-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: clamp(26px, 4vw, 42px);
  background:
    radial-gradient(circle at 14% 18%, rgba(249, 115, 22, 0.26), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(236, 72, 153, 0.22), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #fdf2f8 52%, #ffffff 100%) !important;
  border: 1px solid rgba(251, 146, 60, 0.34);
  box-shadow: 0 28px 80px rgba(124, 45, 18, 0.12);
}

.vb-countdown-one-sale {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: clamp(20px, 3vw, 30px);
  align-items: stretch;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(22px, 4vw, 34px);
  overflow: hidden;
  border-radius: clamp(24px, 4vw, 34px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.20), transparent 34%),
    linear-gradient(135deg, #111827 0%, #7c2d12 48%, #be123c 100%) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.26);
}

.vb-countdown-one-sale::before {
  content: "";
  position: absolute;
  right: -110px;
  bottom: -130px;
  width: 340px;
  height: 340px;
  border-radius: 999px;
  background: rgba(251, 191, 36, 0.18);
  filter: blur(3px);
}

.vb-countdown-one-sale::after {
  content: "";
  position: absolute;
  left: -90px;
  top: -110px;
  width: 260px;
  height: 260px;
  border-radius: 999px;
  background: rgba(236, 72, 153, 0.18);
  filter: blur(4px);
}

.vb-countdown-one-copy,
.vb-countdown-one-panel {
  position: relative;
  z-index: 2;
  min-width: 0;
}

.vb-countdown-one-copy {
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.vb-countdown-one-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-one-copy h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 6vw, 70px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-countdown-one-copy p {
  max-width: 560px;
  margin: 0 0 24px !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-one-offer {
  display: inline-grid;
  align-self: flex-start;
  gap: 5px;
  max-width: 100%;
  padding: 18px 20px;
  border-radius: 22px 22px 22px 6px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.18);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.10);
}

.vb-countdown-one-offer strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4vw, 40px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-countdown-one-offer span {
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 850;
}

.vb-countdown-one-panel {
  display: grid;
  align-content: center;
  gap: 18px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 28px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  backdrop-filter: blur(12px);
}

.vb-countdown-one-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
}

.vb-countdown-one-panel-head span {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  color: #fff7ed !important;
  -webkit-text-fill-color: #fff7ed !important;
  font-size: 12px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-countdown-one-panel-head strong {
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 13px;
  font-weight: 850;
  text-align: right;
}

.vb-countdown-one-timer {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(8px, 1.5vw, 12px);
}

.vb-countdown-one-unit {
  min-width: 0;
  padding: clamp(14px, 2vw, 18px) clamp(7px, 1.2vw, 10px);
  border-radius: clamp(16px, 2vw, 22px);
  background: #ffffff;
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.18);
  text-align: center;
}

.vb-countdown-one-unit strong {
  display: block;
  max-width: 100%;
  margin-bottom: 8px;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: clamp(24px, 3.4vw, 42px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-one-unit span {
  display: block;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: clamp(9px, 1.2vw, 11px);
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-countdown-one-status {
  margin: 0 !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-countdown-one-button {
  display: inline-flex;
  justify-self: start;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #f97316, #ec4899);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 38px rgba(236, 72, 153, 0.34);
}

@media (max-width: 980px) {
  .vb-countdown-one-sale {
    grid-template-columns: 1fr;
  }

  .vb-countdown-one-unit strong {
    font-size: clamp(30px, 8vw, 52px);
  }
}

@media (max-width: 700px) {
  .vb-countdown-one-copy h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-one-panel-head {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-countdown-one-panel-head strong {
    text-align: left;
  }

  .vb-countdown-one-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-one-unit strong {
    font-size: clamp(30px, 13vw, 46px);
  }

  .vb-countdown-one-button {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-one-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-one]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 7;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-01T00:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");
  const cycleLabelEl = timer.querySelector("[data-cycle-label]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextCycleEnd(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextCycleEnd = getNextCycleEnd(now);
    let remaining = nextCycleEnd - now;

    if (remaining <= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);

    cycleLabelEl.textContent = "Sale ends this cycle";
    statusEl.textContent = "Offer ends soon. Grab the deal before the timer reaches zero.";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-one]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 7;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-01T00:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");
  const cycleLabelEl = timer.querySelector("[data-cycle-label]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextCycleEnd(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextCycleEnd = getNextCycleEnd(now);
    let remaining = nextCycleEnd - now;

    if (remaining &lt;= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);

    cycleLabelEl.textContent = "Sale ends this cycle";
    statusEl.textContent = "Offer ends soon. Grab the deal before the timer reaches zero.";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-one-demo"&gt;
  &lt;div class="vb-countdown-one-sale" data-vb-countdown-one data-cycle-days="7"&gt;
    &lt;div class="vb-countdown-one-copy"&gt;
      &lt;span class="vb-countdown-one-kicker"&gt;Example 01&lt;/span&gt;
      &lt;h3&gt;Flash Sale Countdown Timer&lt;/h3&gt;
      &lt;p&gt;Show the remaining time for a weekly flash sale, limited product offer, seasonal campaign, or ecommerce promotion.&lt;/p&gt;

      &lt;div class="vb-countdown-one-offer"&gt;
        &lt;strong&gt;40% OFF&lt;/strong&gt;
        &lt;span&gt;Limited-time ecommerce campaign&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-one-panel"&gt;
      &lt;div class="vb-countdown-one-panel-head"&gt;
        &lt;span&gt;Flash Sale&lt;/span&gt;
        &lt;strong data-cycle-label&gt;Sale active&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-one-timer" aria-label="Flash sale countdown timer"&gt;
        &lt;div class="vb-countdown-one-unit"&gt;
          &lt;strong data-days&gt;00&lt;/strong&gt;
          &lt;span&gt;Days&lt;/span&gt;
        &lt;/div&gt;

        &lt;div class="vb-countdown-one-unit"&gt;
          &lt;strong data-hours&gt;00&lt;/strong&gt;
          &lt;span&gt;Hours&lt;/span&gt;
        &lt;/div&gt;

        &lt;div class="vb-countdown-one-unit"&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
          &lt;span&gt;Minutes&lt;/span&gt;
        &lt;/div&gt;

        &lt;div class="vb-countdown-one-unit"&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
          &lt;span&gt;Seconds&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;p class="vb-countdown-one-status" data-status&gt;Offer ends soon. Grab the deal before the timer reaches zero.&lt;/p&gt;

      &lt;a class="vb-countdown-one-button" href="#shop-sale"&gt;Shop the Sale&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">/* CSS is included in the live preview above. */</pre>



<p class="wp-block-paragraph">This flash sale countdown timer is useful for ecommerce sale sections, landing page campaigns, seasonal offers, product promotions, weekly deals, and limited-time discount banners.</p>



<h2 class="wp-block-heading">2. Event Launch Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>An event launch countdown timer</strong> is useful for conferences, webinars, workshops, online summits, livestreams, product demos, registration pages, and event landing pages. It helps visitors quickly understand when the next event begins.</p>



<p class="wp-block-paragraph">This example uses a clean ticket-style layout with a vertical event date panel, event information, compact countdown cards, and a registration-focused call-to-action. The JavaScript calculates the next event in a recurring event cycle, so the example stays active in the future.</p>



<ul class="wp-block-list">
<li>Event launch countdown timer</li>
<li>Ticket-style event layout</li>
<li>Days, hours, minutes, and seconds</li>
<li>Future-proof recurring event logic</li>
<li>Fully responsive event section</li>
</ul>



<div class="vb-countdown-two-demo">
  <div class="vb-countdown-two-event" data-vb-countdown-two data-cycle-days="14">
    <div class="vb-countdown-two-date">
      <span data-event-month>LIVE</span>
      <strong data-event-day>--</strong>
      <small data-event-year>Event</small>
    </div>

    <div class="vb-countdown-two-info">
      <span class="vb-countdown-two-kicker">Example 02</span>
      <h3>Event Launch Countdown Timer</h3>
      <p>Show how much time is left before the next webinar, workshop, product demo, conference, or live online event.</p>

      <div class="vb-countdown-two-meta">
        <span>Live Online</span>
        <span data-event-cycle>Event cycle active</span>
        <span>Free Registration</span>
      </div>
    </div>

    <div class="vb-countdown-two-box">
      <div class="vb-countdown-two-box-head">
        <strong>Next event starts in</strong>
        <span data-next-label>Loading next date</span>
      </div>

      <div class="vb-countdown-two-timer" aria-label="Event launch countdown timer">
        <div>
          <strong data-days>00</strong>
          <span>Days</span>
        </div>

        <div>
          <strong data-hours>00</strong>
          <span>Hours</span>
        </div>

        <div>
          <strong data-minutes>00</strong>
          <span>Min</span>
        </div>

        <div>
          <strong data-seconds>00</strong>
          <span>Sec</span>
        </div>
      </div>

      <p data-status>Registration is open for the next event.</p>
      <a href="#register">Reserve Your Seat</a>
    </div>
  </div>
</div>

<style>
.vb-countdown-two-demo,
.vb-countdown-two-demo * {
  box-sizing: border-box;
}

.vb-countdown-two-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 8px 56px 8px 56px;
  background:
    linear-gradient(90deg, rgba(15, 23, 42, 0.05) 1px, transparent 1px),
    linear-gradient(0deg, rgba(15, 23, 42, 0.05) 1px, transparent 1px),
    linear-gradient(135deg, #f8fafc 0%, #eff6ff 52%, #ffffff 100%) !important;
  background-size: 28px 28px, 28px 28px, auto !important;
  border: 1px solid rgba(59, 130, 246, 0.22);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-countdown-two-event {
  display: grid;
  grid-template-columns: 132px minmax(0, 1fr) minmax(0, 380px);
  gap: 24px;
  align-items: stretch;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(14px, 2vw, 18px);
  border-radius: 6px 42px 6px 42px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.11);
}

.vb-countdown-two-date {
  display: grid;
  place-items: center;
  align-content: center;
  gap: 8px;
  min-width: 0;
  min-height: 300px;
  border-radius: 4px 30px 4px 30px;
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.22), transparent 34%),
    linear-gradient(135deg, #1e3a8a, #2563eb 55%, #06b6d4) !important;
  color: #ffffff;
}

.vb-countdown-two-date span {
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 14px;
  font-weight: 950;
  letter-spacing: 0.16em;
  text-transform: uppercase;
}

.vb-countdown-two-date strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(48px, 7vw, 78px);
  line-height: 0.85;
  font-weight: 950;
  letter-spacing: -0.06em;
  font-variant-numeric: tabular-nums;
}

.vb-countdown-two-date small {
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-countdown-two-info {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
  padding: 24px 0;
}

.vb-countdown-two-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 6px 16px 6px 16px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-two-info h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5.3vw, 68px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-countdown-two-info p {
  max-width: 620px;
  margin: 0 0 20px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-two-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.vb-countdown-two-meta span {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: #f1f5f9;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-two-box {
  display: grid;
  align-content: center;
  gap: 16px;
  min-width: 0;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 34px 4px 34px 4px;
  background: #0f172a;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
}

.vb-countdown-two-box-head {
  display: grid;
  gap: 5px;
}

.vb-countdown-two-box-head strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-countdown-two-box-head span {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 13px;
  line-height: 1.4;
  font-weight: 750;
}

.vb-countdown-two-timer {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 9px;
}

.vb-countdown-two-timer div {
  min-width: 0;
  overflow: hidden;
  padding: 15px 7px;
  border-radius: 18px 4px 18px 4px;
  background:
    radial-gradient(circle at 24% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, rgba(37, 99, 235, 0.34), rgba(6, 182, 212, 0.18)) !important;
  border: 1px solid rgba(255,255,255,0.12);
  text-align: center;
}

.vb-countdown-two-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 5px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(22px, 2.9vw, 32px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.035em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-two-timer span {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-countdown-two-box p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-countdown-two-box a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 46px;
  padding: 12px 16px;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 13px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(37, 99, 235, 0.34);
}

@media (max-width: 1080px) {
  .vb-countdown-two-event {
    grid-template-columns: 112px minmax(0, 1fr);
  }

  .vb-countdown-two-box {
    grid-column: 1 / -1;
  }

  .vb-countdown-two-timer strong {
    font-size: clamp(28px, 6vw, 42px);
  }
}

@media (max-width: 700px) {
  .vb-countdown-two-event {
    grid-template-columns: 1fr;
  }

  .vb-countdown-two-date {
    min-height: 170px;
  }

  .vb-countdown-two-info {
    padding: 8px 4px;
  }

  .vb-countdown-two-info h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-two-box a {
    width: 100%;
  }

  .vb-countdown-two-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-two-timer strong {
    font-size: clamp(30px, 13vw, 46px);
  }
}

@media (max-width: 360px) {
  .vb-countdown-two-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-two]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 14;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-05T18:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");
  const nextLabelEl = timer.querySelector("[data-next-label]");
  const eventMonthEl = timer.querySelector("[data-event-month]");
  const eventDayEl = timer.querySelector("[data-event-day]");
  const eventYearEl = timer.querySelector("[data-event-year]");
  const eventCycleEl = timer.querySelector("[data-event-cycle]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextEventTime(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateEventDate(nextEventTime) {
    const eventDate = new Date(nextEventTime);
    const month = eventDate.toLocaleString("en-US", { month: "short" }).toUpperCase();

    eventMonthEl.textContent = month;
    eventDayEl.textContent = formatNumber(eventDate.getDate());
    eventYearEl.textContent = eventDate.getFullYear();
    nextLabelEl.textContent = "Next event: " + month + " " + eventDate.getDate();
    eventCycleEl.textContent = "Event schedule active";
  }

  function updateCountdown() {
    const now = Date.now();
    const nextEventTime = getNextEventTime(now);
    let remaining = nextEventTime - now;

    if (remaining <= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);

    updateEventDate(nextEventTime);
    statusEl.textContent = "Registration is open for the next event.";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-two]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 14;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-05T18:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");
  const nextLabelEl = timer.querySelector("[data-next-label]");
  const eventMonthEl = timer.querySelector("[data-event-month]");
  const eventDayEl = timer.querySelector("[data-event-day]");
  const eventYearEl = timer.querySelector("[data-event-year]");
  const eventCycleEl = timer.querySelector("[data-event-cycle]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextEventTime(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateEventDate(nextEventTime) {
    const eventDate = new Date(nextEventTime);
    const month = eventDate.toLocaleString("en-US", { month: "short" }).toUpperCase();

    eventMonthEl.textContent = month;
    eventDayEl.textContent = formatNumber(eventDate.getDate());
    eventYearEl.textContent = eventDate.getFullYear();
    nextLabelEl.textContent = "Next event: " + month + " " + eventDate.getDate();
    eventCycleEl.textContent = "Event schedule active";
  }

  function updateCountdown() {
    const now = Date.now();
    const nextEventTime = getNextEventTime(now);
    let remaining = nextEventTime - now;

    if (remaining &lt;= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);

    updateEventDate(nextEventTime);
    statusEl.textContent = "Registration is open for the next event.";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-two-demo"&gt;
  &lt;div class="vb-countdown-two-event" data-vb-countdown-two data-cycle-days="14"&gt;
    &lt;div class="vb-countdown-two-date"&gt;
      &lt;span data-event-month&gt;LIVE&lt;/span&gt;
      &lt;strong data-event-day&gt;--&lt;/strong&gt;
      &lt;small data-event-year&gt;Event&lt;/small&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-two-info"&gt;
      &lt;span class="vb-countdown-two-kicker"&gt;Example 02&lt;/span&gt;
      &lt;h3&gt;Event Launch Countdown Timer&lt;/h3&gt;
      &lt;p&gt;Show how much time is left before the next webinar, workshop, product demo, conference, or live online event.&lt;/p&gt;

      &lt;div class="vb-countdown-two-meta"&gt;
        &lt;span&gt;Live Online&lt;/span&gt;
        &lt;span data-event-cycle&gt;Event cycle active&lt;/span&gt;
        &lt;span&gt;Free Registration&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-two-box"&gt;
      &lt;div class="vb-countdown-two-box-head"&gt;
        &lt;strong&gt;Next event starts in&lt;/strong&gt;
        &lt;span data-next-label&gt;Loading next date&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-two-timer" aria-label="Event launch countdown timer"&gt;
        &lt;div&gt;
          &lt;strong data-days&gt;00&lt;/strong&gt;
          &lt;span&gt;Days&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-hours&gt;00&lt;/strong&gt;
          &lt;span&gt;Hours&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
          &lt;span&gt;Min&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
          &lt;span&gt;Sec&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;p data-status&gt;Registration is open for the next event.&lt;/p&gt;
      &lt;a href="#register"&gt;Reserve Your Seat&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">/* CSS is included in the live preview above. */</pre>



<p class="wp-block-paragraph">This event launch countdown timer is useful for webinar landing pages, conference registration pages, online summits, product demos, workshop announcements, livestream events, and recurring event sections.</p>



<h2 class="wp-block-heading">3. Product Launch Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A product launch countdown timer</strong> is useful for app releases, SaaS launches, preorder pages, startup landing pages, coming soon sections, digital product drops, and new feature announcements. It helps build anticipation and shows visitors when the product becomes available.</p>



<p class="wp-block-paragraph">This example uses a futuristic product launch layout with a dark glass UI, glowing product orb, launch date badge, email signup form, and responsive countdown blocks. The demo calculates the next launch cycle dynamically, so the countdown keeps working in the future.</p>



<ul class="wp-block-list">
<li>Product launch countdown timer</li>
<li>Futuristic SaaS-style launch design</li>
<li>Days, hours, minutes, and seconds</li>
<li>Email signup form</li>
<li>Responsive layout and readable timer numbers</li>
</ul>



<div class="vb-countdown-three-demo">
  <div class="vb-countdown-three-launch" data-vb-countdown-three data-cycle-days="30">
    <div class="vb-countdown-three-visual">
      <div class="vb-countdown-three-grid"></div>
      <div class="vb-countdown-three-orb">
        <span>JS</span>
      </div>
      <div class="vb-countdown-three-ring vb-countdown-three-ring-one"></div>
      <div class="vb-countdown-three-ring vb-countdown-three-ring-two"></div>
      <div class="vb-countdown-three-dot vb-countdown-three-dot-one"></div>
      <div class="vb-countdown-three-dot vb-countdown-three-dot-two"></div>
    </div>

    <div class="vb-countdown-three-content">
      <span class="vb-countdown-three-kicker">Example 03</span>
      <h3>Product Launch Countdown Timer</h3>
      <p>Use a launch countdown timer for new products, app releases, SaaS features, preorder campaigns, digital products, and startup landing pages.</p>

      <div class="vb-countdown-three-launch-meta">
        <span data-next-launch>Next launch date loading</span>
        <strong>Early access opens soon</strong>
      </div>

      <div class="vb-countdown-three-timer" aria-label="Product launch countdown timer">
        <div>
          <strong data-days>00</strong>
          <span>Days</span>
        </div>

        <div>
          <strong data-hours>00</strong>
          <span>Hours</span>
        </div>

        <div>
          <strong data-minutes>00</strong>
          <span>Minutes</span>
        </div>

        <div>
          <strong data-seconds>00</strong>
          <span>Seconds</span>
        </div>
      </div>

      <p class="vb-countdown-three-status" data-status>The product launch is coming soon. Join the waiting list before early access opens.</p>

      <form class="vb-countdown-three-form">
        <input type="email" placeholder="Enter your email" aria-label="Email address">
        <button type="button">Notify Me</button>
      </form>
    </div>
  </div>
</div>

<style>
.vb-countdown-three-demo,
.vb-countdown-three-demo * {
  box-sizing: border-box;
}

.vb-countdown-three-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: clamp(28px, 5vw, 58px) clamp(28px, 5vw, 58px) 14px clamp(28px, 5vw, 58px);
  background:
    radial-gradient(circle at 18% 18%, rgba(34, 211, 238, 0.18), transparent 34%),
    radial-gradient(circle at 84% 20%, rgba(168, 85, 247, 0.22), transparent 36%),
    linear-gradient(135deg, #020617 0%, #111827 52%, #1e1b4b 100%) !important;
  border: 1px solid rgba(125, 211, 252, 0.20);
  box-shadow: 0 34px 96px rgba(2, 6, 23, 0.42);
}

.vb-countdown-three-launch {
  display: grid;
  grid-template-columns: minmax(260px, 0.84fr) minmax(0, 1.16fr);
  gap: clamp(24px, 4vw, 38px);
  align-items: center;
  max-width: 1160px;
  margin: 0 auto;
}

.vb-countdown-three-visual {
  position: relative;
  min-width: 0;
  min-height: clamp(320px, 44vw, 500px);
  overflow: hidden;
  border-radius: clamp(28px, 4vw, 46px) clamp(28px, 4vw, 46px) 10px clamp(28px, 4vw, 46px);
  background:
    radial-gradient(circle at 50% 50%, rgba(34, 211, 238, 0.22), transparent 30%),
    linear-gradient(135deg, rgba(255,255,255,0.09), rgba(255,255,255,0.025)) !important;
  border: 1px solid rgba(255,255,255,0.11);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
}

.vb-countdown-three-grid {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(rgba(125,211,252,0.08) 1px, transparent 1px),
    linear-gradient(90deg, rgba(125,211,252,0.08) 1px, transparent 1px);
  background-size: 34px 34px;
  mask-image: radial-gradient(circle at center, black 0%, transparent 75%);
}

.vb-countdown-three-orb {
  position: absolute;
  left: 50%;
  top: 50%;
  width: clamp(140px, 20vw, 196px);
  height: clamp(140px, 20vw, 196px);
  border-radius: 999px;
  transform: translate(-50%, -50%);
  background:
    radial-gradient(circle at 32% 28%, rgba(255,255,255,0.52), transparent 22%),
    linear-gradient(135deg, #22d3ee, #2563eb 52%, #a855f7) !important;
  box-shadow:
    0 0 44px rgba(34, 211, 238, 0.46),
    0 0 100px rgba(168, 85, 247, 0.30);
}

.vb-countdown-three-orb span {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(40px, 7vw, 58px);
  font-weight: 950;
  letter-spacing: -0.08em;
}

.vb-countdown-three-ring {
  position: absolute;
  left: 50%;
  top: 50%;
  border-radius: 999px;
  transform: translate(-50%, -50%);
  border: 1px solid rgba(125, 211, 252, 0.28);
}

.vb-countdown-three-ring-one {
  width: clamp(220px, 32vw, 320px);
  height: clamp(220px, 32vw, 320px);
}

.vb-countdown-three-ring-two {
  width: clamp(280px, 40vw, 410px);
  height: clamp(280px, 40vw, 410px);
  border-color: rgba(168, 85, 247, 0.25);
}

.vb-countdown-three-dot {
  position: absolute;
  width: 18px;
  height: 18px;
  border-radius: 999px;
}

.vb-countdown-three-dot-one {
  left: 21%;
  top: 28%;
  background: #67e8f9;
  box-shadow: 0 0 24px rgba(103, 232, 249, 0.72);
}

.vb-countdown-three-dot-two {
  right: 18%;
  bottom: 25%;
  background: #c084fc;
  box-shadow: 0 0 24px rgba(192, 132, 252, 0.72);
}

.vb-countdown-three-content {
  min-width: 0;
}

.vb-countdown-three-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(34, 211, 238, 0.12);
  border: 1px solid rgba(125, 211, 252, 0.18);
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-three-content h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5.7vw, 76px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-countdown-three-content p {
  max-width: 680px;
  margin: 0 0 22px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: clamp(15px, 1.7vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-three-launch-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 16px;
}

.vb-countdown-three-launch-meta span,
.vb-countdown-three-launch-meta strong {
  display: inline-flex;
  align-items: center;
  min-height: 38px;
  padding: 9px 12px;
  border-radius: 999px;
  font-size: 12px;
  line-height: 1.25;
  font-weight: 900;
}

.vb-countdown-three-launch-meta span {
  background: rgba(34, 211, 238, 0.12);
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  border: 1px solid rgba(125, 211, 252, 0.16);
}

.vb-countdown-three-launch-meta strong {
  background: rgba(168, 85, 247, 0.14);
  color: #ddd6fe !important;
  -webkit-text-fill-color: #ddd6fe !important;
  border: 1px solid rgba(196, 181, 253, 0.16);
}

.vb-countdown-three-timer {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(8px, 1.4vw, 12px);
  margin-bottom: 18px;
}

.vb-countdown-three-timer div {
  min-width: 0;
  position: relative;
  overflow: hidden;
  padding: clamp(14px, 2vw, 18px) clamp(7px, 1.2vw, 10px);
  border-radius: 24px 24px 8px 24px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
}

.vb-countdown-three-timer div::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 3px;
  background: linear-gradient(90deg, #22d3ee, #a855f7);
}

.vb-countdown-three-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 8px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(24px, 3.5vw, 44px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-three-timer span {
  display: block;
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: clamp(9px, 1.1vw, 11px);
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-countdown-three-status {
  margin-bottom: 18px !important;
}

.vb-countdown-three-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 140px;
  gap: 10px;
  max-width: 560px;
}

.vb-countdown-three-form input {
  width: 100%;
  min-width: 0;
  min-height: 52px;
  padding: 0 16px;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,0.14);
  outline: none;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 700;
}

.vb-countdown-three-form input::placeholder {
  color: rgba(226, 232, 240, 0.72);
  -webkit-text-fill-color: rgba(226, 232, 240, 0.72);
}

.vb-countdown-three-form button {
  min-height: 52px;
  padding: 0 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #22d3ee, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(34, 211, 238, 0.22);
}

@media (max-width: 980px) {
  .vb-countdown-three-launch {
    grid-template-columns: 1fr;
  }

  .vb-countdown-three-visual {
    min-height: 360px;
  }

  .vb-countdown-three-timer strong {
    font-size: clamp(30px, 8vw, 52px);
  }
}

@media (max-width: 700px) {
  .vb-countdown-three-content h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-three-visual {
    min-height: 310px;
    border-radius: 28px 28px 8px 28px;
  }

  .vb-countdown-three-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-three-timer strong {
    font-size: clamp(30px, 13vw, 46px);
  }

  .vb-countdown-three-form {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 360px) {
  .vb-countdown-three-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-three]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 30;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-10T10:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextLaunchEl = timer.querySelector("[data-next-launch]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextLaunch(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextLaunch = getNextLaunch(now);
    let remaining = nextLaunch - now;

    if (remaining <= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const launchDate = new Date(nextLaunch);
    const dateText = launchDate.toLocaleDateString("en-US", {
      month: "short",
      day: "numeric",
      year: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextLaunchEl.textContent = "Next launch: " + dateText;
    statusEl.textContent = "The product launch is coming soon. Join the waiting list before early access opens.";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-three]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 30;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-10T10:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextLaunchEl = timer.querySelector("[data-next-launch]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextLaunch(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextLaunch = getNextLaunch(now);
    let remaining = nextLaunch - now;

    if (remaining &lt;= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const launchDate = new Date(nextLaunch);
    const dateText = launchDate.toLocaleDateString("en-US", {
      month: "short",
      day: "numeric",
      year: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextLaunchEl.textContent = "Next launch: " + dateText;
    statusEl.textContent = "The product launch is coming soon. Join the waiting list before early access opens.";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-three-demo"&gt;
  &lt;div class="vb-countdown-three-launch" data-vb-countdown-three data-cycle-days="30"&gt;
    &lt;div class="vb-countdown-three-visual"&gt;
      &lt;div class="vb-countdown-three-grid"&gt;&lt;/div&gt;
      &lt;div class="vb-countdown-three-orb"&gt;
        &lt;span&gt;JS&lt;/span&gt;
      &lt;/div&gt;
      &lt;div class="vb-countdown-three-ring vb-countdown-three-ring-one"&gt;&lt;/div&gt;
      &lt;div class="vb-countdown-three-ring vb-countdown-three-ring-two"&gt;&lt;/div&gt;
      &lt;div class="vb-countdown-three-dot vb-countdown-three-dot-one"&gt;&lt;/div&gt;
      &lt;div class="vb-countdown-three-dot vb-countdown-three-dot-two"&gt;&lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-three-content"&gt;
      &lt;span class="vb-countdown-three-kicker"&gt;Example 03&lt;/span&gt;
      &lt;h3&gt;Product Launch Countdown Timer&lt;/h3&gt;
      &lt;p&gt;Use a launch countdown timer for new products, app releases, SaaS features, preorder campaigns, digital products, and startup landing pages.&lt;/p&gt;

      &lt;div class="vb-countdown-three-launch-meta"&gt;
        &lt;span data-next-launch&gt;Next launch date loading&lt;/span&gt;
        &lt;strong&gt;Early access opens soon&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-three-timer" aria-label="Product launch countdown timer"&gt;
        &lt;div&gt;
          &lt;strong data-days&gt;00&lt;/strong&gt;
          &lt;span&gt;Days&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-hours&gt;00&lt;/strong&gt;
          &lt;span&gt;Hours&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
          &lt;span&gt;Minutes&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
          &lt;span&gt;Seconds&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;p class="vb-countdown-three-status" data-status&gt;The product launch is coming soon. Join the waiting list before early access opens.&lt;/p&gt;

      &lt;form class="vb-countdown-three-form"&gt;
        &lt;input type="email" placeholder="Enter your email" aria-label="Email address"&gt;
        &lt;button type="button"&gt;Notify Me&lt;/button&gt;
      &lt;/form&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-three-demo,
.vb-countdown-three-demo * {
  box-sizing: border-box;
}

.vb-countdown-three-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: clamp(28px, 5vw, 58px) clamp(28px, 5vw, 58px) 14px clamp(28px, 5vw, 58px);
  background:
    radial-gradient(circle at 18% 18%, rgba(34, 211, 238, 0.18), transparent 34%),
    radial-gradient(circle at 84% 20%, rgba(168, 85, 247, 0.22), transparent 36%),
    linear-gradient(135deg, #020617 0%, #111827 52%, #1e1b4b 100%) !important;
  border: 1px solid rgba(125, 211, 252, 0.20);
  box-shadow: 0 34px 96px rgba(2, 6, 23, 0.42);
}

.vb-countdown-three-launch {
  display: grid;
  grid-template-columns: minmax(260px, 0.84fr) minmax(0, 1.16fr);
  gap: clamp(24px, 4vw, 38px);
  align-items: center;
  max-width: 1160px;
  margin: 0 auto;
}

.vb-countdown-three-visual {
  position: relative;
  min-width: 0;
  min-height: clamp(320px, 44vw, 500px);
  overflow: hidden;
  border-radius: clamp(28px, 4vw, 46px) clamp(28px, 4vw, 46px) 10px clamp(28px, 4vw, 46px);
  background:
    radial-gradient(circle at 50% 50%, rgba(34, 211, 238, 0.22), transparent 30%),
    linear-gradient(135deg, rgba(255,255,255,0.09), rgba(255,255,255,0.025)) !important;
  border: 1px solid rgba(255,255,255,0.11);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
}

.vb-countdown-three-grid {
  position: absolute;
  inset: 0;
  background:
    linear-gradient(rgba(125,211,252,0.08) 1px, transparent 1px),
    linear-gradient(90deg, rgba(125,211,252,0.08) 1px, transparent 1px);
  background-size: 34px 34px;
  mask-image: radial-gradient(circle at center, black 0%, transparent 75%);
}

.vb-countdown-three-orb {
  position: absolute;
  left: 50%;
  top: 50%;
  width: clamp(140px, 20vw, 196px);
  height: clamp(140px, 20vw, 196px);
  border-radius: 999px;
  transform: translate(-50%, -50%);
  background:
    radial-gradient(circle at 32% 28%, rgba(255,255,255,0.52), transparent 22%),
    linear-gradient(135deg, #22d3ee, #2563eb 52%, #a855f7) !important;
  box-shadow:
    0 0 44px rgba(34, 211, 238, 0.46),
    0 0 100px rgba(168, 85, 247, 0.30);
}

.vb-countdown-three-orb span {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(40px, 7vw, 58px);
  font-weight: 950;
  letter-spacing: -0.08em;
}

.vb-countdown-three-ring {
  position: absolute;
  left: 50%;
  top: 50%;
  border-radius: 999px;
  transform: translate(-50%, -50%);
  border: 1px solid rgba(125, 211, 252, 0.28);
}

.vb-countdown-three-ring-one {
  width: clamp(220px, 32vw, 320px);
  height: clamp(220px, 32vw, 320px);
}

.vb-countdown-three-ring-two {
  width: clamp(280px, 40vw, 410px);
  height: clamp(280px, 40vw, 410px);
  border-color: rgba(168, 85, 247, 0.25);
}

.vb-countdown-three-dot {
  position: absolute;
  width: 18px;
  height: 18px;
  border-radius: 999px;
}

.vb-countdown-three-dot-one {
  left: 21%;
  top: 28%;
  background: #67e8f9;
  box-shadow: 0 0 24px rgba(103, 232, 249, 0.72);
}

.vb-countdown-three-dot-two {
  right: 18%;
  bottom: 25%;
  background: #c084fc;
  box-shadow: 0 0 24px rgba(192, 132, 252, 0.72);
}

.vb-countdown-three-content {
  min-width: 0;
}

.vb-countdown-three-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(34, 211, 238, 0.12);
  border: 1px solid rgba(125, 211, 252, 0.18);
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-three-content h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5.7vw, 76px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-countdown-three-content p {
  max-width: 680px;
  margin: 0 0 22px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: clamp(15px, 1.7vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-three-launch-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 16px;
}

.vb-countdown-three-launch-meta span,
.vb-countdown-three-launch-meta strong {
  display: inline-flex;
  align-items: center;
  min-height: 38px;
  padding: 9px 12px;
  border-radius: 999px;
  font-size: 12px;
  line-height: 1.25;
  font-weight: 900;
}

.vb-countdown-three-launch-meta span {
  background: rgba(34, 211, 238, 0.12);
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  border: 1px solid rgba(125, 211, 252, 0.16);
}

.vb-countdown-three-launch-meta strong {
  background: rgba(168, 85, 247, 0.14);
  color: #ddd6fe !important;
  -webkit-text-fill-color: #ddd6fe !important;
  border: 1px solid rgba(196, 181, 253, 0.16);
}

.vb-countdown-three-timer {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(8px, 1.4vw, 12px);
  margin-bottom: 18px;
}

.vb-countdown-three-timer div {
  min-width: 0;
  position: relative;
  overflow: hidden;
  padding: clamp(14px, 2vw, 18px) clamp(7px, 1.2vw, 10px);
  border-radius: 24px 24px 8px 24px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
}

.vb-countdown-three-timer div::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 3px;
  background: linear-gradient(90deg, #22d3ee, #a855f7);
}

.vb-countdown-three-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 8px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(24px, 3.5vw, 44px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-three-timer span {
  display: block;
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: clamp(9px, 1.1vw, 11px);
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-countdown-three-status {
  margin-bottom: 18px !important;
}

.vb-countdown-three-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 140px;
  gap: 10px;
  max-width: 560px;
}

.vb-countdown-three-form input {
  width: 100%;
  min-width: 0;
  min-height: 52px;
  padding: 0 16px;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,0.14);
  outline: none;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 700;
}

.vb-countdown-three-form input::placeholder {
  color: rgba(226, 232, 240, 0.72);
  -webkit-text-fill-color: rgba(226, 232, 240, 0.72);
}

.vb-countdown-three-form button {
  min-height: 52px;
  padding: 0 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #22d3ee, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(34, 211, 238, 0.22);
}

@media (max-width: 980px) {
  .vb-countdown-three-launch {
    grid-template-columns: 1fr;
  }

  .vb-countdown-three-visual {
    min-height: 360px;
  }

  .vb-countdown-three-timer strong {
    font-size: clamp(30px, 8vw, 52px);
  }
}

@media (max-width: 700px) {
  .vb-countdown-three-content h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-three-visual {
    min-height: 310px;
    border-radius: 28px 28px 8px 28px;
  }

  .vb-countdown-three-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-three-timer strong {
    font-size: clamp(30px, 13vw, 46px);
  }

  .vb-countdown-three-form {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 360px) {
  .vb-countdown-three-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This product launch countdown timer is useful for SaaS launch pages, app releases, preorder pages, startup landing pages, digital product drops, feature launches, and coming soon website sections.</p>



<h2 class="wp-block-heading">4. Daily Deal Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A daily deal countdown timer</strong> is useful for ecommerce stores, online marketplaces, product grids, homepage promotions, flash deals, and limited-time product cards. It shows how long today’s deal remains available before the next day starts.</p>



<p class="wp-block-paragraph">This example uses a compact ecommerce product-card layout with a bright product visual, price block, stock meter, vertical timer strip, and deal message. The JavaScript counts down to the next local midnight, so the demo keeps working day after day.</p>



<ul class="wp-block-list">
<li>Daily deal countdown timer</li>
<li>Counts down to local midnight</li>
<li>Product card style layout</li>
<li>Price, stock, and deal details</li>
<li>Responsive ecommerce timer design</li>
</ul>



<div class="vb-countdown-four-demo">
  <div class="vb-countdown-four-card" data-vb-countdown-four>
    <div class="vb-countdown-four-image">
      <span>Example 04</span>
      <div class="vb-countdown-four-product-shape">
        <i></i>
        <i></i>
      </div>
    </div>

    <div class="vb-countdown-four-info">
      <div class="vb-countdown-four-label">Daily Deal</div>
      <h3>Daily Deal Countdown Timer</h3>
      <p>Use this timer for daily ecommerce offers, marketplace deals, limited product discounts, and product cards that refresh every day.</p>

      <div class="vb-countdown-four-price">
        <div>
          <small>Today only</small>
          <strong>€49</strong>
        </div>
        <span>Save 35%</span>
      </div>

      <div class="vb-countdown-four-stock">
        <strong>Stock left</strong>
        <span><i></i></span>
        <em>18 items</em>
      </div>
    </div>

    <div class="vb-countdown-four-timer" aria-label="Daily deal countdown timer">
      <div>
        <strong data-hours>00</strong>
        <span>Hours</span>
      </div>

      <div>
        <strong data-minutes>00</strong>
        <span>Min</span>
      </div>

      <div>
        <strong data-seconds>00</strong>
        <span>Sec</span>
      </div>

      <p data-status>Deal resets at midnight.</p>
    </div>
  </div>
</div>

<style>
.vb-countdown-four-demo,
.vb-countdown-four-demo * {
  box-sizing: border-box;
}

.vb-countdown-four-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 12px;
  background:
    repeating-linear-gradient(45deg, rgba(15, 23, 42, 0.035) 0 10px, transparent 10px 20px),
    linear-gradient(135deg, #f8fafc 0%, #ecfdf5 52%, #ffffff 100%) !important;
  border: 1px solid rgba(16, 185, 129, 0.22);
  box-shadow: 0 28px 80px rgba(5, 150, 105, 0.10);
}

.vb-countdown-four-card {
  display: grid;
  grid-template-columns: minmax(220px, 320px) minmax(0, 1fr) minmax(150px, 190px);
  gap: 18px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(14px, 2vw, 18px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 72px rgba(15, 23, 42, 0.10);
}

.vb-countdown-four-image {
  position: relative;
  min-width: 0;
  min-height: clamp(280px, 35vw, 360px);
  overflow: hidden;
  border-radius: 26px 8px 26px 8px;
  background:
    radial-gradient(circle at 28% 20%, rgba(255,255,255,0.34), transparent 34%),
    linear-gradient(135deg, #064e3b, #10b981 58%, #a7f3d0) !important;
}

.vb-countdown-four-image span {
  position: absolute;
  left: 18px;
  top: 18px;
  z-index: 3;
  display: inline-flex;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  border: 1px solid rgba(255,255,255,0.22);
  color: #ecfdf5 !important;
  -webkit-text-fill-color: #ecfdf5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-four-product-shape {
  position: absolute;
  left: 50%;
  top: 54%;
  width: clamp(140px, 18vw, 180px);
  height: clamp(170px, 23vw, 210px);
  border-radius: 30px 30px 12px 12px;
  transform: translate(-50%, -50%) rotate(-6deg);
  background:
    linear-gradient(135deg, rgba(255,255,255,0.72), rgba(255,255,255,0.32)) !important;
  border: 1px solid rgba(255,255,255,0.32);
  box-shadow: 0 28px 70px rgba(6, 78, 59, 0.26);
}

.vb-countdown-four-product-shape::before {
  content: "";
  position: absolute;
  left: 24%;
  top: -20px;
  width: 54%;
  height: 42px;
  border-radius: 24px 24px 0 0;
  border: 12px solid rgba(255,255,255,0.42);
  border-bottom: 0;
}

.vb-countdown-four-product-shape i {
  position: absolute;
  display: block;
  border-radius: 999px;
  background: rgba(6, 78, 59, 0.20);
}

.vb-countdown-four-product-shape i:nth-child(1) {
  left: 18%;
  top: 36%;
  width: 64%;
  height: 14px;
}

.vb-countdown-four-product-shape i:nth-child(2) {
  left: 18%;
  top: 52%;
  width: 46%;
  height: 14px;
}

.vb-countdown-four-info {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
  padding: 14px 10px;
}

.vb-countdown-four-label {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 8px 18px 8px 18px;
  background: #d1fae5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-four-info h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 0.93 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-countdown-four-info p {
  max-width: 590px;
  margin: 0 0 20px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-countdown-four-price {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  max-width: 440px;
  margin-bottom: 16px;
  padding: 16px;
  border-radius: 22px;
  background: #f0fdf4;
  border: 1px solid rgba(16, 185, 129, 0.18);
}

.vb-countdown-four-price small {
  display: block;
  margin-bottom: 4px;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-countdown-four-price strong {
  display: block;
  color: #064e3b !important;
  -webkit-text-fill-color: #064e3b !important;
  font-size: clamp(34px, 5vw, 42px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-countdown-four-price span {
  display: inline-flex;
  padding: 9px 12px;
  border-radius: 999px;
  background: #059669;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-countdown-four-stock {
  display: grid;
  grid-template-columns: 80px minmax(0, 1fr) 70px;
  gap: 10px;
  align-items: center;
  max-width: 440px;
}

.vb-countdown-four-stock strong,
.vb-countdown-four-stock em {
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  font-style: normal;
  font-weight: 850;
}

.vb-countdown-four-stock span {
  overflow: hidden;
  height: 10px;
  border-radius: 999px;
  background: #e2e8f0;
}

.vb-countdown-four-stock i {
  display: block;
  width: 66%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #10b981, #facc15) !important;
}

.vb-countdown-four-timer {
  display: grid;
  gap: 10px;
  align-content: stretch;
  min-width: 0;
  padding: 14px;
  border-radius: 26px;
  background: #0f172a;
}

.vb-countdown-four-timer div {
  display: grid;
  place-items: center;
  min-width: 0;
  padding: 15px 8px;
  border-radius: 18px;
  background:
    radial-gradient(circle at 20% 14%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, rgba(16, 185, 129, 0.30), rgba(34, 197, 94, 0.10)) !important;
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-countdown-four-timer strong {
  display: block;
  max-width: 100%;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4vw, 38px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.035em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-four-timer span {
  display: block;
  margin-top: 4px;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 11px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-countdown-four-timer p {
  margin: 4px 0 0 !important;
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 13px;
  line-height: 1.5;
  font-weight: 700;
  text-align: center;
}

@media (max-width: 1060px) {
  .vb-countdown-four-card {
    grid-template-columns: minmax(220px, 300px) minmax(0, 1fr);
  }

  .vb-countdown-four-timer {
    grid-column: 1 / -1;
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .vb-countdown-four-timer p {
    grid-column: 1 / -1;
  }

  .vb-countdown-four-timer strong {
    font-size: clamp(32px, 7vw, 48px);
  }
}

@media (max-width: 740px) {
  .vb-countdown-four-card {
    grid-template-columns: 1fr;
    border-radius: 26px;
  }

  .vb-countdown-four-info h3 {
    font-size: 36px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-four-price {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-countdown-four-stock {
    grid-template-columns: 1fr;
  }

  .vb-countdown-four-timer {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .vb-countdown-four-timer strong {
    font-size: clamp(28px, 12vw, 42px);
  }
}

@media (max-width: 420px) {
  .vb-countdown-four-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-four]");
  if (!timer) return;

  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextMidnight() {
    const deadline = new Date();
    deadline.setHours(24, 0, 0, 0);
    return deadline.getTime();
  }

  function updateCountdown() {
    const now = Date.now();
    const deadline = getNextMidnight();
    let remaining = deadline - now;

    if (remaining <= 0) {
      remaining = 24 * 60 * 60 * 1000;
    }

    const hours = Math.floor(remaining / (1000 * 60 * 60));
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    statusEl.textContent = "Deal resets at midnight.";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-four]");
  if (!timer) return;

  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextMidnight() {
    const deadline = new Date();
    deadline.setHours(24, 0, 0, 0);
    return deadline.getTime();
  }

  function updateCountdown() {
    const now = Date.now();
    const deadline = getNextMidnight();
    let remaining = deadline - now;

    if (remaining &lt;= 0) {
      remaining = 24 * 60 * 60 * 1000;
    }

    const hours = Math.floor(remaining / (1000 * 60 * 60));
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    statusEl.textContent = "Deal resets at midnight.";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-four-demo"&gt;
  &lt;div class="vb-countdown-four-card" data-vb-countdown-four&gt;
    &lt;div class="vb-countdown-four-image"&gt;
      &lt;span&gt;Example 04&lt;/span&gt;
      &lt;div class="vb-countdown-four-product-shape"&gt;
        &lt;i&gt;&lt;/i&gt;
        &lt;i&gt;&lt;/i&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-four-info"&gt;
      &lt;div class="vb-countdown-four-label"&gt;Daily Deal&lt;/div&gt;
      &lt;h3&gt;Daily Deal Countdown Timer&lt;/h3&gt;
      &lt;p&gt;Use this timer for daily ecommerce offers, marketplace deals, limited product discounts, and product cards that refresh every day.&lt;/p&gt;

      &lt;div class="vb-countdown-four-price"&gt;
        &lt;div&gt;
          &lt;small&gt;Today only&lt;/small&gt;
          &lt;strong&gt;€49&lt;/strong&gt;
        &lt;/div&gt;
        &lt;span&gt;Save 35%&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-four-stock"&gt;
        &lt;strong&gt;Stock left&lt;/strong&gt;
        &lt;span&gt;&lt;i&gt;&lt;/i&gt;&lt;/span&gt;
        &lt;em&gt;18 items&lt;/em&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-four-timer" aria-label="Daily deal countdown timer"&gt;
      &lt;div&gt;
        &lt;strong data-hours&gt;00&lt;/strong&gt;
        &lt;span&gt;Hours&lt;/span&gt;
      &lt;/div&gt;

      &lt;div&gt;
        &lt;strong data-minutes&gt;00&lt;/strong&gt;
        &lt;span&gt;Min&lt;/span&gt;
      &lt;/div&gt;

      &lt;div&gt;
        &lt;strong data-seconds&gt;00&lt;/strong&gt;
        &lt;span&gt;Sec&lt;/span&gt;
      &lt;/div&gt;

      &lt;p data-status&gt;Deal resets at midnight.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-four-demo,
.vb-countdown-four-demo * {
  box-sizing: border-box;
}

.vb-countdown-four-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 12px;
  background:
    repeating-linear-gradient(45deg, rgba(15, 23, 42, 0.035) 0 10px, transparent 10px 20px),
    linear-gradient(135deg, #f8fafc 0%, #ecfdf5 52%, #ffffff 100%) !important;
  border: 1px solid rgba(16, 185, 129, 0.22);
  box-shadow: 0 28px 80px rgba(5, 150, 105, 0.10);
}

.vb-countdown-four-card {
  display: grid;
  grid-template-columns: minmax(220px, 320px) minmax(0, 1fr) minmax(150px, 190px);
  gap: 18px;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(14px, 2vw, 18px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 72px rgba(15, 23, 42, 0.10);
}

.vb-countdown-four-image {
  position: relative;
  min-width: 0;
  min-height: clamp(280px, 35vw, 360px);
  overflow: hidden;
  border-radius: 26px 8px 26px 8px;
  background:
    radial-gradient(circle at 28% 20%, rgba(255,255,255,0.34), transparent 34%),
    linear-gradient(135deg, #064e3b, #10b981 58%, #a7f3d0) !important;
}

.vb-countdown-four-image span {
  position: absolute;
  left: 18px;
  top: 18px;
  z-index: 3;
  display: inline-flex;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  border: 1px solid rgba(255,255,255,0.22);
  color: #ecfdf5 !important;
  -webkit-text-fill-color: #ecfdf5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-four-product-shape {
  position: absolute;
  left: 50%;
  top: 54%;
  width: clamp(140px, 18vw, 180px);
  height: clamp(170px, 23vw, 210px);
  border-radius: 30px 30px 12px 12px;
  transform: translate(-50%, -50%) rotate(-6deg);
  background:
    linear-gradient(135deg, rgba(255,255,255,0.72), rgba(255,255,255,0.32)) !important;
  border: 1px solid rgba(255,255,255,0.32);
  box-shadow: 0 28px 70px rgba(6, 78, 59, 0.26);
}

.vb-countdown-four-product-shape::before {
  content: "";
  position: absolute;
  left: 24%;
  top: -20px;
  width: 54%;
  height: 42px;
  border-radius: 24px 24px 0 0;
  border: 12px solid rgba(255,255,255,0.42);
  border-bottom: 0;
}

.vb-countdown-four-product-shape i {
  position: absolute;
  display: block;
  border-radius: 999px;
  background: rgba(6, 78, 59, 0.20);
}

.vb-countdown-four-product-shape i:nth-child(1) {
  left: 18%;
  top: 36%;
  width: 64%;
  height: 14px;
}

.vb-countdown-four-product-shape i:nth-child(2) {
  left: 18%;
  top: 52%;
  width: 46%;
  height: 14px;
}

.vb-countdown-four-info {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
  padding: 14px 10px;
}

.vb-countdown-four-label {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 8px 18px 8px 18px;
  background: #d1fae5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-four-info h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 0.93 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-countdown-four-info p {
  max-width: 590px;
  margin: 0 0 20px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-countdown-four-price {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  max-width: 440px;
  margin-bottom: 16px;
  padding: 16px;
  border-radius: 22px;
  background: #f0fdf4;
  border: 1px solid rgba(16, 185, 129, 0.18);
}

.vb-countdown-four-price small {
  display: block;
  margin-bottom: 4px;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-countdown-four-price strong {
  display: block;
  color: #064e3b !important;
  -webkit-text-fill-color: #064e3b !important;
  font-size: clamp(34px, 5vw, 42px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-countdown-four-price span {
  display: inline-flex;
  padding: 9px 12px;
  border-radius: 999px;
  background: #059669;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-countdown-four-stock {
  display: grid;
  grid-template-columns: 80px minmax(0, 1fr) 70px;
  gap: 10px;
  align-items: center;
  max-width: 440px;
}

.vb-countdown-four-stock strong,
.vb-countdown-four-stock em {
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  font-style: normal;
  font-weight: 850;
}

.vb-countdown-four-stock span {
  overflow: hidden;
  height: 10px;
  border-radius: 999px;
  background: #e2e8f0;
}

.vb-countdown-four-stock i {
  display: block;
  width: 66%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #10b981, #facc15) !important;
}

.vb-countdown-four-timer {
  display: grid;
  gap: 10px;
  align-content: stretch;
  min-width: 0;
  padding: 14px;
  border-radius: 26px;
  background: #0f172a;
}

.vb-countdown-four-timer div {
  display: grid;
  place-items: center;
  min-width: 0;
  padding: 15px 8px;
  border-radius: 18px;
  background:
    radial-gradient(circle at 20% 14%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, rgba(16, 185, 129, 0.30), rgba(34, 197, 94, 0.10)) !important;
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-countdown-four-timer strong {
  display: block;
  max-width: 100%;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4vw, 38px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.035em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-four-timer span {
  display: block;
  margin-top: 4px;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 11px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-countdown-four-timer p {
  margin: 4px 0 0 !important;
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 13px;
  line-height: 1.5;
  font-weight: 700;
  text-align: center;
}

@media (max-width: 1060px) {
  .vb-countdown-four-card {
    grid-template-columns: minmax(220px, 300px) minmax(0, 1fr);
  }

  .vb-countdown-four-timer {
    grid-column: 1 / -1;
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .vb-countdown-four-timer p {
    grid-column: 1 / -1;
  }

  .vb-countdown-four-timer strong {
    font-size: clamp(32px, 7vw, 48px);
  }
}

@media (max-width: 740px) {
  .vb-countdown-four-card {
    grid-template-columns: 1fr;
    border-radius: 26px;
  }

  .vb-countdown-four-info h3 {
    font-size: 36px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-four-price {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-countdown-four-stock {
    grid-template-columns: 1fr;
  }

  .vb-countdown-four-timer {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .vb-countdown-four-timer strong {
    font-size: clamp(28px, 12vw, 42px);
  }
}

@media (max-width: 420px) {
  .vb-countdown-four-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This daily deal countdown timer is useful for ecommerce product cards, daily offer sections, marketplace deals, product grids, homepage promotions, flash deal blocks, and limited-time product campaigns.</p>



<h2 class="wp-block-heading">5. Checkout Reservation Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A checkout reservation countdown timer</strong> is useful for ecommerce checkout pages, booking flows, ticket reservations, cart holds, limited inventory purchases, appointment systems, and payment pages where users need to complete an action before a temporary reservation ends.</p>



<p class="wp-block-paragraph">This example uses a checkout-focused design with a reserved cart message, payment-style summary card, shrinking progress bar, and compact minutes-and-seconds timer. The JavaScript restarts the reservation cycle when it reaches zero, so the demo keeps working in the future.</p>



<ul class="wp-block-list">
<li>Checkout reservation countdown timer</li>
<li>Minutes and seconds countdown</li>
<li>Progress bar that decreases over time</li>
<li>Checkout summary card layout</li>
<li>Responsive reservation UI section</li>
</ul>



<div class="vb-countdown-five-demo">
  <div class="vb-countdown-five-checkout" data-vb-countdown-five data-duration="900">
    <div class="vb-countdown-five-copy">
      <span class="vb-countdown-five-kicker">Example 05</span>
      <h3>Checkout Reservation Countdown Timer</h3>
      <p>Use this countdown timer to show how long a cart, ticket, booking, appointment, or checkout session is reserved.</p>

      <div class="vb-countdown-five-progress">
        <span data-progress></span>
      </div>

      <p class="vb-countdown-five-status" data-status>Your checkout reservation is active. Complete checkout before the timer reaches zero.</p>
    </div>

    <aside class="vb-countdown-five-card">
      <div class="vb-countdown-five-card-top">
        <strong>Reserved checkout</strong>
        <span>Secure session</span>
      </div>

      <div class="vb-countdown-five-timer" aria-label="Checkout reservation countdown timer">
        <div>
          <strong data-minutes>00</strong>
          <span>Minutes</span>
        </div>

        <div>
          <strong data-seconds>00</strong>
          <span>Seconds</span>
        </div>
      </div>

      <div class="vb-countdown-five-summary">
        <div>
          <span>Subtotal</span>
          <strong>€129</strong>
        </div>
        <div>
          <span>Discount</span>
          <strong>-€30</strong>
        </div>
        <div>
          <span>Total</span>
          <strong>€99</strong>
        </div>
      </div>

      <button type="button">Continue Checkout</button>
    </aside>
  </div>
</div>

<style>
.vb-countdown-five-demo,
.vb-countdown-five-demo * {
  box-sizing: border-box;
}

.vb-countdown-five-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px 10px 34px 10px;
  background:
    radial-gradient(circle at 12% 18%, rgba(59, 130, 246, 0.18), transparent 34%),
    radial-gradient(circle at 86% 22%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #f0fdf4 52%, #ffffff 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.22);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-countdown-five-checkout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(270px, 380px);
  gap: clamp(20px, 3vw, 28px);
  align-items: stretch;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-countdown-five-copy {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
  padding: clamp(24px, 4vw, 36px);
  border-radius: 28px 8px 28px 8px;
  background:
    radial-gradient(circle at 18% 16%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #1d4ed8 55%, #047857 100%) !important;
  box-shadow: 0 26px 76px rgba(15, 23, 42, 0.22);
}

.vb-countdown-five-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-five-copy h3 {
  max-width: 760px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5.4vw, 70px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-countdown-five-copy p {
  max-width: 680px;
  margin: 0 0 24px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-five-progress {
  overflow: hidden;
  width: 100%;
  max-width: 620px;
  height: 14px;
  margin-bottom: 18px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.16);
}

.vb-countdown-five-progress span {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #22c55e, #facc15, #f97316) !important;
  transition: width 0.4s linear;
}

.vb-countdown-five-status {
  margin-bottom: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
}

.vb-countdown-five-card {
  min-width: 0;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.12);
}

.vb-countdown-five-card-top {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: center;
  margin-bottom: 18px;
}

.vb-countdown-five-card-top strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px;
  line-height: 1.15;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-countdown-five-card-top span {
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dcfce7;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 11px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-countdown-five-timer {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  margin-bottom: 18px;
}

.vb-countdown-five-timer div {
  min-width: 0;
  padding: 18px 10px;
  border-radius: 22px;
  background: #eff6ff;
  border: 1px solid rgba(59, 130, 246, 0.18);
  text-align: center;
}

.vb-countdown-five-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 7px;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: clamp(34px, 7vw, 58px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.06em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-five-timer span {
  display: block;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-five-summary {
  display: grid;
  gap: 10px;
  margin-bottom: 18px;
  padding: 16px;
  border-radius: 22px;
  background: #f8fafc;
}

.vb-countdown-five-summary div {
  display: flex;
  justify-content: space-between;
  gap: 12px;
}

.vb-countdown-five-summary span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-countdown-five-summary strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-countdown-five-card button {
  width: 100%;
  min-height: 48px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #10b981);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 34px rgba(37, 99, 235, 0.24);
}

@media (max-width: 900px) {
  .vb-countdown-five-checkout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-countdown-five-copy {
    border-radius: 22px 8px 22px 8px;
  }

  .vb-countdown-five-copy h3 {
    font-size: 36px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-five-card {
    border-radius: 24px;
  }

  .vb-countdown-five-card-top {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-countdown-five-timer strong {
    font-size: clamp(34px, 15vw, 52px);
  }
}

@media (max-width: 380px) {
  .vb-countdown-five-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-five]");
  if (!timer) return;

  const duration = Number(timer.getAttribute("data-duration")) || 900;
  let remaining = duration;

  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");
  const progressEl = timer.querySelector("[data-progress]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function updateTimer() {
    if (remaining <= 0) {
      remaining = duration;
    }

    const minutes = Math.floor(remaining / 60);
    const seconds = remaining % 60;
    const progress = (remaining / duration) * 100;

    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    progressEl.style.width = progress + "%";
    statusEl.textContent = "Your checkout reservation is active. Complete checkout before the timer reaches zero.";

    remaining -= 1;
  }

  updateTimer();
  setInterval(updateTimer, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-five]");
  if (!timer) return;

  const duration = Number(timer.getAttribute("data-duration")) || 900;
  let remaining = duration;

  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");
  const progressEl = timer.querySelector("[data-progress]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function updateTimer() {
    if (remaining &lt;= 0) {
      remaining = duration;
    }

    const minutes = Math.floor(remaining / 60);
    const seconds = remaining % 60;
    const progress = (remaining / duration) * 100;

    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    progressEl.style.width = progress + "%";
    statusEl.textContent = "Your checkout reservation is active. Complete checkout before the timer reaches zero.";

    remaining -= 1;
  }

  updateTimer();
  setInterval(updateTimer, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-five-demo"&gt;
  &lt;div class="vb-countdown-five-checkout" data-vb-countdown-five data-duration="900"&gt;
    &lt;div class="vb-countdown-five-copy"&gt;
      &lt;span class="vb-countdown-five-kicker"&gt;Example 05&lt;/span&gt;
      &lt;h3&gt;Checkout Reservation Countdown Timer&lt;/h3&gt;
      &lt;p&gt;Use this countdown timer to show how long a cart, ticket, booking, appointment, or checkout session is reserved.&lt;/p&gt;

      &lt;div class="vb-countdown-five-progress"&gt;
        &lt;span data-progress&gt;&lt;/span&gt;
      &lt;/div&gt;

      &lt;p class="vb-countdown-five-status" data-status&gt;Your checkout reservation is active. Complete checkout before the timer reaches zero.&lt;/p&gt;
    &lt;/div&gt;

    &lt;aside class="vb-countdown-five-card"&gt;
      &lt;div class="vb-countdown-five-card-top"&gt;
        &lt;strong&gt;Reserved checkout&lt;/strong&gt;
        &lt;span&gt;Secure session&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-five-timer" aria-label="Checkout reservation countdown timer"&gt;
        &lt;div&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
          &lt;span&gt;Minutes&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
          &lt;span&gt;Seconds&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-five-summary"&gt;
        &lt;div&gt;
          &lt;span&gt;Subtotal&lt;/span&gt;
          &lt;strong&gt;€129&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Discount&lt;/span&gt;
          &lt;strong&gt;-€30&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Total&lt;/span&gt;
          &lt;strong&gt;€99&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;button type="button"&gt;Continue Checkout&lt;/button&gt;
    &lt;/aside&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-five-demo,
.vb-countdown-five-demo * {
  box-sizing: border-box;
}

.vb-countdown-five-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px 10px 34px 10px;
  background:
    radial-gradient(circle at 12% 18%, rgba(59, 130, 246, 0.18), transparent 34%),
    radial-gradient(circle at 86% 22%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #f0fdf4 52%, #ffffff 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.22);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-countdown-five-checkout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(270px, 380px);
  gap: clamp(20px, 3vw, 28px);
  align-items: stretch;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-countdown-five-copy {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
  padding: clamp(24px, 4vw, 36px);
  border-radius: 28px 8px 28px 8px;
  background:
    radial-gradient(circle at 18% 16%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #1d4ed8 55%, #047857 100%) !important;
  box-shadow: 0 26px 76px rgba(15, 23, 42, 0.22);
}

.vb-countdown-five-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-five-copy h3 {
  max-width: 760px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5.4vw, 70px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-countdown-five-copy p {
  max-width: 680px;
  margin: 0 0 24px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-five-progress {
  overflow: hidden;
  width: 100%;
  max-width: 620px;
  height: 14px;
  margin-bottom: 18px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.16);
}

.vb-countdown-five-progress span {
  display: block;
  width: 100%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #22c55e, #facc15, #f97316) !important;
  transition: width 0.4s linear;
}

.vb-countdown-five-status {
  margin-bottom: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
}

.vb-countdown-five-card {
  min-width: 0;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.12);
}

.vb-countdown-five-card-top {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: center;
  margin-bottom: 18px;
}

.vb-countdown-five-card-top strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px;
  line-height: 1.15;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-countdown-five-card-top span {
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dcfce7;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 11px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-countdown-five-timer {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  margin-bottom: 18px;
}

.vb-countdown-five-timer div {
  min-width: 0;
  padding: 18px 10px;
  border-radius: 22px;
  background: #eff6ff;
  border: 1px solid rgba(59, 130, 246, 0.18);
  text-align: center;
}

.vb-countdown-five-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 7px;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: clamp(34px, 7vw, 58px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.06em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-five-timer span {
  display: block;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-five-summary {
  display: grid;
  gap: 10px;
  margin-bottom: 18px;
  padding: 16px;
  border-radius: 22px;
  background: #f8fafc;
}

.vb-countdown-five-summary div {
  display: flex;
  justify-content: space-between;
  gap: 12px;
}

.vb-countdown-five-summary span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-countdown-five-summary strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-countdown-five-card button {
  width: 100%;
  min-height: 48px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #10b981);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 34px rgba(37, 99, 235, 0.24);
}

@media (max-width: 900px) {
  .vb-countdown-five-checkout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-countdown-five-copy {
    border-radius: 22px 8px 22px 8px;
  }

  .vb-countdown-five-copy h3 {
    font-size: 36px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-five-card {
    border-radius: 24px;
  }

  .vb-countdown-five-card-top {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-countdown-five-timer strong {
    font-size: clamp(34px, 15vw, 52px);
  }
}

@media (max-width: 380px) {
  .vb-countdown-five-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This checkout reservation countdown timer is useful for ecommerce checkouts, ticket reservations, cart holds, booking systems, payment pages, appointment flows, and limited inventory purchase pages.</p>



<h2 class="wp-block-heading">6. Circular Progress Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A circular progress countdown timer</strong> is useful for dashboards, app interfaces, fitness sessions, study timers, productivity tools, course lessons, onboarding steps, and modern landing pages that need a visual time progress indicator.</p>



<p class="wp-block-paragraph">This example uses a circular SVG progress ring, central countdown display, supporting status cards, and a dark app-style interface. The JavaScript restarts the circular timer when it reaches zero, so the demo keeps running instead of stopping.</p>



<ul class="wp-block-list">
<li>Circular SVG progress countdown</li>
<li>Minutes and seconds display</li>
<li>Progress ring animation</li>
<li>Dashboard and app-style layout</li>
<li>Responsive circular timer component</li>
</ul>



<div class="vb-countdown-six-demo">
  <div class="vb-countdown-six-app" data-vb-countdown-six data-duration="600">
    <div class="vb-countdown-six-content">
      <span class="vb-countdown-six-kicker">Example 06</span>
      <h3>Circular Progress Countdown Timer</h3>
      <p>Use a circular JavaScript countdown timer for sessions, dashboards, lessons, workouts, productivity blocks, and progress-based UI components.</p>

      <div class="vb-countdown-six-cards">
        <div>
          <strong>10 min</strong>
          <span>Session length</span>
        </div>
        <div>
          <strong>Live</strong>
          <span>Timer status</span>
        </div>
        <div>
          <strong>Loop</strong>
          <span>Demo cycle</span>
        </div>
      </div>
    </div>

    <div class="vb-countdown-six-circle-wrap">
      <svg class="vb-countdown-six-svg" viewBox="0 0 220 220" aria-hidden="true">
        <defs>
          <linearGradient id="vbCountdownSixGradient" x1="0%" y1="0%" x2="100%" y2="100%">
            <stop offset="0%" stop-color="#22d3ee"></stop>
            <stop offset="55%" stop-color="#8b5cf6"></stop>
            <stop offset="100%" stop-color="#ec4899"></stop>
          </linearGradient>
        </defs>
        <circle class="vb-countdown-six-track" cx="110" cy="110" r="92"></circle>
        <circle class="vb-countdown-six-progress" cx="110" cy="110" r="92" data-circle-progress></circle>
      </svg>

      <div class="vb-countdown-six-center">
        <strong data-time>10:00</strong>
        <span data-status>Session in progress</span>
      </div>
    </div>
  </div>
</div>

<style>
.vb-countdown-six-demo,
.vb-countdown-six-demo * {
  box-sizing: border-box;
}

.vb-countdown-six-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: clamp(34px, 5vw, 60px);
  background:
    radial-gradient(circle at 16% 18%, rgba(168, 85, 247, 0.16), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(14, 165, 233, 0.18), transparent 34%),
    linear-gradient(135deg, #f5f3ff 0%, #e0f2fe 52%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.22);
  box-shadow: 0 28px 80px rgba(88, 28, 135, 0.11);
}

.vb-countdown-six-app {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 390px);
  gap: clamp(24px, 4vw, 36px);
  align-items: center;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(24px, 4vw, 36px);
  border-radius: clamp(30px, 4vw, 46px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.12), transparent 34%),
    linear-gradient(135deg, #111827 0%, #4c1d95 54%, #0f172a 100%) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.26);
}

.vb-countdown-six-content {
  min-width: 0;
}

.vb-countdown-six-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 10px 22px 10px 22px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.18);
  color: #ddd6fe !important;
  -webkit-text-fill-color: #ddd6fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-six-content h3 {
  max-width: 740px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5.6vw, 72px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-countdown-six-content p {
  max-width: 680px;
  margin: 0 0 24px !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-six-cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  max-width: 640px;
}

.vb-countdown-six-cards div {
  min-width: 0;
  padding: 18px;
  border-radius: 22px 22px 8px 22px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-countdown-six-cards strong {
  display: block;
  margin-bottom: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(20px, 3vw, 28px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-countdown-six-cards span {
  display: block;
  color: #c4b5fd !important;
  -webkit-text-fill-color: #c4b5fd !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 850;
}

.vb-countdown-six-circle-wrap {
  position: relative;
  width: min(100%, 390px);
  aspect-ratio: 1 / 1;
  margin: 0 auto;
  border-radius: 999px;
  background:
    radial-gradient(circle at 50% 50%, rgba(255,255,255,0.12), transparent 48%),
    linear-gradient(135deg, rgba(255,255,255,0.09), rgba(255,255,255,0.03)) !important;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
}

.vb-countdown-six-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
}

.vb-countdown-six-track,
.vb-countdown-six-progress {
  fill: none;
  stroke-width: 14;
}

.vb-countdown-six-track {
  stroke: rgba(255,255,255,0.12);
}

.vb-countdown-six-progress {
  stroke: url("#vbCountdownSixGradient");
  stroke-linecap: round;
  transition: stroke-dashoffset 0.4s linear;
}

.vb-countdown-six-center {
  position: absolute;
  inset: 18%;
  display: grid;
  place-items: center;
  align-content: center;
  gap: 10px;
  border-radius: 999px;
  background:
    radial-gradient(circle at 32% 28%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #1e1b4b, #312e81) !important;
  border: 1px solid rgba(255,255,255,0.12);
  text-align: center;
}

.vb-countdown-six-center strong {
  display: block;
  max-width: 100%;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 9vw, 74px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.06em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-six-center span {
  display: block;
  padding: 0 14px;
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 850;
}

@media (max-width: 900px) {
  .vb-countdown-six-app {
    grid-template-columns: 1fr;
  }

  .vb-countdown-six-circle-wrap {
    width: min(100%, 340px);
  }
}

@media (max-width: 640px) {
  .vb-countdown-six-content h3 {
    font-size: 36px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-six-cards {
    grid-template-columns: 1fr;
  }

  .vb-countdown-six-circle-wrap {
    width: min(100%, 300px);
  }

  .vb-countdown-six-center strong {
    font-size: clamp(38px, 17vw, 62px);
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-six]");
  if (!timer) return;

  const duration = Number(timer.getAttribute("data-duration")) || 600;
  let remaining = duration;

  const timeEl = timer.querySelector("[data-time]");
  const statusEl = timer.querySelector("[data-status]");
  const progressCircle = timer.querySelector("[data-circle-progress]");

  const radius = 92;
  const circumference = 2 * Math.PI * radius;

  progressCircle.style.strokeDasharray = circumference;
  progressCircle.style.strokeDashoffset = 0;

  function formatTime(totalSeconds) {
    const minutes = Math.floor(totalSeconds / 60);
    const seconds = totalSeconds % 60;

    return String(minutes).padStart(2, "0") + ":" + String(seconds).padStart(2, "0");
  }

  function updateTimer() {
    if (remaining <= 0) {
      remaining = duration;
    }

    const progress = remaining / duration;
    const offset = circumference * (1 - progress);

    timeEl.textContent = formatTime(remaining);
    progressCircle.style.strokeDashoffset = offset;
    statusEl.textContent = "Session in progress";

    remaining -= 1;
  }

  updateTimer();
  setInterval(updateTimer, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-six]");
  if (!timer) return;

  const duration = Number(timer.getAttribute("data-duration")) || 600;
  let remaining = duration;

  const timeEl = timer.querySelector("[data-time]");
  const statusEl = timer.querySelector("[data-status]");
  const progressCircle = timer.querySelector("[data-circle-progress]");

  const radius = 92;
  const circumference = 2 * Math.PI * radius;

  progressCircle.style.strokeDasharray = circumference;
  progressCircle.style.strokeDashoffset = 0;

  function formatTime(totalSeconds) {
    const minutes = Math.floor(totalSeconds / 60);
    const seconds = totalSeconds % 60;

    return String(minutes).padStart(2, "0") + ":" + String(seconds).padStart(2, "0");
  }

  function updateTimer() {
    if (remaining &lt;= 0) {
      remaining = duration;
    }

    const progress = remaining / duration;
    const offset = circumference * (1 - progress);

    timeEl.textContent = formatTime(remaining);
    progressCircle.style.strokeDashoffset = offset;
    statusEl.textContent = "Session in progress";

    remaining -= 1;
  }

  updateTimer();
  setInterval(updateTimer, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-six-demo"&gt;
  &lt;div class="vb-countdown-six-app" data-vb-countdown-six data-duration="600"&gt;
    &lt;div class="vb-countdown-six-content"&gt;
      &lt;span class="vb-countdown-six-kicker"&gt;Example 06&lt;/span&gt;
      &lt;h3&gt;Circular Progress Countdown Timer&lt;/h3&gt;
      &lt;p&gt;Use a circular JavaScript countdown timer for sessions, dashboards, lessons, workouts, productivity blocks, and progress-based UI components.&lt;/p&gt;

      &lt;div class="vb-countdown-six-cards"&gt;
        &lt;div&gt;
          &lt;strong&gt;10 min&lt;/strong&gt;
          &lt;span&gt;Session length&lt;/span&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;strong&gt;Live&lt;/strong&gt;
          &lt;span&gt;Timer status&lt;/span&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;strong&gt;Loop&lt;/strong&gt;
          &lt;span&gt;Demo cycle&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-six-circle-wrap"&gt;
      &lt;svg class="vb-countdown-six-svg" viewBox="0 0 220 220" aria-hidden="true"&gt;
        &lt;defs&gt;
          &lt;linearGradient id="vbCountdownSixGradient" x1="0%" y1="0%" x2="100%" y2="100%"&gt;
            &lt;stop offset="0%" stop-color="#22d3ee"&gt;&lt;/stop&gt;
            &lt;stop offset="55%" stop-color="#8b5cf6"&gt;&lt;/stop&gt;
            &lt;stop offset="100%" stop-color="#ec4899"&gt;&lt;/stop&gt;
          &lt;/linearGradient&gt;
        &lt;/defs&gt;
        &lt;circle class="vb-countdown-six-track" cx="110" cy="110" r="92"&gt;&lt;/circle&gt;
        &lt;circle class="vb-countdown-six-progress" cx="110" cy="110" r="92" data-circle-progress&gt;&lt;/circle&gt;
      &lt;/svg&gt;

      &lt;div class="vb-countdown-six-center"&gt;
        &lt;strong data-time&gt;10:00&lt;/strong&gt;
        &lt;span data-status&gt;Session in progress&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-six-demo,
.vb-countdown-six-demo * {
  box-sizing: border-box;
}

.vb-countdown-six-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: clamp(34px, 5vw, 60px);
  background:
    radial-gradient(circle at 16% 18%, rgba(168, 85, 247, 0.16), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(14, 165, 233, 0.18), transparent 34%),
    linear-gradient(135deg, #f5f3ff 0%, #e0f2fe 52%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.22);
  box-shadow: 0 28px 80px rgba(88, 28, 135, 0.11);
}

.vb-countdown-six-app {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 390px);
  gap: clamp(24px, 4vw, 36px);
  align-items: center;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(24px, 4vw, 36px);
  border-radius: clamp(30px, 4vw, 46px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.12), transparent 34%),
    linear-gradient(135deg, #111827 0%, #4c1d95 54%, #0f172a 100%) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.26);
}

.vb-countdown-six-content {
  min-width: 0;
}

.vb-countdown-six-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 10px 22px 10px 22px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.18);
  color: #ddd6fe !important;
  -webkit-text-fill-color: #ddd6fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-six-content h3 {
  max-width: 740px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5.6vw, 72px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-countdown-six-content p {
  max-width: 680px;
  margin: 0 0 24px !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-six-cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  max-width: 640px;
}

.vb-countdown-six-cards div {
  min-width: 0;
  padding: 18px;
  border-radius: 22px 22px 8px 22px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-countdown-six-cards strong {
  display: block;
  margin-bottom: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(20px, 3vw, 28px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-countdown-six-cards span {
  display: block;
  color: #c4b5fd !important;
  -webkit-text-fill-color: #c4b5fd !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 850;
}

.vb-countdown-six-circle-wrap {
  position: relative;
  width: min(100%, 390px);
  aspect-ratio: 1 / 1;
  margin: 0 auto;
  border-radius: 999px;
  background:
    radial-gradient(circle at 50% 50%, rgba(255,255,255,0.12), transparent 48%),
    linear-gradient(135deg, rgba(255,255,255,0.09), rgba(255,255,255,0.03)) !important;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
}

.vb-countdown-six-svg {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  transform: rotate(-90deg);
}

.vb-countdown-six-track,
.vb-countdown-six-progress {
  fill: none;
  stroke-width: 14;
}

.vb-countdown-six-track {
  stroke: rgba(255,255,255,0.12);
}

.vb-countdown-six-progress {
  stroke: url("#vbCountdownSixGradient");
  stroke-linecap: round;
  transition: stroke-dashoffset 0.4s linear;
}

.vb-countdown-six-center {
  position: absolute;
  inset: 18%;
  display: grid;
  place-items: center;
  align-content: center;
  gap: 10px;
  border-radius: 999px;
  background:
    radial-gradient(circle at 32% 28%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #1e1b4b, #312e81) !important;
  border: 1px solid rgba(255,255,255,0.12);
  text-align: center;
}

.vb-countdown-six-center strong {
  display: block;
  max-width: 100%;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 9vw, 74px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.06em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-six-center span {
  display: block;
  padding: 0 14px;
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 850;
}

@media (max-width: 900px) {
  .vb-countdown-six-app {
    grid-template-columns: 1fr;
  }

  .vb-countdown-six-circle-wrap {
    width: min(100%, 340px);
  }
}

@media (max-width: 640px) {
  .vb-countdown-six-content h3 {
    font-size: 36px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-six-cards {
    grid-template-columns: 1fr;
  }

  .vb-countdown-six-circle-wrap {
    width: min(100%, 300px);
  }

  .vb-countdown-six-center strong {
    font-size: clamp(38px, 17vw, 62px);
  }
}</pre>



<p class="wp-block-paragraph">This circular progress countdown timer is useful for dashboard widgets, app interfaces, productivity sessions, study timers, fitness timers, onboarding flows, course lessons, and progress-based landing page sections.</p>



<h2 class="wp-block-heading">7. Coming Soon Page Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A coming soon page countdown timer</strong> is useful for new websites, product previews, app launches, landing pages, brand campaigns, waitlist pages, and pre-launch marketing pages. It gives visitors a clear launch message while collecting attention before the website or product goes live.</p>



<p class="wp-block-paragraph">This example uses a cinematic coming soon layout with a split dark gradient background, large launch text, glass countdown cards, waitlist form, and decorative light beams. The JavaScript calculates a future launch cycle dynamically, so the demo keeps working instead of stopping on an old date.</p>



<ul class="wp-block-list">
<li>Coming soon page countdown timer</li>
<li>Landing page launch design</li>
<li>Days, hours, minutes, and seconds</li>
<li>Email waitlist form</li>
<li>Fully responsive countdown layout</li>
</ul>



<div class="vb-countdown-seven-demo">
  <section class="vb-countdown-seven-coming" data-vb-countdown-seven data-cycle-days="21">
    <div class="vb-countdown-seven-copy">
      <span class="vb-countdown-seven-kicker">Example 07</span>
      <h3>Coming Soon Page Countdown Timer</h3>
      <p>Use a polished countdown section for website launches, new product previews, app waitlists, brand campaigns, and coming soon landing pages.</p>

      <form class="vb-countdown-seven-form">
        <input type="email" placeholder="Join the waitlist" aria-label="Email address">
        <button type="button">Notify Me</button>
      </form>

      <p class="vb-countdown-seven-note" data-next-launch>Launch date loading</p>
    </div>

    <div class="vb-countdown-seven-panel">
      <div class="vb-countdown-seven-panel-top">
        <span>Launch Countdown</span>
        <strong data-status>Coming soon</strong>
      </div>

      <div class="vb-countdown-seven-timer" aria-label="Coming soon countdown timer">
        <div>
          <strong data-days>00</strong>
          <span>Days</span>
        </div>

        <div>
          <strong data-hours>00</strong>
          <span>Hours</span>
        </div>

        <div>
          <strong data-minutes>00</strong>
          <span>Minutes</span>
        </div>

        <div>
          <strong data-seconds>00</strong>
          <span>Seconds</span>
        </div>
      </div>
    </div>
  </section>
</div>

<style>
.vb-countdown-seven-demo,
.vb-countdown-seven-demo * {
  box-sizing: border-box;
}

.vb-countdown-seven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 18px 58px 58px 18px;
  background:
    radial-gradient(circle at 12% 18%, rgba(59, 130, 246, 0.22), transparent 32%),
    radial-gradient(circle at 88% 22%, rgba(217, 70, 239, 0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #1e1b4b 54%, #020617 100%) !important;
  border: 1px solid rgba(147, 197, 253, 0.18);
  box-shadow: 0 34px 96px rgba(2, 6, 23, 0.38);
}

.vb-countdown-seven-coming {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(280px, 460px);
  gap: clamp(24px, 4vw, 40px);
  align-items: center;
  max-width: 1160px;
  min-height: 520px;
  margin: 0 auto;
  overflow: hidden;
}

.vb-countdown-seven-coming::before {
  content: "";
  position: absolute;
  left: 46%;
  top: -20%;
  width: 2px;
  height: 150%;
  background: linear-gradient(to bottom, transparent, rgba(125, 211, 252, 0.54), transparent);
  transform: rotate(18deg);
  box-shadow: 0 0 48px rgba(125, 211, 252, 0.42);
}

.vb-countdown-seven-coming::after {
  content: "";
  position: absolute;
  right: 8%;
  bottom: 8%;
  width: 180px;
  height: 180px;
  border-radius: 999px;
  background: rgba(217, 70, 239, 0.14);
  filter: blur(2px);
}

.vb-countdown-seven-copy,
.vb-countdown-seven-panel {
  position: relative;
  z-index: 2;
  min-width: 0;
}

.vb-countdown-seven-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 4px 18px 18px 4px;
  background: rgba(59, 130, 246, 0.16);
  border: 1px solid rgba(147, 197, 253, 0.20);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.vb-countdown-seven-copy h3 {
  max-width: 780px;
  margin: 0 0 18px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 82px) !important;
  line-height: 0.88 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
  overflow-wrap: anywhere;
}

.vb-countdown-seven-copy p {
  max-width: 650px;
  margin: 0 0 24px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: clamp(15px, 1.8vw, 17px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-seven-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 140px;
  gap: 10px;
  max-width: 560px;
  margin-bottom: 14px;
}

.vb-countdown-seven-form input {
  width: 100%;
  min-width: 0;
  min-height: 52px;
  padding: 0 16px;
  border-radius: 14px 999px 999px 14px;
  border: 1px solid rgba(191, 219, 254, 0.18);
  outline: none;
  background: rgba(255,255,255,0.08);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-countdown-seven-form input::placeholder {
  color: rgba(219, 234, 254, 0.72);
  -webkit-text-fill-color: rgba(219, 234, 254, 0.72);
}

.vb-countdown-seven-form button {
  min-height: 52px;
  border: 0;
  border-radius: 999px 14px 14px 999px;
  background: linear-gradient(135deg, #3b82f6, #d946ef);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 36px rgba(59, 130, 246, 0.26);
}

.vb-countdown-seven-note {
  margin: 0 !important;
  color: #c4b5fd !important;
  -webkit-text-fill-color: #c4b5fd !important;
  font-size: 13px !important;
  font-weight: 850 !important;
}

.vb-countdown-seven-panel {
  padding: clamp(18px, 3vw, 26px);
  border-radius: 36px 12px 36px 12px;
  background:
    radial-gradient(circle at 24% 18%, rgba(255,255,255,0.14), transparent 34%),
    linear-gradient(135deg, rgba(255,255,255,0.13), rgba(255,255,255,0.045)) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 26px 76px rgba(2, 6, 23, 0.28);
  backdrop-filter: blur(14px);
}

.vb-countdown-seven-panel-top {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  align-items: center;
  margin-bottom: 18px;
}

.vb-countdown-seven-panel-top span {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-countdown-seven-panel-top strong {
  color: #f0abfc !important;
  -webkit-text-fill-color: #f0abfc !important;
  font-size: 13px;
  font-weight: 900;
  text-align: right;
}

.vb-countdown-seven-timer {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-countdown-seven-timer div {
  min-width: 0;
  padding: clamp(16px, 3vw, 24px) 10px;
  border-radius: 22px 8px 22px 8px;
  background: rgba(15, 23, 42, 0.72);
  border: 1px solid rgba(255,255,255,0.11);
  text-align: center;
}

.vb-countdown-seven-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 8px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 7vw, 58px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.05em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-seven-timer span {
  display: block;
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

@media (max-width: 900px) {
  .vb-countdown-seven-coming {
    grid-template-columns: 1fr;
    min-height: auto;
  }
}

@media (max-width: 640px) {
  .vb-countdown-seven-demo {
    border-radius: 16px 34px 34px 16px;
  }

  .vb-countdown-seven-copy h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-seven-form {
    grid-template-columns: 1fr;
  }

  .vb-countdown-seven-form input,
  .vb-countdown-seven-form button {
    border-radius: 999px;
  }

  .vb-countdown-seven-panel-top {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-countdown-seven-panel-top strong {
    text-align: left;
  }
}

@media (max-width: 380px) {
  .vb-countdown-seven-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-seven]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 21;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-07T09:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextLaunchEl = timer.querySelector("[data-next-launch]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextLaunch(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextLaunch = getNextLaunch(now);
    let remaining = nextLaunch - now;

    if (remaining <= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(nextLaunch).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric",
      year: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextLaunchEl.textContent = "Next launch window: " + dateText;
    statusEl.textContent = "Coming soon";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-seven]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 21;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-07T09:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextLaunchEl = timer.querySelector("[data-next-launch]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextLaunch(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextLaunch = getNextLaunch(now);
    let remaining = nextLaunch - now;

    if (remaining &lt;= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(nextLaunch).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric",
      year: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextLaunchEl.textContent = "Next launch window: " + dateText;
    statusEl.textContent = "Coming soon";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-seven-demo"&gt;
  &lt;section class="vb-countdown-seven-coming" data-vb-countdown-seven data-cycle-days="21"&gt;
    &lt;div class="vb-countdown-seven-copy"&gt;
      &lt;span class="vb-countdown-seven-kicker"&gt;Example 07&lt;/span&gt;
      &lt;h3&gt;Coming Soon Page Countdown Timer&lt;/h3&gt;
      &lt;p&gt;Use a polished countdown section for website launches, new product previews, app waitlists, brand campaigns, and coming soon landing pages.&lt;/p&gt;

      &lt;form class="vb-countdown-seven-form"&gt;
        &lt;input type="email" placeholder="Join the waitlist" aria-label="Email address"&gt;
        &lt;button type="button"&gt;Notify Me&lt;/button&gt;
      &lt;/form&gt;

      &lt;p class="vb-countdown-seven-note" data-next-launch&gt;Launch date loading&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-seven-panel"&gt;
      &lt;div class="vb-countdown-seven-panel-top"&gt;
        &lt;span&gt;Launch Countdown&lt;/span&gt;
        &lt;strong data-status&gt;Coming soon&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-seven-timer" aria-label="Coming soon countdown timer"&gt;
        &lt;div&gt;
          &lt;strong data-days&gt;00&lt;/strong&gt;
          &lt;span&gt;Days&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-hours&gt;00&lt;/strong&gt;
          &lt;span&gt;Hours&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
          &lt;span&gt;Minutes&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
          &lt;span&gt;Seconds&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/section&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-seven-demo,
.vb-countdown-seven-demo * {
  box-sizing: border-box;
}

.vb-countdown-seven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 18px 58px 58px 18px;
  background:
    radial-gradient(circle at 12% 18%, rgba(59, 130, 246, 0.22), transparent 32%),
    radial-gradient(circle at 88% 22%, rgba(217, 70, 239, 0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #1e1b4b 54%, #020617 100%) !important;
  border: 1px solid rgba(147, 197, 253, 0.18);
  box-shadow: 0 34px 96px rgba(2, 6, 23, 0.38);
}

.vb-countdown-seven-coming {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(280px, 460px);
  gap: clamp(24px, 4vw, 40px);
  align-items: center;
  max-width: 1160px;
  min-height: 520px;
  margin: 0 auto;
  overflow: hidden;
}

.vb-countdown-seven-coming::before {
  content: "";
  position: absolute;
  left: 46%;
  top: -20%;
  width: 2px;
  height: 150%;
  background: linear-gradient(to bottom, transparent, rgba(125, 211, 252, 0.54), transparent);
  transform: rotate(18deg);
  box-shadow: 0 0 48px rgba(125, 211, 252, 0.42);
}

.vb-countdown-seven-coming::after {
  content: "";
  position: absolute;
  right: 8%;
  bottom: 8%;
  width: 180px;
  height: 180px;
  border-radius: 999px;
  background: rgba(217, 70, 239, 0.14);
  filter: blur(2px);
}

.vb-countdown-seven-copy,
.vb-countdown-seven-panel {
  position: relative;
  z-index: 2;
  min-width: 0;
}

.vb-countdown-seven-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 4px 18px 18px 4px;
  background: rgba(59, 130, 246, 0.16);
  border: 1px solid rgba(147, 197, 253, 0.20);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.vb-countdown-seven-copy h3 {
  max-width: 780px;
  margin: 0 0 18px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 82px) !important;
  line-height: 0.88 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
  overflow-wrap: anywhere;
}

.vb-countdown-seven-copy p {
  max-width: 650px;
  margin: 0 0 24px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: clamp(15px, 1.8vw, 17px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-seven-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 140px;
  gap: 10px;
  max-width: 560px;
  margin-bottom: 14px;
}

.vb-countdown-seven-form input {
  width: 100%;
  min-width: 0;
  min-height: 52px;
  padding: 0 16px;
  border-radius: 14px 999px 999px 14px;
  border: 1px solid rgba(191, 219, 254, 0.18);
  outline: none;
  background: rgba(255,255,255,0.08);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-countdown-seven-form input::placeholder {
  color: rgba(219, 234, 254, 0.72);
  -webkit-text-fill-color: rgba(219, 234, 254, 0.72);
}

.vb-countdown-seven-form button {
  min-height: 52px;
  border: 0;
  border-radius: 999px 14px 14px 999px;
  background: linear-gradient(135deg, #3b82f6, #d946ef);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 36px rgba(59, 130, 246, 0.26);
}

.vb-countdown-seven-note {
  margin: 0 !important;
  color: #c4b5fd !important;
  -webkit-text-fill-color: #c4b5fd !important;
  font-size: 13px !important;
  font-weight: 850 !important;
}

.vb-countdown-seven-panel {
  padding: clamp(18px, 3vw, 26px);
  border-radius: 36px 12px 36px 12px;
  background:
    radial-gradient(circle at 24% 18%, rgba(255,255,255,0.14), transparent 34%),
    linear-gradient(135deg, rgba(255,255,255,0.13), rgba(255,255,255,0.045)) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 26px 76px rgba(2, 6, 23, 0.28);
  backdrop-filter: blur(14px);
}

.vb-countdown-seven-panel-top {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  align-items: center;
  margin-bottom: 18px;
}

.vb-countdown-seven-panel-top span {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-countdown-seven-panel-top strong {
  color: #f0abfc !important;
  -webkit-text-fill-color: #f0abfc !important;
  font-size: 13px;
  font-weight: 900;
  text-align: right;
}

.vb-countdown-seven-timer {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-countdown-seven-timer div {
  min-width: 0;
  padding: clamp(16px, 3vw, 24px) 10px;
  border-radius: 22px 8px 22px 8px;
  background: rgba(15, 23, 42, 0.72);
  border: 1px solid rgba(255,255,255,0.11);
  text-align: center;
}

.vb-countdown-seven-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 8px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 7vw, 58px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.05em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-seven-timer span {
  display: block;
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

@media (max-width: 900px) {
  .vb-countdown-seven-coming {
    grid-template-columns: 1fr;
    min-height: auto;
  }
}

@media (max-width: 640px) {
  .vb-countdown-seven-demo {
    border-radius: 16px 34px 34px 16px;
  }

  .vb-countdown-seven-copy h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-seven-form {
    grid-template-columns: 1fr;
  }

  .vb-countdown-seven-form input,
  .vb-countdown-seven-form button {
    border-radius: 999px;
  }

  .vb-countdown-seven-panel-top {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-countdown-seven-panel-top strong {
    text-align: left;
  }
}

@media (max-width: 380px) {
  .vb-countdown-seven-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This coming soon page countdown timer is useful for website launches, waitlist landing pages, app previews, product teasers, brand campaigns, SaaS launch pages, and pre-release marketing sections.</p>



<h2 class="wp-block-heading">8. Webinar Registration Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A webinar registration countdown timer</strong> is useful for online workshops, training events, live classes, product demos, virtual summits, coaching sessions, and educational landing pages. It helps visitors see how much time remains before the next registration window closes.</p>



<p class="wp-block-paragraph">This example uses a clean webinar registration card with a speaker section, schedule details, seat counter, countdown sidebar, and registration button. The JavaScript uses a repeating weekly webinar schedule, so the timer keeps working over time.</p>



<ul class="wp-block-list">
<li>Webinar registration countdown timer</li>
<li>Weekly webinar schedule logic</li>
<li>Speaker and seat details</li>
<li>Registration-focused CTA</li>
<li>Responsive landing page card design</li>
</ul>



<div class="vb-countdown-eight-demo">
  <section class="vb-countdown-eight-webinar" data-vb-countdown-eight data-cycle-days="7">
    <div class="vb-countdown-eight-main">
      <div class="vb-countdown-eight-speaker">
        <div class="vb-countdown-eight-avatar">W</div>
        <div>
          <span>Live Training</span>
          <strong>Webinar Registration Countdown Timer</strong>
        </div>
      </div>

      <h3>Webinar Registration Countdown Timer</h3>
      <p>Use this countdown timer for webinar landing pages, live product demos, workshops, online lessons, training sessions, and virtual event registration pages.</p>

      <div class="vb-countdown-eight-details">
        <div>
          <span>Format</span>
          <strong>Live Online</strong>
        </div>
        <div>
          <span>Seats</span>
          <strong>42 left</strong>
        </div>
        <div>
          <span>Access</span>
          <strong>Free</strong>
        </div>
      </div>
    </div>

    <aside class="vb-countdown-eight-countbox">
      <span class="vb-countdown-eight-kicker">Example 08</span>
      <strong class="vb-countdown-eight-date" data-next-webinar>Next webinar loading</strong>

      <div class="vb-countdown-eight-timer" aria-label="Webinar registration countdown timer">
        <div>
          <strong data-days>00</strong>
          <span>Days</span>
        </div>

        <div>
          <strong data-hours>00</strong>
          <span>Hours</span>
        </div>

        <div>
          <strong data-minutes>00</strong>
          <span>Min</span>
        </div>

        <div>
          <strong data-seconds>00</strong>
          <span>Sec</span>
        </div>
      </div>

      <p data-status>Registration is open for the next webinar.</p>
      <a href="#webinar-registration">Register Now</a>
    </aside>
  </section>
</div>

<style>
.vb-countdown-eight-demo,
.vb-countdown-eight-demo * {
  box-sizing: border-box;
}

.vb-countdown-eight-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 46px 46px 46px 10px;
  background:
    radial-gradient(circle at 14% 18%, rgba(14, 165, 233, 0.18), transparent 34%),
    radial-gradient(circle at 88% 24%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.20);
  box-shadow: 0 28px 80px rgba(49, 46, 129, 0.10);
}

.vb-countdown-eight-webinar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(270px, 360px);
  gap: clamp(20px, 3vw, 28px);
  align-items: stretch;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-countdown-eight-main {
  min-width: 0;
  padding: clamp(24px, 4vw, 38px);
  border-radius: 34px 34px 34px 8px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.09);
}

.vb-countdown-eight-speaker {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 22px;
}

.vb-countdown-eight-avatar {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 58px;
  height: 58px;
  border-radius: 18px 18px 18px 4px;
  background: linear-gradient(135deg, #0ea5e9, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  font-weight: 950;
  box-shadow: 0 14px 32px rgba(99, 102, 241, 0.22);
}

.vb-countdown-eight-speaker span {
  display: block;
  margin-bottom: 4px;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-eight-speaker strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  line-height: 1.25;
  font-weight: 900;
}

.vb-countdown-eight-main h3 {
  margin: 0 0 16px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5.4vw, 68px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-countdown-eight-main p {
  max-width: 690px;
  margin: 0 0 24px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-eight-details {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-countdown-eight-details div {
  min-width: 0;
  padding: 16px;
  border-radius: 20px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.18);
}

.vb-countdown-eight-details span {
  display: block;
  margin-bottom: 6px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-eight-details strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(18px, 3vw, 24px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-countdown-eight-countbox {
  min-width: 0;
  display: grid;
  align-content: center;
  gap: 16px;
  padding: clamp(20px, 3vw, 26px);
  border-radius: 34px 8px 34px 34px;
  background:
    radial-gradient(circle at 18% 16%, rgba(255,255,255,0.14), transparent 34%),
    linear-gradient(135deg, #0f172a, #312e81 58%, #1e1b4b) !important;
  box-shadow: 0 24px 70px rgba(49, 46, 129, 0.20);
}

.vb-countdown-eight-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-eight-date {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-countdown-eight-timer {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.vb-countdown-eight-timer div {
  min-width: 0;
  padding: 16px 8px;
  border-radius: 18px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.12);
  text-align: center;
}

.vb-countdown-eight-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 6vw, 48px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-eight-timer span {
  display: block;
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-eight-countbox p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-countdown-eight-countbox a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #0ea5e9, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(14, 165, 233, 0.24);
}

@media (max-width: 900px) {
  .vb-countdown-eight-webinar {
    grid-template-columns: 1fr;
  }

  .vb-countdown-eight-timer {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .vb-countdown-eight-timer strong {
    font-size: clamp(26px, 6vw, 42px);
  }
}

@media (max-width: 640px) {
  .vb-countdown-eight-demo {
    border-radius: 32px 32px 32px 8px;
  }

  .vb-countdown-eight-main h3 {
    font-size: 36px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-eight-details {
    grid-template-columns: 1fr;
  }

  .vb-countdown-eight-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-eight-countbox a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-eight-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-eight]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 7;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-06T17:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextWebinarEl = timer.querySelector("[data-next-webinar]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextWebinar(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextWebinar = getNextWebinar(now);
    let remaining = nextWebinar - now;

    if (remaining <= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(nextWebinar).toLocaleDateString("en-US", {
      weekday: "short",
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextWebinarEl.textContent = "Next webinar: " + dateText;
    statusEl.textContent = "Registration is open for the next webinar.";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-eight]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 7;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-06T17:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextWebinarEl = timer.querySelector("[data-next-webinar]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextWebinar(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextWebinar = getNextWebinar(now);
    let remaining = nextWebinar - now;

    if (remaining &lt;= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(nextWebinar).toLocaleDateString("en-US", {
      weekday: "short",
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextWebinarEl.textContent = "Next webinar: " + dateText;
    statusEl.textContent = "Registration is open for the next webinar.";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-eight-demo"&gt;
  &lt;section class="vb-countdown-eight-webinar" data-vb-countdown-eight data-cycle-days="7"&gt;
    &lt;div class="vb-countdown-eight-main"&gt;
      &lt;div class="vb-countdown-eight-speaker"&gt;
        &lt;div class="vb-countdown-eight-avatar"&gt;W&lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Live Training&lt;/span&gt;
          &lt;strong&gt;Webinar Registration Countdown Timer&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;h3&gt;Webinar Registration Countdown Timer&lt;/h3&gt;
      &lt;p&gt;Use this countdown timer for webinar landing pages, live product demos, workshops, online lessons, training sessions, and virtual event registration pages.&lt;/p&gt;

      &lt;div class="vb-countdown-eight-details"&gt;
        &lt;div&gt;
          &lt;span&gt;Format&lt;/span&gt;
          &lt;strong&gt;Live Online&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Seats&lt;/span&gt;
          &lt;strong&gt;42 left&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Access&lt;/span&gt;
          &lt;strong&gt;Free&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;aside class="vb-countdown-eight-countbox"&gt;
      &lt;span class="vb-countdown-eight-kicker"&gt;Example 08&lt;/span&gt;
      &lt;strong class="vb-countdown-eight-date" data-next-webinar&gt;Next webinar loading&lt;/strong&gt;

      &lt;div class="vb-countdown-eight-timer" aria-label="Webinar registration countdown timer"&gt;
        &lt;div&gt;
          &lt;strong data-days&gt;00&lt;/strong&gt;
          &lt;span&gt;Days&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-hours&gt;00&lt;/strong&gt;
          &lt;span&gt;Hours&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
          &lt;span&gt;Min&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
          &lt;span&gt;Sec&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;p data-status&gt;Registration is open for the next webinar.&lt;/p&gt;
      &lt;a href="#webinar-registration"&gt;Register Now&lt;/a&gt;
    &lt;/aside&gt;
  &lt;/section&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-eight-demo,
.vb-countdown-eight-demo * {
  box-sizing: border-box;
}

.vb-countdown-eight-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 46px 46px 46px 10px;
  background:
    radial-gradient(circle at 14% 18%, rgba(14, 165, 233, 0.18), transparent 34%),
    radial-gradient(circle at 88% 24%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.20);
  box-shadow: 0 28px 80px rgba(49, 46, 129, 0.10);
}

.vb-countdown-eight-webinar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(270px, 360px);
  gap: clamp(20px, 3vw, 28px);
  align-items: stretch;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-countdown-eight-main {
  min-width: 0;
  padding: clamp(24px, 4vw, 38px);
  border-radius: 34px 34px 34px 8px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.09);
}

.vb-countdown-eight-speaker {
  display: flex;
  align-items: center;
  gap: 14px;
  margin-bottom: 22px;
}

.vb-countdown-eight-avatar {
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  width: 58px;
  height: 58px;
  border-radius: 18px 18px 18px 4px;
  background: linear-gradient(135deg, #0ea5e9, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  font-weight: 950;
  box-shadow: 0 14px 32px rgba(99, 102, 241, 0.22);
}

.vb-countdown-eight-speaker span {
  display: block;
  margin-bottom: 4px;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-eight-speaker strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  line-height: 1.25;
  font-weight: 900;
}

.vb-countdown-eight-main h3 {
  margin: 0 0 16px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5.4vw, 68px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-countdown-eight-main p {
  max-width: 690px;
  margin: 0 0 24px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-eight-details {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-countdown-eight-details div {
  min-width: 0;
  padding: 16px;
  border-radius: 20px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.18);
}

.vb-countdown-eight-details span {
  display: block;
  margin-bottom: 6px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-eight-details strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(18px, 3vw, 24px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-countdown-eight-countbox {
  min-width: 0;
  display: grid;
  align-content: center;
  gap: 16px;
  padding: clamp(20px, 3vw, 26px);
  border-radius: 34px 8px 34px 34px;
  background:
    radial-gradient(circle at 18% 16%, rgba(255,255,255,0.14), transparent 34%),
    linear-gradient(135deg, #0f172a, #312e81 58%, #1e1b4b) !important;
  box-shadow: 0 24px 70px rgba(49, 46, 129, 0.20);
}

.vb-countdown-eight-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-eight-date {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-countdown-eight-timer {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.vb-countdown-eight-timer div {
  min-width: 0;
  padding: 16px 8px;
  border-radius: 18px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.12);
  text-align: center;
}

.vb-countdown-eight-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 6vw, 48px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-eight-timer span {
  display: block;
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-eight-countbox p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-countdown-eight-countbox a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #0ea5e9, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(14, 165, 233, 0.24);
}

@media (max-width: 900px) {
  .vb-countdown-eight-webinar {
    grid-template-columns: 1fr;
  }

  .vb-countdown-eight-timer {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .vb-countdown-eight-timer strong {
    font-size: clamp(26px, 6vw, 42px);
  }
}

@media (max-width: 640px) {
  .vb-countdown-eight-demo {
    border-radius: 32px 32px 32px 8px;
  }

  .vb-countdown-eight-main h3 {
    font-size: 36px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-eight-details {
    grid-template-columns: 1fr;
  }

  .vb-countdown-eight-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-eight-countbox a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-eight-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This webinar registration countdown timer is useful for webinar landing pages, live product demos, online workshops, training pages, course launches, virtual event registration pages, and coaching session campaigns.</p>



<h2 class="wp-block-heading">9. Black Friday Sale Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A Black Friday sale countdown timer</strong> is useful for seasonal ecommerce campaigns, Black Friday landing pages, Cyber Monday promotions, holiday discounts, product sale sections, and limited-time offer banners. It helps highlight a major campaign deadline with strong visual urgency.</p>



<p class="wp-block-paragraph">This example uses a dark retail campaign layout with neon sale styling, large discount text, angled promo cards, responsive countdown blocks, and a strong shopping CTA. The JavaScript calculates the next yearly Black Friday campaign window, so the demo keeps working year after year.</p>



<ul class="wp-block-list">
<li>Black Friday sale countdown timer</li>
<li>Yearly seasonal campaign logic</li>
<li>Dark ecommerce promo layout</li>
<li>Large responsive timer cards</li>
<li>Retail discount CTA section</li>
</ul>



<div class="vb-countdown-nine-demo">
  <section class="vb-countdown-nine-sale" data-vb-countdown-nine>
    <div class="vb-countdown-nine-left">
      <span class="vb-countdown-nine-kicker">Example 09</span>
      <h3>Black Friday Sale Countdown Timer</h3>
      <p>Use a high-impact countdown timer for Black Friday sales, Cyber Monday promotions, seasonal ecommerce campaigns, and limited holiday offers.</p>

      <div class="vb-countdown-nine-discount">
        <strong>70% OFF</strong>
        <span>Seasonal ecommerce promotion</span>
      </div>

      <a href="#black-friday-sale" class="vb-countdown-nine-button">View Deals</a>
    </div>

    <div class="vb-countdown-nine-right">
      <div class="vb-countdown-nine-card">
        <div class="vb-countdown-nine-card-top">
          <span>Sale starts in</span>
          <strong data-next-sale>Black Friday loading</strong>
        </div>

        <div class="vb-countdown-nine-timer" aria-label="Black Friday sale countdown timer">
          <div>
            <strong data-days>00</strong>
            <span>Days</span>
          </div>

          <div>
            <strong data-hours>00</strong>
            <span>Hours</span>
          </div>

          <div>
            <strong data-minutes>00</strong>
            <span>Min</span>
          </div>

          <div>
            <strong data-seconds>00</strong>
            <span>Sec</span>
          </div>
        </div>

        <p data-status>Black Friday campaign countdown is active.</p>
      </div>
    </div>
  </section>
</div>

<style>
.vb-countdown-nine-demo,
.vb-countdown-nine-demo * {
  box-sizing: border-box;
}

.vb-countdown-nine-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 10px 10px 54px 54px;
  background:
    repeating-linear-gradient(-45deg, rgba(255,255,255,0.04) 0 8px, transparent 8px 18px),
    radial-gradient(circle at 18% 22%, rgba(239, 68, 68, 0.22), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(250, 204, 21, 0.16), transparent 34%),
    linear-gradient(135deg, #020617 0%, #111827 48%, #450a0a 100%) !important;
  border: 1px solid rgba(248, 113, 113, 0.22);
  box-shadow: 0 34px 96px rgba(2, 6, 23, 0.42);
}

.vb-countdown-nine-sale {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(280px, 0.75fr);
  gap: clamp(24px, 4vw, 42px);
  align-items: center;
  max-width: 1160px;
  margin: 0 auto;
  overflow: hidden;
}

.vb-countdown-nine-sale::before {
  content: "";
  position: absolute;
  left: 46%;
  top: 4%;
  width: 140px;
  height: 92%;
  background: rgba(250, 204, 21, 0.10);
  transform: skewX(-16deg);
  filter: blur(1px);
}

.vb-countdown-nine-left,
.vb-countdown-nine-right {
  position: relative;
  z-index: 2;
  min-width: 0;
}

.vb-countdown-nine-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 2px 16px 2px 16px;
  background: rgba(239, 68, 68, 0.18);
  border: 1px solid rgba(248, 113, 113, 0.26);
  color: #fecaca !important;
  -webkit-text-fill-color: #fecaca !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.vb-countdown-nine-left h3 {
  max-width: 820px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6.2vw, 86px) !important;
  line-height: 0.86 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
  overflow-wrap: anywhere;
}

.vb-countdown-nine-left p {
  max-width: 660px;
  margin: 0 0 22px !important;
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: clamp(15px, 1.8vw, 17px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-nine-discount {
  display: inline-grid;
  gap: 5px;
  max-width: 100%;
  margin-bottom: 18px;
  padding: 18px 20px;
  border-radius: 4px 28px 4px 28px;
  background: linear-gradient(135deg, rgba(239, 68, 68, 0.30), rgba(250, 204, 21, 0.14)) !important;
  border: 1px solid rgba(250, 204, 21, 0.24);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.10);
}

.vb-countdown-nine-discount strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 6vw, 60px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.07em;
}

.vb-countdown-nine-discount span {
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 850;
}

.vb-countdown-nine-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 14px 20px;
  border-radius: 4px 999px 999px 4px;
  background: linear-gradient(135deg, #ef4444, #f97316 55%, #facc15);
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 18px 40px rgba(239, 68, 68, 0.28);
}

.vb-countdown-nine-right {
  display: flex;
  justify-content: center;
}

.vb-countdown-nine-card {
  width: min(100%, 430px);
  padding: clamp(20px, 3vw, 28px);
  border-radius: 38px 8px 38px 8px;
  background:
    radial-gradient(circle at 18% 14%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, rgba(255,255,255,0.12), rgba(255,255,255,0.045)) !important;
  border: 1px solid rgba(255,255,255,0.14);
  backdrop-filter: blur(14px);
  box-shadow: 0 28px 80px rgba(0,0,0,0.24);
}

.vb-countdown-nine-card-top {
  display: grid;
  gap: 7px;
  margin-bottom: 18px;
}

.vb-countdown-nine-card-top span {
  color: #fecaca !important;
  -webkit-text-fill-color: #fecaca !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-nine-card-top strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-countdown-nine-timer {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  margin-bottom: 16px;
}

.vb-countdown-nine-timer div {
  min-width: 0;
  padding: 18px 10px;
  border-radius: 8px 22px 8px 22px;
  background: #ffffff;
  border: 1px solid rgba(255,255,255,0.16);
  text-align: center;
  box-shadow: 0 18px 42px rgba(0,0,0,0.18);
}

.vb-countdown-nine-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 6px;
  color: #991b1b !important;
  -webkit-text-fill-color: #991b1b !important;
  font-size: clamp(34px, 7vw, 56px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-nine-timer span {
  display: block;
  color: #7f1d1d !important;
  -webkit-text-fill-color: #7f1d1d !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-nine-card p {
  margin: 0 !important;
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 920px) {
  .vb-countdown-nine-sale {
    grid-template-columns: 1fr;
  }

  .vb-countdown-nine-right {
    justify-content: flex-start;
  }
}

@media (max-width: 640px) {
  .vb-countdown-nine-demo {
    border-radius: 10px 10px 34px 34px;
  }

  .vb-countdown-nine-left h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-nine-button {
    width: 100%;
    border-radius: 999px;
  }
}

@media (max-width: 380px) {
  .vb-countdown-nine-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-nine]");
  if (!timer) return;

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextSaleEl = timer.querySelector("[data-next-sale]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getBlackFriday(year) {
    const date = new Date(year, 10, 1, 0, 0, 0);
    let fridayCount = 0;

    while (date.getMonth() === 10) {
      if (date.getDay() === 5) {
        fridayCount += 1;
        if (fridayCount === 4) {
          date.setHours(0, 0, 0, 0);
          return date.getTime();
        }
      }

      date.setDate(date.getDate() + 1);
    }

    return new Date(year, 10, 29, 0, 0, 0).getTime();
  }

  function getNextBlackFriday(now) {
    const currentYear = new Date(now).getFullYear();
    const thisYear = getBlackFriday(currentYear);

    if (thisYear > now) {
      return thisYear;
    }

    return getBlackFriday(currentYear + 1);
  }

  function updateCountdown() {
    const now = Date.now();
    const nextSale = getNextBlackFriday(now);
    let remaining = nextSale - now;

    if (remaining <= 0) {
      remaining = getBlackFriday(new Date(now).getFullYear() + 1) - now;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const saleDate = new Date(nextSale).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric",
      year: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextSaleEl.textContent = "Next Black Friday: " + saleDate;
    statusEl.textContent = "Black Friday campaign countdown is active.";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-nine]");
  if (!timer) return;

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextSaleEl = timer.querySelector("[data-next-sale]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getBlackFriday(year) {
    const date = new Date(year, 10, 1, 0, 0, 0);
    let fridayCount = 0;

    while (date.getMonth() === 10) {
      if (date.getDay() === 5) {
        fridayCount += 1;
        if (fridayCount === 4) {
          date.setHours(0, 0, 0, 0);
          return date.getTime();
        }
      }

      date.setDate(date.getDate() + 1);
    }

    return new Date(year, 10, 29, 0, 0, 0).getTime();
  }

  function getNextBlackFriday(now) {
    const currentYear = new Date(now).getFullYear();
    const thisYear = getBlackFriday(currentYear);

    if (thisYear > now) {
      return thisYear;
    }

    return getBlackFriday(currentYear + 1);
  }

  function updateCountdown() {
    const now = Date.now();
    const nextSale = getNextBlackFriday(now);
    let remaining = nextSale - now;

    if (remaining &lt;= 0) {
      remaining = getBlackFriday(new Date(now).getFullYear() + 1) - now;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const saleDate = new Date(nextSale).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric",
      year: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextSaleEl.textContent = "Next Black Friday: " + saleDate;
    statusEl.textContent = "Black Friday campaign countdown is active.";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-nine-demo"&gt;
  &lt;section class="vb-countdown-nine-sale" data-vb-countdown-nine&gt;
    &lt;div class="vb-countdown-nine-left"&gt;
      &lt;span class="vb-countdown-nine-kicker"&gt;Example 09&lt;/span&gt;
      &lt;h3&gt;Black Friday Sale Countdown Timer&lt;/h3&gt;
      &lt;p&gt;Use a high-impact countdown timer for Black Friday sales, Cyber Monday promotions, seasonal ecommerce campaigns, and limited holiday offers.&lt;/p&gt;

      &lt;div class="vb-countdown-nine-discount"&gt;
        &lt;strong&gt;70% OFF&lt;/strong&gt;
        &lt;span&gt;Seasonal ecommerce promotion&lt;/span&gt;
      &lt;/div&gt;

      &lt;a href="#black-friday-sale" class="vb-countdown-nine-button"&gt;View Deals&lt;/a&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-nine-right"&gt;
      &lt;div class="vb-countdown-nine-card"&gt;
        &lt;div class="vb-countdown-nine-card-top"&gt;
          &lt;span&gt;Sale starts in&lt;/span&gt;
          &lt;strong data-next-sale&gt;Black Friday loading&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-countdown-nine-timer" aria-label="Black Friday sale countdown timer"&gt;
          &lt;div&gt;
            &lt;strong data-days&gt;00&lt;/strong&gt;
            &lt;span&gt;Days&lt;/span&gt;
          &lt;/div&gt;

          &lt;div&gt;
            &lt;strong data-hours&gt;00&lt;/strong&gt;
            &lt;span&gt;Hours&lt;/span&gt;
          &lt;/div&gt;

          &lt;div&gt;
            &lt;strong data-minutes&gt;00&lt;/strong&gt;
            &lt;span&gt;Min&lt;/span&gt;
          &lt;/div&gt;

          &lt;div&gt;
            &lt;strong data-seconds&gt;00&lt;/strong&gt;
            &lt;span&gt;Sec&lt;/span&gt;
          &lt;/div&gt;
        &lt;/div&gt;

        &lt;p data-status&gt;Black Friday campaign countdown is active.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/section&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-nine-demo,
.vb-countdown-nine-demo * {
  box-sizing: border-box;
}

.vb-countdown-nine-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 10px 10px 54px 54px;
  background:
    repeating-linear-gradient(-45deg, rgba(255,255,255,0.04) 0 8px, transparent 8px 18px),
    radial-gradient(circle at 18% 22%, rgba(239, 68, 68, 0.22), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(250, 204, 21, 0.16), transparent 34%),
    linear-gradient(135deg, #020617 0%, #111827 48%, #450a0a 100%) !important;
  border: 1px solid rgba(248, 113, 113, 0.22);
  box-shadow: 0 34px 96px rgba(2, 6, 23, 0.42);
}

.vb-countdown-nine-sale {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(280px, 0.75fr);
  gap: clamp(24px, 4vw, 42px);
  align-items: center;
  max-width: 1160px;
  margin: 0 auto;
  overflow: hidden;
}

.vb-countdown-nine-sale::before {
  content: "";
  position: absolute;
  left: 46%;
  top: 4%;
  width: 140px;
  height: 92%;
  background: rgba(250, 204, 21, 0.10);
  transform: skewX(-16deg);
  filter: blur(1px);
}

.vb-countdown-nine-left,
.vb-countdown-nine-right {
  position: relative;
  z-index: 2;
  min-width: 0;
}

.vb-countdown-nine-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 2px 16px 2px 16px;
  background: rgba(239, 68, 68, 0.18);
  border: 1px solid rgba(248, 113, 113, 0.26);
  color: #fecaca !important;
  -webkit-text-fill-color: #fecaca !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.vb-countdown-nine-left h3 {
  max-width: 820px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6.2vw, 86px) !important;
  line-height: 0.86 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
  overflow-wrap: anywhere;
}

.vb-countdown-nine-left p {
  max-width: 660px;
  margin: 0 0 22px !important;
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: clamp(15px, 1.8vw, 17px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-nine-discount {
  display: inline-grid;
  gap: 5px;
  max-width: 100%;
  margin-bottom: 18px;
  padding: 18px 20px;
  border-radius: 4px 28px 4px 28px;
  background: linear-gradient(135deg, rgba(239, 68, 68, 0.30), rgba(250, 204, 21, 0.14)) !important;
  border: 1px solid rgba(250, 204, 21, 0.24);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.10);
}

.vb-countdown-nine-discount strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 6vw, 60px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.07em;
}

.vb-countdown-nine-discount span {
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 850;
}

.vb-countdown-nine-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 14px 20px;
  border-radius: 4px 999px 999px 4px;
  background: linear-gradient(135deg, #ef4444, #f97316 55%, #facc15);
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 18px 40px rgba(239, 68, 68, 0.28);
}

.vb-countdown-nine-right {
  display: flex;
  justify-content: center;
}

.vb-countdown-nine-card {
  width: min(100%, 430px);
  padding: clamp(20px, 3vw, 28px);
  border-radius: 38px 8px 38px 8px;
  background:
    radial-gradient(circle at 18% 14%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, rgba(255,255,255,0.12), rgba(255,255,255,0.045)) !important;
  border: 1px solid rgba(255,255,255,0.14);
  backdrop-filter: blur(14px);
  box-shadow: 0 28px 80px rgba(0,0,0,0.24);
}

.vb-countdown-nine-card-top {
  display: grid;
  gap: 7px;
  margin-bottom: 18px;
}

.vb-countdown-nine-card-top span {
  color: #fecaca !important;
  -webkit-text-fill-color: #fecaca !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-nine-card-top strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-countdown-nine-timer {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  margin-bottom: 16px;
}

.vb-countdown-nine-timer div {
  min-width: 0;
  padding: 18px 10px;
  border-radius: 8px 22px 8px 22px;
  background: #ffffff;
  border: 1px solid rgba(255,255,255,0.16);
  text-align: center;
  box-shadow: 0 18px 42px rgba(0,0,0,0.18);
}

.vb-countdown-nine-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 6px;
  color: #991b1b !important;
  -webkit-text-fill-color: #991b1b !important;
  font-size: clamp(34px, 7vw, 56px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-nine-timer span {
  display: block;
  color: #7f1d1d !important;
  -webkit-text-fill-color: #7f1d1d !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-nine-card p {
  margin: 0 !important;
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 920px) {
  .vb-countdown-nine-sale {
    grid-template-columns: 1fr;
  }

  .vb-countdown-nine-right {
    justify-content: flex-start;
  }
}

@media (max-width: 640px) {
  .vb-countdown-nine-demo {
    border-radius: 10px 10px 34px 34px;
  }

  .vb-countdown-nine-left h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-nine-button {
    width: 100%;
    border-radius: 999px;
  }
}

@media (max-width: 380px) {
  .vb-countdown-nine-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This Black Friday sale countdown timer is useful for ecommerce campaign pages, holiday sale banners, Cyber Monday promotions, product discount sections, seasonal landing pages, and major retail offer pages.</p>



<h2 class="wp-block-heading">10. Limited Stock Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A limited stock countdown timer</strong> is useful for ecommerce product pages, product cards, drops, flash inventory alerts, preorder campaigns, ticket sales, and limited quantity offers. It combines time urgency with stock availability so visitors can see both deadline and inventory status.</p>



<p class="wp-block-paragraph">This example uses an inventory-focused layout with a stock meter, product availability badge, compact countdown display, and action button. The JavaScript uses a short repeating inventory window, so the demo never stays stuck after reaching zero.</p>



<ul class="wp-block-list">
<li>Limited stock countdown timer</li>
<li>Inventory and stock meter layout</li>
<li>Short repeating timer window</li>
<li>Responsive product availability card</li>
<li>Useful for product pages and drops</li>
</ul>



<div class="vb-countdown-ten-demo">
  <section class="vb-countdown-ten-stock" data-vb-countdown-ten data-duration="3600">
    <div class="vb-countdown-ten-product">
      <div class="vb-countdown-ten-image">
        <span>Example 10</span>
        <div class="vb-countdown-ten-box">
          <i></i>
          <i></i>
          <i></i>
        </div>
      </div>

      <div class="vb-countdown-ten-info">
        <div class="vb-countdown-ten-label">Limited Stock</div>
        <h3>Limited Stock Countdown Timer</h3>
        <p>Use this countdown timer for product pages, limited drops, inventory campaigns, product cards, ticket sales, and preorder availability sections.</p>

        <div class="vb-countdown-ten-meter">
          <div class="vb-countdown-ten-meter-head">
            <strong>Only 12 items left</strong>
            <span>Low stock</span>
          </div>
          <div class="vb-countdown-ten-meter-bar">
            <i></i>
          </div>
        </div>
      </div>
    </div>

    <aside class="vb-countdown-ten-sidebar">
      <span class="vb-countdown-ten-kicker">Stock window</span>
      <strong class="vb-countdown-ten-title">Reserve before timer ends</strong>

      <div class="vb-countdown-ten-timer" aria-label="Limited stock countdown timer">
        <div>
          <strong data-hours>00</strong>
          <span>Hours</span>
        </div>

        <div>
          <strong data-minutes>00</strong>
          <span>Min</span>
        </div>

        <div>
          <strong data-seconds>00</strong>
          <span>Sec</span>
        </div>
      </div>

      <p data-status>Inventory hold is active.</p>
      <a href="#reserve-stock">Reserve Stock</a>
    </aside>
  </section>
</div>

<style>
.vb-countdown-ten-demo,
.vb-countdown-ten-demo * {
  box-sizing: border-box;
}

.vb-countdown-ten-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 8px 48px 8px 48px;
  background:
    radial-gradient(circle at 12% 18%, rgba(245, 158, 11, 0.18), transparent 34%),
    radial-gradient(circle at 86% 24%, rgba(20, 184, 166, 0.18), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #f0fdfa 52%, #ffffff 100%) !important;
  border: 1px solid rgba(245, 158, 11, 0.24);
  box-shadow: 0 28px 80px rgba(120, 53, 15, 0.10);
}

.vb-countdown-ten-stock {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(250px, 330px);
  gap: clamp(18px, 3vw, 26px);
  align-items: stretch;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-countdown-ten-product {
  display: grid;
  grid-template-columns: minmax(220px, 310px) minmax(0, 1fr);
  gap: 18px;
  min-width: 0;
  padding: clamp(14px, 2vw, 18px);
  border-radius: 30px 8px 30px 8px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.09);
}

.vb-countdown-ten-image {
  position: relative;
  min-width: 0;
  min-height: clamp(260px, 32vw, 340px);
  overflow: hidden;
  border-radius: 24px 8px 24px 8px;
  background:
    radial-gradient(circle at 30% 18%, rgba(255,255,255,0.30), transparent 34%),
    linear-gradient(135deg, #92400e, #f59e0b 52%, #14b8a6) !important;
}

.vb-countdown-ten-image > span {
  position: absolute;
  left: 16px;
  top: 16px;
  z-index: 3;
  display: inline-flex;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  border: 1px solid rgba(255,255,255,0.22);
  color: #fffbeb !important;
  -webkit-text-fill-color: #fffbeb !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-ten-box {
  position: absolute;
  left: 50%;
  top: 55%;
  width: clamp(150px, 20vw, 200px);
  height: clamp(150px, 20vw, 200px);
  transform: translate(-50%, -50%) rotate(8deg);
  border-radius: 28px 10px 28px 10px;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.70), rgba(255,255,255,0.30)) !important;
  border: 1px solid rgba(255,255,255,0.34);
  box-shadow: 0 28px 68px rgba(120, 53, 15, 0.24);
}

.vb-countdown-ten-box i {
  position: absolute;
  display: block;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.18);
}

.vb-countdown-ten-box i:nth-child(1) {
  left: 24px;
  top: 42px;
  width: 60%;
  height: 14px;
}

.vb-countdown-ten-box i:nth-child(2) {
  left: 24px;
  top: 78px;
  width: 46%;
  height: 14px;
}

.vb-countdown-ten-box i:nth-child(3) {
  left: 24px;
  bottom: 32px;
  width: 32%;
  height: 28px;
  border-radius: 10px;
  background: rgba(20, 184, 166, 0.30);
}

.vb-countdown-ten-info {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
  padding: 12px 8px;
}

.vb-countdown-ten-label {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px 999px 999px 4px;
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-ten-info h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 0.93 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-countdown-ten-info p {
  max-width: 590px;
  margin: 0 0 20px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-countdown-ten-meter {
  max-width: 480px;
  padding: 16px;
  border-radius: 22px;
  background: #fffbeb;
  border: 1px solid rgba(245, 158, 11, 0.22);
}

.vb-countdown-ten-meter-head {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}

.vb-countdown-ten-meter-head strong {
  color: #78350f !important;
  -webkit-text-fill-color: #78350f !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-countdown-ten-meter-head span {
  color: #b45309 !important;
  -webkit-text-fill-color: #b45309 !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-ten-meter-bar {
  overflow: hidden;
  height: 12px;
  border-radius: 999px;
  background: #fde68a;
}

.vb-countdown-ten-meter-bar i {
  display: block;
  width: 32%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #ef4444, #f59e0b) !important;
}

.vb-countdown-ten-sidebar {
  min-width: 0;
  display: grid;
  align-content: center;
  gap: 16px;
  padding: clamp(20px, 3vw, 26px);
  border-radius: 8px 34px 8px 34px;
  background:
    radial-gradient(circle at 24% 16%, rgba(255,255,255,0.14), transparent 34%),
    linear-gradient(135deg, #0f172a, #134e4a 58%, #042f2e) !important;
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.18);
}

.vb-countdown-ten-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(20, 184, 166, 0.14);
  border: 1px solid rgba(94, 234, 212, 0.20);
  color: #99f6e4 !important;
  -webkit-text-fill-color: #99f6e4 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-ten-title {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 26px;
  line-height: 1.08;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-countdown-ten-timer {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
}

.vb-countdown-ten-timer div {
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 14px 16px;
  border-radius: 18px 6px 18px 6px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-countdown-ten-timer strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 6vw, 44px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-ten-timer span {
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-ten-sidebar p {
  margin: 0 !important;
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-countdown-ten-sidebar a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #f59e0b, #14b8a6);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(20, 184, 166, 0.24);
}

@media (max-width: 980px) {
  .vb-countdown-ten-stock {
    grid-template-columns: 1fr;
  }

  .vb-countdown-ten-timer {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .vb-countdown-ten-timer div {
    display: grid;
    place-items: center;
    text-align: center;
  }
}

@media (max-width: 760px) {
  .vb-countdown-ten-product {
    grid-template-columns: 1fr;
  }

  .vb-countdown-ten-info h3 {
    font-size: 36px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-ten-meter-head {
    flex-direction: column;
  }

  .vb-countdown-ten-sidebar a {
    width: 100%;
  }
}

@media (max-width: 420px) {
  .vb-countdown-ten-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-ten]");
  if (!timer) return;

  const duration = Number(timer.getAttribute("data-duration")) || 3600;
  let remaining = duration;

  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function updateCountdown() {
    if (remaining <= 0) {
      remaining = duration;
    }

    const hours = Math.floor(remaining / (1000 * 60 * 60));
    const minutes = Math.floor((remaining / 60) % 60);
    const seconds = remaining % 60;

    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    statusEl.textContent = "Inventory hold is active.";

    remaining -= 1;
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-ten]");
  if (!timer) return;

  const duration = Number(timer.getAttribute("data-duration")) || 3600;
  let remaining = duration;

  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function updateCountdown() {
    if (remaining &lt;= 0) {
      remaining = duration;
    }

    const hours = Math.floor(remaining / (1000 * 60 * 60));
    const minutes = Math.floor((remaining / 60) % 60);
    const seconds = remaining % 60;

    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    statusEl.textContent = "Inventory hold is active.";

    remaining -= 1;
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-ten-demo"&gt;
  &lt;section class="vb-countdown-ten-stock" data-vb-countdown-ten data-duration="3600"&gt;
    &lt;div class="vb-countdown-ten-product"&gt;
      &lt;div class="vb-countdown-ten-image"&gt;
        &lt;span&gt;Example 10&lt;/span&gt;
        &lt;div class="vb-countdown-ten-box"&gt;
          &lt;i&gt;&lt;/i&gt;
          &lt;i&gt;&lt;/i&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-ten-info"&gt;
        &lt;div class="vb-countdown-ten-label"&gt;Limited Stock&lt;/div&gt;
        &lt;h3&gt;Limited Stock Countdown Timer&lt;/h3&gt;
        &lt;p&gt;Use this countdown timer for product pages, limited drops, inventory campaigns, product cards, ticket sales, and preorder availability sections.&lt;/p&gt;

        &lt;div class="vb-countdown-ten-meter"&gt;
          &lt;div class="vb-countdown-ten-meter-head"&gt;
            &lt;strong&gt;Only 12 items left&lt;/strong&gt;
            &lt;span&gt;Low stock&lt;/span&gt;
          &lt;/div&gt;
          &lt;div class="vb-countdown-ten-meter-bar"&gt;
            &lt;i&gt;&lt;/i&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;aside class="vb-countdown-ten-sidebar"&gt;
      &lt;span class="vb-countdown-ten-kicker"&gt;Stock window&lt;/span&gt;
      &lt;strong class="vb-countdown-ten-title"&gt;Reserve before timer ends&lt;/strong&gt;

      &lt;div class="vb-countdown-ten-timer" aria-label="Limited stock countdown timer"&gt;
        &lt;div&gt;
          &lt;strong data-hours&gt;00&lt;/strong&gt;
          &lt;span&gt;Hours&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
          &lt;span&gt;Min&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
          &lt;span&gt;Sec&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;p data-status&gt;Inventory hold is active.&lt;/p&gt;
      &lt;a href="#reserve-stock"&gt;Reserve Stock&lt;/a&gt;
    &lt;/aside&gt;
  &lt;/section&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-ten-demo,
.vb-countdown-ten-demo * {
  box-sizing: border-box;
}

.vb-countdown-ten-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 8px 48px 8px 48px;
  background:
    radial-gradient(circle at 12% 18%, rgba(245, 158, 11, 0.18), transparent 34%),
    radial-gradient(circle at 86% 24%, rgba(20, 184, 166, 0.18), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #f0fdfa 52%, #ffffff 100%) !important;
  border: 1px solid rgba(245, 158, 11, 0.24);
  box-shadow: 0 28px 80px rgba(120, 53, 15, 0.10);
}

.vb-countdown-ten-stock {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(250px, 330px);
  gap: clamp(18px, 3vw, 26px);
  align-items: stretch;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-countdown-ten-product {
  display: grid;
  grid-template-columns: minmax(220px, 310px) minmax(0, 1fr);
  gap: 18px;
  min-width: 0;
  padding: clamp(14px, 2vw, 18px);
  border-radius: 30px 8px 30px 8px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.09);
}

.vb-countdown-ten-image {
  position: relative;
  min-width: 0;
  min-height: clamp(260px, 32vw, 340px);
  overflow: hidden;
  border-radius: 24px 8px 24px 8px;
  background:
    radial-gradient(circle at 30% 18%, rgba(255,255,255,0.30), transparent 34%),
    linear-gradient(135deg, #92400e, #f59e0b 52%, #14b8a6) !important;
}

.vb-countdown-ten-image > span {
  position: absolute;
  left: 16px;
  top: 16px;
  z-index: 3;
  display: inline-flex;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  border: 1px solid rgba(255,255,255,0.22);
  color: #fffbeb !important;
  -webkit-text-fill-color: #fffbeb !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-ten-box {
  position: absolute;
  left: 50%;
  top: 55%;
  width: clamp(150px, 20vw, 200px);
  height: clamp(150px, 20vw, 200px);
  transform: translate(-50%, -50%) rotate(8deg);
  border-radius: 28px 10px 28px 10px;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.70), rgba(255,255,255,0.30)) !important;
  border: 1px solid rgba(255,255,255,0.34);
  box-shadow: 0 28px 68px rgba(120, 53, 15, 0.24);
}

.vb-countdown-ten-box i {
  position: absolute;
  display: block;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.18);
}

.vb-countdown-ten-box i:nth-child(1) {
  left: 24px;
  top: 42px;
  width: 60%;
  height: 14px;
}

.vb-countdown-ten-box i:nth-child(2) {
  left: 24px;
  top: 78px;
  width: 46%;
  height: 14px;
}

.vb-countdown-ten-box i:nth-child(3) {
  left: 24px;
  bottom: 32px;
  width: 32%;
  height: 28px;
  border-radius: 10px;
  background: rgba(20, 184, 166, 0.30);
}

.vb-countdown-ten-info {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
  padding: 12px 8px;
}

.vb-countdown-ten-label {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px 999px 999px 4px;
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-ten-info h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 0.93 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-countdown-ten-info p {
  max-width: 590px;
  margin: 0 0 20px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.72;
  font-weight: 650;
}

.vb-countdown-ten-meter {
  max-width: 480px;
  padding: 16px;
  border-radius: 22px;
  background: #fffbeb;
  border: 1px solid rgba(245, 158, 11, 0.22);
}

.vb-countdown-ten-meter-head {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 10px;
}

.vb-countdown-ten-meter-head strong {
  color: #78350f !important;
  -webkit-text-fill-color: #78350f !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-countdown-ten-meter-head span {
  color: #b45309 !important;
  -webkit-text-fill-color: #b45309 !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-ten-meter-bar {
  overflow: hidden;
  height: 12px;
  border-radius: 999px;
  background: #fde68a;
}

.vb-countdown-ten-meter-bar i {
  display: block;
  width: 32%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #ef4444, #f59e0b) !important;
}

.vb-countdown-ten-sidebar {
  min-width: 0;
  display: grid;
  align-content: center;
  gap: 16px;
  padding: clamp(20px, 3vw, 26px);
  border-radius: 8px 34px 8px 34px;
  background:
    radial-gradient(circle at 24% 16%, rgba(255,255,255,0.14), transparent 34%),
    linear-gradient(135deg, #0f172a, #134e4a 58%, #042f2e) !important;
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.18);
}

.vb-countdown-ten-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(20, 184, 166, 0.14);
  border: 1px solid rgba(94, 234, 212, 0.20);
  color: #99f6e4 !important;
  -webkit-text-fill-color: #99f6e4 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-ten-title {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 26px;
  line-height: 1.08;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-countdown-ten-timer {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
}

.vb-countdown-ten-timer div {
  min-width: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 14px 16px;
  border-radius: 18px 6px 18px 6px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-countdown-ten-timer strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 6vw, 44px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-ten-timer span {
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-ten-sidebar p {
  margin: 0 !important;
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-countdown-ten-sidebar a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #f59e0b, #14b8a6);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(20, 184, 166, 0.24);
}

@media (max-width: 980px) {
  .vb-countdown-ten-stock {
    grid-template-columns: 1fr;
  }

  .vb-countdown-ten-timer {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .vb-countdown-ten-timer div {
    display: grid;
    place-items: center;
    text-align: center;
  }
}

@media (max-width: 760px) {
  .vb-countdown-ten-product {
    grid-template-columns: 1fr;
  }

  .vb-countdown-ten-info h3 {
    font-size: 36px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-ten-meter-head {
    flex-direction: column;
  }

  .vb-countdown-ten-sidebar a {
    width: 100%;
  }
}

@media (max-width: 420px) {
  .vb-countdown-ten-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This limited stock countdown timer is useful for ecommerce product pages, product cards, limited inventory campaigns, preorder drops, ticket availability sections, and flash stock alerts.</p>



<h2 class="wp-block-heading">11. Sticky Top Bar Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A sticky top bar countdown timer</strong> is useful for ecommerce stores, SaaS websites, course launches, limited offers, announcement bars, free shipping campaigns, and site-wide promotions. It keeps the deadline visible without taking over the full page.</p>



<p class="wp-block-paragraph">This example uses a slim sticky-style announcement bar with a compact countdown, promo message, pill CTA button, and responsive stacking for smaller screens. The JavaScript uses a repeating 6-hour campaign window, so the demo keeps running and never stays stopped.</p>



<ul class="wp-block-list">
<li>Sticky top bar countdown timer</li>
<li>Compact announcement bar layout</li>
<li>Hours, minutes, and seconds</li>
<li>Repeating campaign window</li>
<li>Responsive mobile-friendly top bar</li>
</ul>



<div class="vb-countdown-eleven-demo">
  <div class="vb-countdown-eleven-bar" data-vb-countdown-eleven data-duration="21600">
    <div class="vb-countdown-eleven-message">
      <span class="vb-countdown-eleven-kicker">Example 11</span>
      <strong>Limited offer ends soon</strong>
      <p>Use this sticky top bar countdown for site-wide sale messages, free shipping offers, and promotional campaigns.</p>
    </div>

    <div class="vb-countdown-eleven-timer" aria-label="Sticky top bar countdown timer">
      <div>
        <strong data-hours>00</strong>
        <span>Hours</span>
      </div>

      <div>
        <strong data-minutes>00</strong>
        <span>Min</span>
      </div>

      <div>
        <strong data-seconds>00</strong>
        <span>Sec</span>
      </div>
    </div>

    <a href="#top-bar-offer" class="vb-countdown-eleven-button">Claim Offer</a>
  </div>
</div>

<style>
.vb-countdown-eleven-demo,
.vb-countdown-eleven-demo * {
  box-sizing: border-box;
}

.vb-countdown-eleven-demo {
  margin: 28px 0;
  padding: clamp(16px, 3vw, 30px);
  border-radius: 32px 32px 8px 8px;
  background:
    linear-gradient(135deg, #f8fafc 0%, #fff7ed 50%, #ffffff 100%) !important;
  border: 1px solid rgba(249, 115, 22, 0.20);
  box-shadow: 0 24px 70px rgba(124, 45, 18, 0.09);
}

.vb-countdown-eleven-bar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: clamp(14px, 2.5vw, 22px);
  align-items: center;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(14px, 2vw, 18px);
  border-radius: 999px;
  background:
    radial-gradient(circle at 12% 50%, rgba(251, 146, 60, 0.28), transparent 34%),
    linear-gradient(135deg, #111827 0%, #7c2d12 48%, #ea580c 100%) !important;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 24px 64px rgba(15, 23, 42, 0.22);
}

.vb-countdown-eleven-message {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  min-width: 0;
}

.vb-countdown-eleven-kicker {
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  white-space: nowrap;
}

.vb-countdown-eleven-message strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(15px, 2vw, 18px);
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.035em;
  white-space: nowrap;
}

.vb-countdown-eleven-message p {
  min-width: 0;
  margin: 0 !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-countdown-eleven-timer {
  display: grid;
  grid-template-columns: repeat(3, minmax(54px, 1fr));
  gap: 8px;
  min-width: 0;
}

.vb-countdown-eleven-timer div {
  min-width: 0;
  padding: 9px 8px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
  text-align: center;
}

.vb-countdown-eleven-timer strong {
  display: block;
  margin-bottom: 2px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(18px, 2.6vw, 26px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
}

.vb-countdown-eleven-timer span {
  display: block;
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 9px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-eleven-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 12px 17px;
  border-radius: 999px;
  background: #ffffff;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  text-decoration: none !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
  box-shadow: 0 14px 30px rgba(15, 23, 42, 0.18);
}

@media (max-width: 980px) {
  .vb-countdown-eleven-bar {
    grid-template-columns: 1fr;
    border-radius: 28px;
  }

  .vb-countdown-eleven-message {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .vb-countdown-eleven-message p {
    grid-column: 1 / -1;
  }

  .vb-countdown-eleven-button {
    width: 100%;
  }
}

@media (max-width: 520px) {
  .vb-countdown-eleven-message {
    grid-template-columns: 1fr;
  }

  .vb-countdown-eleven-message strong {
    white-space: normal;
  }

  .vb-countdown-eleven-timer {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 340px) {
  .vb-countdown-eleven-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-eleven]");
  if (!timer) return;

  const duration = Number(timer.getAttribute("data-duration")) || 21600;
  let remaining = duration;

  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function updateCountdown() {
    if (remaining <= 0) {
      remaining = duration;
    }

    const hours = Math.floor(remaining / 3600);
    const minutes = Math.floor((remaining / 60) % 60);
    const seconds = remaining % 60;

    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);

    remaining -= 1;
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-eleven]");
  if (!timer) return;

  const duration = Number(timer.getAttribute("data-duration")) || 21600;
  let remaining = duration;

  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function updateCountdown() {
    if (remaining &lt;= 0) {
      remaining = duration;
    }

    const hours = Math.floor(remaining / 3600);
    const minutes = Math.floor((remaining / 60) % 60);
    const seconds = remaining % 60;

    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);

    remaining -= 1;
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-eleven-demo"&gt;
  &lt;div class="vb-countdown-eleven-bar" data-vb-countdown-eleven data-duration="21600"&gt;
    &lt;div class="vb-countdown-eleven-message"&gt;
      &lt;span class="vb-countdown-eleven-kicker"&gt;Example 11&lt;/span&gt;
      &lt;strong&gt;Limited offer ends soon&lt;/strong&gt;
      &lt;p&gt;Use this sticky top bar countdown for site-wide sale messages, free shipping offers, and promotional campaigns.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-eleven-timer" aria-label="Sticky top bar countdown timer"&gt;
      &lt;div&gt;
        &lt;strong data-hours&gt;00&lt;/strong&gt;
        &lt;span&gt;Hours&lt;/span&gt;
      &lt;/div&gt;

      &lt;div&gt;
        &lt;strong data-minutes&gt;00&lt;/strong&gt;
        &lt;span&gt;Min&lt;/span&gt;
      &lt;/div&gt;

      &lt;div&gt;
        &lt;strong data-seconds&gt;00&lt;/strong&gt;
        &lt;span&gt;Sec&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;a href="#top-bar-offer" class="vb-countdown-eleven-button"&gt;Claim Offer&lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-eleven-demo,
.vb-countdown-eleven-demo * {
  box-sizing: border-box;
}

.vb-countdown-eleven-demo {
  margin: 28px 0;
  padding: clamp(16px, 3vw, 30px);
  border-radius: 32px 32px 8px 8px;
  background:
    linear-gradient(135deg, #f8fafc 0%, #fff7ed 50%, #ffffff 100%) !important;
  border: 1px solid rgba(249, 115, 22, 0.20);
  box-shadow: 0 24px 70px rgba(124, 45, 18, 0.09);
}

.vb-countdown-eleven-bar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: clamp(14px, 2.5vw, 22px);
  align-items: center;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(14px, 2vw, 18px);
  border-radius: 999px;
  background:
    radial-gradient(circle at 12% 50%, rgba(251, 146, 60, 0.28), transparent 34%),
    linear-gradient(135deg, #111827 0%, #7c2d12 48%, #ea580c 100%) !important;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 24px 64px rgba(15, 23, 42, 0.22);
}

.vb-countdown-eleven-message {
  display: grid;
  grid-template-columns: auto auto minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  min-width: 0;
}

.vb-countdown-eleven-kicker {
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  white-space: nowrap;
}

.vb-countdown-eleven-message strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(15px, 2vw, 18px);
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.035em;
  white-space: nowrap;
}

.vb-countdown-eleven-message p {
  min-width: 0;
  margin: 0 !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-countdown-eleven-timer {
  display: grid;
  grid-template-columns: repeat(3, minmax(54px, 1fr));
  gap: 8px;
  min-width: 0;
}

.vb-countdown-eleven-timer div {
  min-width: 0;
  padding: 9px 8px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
  text-align: center;
}

.vb-countdown-eleven-timer strong {
  display: block;
  margin-bottom: 2px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(18px, 2.6vw, 26px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
}

.vb-countdown-eleven-timer span {
  display: block;
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 9px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-eleven-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 12px 17px;
  border-radius: 999px;
  background: #ffffff;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  text-decoration: none !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
  box-shadow: 0 14px 30px rgba(15, 23, 42, 0.18);
}

@media (max-width: 980px) {
  .vb-countdown-eleven-bar {
    grid-template-columns: 1fr;
    border-radius: 28px;
  }

  .vb-countdown-eleven-message {
    grid-template-columns: auto minmax(0, 1fr);
  }

  .vb-countdown-eleven-message p {
    grid-column: 1 / -1;
  }

  .vb-countdown-eleven-button {
    width: 100%;
  }
}

@media (max-width: 520px) {
  .vb-countdown-eleven-message {
    grid-template-columns: 1fr;
  }

  .vb-countdown-eleven-message strong {
    white-space: normal;
  }

  .vb-countdown-eleven-timer {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 340px) {
  .vb-countdown-eleven-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This sticky top bar countdown timer is useful for ecommerce announcement bars, website-wide offers, free shipping campaigns, SaaS promotions, course launches, and limited-time header messages.</p>



<h2 class="wp-block-heading">12. Hero Section Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A hero section countdown timer</strong> is useful for landing pages, product campaigns, startup launches, SaaS offers, event pages, course launches, and homepage promotions where the timer should be part of the main first-screen message.</p>



<p class="wp-block-paragraph">This example uses a large hero layout with a split visual composition, layered gradient shapes, big headline, CTA buttons, trust badges, and a bold countdown panel. The JavaScript uses a repeating 10-day campaign cycle, so the timer keeps working without ending permanently.</p>



<ul class="wp-block-list">
<li>Hero section countdown timer</li>
<li>Large landing page layout</li>
<li>Days, hours, minutes, and seconds</li>
<li>CTA buttons and trust badges</li>
<li>Responsive desktop and mobile hero section</li>
</ul>



<div class="vb-countdown-twelve-demo">
  <section class="vb-countdown-twelve-hero" data-vb-countdown-twelve data-cycle-days="10">
    <div class="vb-countdown-twelve-copy">
      <span class="vb-countdown-twelve-kicker">Example 12</span>
      <h3>Hero Section Countdown Timer</h3>
      <p>Use this countdown timer inside a hero section for launches, landing pages, product campaigns, event pages, seasonal offers, and startup promotions.</p>

      <div class="vb-countdown-twelve-actions">
        <a href="#hero-offer">Start Now</a>
        <button type="button">View Details</button>
      </div>

      <div class="vb-countdown-twelve-badges">
        <span>No credit card required</span>
        <span>Limited campaign</span>
        <span data-next-date>Next cycle loading</span>
      </div>
    </div>

    <div class="vb-countdown-twelve-card">
      <div class="vb-countdown-twelve-card-top">
        <span>Campaign ends in</span>
        <strong data-status>Countdown active</strong>
      </div>

      <div class="vb-countdown-twelve-timer" aria-label="Hero section countdown timer">
        <div>
          <strong data-days>00</strong>
          <span>Days</span>
        </div>

        <div>
          <strong data-hours>00</strong>
          <span>Hours</span>
        </div>

        <div>
          <strong data-minutes>00</strong>
          <span>Min</span>
        </div>

        <div>
          <strong data-seconds>00</strong>
          <span>Sec</span>
        </div>
      </div>
    </div>
  </section>
</div>

<style>
.vb-countdown-twelve-demo,
.vb-countdown-twelve-demo * {
  box-sizing: border-box;
}

.vb-countdown-twelve-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 54px 18px 54px 18px;
  background:
    radial-gradient(circle at 16% 18%, rgba(16, 185, 129, 0.20), transparent 34%),
    radial-gradient(circle at 88% 22%, rgba(59, 130, 246, 0.20), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #eff6ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(16, 185, 129, 0.20);
  box-shadow: 0 28px 80px rgba(5, 150, 105, 0.10);
}

.vb-countdown-twelve-hero {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(280px, 0.72fr);
  gap: clamp(24px, 4vw, 42px);
  align-items: center;
  max-width: 1160px;
  min-height: 560px;
  margin: 0 auto;
  padding: clamp(24px, 5vw, 54px);
  overflow: hidden;
  border-radius: 44px 12px 44px 12px;
  background:
    radial-gradient(circle at 24% 22%, rgba(255,255,255,0.20), transparent 34%),
    linear-gradient(135deg, #052e2b 0%, #064e3b 48%, #1d4ed8 100%) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.24);
}

.vb-countdown-twelve-hero::before {
  content: "";
  position: absolute;
  right: -140px;
  top: -160px;
  width: 390px;
  height: 390px;
  border-radius: 44% 56% 32% 68%;
  background: rgba(125, 211, 252, 0.18);
}

.vb-countdown-twelve-hero::after {
  content: "";
  position: absolute;
  left: 44%;
  bottom: -160px;
  width: 320px;
  height: 320px;
  border-radius: 68% 32% 58% 42%;
  background: rgba(52, 211, 153, 0.16);
}

.vb-countdown-twelve-copy,
.vb-countdown-twelve-card {
  position: relative;
  z-index: 2;
  min-width: 0;
}

.vb-countdown-twelve-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px 999px 999px 4px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twelve-copy h3 {
  max-width: 820px;
  margin: 0 0 18px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 6.4vw, 88px) !important;
  line-height: 0.86 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
  overflow-wrap: anywhere;
}

.vb-countdown-twelve-copy p {
  max-width: 690px;
  margin: 0 0 24px !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: clamp(15px, 1.8vw, 17px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-twelve-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 20px;
}

.vb-countdown-twelve-actions a,
.vb-countdown-twelve-actions button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 14px 20px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-countdown-twelve-actions a {
  background: #ffffff;
  color: #065f46 !important;
  -webkit-text-fill-color: #065f46 !important;
  text-decoration: none !important;
  box-shadow: 0 16px 34px rgba(15, 23, 42, 0.18);
}

.vb-countdown-twelve-actions button {
  border: 1px solid rgba(255,255,255,0.20);
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-countdown-twelve-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.vb-countdown-twelve-badges span {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.12);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-twelve-card {
  padding: clamp(20px, 3vw, 28px);
  border-radius: 18px 42px 18px 42px;
  background:
    radial-gradient(circle at 22% 16%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, rgba(255,255,255,0.16), rgba(255,255,255,0.055)) !important;
  border: 1px solid rgba(255,255,255,0.16);
  backdrop-filter: blur(14px);
  box-shadow: 0 28px 80px rgba(2, 6, 23, 0.22);
}

.vb-countdown-twelve-card-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 18px;
}

.vb-countdown-twelve-card-top span {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-twelve-card-top strong {
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 13px;
  font-weight: 900;
  text-align: right;
}

.vb-countdown-twelve-timer {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
}

.vb-countdown-twelve-timer div {
  min-width: 0;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 14px;
  align-items: center;
  padding: 14px 16px;
  border-radius: 16px 28px 16px 28px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-countdown-twelve-timer strong {
  min-width: 72px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 6vw, 52px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-twelve-timer span {
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

@media (max-width: 920px) {
  .vb-countdown-twelve-hero {
    grid-template-columns: 1fr;
    min-height: auto;
  }

  .vb-countdown-twelve-timer {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .vb-countdown-twelve-timer div {
    grid-template-columns: 1fr;
    place-items: center;
    text-align: center;
  }

  .vb-countdown-twelve-timer strong {
    min-width: 0;
    font-size: clamp(28px, 6vw, 44px);
  }
}

@media (max-width: 640px) {
  .vb-countdown-twelve-demo {
    border-radius: 34px 12px 34px 12px;
  }

  .vb-countdown-twelve-hero {
    border-radius: 28px 10px 28px 10px;
  }

  .vb-countdown-twelve-copy h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-twelve-actions a,
  .vb-countdown-twelve-actions button {
    width: 100%;
  }

  .vb-countdown-twelve-card-top {
    flex-direction: column;
    align-items: flex-start;
  }

  .vb-countdown-twelve-card-top strong {
    text-align: left;
  }

  .vb-countdown-twelve-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-twelve-timer strong {
    font-size: clamp(30px, 13vw, 46px);
  }
}

@media (max-width: 360px) {
  .vb-countdown-twelve-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-twelve]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 10;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-03T12:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextDateEl = timer.querySelector("[data-next-date]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextCampaignEnd(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextEnd = getNextCampaignEnd(now);
    let remaining = nextEnd - now;

    if (remaining <= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(nextEnd).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextDateEl.textContent = "Ends " + dateText;
    statusEl.textContent = "Countdown active";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-twelve]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 10;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-03T12:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextDateEl = timer.querySelector("[data-next-date]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextCampaignEnd(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextEnd = getNextCampaignEnd(now);
    let remaining = nextEnd - now;

    if (remaining &lt;= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(nextEnd).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextDateEl.textContent = "Ends " + dateText;
    statusEl.textContent = "Countdown active";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-twelve-demo"&gt;
  &lt;section class="vb-countdown-twelve-hero" data-vb-countdown-twelve data-cycle-days="10"&gt;
    &lt;div class="vb-countdown-twelve-copy"&gt;
      &lt;span class="vb-countdown-twelve-kicker"&gt;Example 12&lt;/span&gt;
      &lt;h3&gt;Hero Section Countdown Timer&lt;/h3&gt;
      &lt;p&gt;Use this countdown timer inside a hero section for launches, landing pages, product campaigns, event pages, seasonal offers, and startup promotions.&lt;/p&gt;

      &lt;div class="vb-countdown-twelve-actions"&gt;
        &lt;a href="#hero-offer"&gt;Start Now&lt;/a&gt;
        &lt;button type="button"&gt;View Details&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-twelve-badges"&gt;
        &lt;span&gt;No credit card required&lt;/span&gt;
        &lt;span&gt;Limited campaign&lt;/span&gt;
        &lt;span data-next-date&gt;Next cycle loading&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-twelve-card"&gt;
      &lt;div class="vb-countdown-twelve-card-top"&gt;
        &lt;span&gt;Campaign ends in&lt;/span&gt;
        &lt;strong data-status&gt;Countdown active&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-twelve-timer" aria-label="Hero section countdown timer"&gt;
        &lt;div&gt;
          &lt;strong data-days&gt;00&lt;/strong&gt;
          &lt;span&gt;Days&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-hours&gt;00&lt;/strong&gt;
          &lt;span&gt;Hours&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
          &lt;span&gt;Min&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
          &lt;span&gt;Sec&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/section&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-twelve-demo,
.vb-countdown-twelve-demo * {
  box-sizing: border-box;
}

.vb-countdown-twelve-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 54px 18px 54px 18px;
  background:
    radial-gradient(circle at 16% 18%, rgba(16, 185, 129, 0.20), transparent 34%),
    radial-gradient(circle at 88% 22%, rgba(59, 130, 246, 0.20), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #eff6ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(16, 185, 129, 0.20);
  box-shadow: 0 28px 80px rgba(5, 150, 105, 0.10);
}

.vb-countdown-twelve-hero {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.08fr) minmax(280px, 0.72fr);
  gap: clamp(24px, 4vw, 42px);
  align-items: center;
  max-width: 1160px;
  min-height: 560px;
  margin: 0 auto;
  padding: clamp(24px, 5vw, 54px);
  overflow: hidden;
  border-radius: 44px 12px 44px 12px;
  background:
    radial-gradient(circle at 24% 22%, rgba(255,255,255,0.20), transparent 34%),
    linear-gradient(135deg, #052e2b 0%, #064e3b 48%, #1d4ed8 100%) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.24);
}

.vb-countdown-twelve-hero::before {
  content: "";
  position: absolute;
  right: -140px;
  top: -160px;
  width: 390px;
  height: 390px;
  border-radius: 44% 56% 32% 68%;
  background: rgba(125, 211, 252, 0.18);
}

.vb-countdown-twelve-hero::after {
  content: "";
  position: absolute;
  left: 44%;
  bottom: -160px;
  width: 320px;
  height: 320px;
  border-radius: 68% 32% 58% 42%;
  background: rgba(52, 211, 153, 0.16);
}

.vb-countdown-twelve-copy,
.vb-countdown-twelve-card {
  position: relative;
  z-index: 2;
  min-width: 0;
}

.vb-countdown-twelve-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px 999px 999px 4px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twelve-copy h3 {
  max-width: 820px;
  margin: 0 0 18px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 6.4vw, 88px) !important;
  line-height: 0.86 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
  overflow-wrap: anywhere;
}

.vb-countdown-twelve-copy p {
  max-width: 690px;
  margin: 0 0 24px !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: clamp(15px, 1.8vw, 17px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-twelve-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 20px;
}

.vb-countdown-twelve-actions a,
.vb-countdown-twelve-actions button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 14px 20px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-countdown-twelve-actions a {
  background: #ffffff;
  color: #065f46 !important;
  -webkit-text-fill-color: #065f46 !important;
  text-decoration: none !important;
  box-shadow: 0 16px 34px rgba(15, 23, 42, 0.18);
}

.vb-countdown-twelve-actions button {
  border: 1px solid rgba(255,255,255,0.20);
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-countdown-twelve-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.vb-countdown-twelve-badges span {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.12);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-twelve-card {
  padding: clamp(20px, 3vw, 28px);
  border-radius: 18px 42px 18px 42px;
  background:
    radial-gradient(circle at 22% 16%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, rgba(255,255,255,0.16), rgba(255,255,255,0.055)) !important;
  border: 1px solid rgba(255,255,255,0.16);
  backdrop-filter: blur(14px);
  box-shadow: 0 28px 80px rgba(2, 6, 23, 0.22);
}

.vb-countdown-twelve-card-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 18px;
}

.vb-countdown-twelve-card-top span {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-twelve-card-top strong {
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 13px;
  font-weight: 900;
  text-align: right;
}

.vb-countdown-twelve-timer {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
}

.vb-countdown-twelve-timer div {
  min-width: 0;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 14px;
  align-items: center;
  padding: 14px 16px;
  border-radius: 16px 28px 16px 28px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-countdown-twelve-timer strong {
  min-width: 72px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 6vw, 52px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-twelve-timer span {
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

@media (max-width: 920px) {
  .vb-countdown-twelve-hero {
    grid-template-columns: 1fr;
    min-height: auto;
  }

  .vb-countdown-twelve-timer {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .vb-countdown-twelve-timer div {
    grid-template-columns: 1fr;
    place-items: center;
    text-align: center;
  }

  .vb-countdown-twelve-timer strong {
    min-width: 0;
    font-size: clamp(28px, 6vw, 44px);
  }
}

@media (max-width: 640px) {
  .vb-countdown-twelve-demo {
    border-radius: 34px 12px 34px 12px;
  }

  .vb-countdown-twelve-hero {
    border-radius: 28px 10px 28px 10px;
  }

  .vb-countdown-twelve-copy h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-twelve-actions a,
  .vb-countdown-twelve-actions button {
    width: 100%;
  }

  .vb-countdown-twelve-card-top {
    flex-direction: column;
    align-items: flex-start;
  }

  .vb-countdown-twelve-card-top strong {
    text-align: left;
  }

  .vb-countdown-twelve-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-twelve-timer strong {
    font-size: clamp(30px, 13vw, 46px);
  }
}

@media (max-width: 360px) {
  .vb-countdown-twelve-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This hero section countdown timer is useful for landing pages, SaaS launches, product campaigns, event pages, course launch sections, homepage promotions, and startup offer pages.</p>



<h2 class="wp-block-heading">13. Minimal Inline Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A minimal inline countdown timer</strong> is useful for pricing pages, product pages, checkout messages, small promo banners, course enrollment notices, blog CTA sections, and compact website areas where a full countdown block would be too large.</p>



<p class="wp-block-paragraph">This example uses a clean inline layout with a short message, compact timer chips, subtle border styling, and a simple call-to-action link. The JavaScript uses a repeating 3-hour offer window, so the demo keeps working and never stays stopped at zero.</p>



<ul class="wp-block-list">
<li>Minimal inline countdown timer</li>
<li>Small compact timer chips</li>
<li>Hours, minutes, and seconds</li>
<li>Repeating offer window</li>
<li>Responsive inline promo layout</li>
</ul>



<div class="vb-countdown-thirteen-demo">
  <div class="vb-countdown-thirteen-inline" data-vb-countdown-thirteen data-duration="10800">
    <div class="vb-countdown-thirteen-copy">
      <span>Example 13</span>
      <strong>Minimal Inline Countdown Timer</strong>
      <p>Compact countdown for small promo messages, pricing sections, checkout notices, and lightweight website CTAs.</p>
    </div>

    <div class="vb-countdown-thirteen-timer" aria-label="Minimal inline countdown timer">
      <div>
        <strong data-hours>00</strong>
        <span>Hrs</span>
      </div>

      <div>
        <strong data-minutes>00</strong>
        <span>Min</span>
      </div>

      <div>
        <strong data-seconds>00</strong>
        <span>Sec</span>
      </div>
    </div>

    <a href="#inline-offer">Get Offer</a>
  </div>
</div>

<style>
.vb-countdown-thirteen-demo,
.vb-countdown-thirteen-demo * {
  box-sizing: border-box;
}

.vb-countdown-thirteen-demo {
  margin: 28px 0;
  padding: clamp(16px, 3vw, 28px);
  border-radius: 22px;
  background:
    linear-gradient(135deg, #ffffff 0%, #f8fafc 52%, #f1f5f9 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 20px 60px rgba(15, 23, 42, 0.08);
}

.vb-countdown-thirteen-inline {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: clamp(14px, 2vw, 22px);
  align-items: center;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(16px, 2.2vw, 22px);
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(203, 213, 225, 0.9);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.9);
}

.vb-countdown-thirteen-copy {
  min-width: 0;
  display: grid;
  gap: 5px;
}

.vb-countdown-thirteen-copy span {
  display: inline-flex;
  width: fit-content;
  padding: 5px 9px;
  border-radius: 999px;
  background: #eef2ff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-thirteen-copy strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(18px, 3vw, 28px);
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.045em;
  overflow-wrap: anywhere;
}

.vb-countdown-thirteen-copy p {
  max-width: 680px;
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-countdown-thirteen-timer {
  display: grid;
  grid-template-columns: repeat(3, minmax(56px, 1fr));
  gap: 8px;
  min-width: 0;
}

.vb-countdown-thirteen-timer div {
  min-width: 0;
  padding: 10px 8px;
  border-radius: 14px;
  background: #0f172a;
  text-align: center;
}

.vb-countdown-thirteen-timer strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(20px, 3vw, 30px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
}

.vb-countdown-thirteen-timer span {
  display: block;
  margin-top: 4px;
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 9px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-thirteen-inline a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 12px 16px;
  border-radius: 14px;
  background: #4f46e5;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
  box-shadow: 0 14px 28px rgba(79, 70, 229, 0.20);
}

@media (max-width: 860px) {
  .vb-countdown-thirteen-inline {
    grid-template-columns: 1fr;
  }

  .vb-countdown-thirteen-inline a {
    width: 100%;
  }
}

@media (max-width: 420px) {
  .vb-countdown-thirteen-timer {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .vb-countdown-thirteen-copy strong {
    font-size: 22px;
  }
}

@media (max-width: 320px) {
  .vb-countdown-thirteen-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-thirteen]");
  if (!timer) return;

  const duration = Number(timer.getAttribute("data-duration")) || 10800;
  let remaining = duration;

  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function updateCountdown() {
    if (remaining <= 0) {
      remaining = duration;
    }

    const hours = Math.floor(remaining / 3600);
    const minutes = Math.floor((remaining / 60) % 60);
    const seconds = remaining % 60;

    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);

    remaining -= 1;
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-thirteen]");
  if (!timer) return;

  const duration = Number(timer.getAttribute("data-duration")) || 10800;
  let remaining = duration;

  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function updateCountdown() {
    if (remaining &lt;= 0) {
      remaining = duration;
    }

    const hours = Math.floor(remaining / 3600);
    const minutes = Math.floor((remaining / 60) % 60);
    const seconds = remaining % 60;

    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);

    remaining -= 1;
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-thirteen-demo"&gt;
  &lt;div class="vb-countdown-thirteen-inline" data-vb-countdown-thirteen data-duration="10800"&gt;
    &lt;div class="vb-countdown-thirteen-copy"&gt;
      &lt;span&gt;Example 13&lt;/span&gt;
      &lt;strong&gt;Minimal Inline Countdown Timer&lt;/strong&gt;
      &lt;p&gt;Compact countdown for small promo messages, pricing sections, checkout notices, and lightweight website CTAs.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-thirteen-timer" aria-label="Minimal inline countdown timer"&gt;
      &lt;div&gt;
        &lt;strong data-hours&gt;00&lt;/strong&gt;
        &lt;span&gt;Hrs&lt;/span&gt;
      &lt;/div&gt;

      &lt;div&gt;
        &lt;strong data-minutes&gt;00&lt;/strong&gt;
        &lt;span&gt;Min&lt;/span&gt;
      &lt;/div&gt;

      &lt;div&gt;
        &lt;strong data-seconds&gt;00&lt;/strong&gt;
        &lt;span&gt;Sec&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;a href="#inline-offer"&gt;Get Offer&lt;/a&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-thirteen-demo,
.vb-countdown-thirteen-demo * {
  box-sizing: border-box;
}

.vb-countdown-thirteen-demo {
  margin: 28px 0;
  padding: clamp(16px, 3vw, 28px);
  border-radius: 22px;
  background:
    linear-gradient(135deg, #ffffff 0%, #f8fafc 52%, #f1f5f9 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 20px 60px rgba(15, 23, 42, 0.08);
}

.vb-countdown-thirteen-inline {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: clamp(14px, 2vw, 22px);
  align-items: center;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(16px, 2.2vw, 22px);
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(203, 213, 225, 0.9);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.9);
}

.vb-countdown-thirteen-copy {
  min-width: 0;
  display: grid;
  gap: 5px;
}

.vb-countdown-thirteen-copy span {
  display: inline-flex;
  width: fit-content;
  padding: 5px 9px;
  border-radius: 999px;
  background: #eef2ff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-thirteen-copy strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(18px, 3vw, 28px);
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.045em;
  overflow-wrap: anywhere;
}

.vb-countdown-thirteen-copy p {
  max-width: 680px;
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-countdown-thirteen-timer {
  display: grid;
  grid-template-columns: repeat(3, minmax(56px, 1fr));
  gap: 8px;
  min-width: 0;
}

.vb-countdown-thirteen-timer div {
  min-width: 0;
  padding: 10px 8px;
  border-radius: 14px;
  background: #0f172a;
  text-align: center;
}

.vb-countdown-thirteen-timer strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(20px, 3vw, 30px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
}

.vb-countdown-thirteen-timer span {
  display: block;
  margin-top: 4px;
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 9px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-thirteen-inline a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 12px 16px;
  border-radius: 14px;
  background: #4f46e5;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
  box-shadow: 0 14px 28px rgba(79, 70, 229, 0.20);
}

@media (max-width: 860px) {
  .vb-countdown-thirteen-inline {
    grid-template-columns: 1fr;
  }

  .vb-countdown-thirteen-inline a {
    width: 100%;
  }
}

@media (max-width: 420px) {
  .vb-countdown-thirteen-timer {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .vb-countdown-thirteen-copy strong {
    font-size: 22px;
  }
}

@media (max-width: 320px) {
  .vb-countdown-thirteen-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This minimal inline countdown timer is useful for compact promo rows, checkout reminders, product page notices, pricing page offers, course enrollment CTAs, and small website announcement sections.</p>



<h2 class="wp-block-heading">14. Flip Clock Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A flip clock countdown timer</strong> is useful for launch pages, event pages, ecommerce campaigns, coming soon websites, product drops, conference pages, and premium landing pages that need a more visual timer style.</p>



<p class="wp-block-paragraph">This example uses a retro flip-clock inspired design with split number cards, a dark stage background, metallic borders, and a centered campaign layout. The JavaScript uses a repeating 12-day cycle, so the countdown continues working instead of staying expired.</p>



<ul class="wp-block-list">
<li>Flip clock countdown timer</li>
<li>Retro split-card number design</li>
<li>Days, hours, minutes, and seconds</li>
<li>Repeating launch cycle</li>
<li>Responsive flip timer layout</li>
</ul>



<div class="vb-countdown-fourteen-demo">
  <section class="vb-countdown-fourteen-stage" data-vb-countdown-fourteen data-cycle-days="12">
    <div class="vb-countdown-fourteen-header">
      <span>Example 14</span>
      <h3>Flip Clock Countdown Timer</h3>
      <p>Use this flip-style countdown timer for premium launches, event pages, coming soon campaigns, product drops, and visual landing page sections.</p>
    </div>

    <div class="vb-countdown-fourteen-clock" aria-label="Flip clock countdown timer">
      <div class="vb-countdown-fourteen-unit">
        <strong data-days>00</strong>
        <span>Days</span>
      </div>

      <div class="vb-countdown-fourteen-unit">
        <strong data-hours>00</strong>
        <span>Hours</span>
      </div>

      <div class="vb-countdown-fourteen-unit">
        <strong data-minutes>00</strong>
        <span>Minutes</span>
      </div>

      <div class="vb-countdown-fourteen-unit">
        <strong data-seconds>00</strong>
        <span>Seconds</span>
      </div>
    </div>

    <div class="vb-countdown-fourteen-footer">
      <p data-status>Launch countdown is active.</p>
      <a href="#flip-clock-launch">Join Launch List</a>
    </div>
  </section>
</div>

<style>
.vb-countdown-fourteen-demo,
.vb-countdown-fourteen-demo * {
  box-sizing: border-box;
}

.vb-countdown-fourteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 18px;
  background:
    radial-gradient(circle at 18% 18%, rgba(234, 179, 8, 0.18), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(148, 163, 184, 0.16), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #fefce8 52%, #ffffff 100%) !important;
  border: 1px solid rgba(234, 179, 8, 0.22);
  box-shadow: 0 28px 80px rgba(113, 63, 18, 0.10);
}

.vb-countdown-fourteen-stage {
  position: relative;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(24px, 5vw, 50px);
  overflow: hidden;
  border-radius: 12px 42px 12px 42px;
  background:
    linear-gradient(90deg, rgba(255,255,255,0.04) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.04) 1px, transparent 1px),
    linear-gradient(135deg, #020617 0%, #111827 54%, #1f2937 100%) !important;
  background-size: 34px 34px, 34px 34px, auto !important;
  border: 1px solid rgba(255,255,255,0.10);
  box-shadow: 0 30px 90px rgba(2, 6, 23, 0.36);
}

.vb-countdown-fourteen-stage::before {
  content: "";
  position: absolute;
  left: -100px;
  top: -120px;
  width: 280px;
  height: 280px;
  border-radius: 999px;
  background: rgba(234, 179, 8, 0.15);
  filter: blur(2px);
}

.vb-countdown-fourteen-stage::after {
  content: "";
  position: absolute;
  right: -120px;
  bottom: -120px;
  width: 320px;
  height: 320px;
  border-radius: 999px;
  background: rgba(59, 130, 246, 0.12);
  filter: blur(2px);
}

.vb-countdown-fourteen-header,
.vb-countdown-fourteen-clock,
.vb-countdown-fourteen-footer {
  position: relative;
  z-index: 2;
}

.vb-countdown-fourteen-header {
  max-width: 820px;
  margin: 0 auto 28px;
  text-align: center;
}

.vb-countdown-fourteen-header span {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 8px;
  background: rgba(234, 179, 8, 0.14);
  border: 1px solid rgba(250, 204, 21, 0.22);
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.vb-countdown-fourteen-header h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 78px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
  overflow-wrap: anywhere;
}

.vb-countdown-fourteen-header p {
  max-width: 720px;
  margin: 0 auto !important;
  color: #d1d5db !important;
  -webkit-text-fill-color: #d1d5db !important;
  font-size: clamp(15px, 1.8vw, 17px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-fourteen-clock {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(10px, 2vw, 18px);
  margin: 0 auto 26px;
}

.vb-countdown-fourteen-unit {
  min-width: 0;
  display: grid;
  gap: 10px;
  text-align: center;
}

.vb-countdown-fourteen-unit strong {
  position: relative;
  display: grid;
  place-items: center;
  min-height: clamp(92px, 12vw, 145px);
  padding: 14px 8px;
  overflow: hidden;
  border-radius: 12px;
  background:
    linear-gradient(to bottom, #111827 0%, #111827 49%, #020617 50%, #020617 100%) !important;
  border: 1px solid rgba(255,255,255,0.12);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 7vw, 76px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.065em;
  font-variant-numeric: tabular-nums;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.09),
    0 20px 46px rgba(0,0,0,0.28);
}

.vb-countdown-fourteen-unit strong::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 1px;
  background: rgba(255,255,255,0.16);
}

.vb-countdown-fourteen-unit strong::after {
  content: "";
  position: absolute;
  left: 10px;
  right: 10px;
  top: 10px;
  height: 28%;
  border-radius: 8px;
  background: linear-gradient(to bottom, rgba(255,255,255,0.08), transparent);
}

.vb-countdown-fourteen-unit span {
  display: inline-flex;
  justify-content: center;
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-fourteen-footer {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  flex-wrap: wrap;
}

.vb-countdown-fourteen-footer p {
  margin: 0 !important;
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-countdown-fourteen-footer a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 10px;
  background: linear-gradient(135deg, #eab308, #f97316);
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(234, 179, 8, 0.22);
}

@media (max-width: 820px) {
  .vb-countdown-fourteen-clock {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-fourteen-unit strong {
    font-size: clamp(44px, 13vw, 72px);
  }
}

@media (max-width: 640px) {
  .vb-countdown-fourteen-stage {
    border-radius: 10px 28px 10px 28px;
  }

  .vb-countdown-fourteen-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-fourteen-footer a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-fourteen-clock {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-fourteen]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 12;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-04T08:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextCycleEnd(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextEnd = getNextCycleEnd(now);
    let remaining = nextEnd - now;

    if (remaining <= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    statusEl.textContent = "Launch countdown is active.";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-fourteen]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 12;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-04T08:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextCycleEnd(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextEnd = getNextCycleEnd(now);
    let remaining = nextEnd - now;

    if (remaining &lt;= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    statusEl.textContent = "Launch countdown is active.";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-fourteen-demo"&gt;
  &lt;section class="vb-countdown-fourteen-stage" data-vb-countdown-fourteen data-cycle-days="12"&gt;
    &lt;div class="vb-countdown-fourteen-header"&gt;
      &lt;span&gt;Example 14&lt;/span&gt;
      &lt;h3&gt;Flip Clock Countdown Timer&lt;/h3&gt;
      &lt;p&gt;Use this flip-style countdown timer for premium launches, event pages, coming soon campaigns, product drops, and visual landing page sections.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-fourteen-clock" aria-label="Flip clock countdown timer"&gt;
      &lt;div class="vb-countdown-fourteen-unit"&gt;
        &lt;strong data-days&gt;00&lt;/strong&gt;
        &lt;span&gt;Days&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-fourteen-unit"&gt;
        &lt;strong data-hours&gt;00&lt;/strong&gt;
        &lt;span&gt;Hours&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-fourteen-unit"&gt;
        &lt;strong data-minutes&gt;00&lt;/strong&gt;
        &lt;span&gt;Minutes&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-fourteen-unit"&gt;
        &lt;strong data-seconds&gt;00&lt;/strong&gt;
        &lt;span&gt;Seconds&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-fourteen-footer"&gt;
      &lt;p data-status&gt;Launch countdown is active.&lt;/p&gt;
      &lt;a href="#flip-clock-launch"&gt;Join Launch List&lt;/a&gt;
    &lt;/div&gt;
  &lt;/section&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-fourteen-demo,
.vb-countdown-fourteen-demo * {
  box-sizing: border-box;
}

.vb-countdown-fourteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 18px;
  background:
    radial-gradient(circle at 18% 18%, rgba(234, 179, 8, 0.18), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(148, 163, 184, 0.16), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #fefce8 52%, #ffffff 100%) !important;
  border: 1px solid rgba(234, 179, 8, 0.22);
  box-shadow: 0 28px 80px rgba(113, 63, 18, 0.10);
}

.vb-countdown-fourteen-stage {
  position: relative;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(24px, 5vw, 50px);
  overflow: hidden;
  border-radius: 12px 42px 12px 42px;
  background:
    linear-gradient(90deg, rgba(255,255,255,0.04) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.04) 1px, transparent 1px),
    linear-gradient(135deg, #020617 0%, #111827 54%, #1f2937 100%) !important;
  background-size: 34px 34px, 34px 34px, auto !important;
  border: 1px solid rgba(255,255,255,0.10);
  box-shadow: 0 30px 90px rgba(2, 6, 23, 0.36);
}

.vb-countdown-fourteen-stage::before {
  content: "";
  position: absolute;
  left: -100px;
  top: -120px;
  width: 280px;
  height: 280px;
  border-radius: 999px;
  background: rgba(234, 179, 8, 0.15);
  filter: blur(2px);
}

.vb-countdown-fourteen-stage::after {
  content: "";
  position: absolute;
  right: -120px;
  bottom: -120px;
  width: 320px;
  height: 320px;
  border-radius: 999px;
  background: rgba(59, 130, 246, 0.12);
  filter: blur(2px);
}

.vb-countdown-fourteen-header,
.vb-countdown-fourteen-clock,
.vb-countdown-fourteen-footer {
  position: relative;
  z-index: 2;
}

.vb-countdown-fourteen-header {
  max-width: 820px;
  margin: 0 auto 28px;
  text-align: center;
}

.vb-countdown-fourteen-header span {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 8px;
  background: rgba(234, 179, 8, 0.14);
  border: 1px solid rgba(250, 204, 21, 0.22);
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.vb-countdown-fourteen-header h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 78px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
  overflow-wrap: anywhere;
}

.vb-countdown-fourteen-header p {
  max-width: 720px;
  margin: 0 auto !important;
  color: #d1d5db !important;
  -webkit-text-fill-color: #d1d5db !important;
  font-size: clamp(15px, 1.8vw, 17px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-fourteen-clock {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(10px, 2vw, 18px);
  margin: 0 auto 26px;
}

.vb-countdown-fourteen-unit {
  min-width: 0;
  display: grid;
  gap: 10px;
  text-align: center;
}

.vb-countdown-fourteen-unit strong {
  position: relative;
  display: grid;
  place-items: center;
  min-height: clamp(92px, 12vw, 145px);
  padding: 14px 8px;
  overflow: hidden;
  border-radius: 12px;
  background:
    linear-gradient(to bottom, #111827 0%, #111827 49%, #020617 50%, #020617 100%) !important;
  border: 1px solid rgba(255,255,255,0.12);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 7vw, 76px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.065em;
  font-variant-numeric: tabular-nums;
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.09),
    0 20px 46px rgba(0,0,0,0.28);
}

.vb-countdown-fourteen-unit strong::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  height: 1px;
  background: rgba(255,255,255,0.16);
}

.vb-countdown-fourteen-unit strong::after {
  content: "";
  position: absolute;
  left: 10px;
  right: 10px;
  top: 10px;
  height: 28%;
  border-radius: 8px;
  background: linear-gradient(to bottom, rgba(255,255,255,0.08), transparent);
}

.vb-countdown-fourteen-unit span {
  display: inline-flex;
  justify-content: center;
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-fourteen-footer {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  flex-wrap: wrap;
}

.vb-countdown-fourteen-footer p {
  margin: 0 !important;
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-countdown-fourteen-footer a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 10px;
  background: linear-gradient(135deg, #eab308, #f97316);
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(234, 179, 8, 0.22);
}

@media (max-width: 820px) {
  .vb-countdown-fourteen-clock {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-fourteen-unit strong {
    font-size: clamp(44px, 13vw, 72px);
  }
}

@media (max-width: 640px) {
  .vb-countdown-fourteen-stage {
    border-radius: 10px 28px 10px 28px;
  }

  .vb-countdown-fourteen-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-fourteen-footer a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-fourteen-clock {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This flip clock countdown timer is useful for launch pages, event landing pages, coming soon websites, premium ecommerce campaigns, digital product drops, conference pages, and visual promotional sections.</p>



<h2 class="wp-block-heading">15. Card Grid Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A card grid countdown timer</strong> is useful for product grids, course grids, event listings, deal sections, marketplace offers, pricing blocks, and landing pages where several countdown cards need to sit in a clean responsive layout.</p>



<p class="wp-block-paragraph">This example uses a modern card grid layout with three promotional cards, a main countdown card, soft shadows, rounded product blocks, and responsive behavior for tablet and mobile screens. The JavaScript uses a repeating 5-day cycle, so the demo keeps working over time.</p>



<ul class="wp-block-list">
<li>Card grid countdown timer</li>
<li>Responsive promotional card layout</li>
<li>Days, hours, minutes, and seconds</li>
<li>Useful for product and course grids</li>
<li>Repeating JavaScript countdown cycle</li>
</ul>



<div class="vb-countdown-fifteen-demo">
  <section class="vb-countdown-fifteen-grid" data-vb-countdown-fifteen data-cycle-days="5">
    <div class="vb-countdown-fifteen-card vb-countdown-fifteen-main">
      <span class="vb-countdown-fifteen-kicker">Example 15</span>
      <h3>Card Grid Countdown Timer</h3>
      <p>Use this countdown card grid for product offers, course launches, marketplace deals, event cards, and landing page promotion blocks.</p>

      <div class="vb-countdown-fifteen-timer" aria-label="Card grid countdown timer">
        <div>
          <strong data-days>00</strong>
          <span>Days</span>
        </div>

        <div>
          <strong data-hours>00</strong>
          <span>Hours</span>
        </div>

        <div>
          <strong data-minutes>00</strong>
          <span>Min</span>
        </div>

        <div>
          <strong data-seconds>00</strong>
          <span>Sec</span>
        </div>
      </div>

      <a href="#grid-offer">View Campaign</a>
    </div>

    <div class="vb-countdown-fifteen-card vb-countdown-fifteen-small">
      <span>Product Deal</span>
      <strong>Save 25%</strong>
      <p>Limited card offer for featured products.</p>
    </div>

    <div class="vb-countdown-fifteen-card vb-countdown-fifteen-small">
      <span>Course Offer</span>
      <strong>Early Access</strong>
      <p>Enrollment window closes soon.</p>
    </div>

    <div class="vb-countdown-fifteen-card vb-countdown-fifteen-small">
      <span data-status>Campaign active</span>
      <strong data-next-cycle>Next cycle loading</strong>
      <p>The timer stays active with a repeating cycle.</p>
    </div>
  </section>
</div>

<style>
.vb-countdown-fifteen-demo,
.vb-countdown-fifteen-demo * {
  box-sizing: border-box;
}

.vb-countdown-fifteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 15% 20%, rgba(99, 102, 241, 0.15), transparent 34%),
    radial-gradient(circle at 85% 18%, rgba(236, 72, 153, 0.13), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #fdf2f8 54%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.18);
  box-shadow: 0 28px 80px rgba(49, 46, 129, 0.09);
}

.vb-countdown-fifteen-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(220px, 0.65fr);
  grid-template-rows: repeat(3, minmax(0, 1fr));
  gap: clamp(14px, 2vw, 18px);
  max-width: 1120px;
  margin: 0 auto;
}

.vb-countdown-fifteen-card {
  min-width: 0;
  border: 1px solid rgba(148, 163, 184, 0.22);
  background: #ffffff;
  box-shadow: 0 20px 60px rgba(15, 23, 42, 0.08);
}

.vb-countdown-fifteen-main {
  grid-row: 1 / 4;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(26px, 5vw, 48px);
  border-radius: 34px 12px 34px 12px;
  background:
    radial-gradient(circle at 20% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #312e81 0%, #4f46e5 50%, #be185d 100%) !important;
}

.vb-countdown-fifteen-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-fifteen-main h3 {
  max-width: 760px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 80px) !important;
  line-height: 0.88 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
  overflow-wrap: anywhere;
}

.vb-countdown-fifteen-main p {
  max-width: 660px;
  margin: 0 0 24px !important;
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: clamp(15px, 1.8vw, 17px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-fifteen-timer {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(8px, 1.4vw, 12px);
  margin-bottom: 22px;
}

.vb-countdown-fifteen-timer div {
  min-width: 0;
  padding: clamp(15px, 2.4vw, 22px) 8px;
  border-radius: 20px 20px 6px 20px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.16);
  text-align: center;
}

.vb-countdown-fifteen-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4.7vw, 54px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-fifteen-timer span {
  display: block;
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-fifteen-main a {
  display: inline-flex;
  align-self: flex-start;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 14px 20px;
  border-radius: 999px;
  background: #ffffff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(15, 23, 42, 0.20);
}

.vb-countdown-fifteen-small {
  display: grid;
  align-content: center;
  gap: 8px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 10px 28px 10px 28px;
}

.vb-countdown-fifteen-small:nth-child(2) {
  background: #fff7ed;
}

.vb-countdown-fifteen-small:nth-child(3) {
  background: #ecfdf5;
}

.vb-countdown-fifteen-small:nth-child(4) {
  background: #eef2ff;
}

.vb-countdown-fifteen-small span {
  display: inline-flex;
  width: fit-content;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.06);
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-fifteen-small strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(24px, 4vw, 34px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
  overflow-wrap: anywhere;
}

.vb-countdown-fifteen-small p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-countdown-fifteen-grid {
    grid-template-columns: 1fr;
    grid-template-rows: auto;
  }

  .vb-countdown-fifteen-main {
    grid-row: auto;
  }
}

@media (max-width: 640px) {
  .vb-countdown-fifteen-main h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-fifteen-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-fifteen-timer strong {
    font-size: clamp(30px, 13vw, 48px);
  }

  .vb-countdown-fifteen-main a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-fifteen-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-fifteen]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 5;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-02T10:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextCycleEl = timer.querySelector("[data-next-cycle]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextCycleEnd(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextEnd = getNextCycleEnd(now);
    let remaining = nextEnd - now;

    if (remaining <= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(nextEnd).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextCycleEl.textContent = "Ends " + dateText;
    statusEl.textContent = "Campaign active";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-fifteen]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 5;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-02T10:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextCycleEl = timer.querySelector("[data-next-cycle]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextCycleEnd(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextEnd = getNextCycleEnd(now);
    let remaining = nextEnd - now;

    if (remaining &lt;= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(nextEnd).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextCycleEl.textContent = "Ends " + dateText;
    statusEl.textContent = "Campaign active";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-fifteen-demo"&gt;
  &lt;section class="vb-countdown-fifteen-grid" data-vb-countdown-fifteen data-cycle-days="5"&gt;
    &lt;div class="vb-countdown-fifteen-card vb-countdown-fifteen-main"&gt;
      &lt;span class="vb-countdown-fifteen-kicker"&gt;Example 15&lt;/span&gt;
      &lt;h3&gt;Card Grid Countdown Timer&lt;/h3&gt;
      &lt;p&gt;Use this countdown card grid for product offers, course launches, marketplace deals, event cards, and landing page promotion blocks.&lt;/p&gt;

      &lt;div class="vb-countdown-fifteen-timer" aria-label="Card grid countdown timer"&gt;
        &lt;div&gt;
          &lt;strong data-days&gt;00&lt;/strong&gt;
          &lt;span&gt;Days&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-hours&gt;00&lt;/strong&gt;
          &lt;span&gt;Hours&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
          &lt;span&gt;Min&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
          &lt;span&gt;Sec&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;a href="#grid-offer"&gt;View Campaign&lt;/a&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-fifteen-card vb-countdown-fifteen-small"&gt;
      &lt;span&gt;Product Deal&lt;/span&gt;
      &lt;strong&gt;Save 25%&lt;/strong&gt;
      &lt;p&gt;Limited card offer for featured products.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-fifteen-card vb-countdown-fifteen-small"&gt;
      &lt;span&gt;Course Offer&lt;/span&gt;
      &lt;strong&gt;Early Access&lt;/strong&gt;
      &lt;p&gt;Enrollment window closes soon.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-fifteen-card vb-countdown-fifteen-small"&gt;
      &lt;span data-status&gt;Campaign active&lt;/span&gt;
      &lt;strong data-next-cycle&gt;Next cycle loading&lt;/strong&gt;
      &lt;p&gt;The timer stays active with a repeating cycle.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/section&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-fifteen-demo,
.vb-countdown-fifteen-demo * {
  box-sizing: border-box;
}

.vb-countdown-fifteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 15% 20%, rgba(99, 102, 241, 0.15), transparent 34%),
    radial-gradient(circle at 85% 18%, rgba(236, 72, 153, 0.13), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #fdf2f8 54%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.18);
  box-shadow: 0 28px 80px rgba(49, 46, 129, 0.09);
}

.vb-countdown-fifteen-grid {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(220px, 0.65fr);
  grid-template-rows: repeat(3, minmax(0, 1fr));
  gap: clamp(14px, 2vw, 18px);
  max-width: 1120px;
  margin: 0 auto;
}

.vb-countdown-fifteen-card {
  min-width: 0;
  border: 1px solid rgba(148, 163, 184, 0.22);
  background: #ffffff;
  box-shadow: 0 20px 60px rgba(15, 23, 42, 0.08);
}

.vb-countdown-fifteen-main {
  grid-row: 1 / 4;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(26px, 5vw, 48px);
  border-radius: 34px 12px 34px 12px;
  background:
    radial-gradient(circle at 20% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #312e81 0%, #4f46e5 50%, #be185d 100%) !important;
}

.vb-countdown-fifteen-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-fifteen-main h3 {
  max-width: 760px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 80px) !important;
  line-height: 0.88 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
  overflow-wrap: anywhere;
}

.vb-countdown-fifteen-main p {
  max-width: 660px;
  margin: 0 0 24px !important;
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: clamp(15px, 1.8vw, 17px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-fifteen-timer {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(8px, 1.4vw, 12px);
  margin-bottom: 22px;
}

.vb-countdown-fifteen-timer div {
  min-width: 0;
  padding: clamp(15px, 2.4vw, 22px) 8px;
  border-radius: 20px 20px 6px 20px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.16);
  text-align: center;
}

.vb-countdown-fifteen-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4.7vw, 54px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-fifteen-timer span {
  display: block;
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-fifteen-main a {
  display: inline-flex;
  align-self: flex-start;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 14px 20px;
  border-radius: 999px;
  background: #ffffff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(15, 23, 42, 0.20);
}

.vb-countdown-fifteen-small {
  display: grid;
  align-content: center;
  gap: 8px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 10px 28px 10px 28px;
}

.vb-countdown-fifteen-small:nth-child(2) {
  background: #fff7ed;
}

.vb-countdown-fifteen-small:nth-child(3) {
  background: #ecfdf5;
}

.vb-countdown-fifteen-small:nth-child(4) {
  background: #eef2ff;
}

.vb-countdown-fifteen-small span {
  display: inline-flex;
  width: fit-content;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.06);
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-fifteen-small strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(24px, 4vw, 34px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
  overflow-wrap: anywhere;
}

.vb-countdown-fifteen-small p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-countdown-fifteen-grid {
    grid-template-columns: 1fr;
    grid-template-rows: auto;
  }

  .vb-countdown-fifteen-main {
    grid-row: auto;
  }
}

@media (max-width: 640px) {
  .vb-countdown-fifteen-main h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-fifteen-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-fifteen-timer strong {
    font-size: clamp(30px, 13vw, 48px);
  }

  .vb-countdown-fifteen-main a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-fifteen-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This card grid countdown timer is useful for ecommerce deal grids, event cards, course launch cards, marketplace promotions, product offer sections, and responsive landing page campaign blocks.</p>



<h2 class="wp-block-heading">16. Coupon Expiry Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A coupon expiry countdown timer</strong> is useful for discount codes, ecommerce checkout pages, popup offers, coupon landing pages, email campaign pages, cart recovery pages, and promotional banners where visitors need to use a coupon before it expires.</p>



<p class="wp-block-paragraph">This example uses a coupon-style layout with dashed borders, a tear-off edge, coupon code block, timer strip, and clear call-to-action button. The JavaScript uses a repeating 8-hour coupon window, so the demo stays active and never remains stopped at zero.</p>



<ul class="wp-block-list">
<li>Coupon expiry countdown timer</li>
<li>Coupon code and discount layout</li>
<li>Hours, minutes, and seconds</li>
<li>Repeating coupon window</li>
<li>Responsive ecommerce coupon design</li>
</ul>



<div class="vb-countdown-sixteen-demo">
  <section class="vb-countdown-sixteen-coupon" data-vb-countdown-sixteen data-duration="28800">
    <div class="vb-countdown-sixteen-left">
      <span class="vb-countdown-sixteen-kicker">Example 16</span>
      <h3>Coupon Expiry Countdown Timer</h3>
      <p>Use this countdown timer for coupon codes, checkout discounts, popup offers, cart recovery campaigns, and promotional landing pages.</p>

      <div class="vb-countdown-sixteen-code">
        <span>Coupon Code</span>
        <strong>SAVE30</strong>
      </div>
    </div>

    <div class="vb-countdown-sixteen-divider"></div>

    <div class="vb-countdown-sixteen-right">
      <strong class="vb-countdown-sixteen-offer">30% OFF</strong>
      <p data-status>Coupon expires soon.</p>

      <div class="vb-countdown-sixteen-timer" aria-label="Coupon expiry countdown timer">
        <div>
          <strong data-hours>00</strong>
          <span>Hours</span>
        </div>

        <div>
          <strong data-minutes>00</strong>
          <span>Min</span>
        </div>

        <div>
          <strong data-seconds>00</strong>
          <span>Sec</span>
        </div>
      </div>

      <a href="#coupon-offer">Use Coupon</a>
    </div>
  </section>
</div>

<style>
.vb-countdown-sixteen-demo,
.vb-countdown-sixteen-demo * {
  box-sizing: border-box;
}

.vb-countdown-sixteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 26px;
  background:
    radial-gradient(circle at 15% 20%, rgba(245, 158, 11, 0.16), transparent 34%),
    radial-gradient(circle at 85% 20%, rgba(244, 63, 94, 0.14), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fff1f2 52%, #ffffff 100%) !important;
  border: 1px solid rgba(245, 158, 11, 0.22);
  box-shadow: 0 28px 80px rgba(120, 53, 15, 0.09);
}

.vb-countdown-sixteen-coupon {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 26px minmax(250px, 360px);
  gap: clamp(16px, 2.6vw, 24px);
  align-items: stretch;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(18px, 3vw, 26px);
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 2px dashed rgba(245, 158, 11, 0.42);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-countdown-sixteen-coupon::before,
.vb-countdown-sixteen-coupon::after {
  content: "";
  position: absolute;
  top: 50%;
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: #fffbeb;
  border: 1px solid rgba(245, 158, 11, 0.20);
  transform: translateY(-50%);
  z-index: 3;
}

.vb-countdown-sixteen-coupon::before {
  left: -22px;
}

.vb-countdown-sixteen-coupon::after {
  right: -22px;
}

.vb-countdown-sixteen-left,
.vb-countdown-sixteen-right {
  min-width: 0;
}

.vb-countdown-sixteen-left {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(18px, 3vw, 28px);
}

.vb-countdown-sixteen-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px 999px 4px 999px;
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-sixteen-left h3 {
  max-width: 740px;
  margin: 0 0 16px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5.8vw, 76px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
  overflow-wrap: anywhere;
}

.vb-countdown-sixteen-left p {
  max-width: 650px;
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.72;
  font-weight: 650;
}

.vb-countdown-sixteen-code {
  display: inline-grid;
  gap: 6px;
  align-self: flex-start;
  max-width: 100%;
  padding: 16px 20px;
  border-radius: 18px 6px 18px 6px;
  background: #0f172a;
  box-shadow: 0 16px 34px rgba(15, 23, 42, 0.16);
}

.vb-countdown-sixteen-code span {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-sixteen-code strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 5vw, 42px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: 0.08em;
}

.vb-countdown-sixteen-divider {
  position: relative;
  min-height: 100%;
  border-left: 2px dashed rgba(245, 158, 11, 0.40);
}

.vb-countdown-sixteen-divider::before,
.vb-countdown-sixteen-divider::after {
  content: "";
  position: absolute;
  left: -14px;
  width: 26px;
  height: 26px;
  border-radius: 999px;
  background: #fffbeb;
  border: 1px solid rgba(245, 158, 11, 0.20);
}

.vb-countdown-sixteen-divider::before {
  top: -28px;
}

.vb-countdown-sixteen-divider::after {
  bottom: -28px;
}

.vb-countdown-sixteen-right {
  display: grid;
  align-content: center;
  gap: 16px;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 22px;
  background:
    radial-gradient(circle at 20% 18%, rgba(255,255,255,0.20), transparent 34%),
    linear-gradient(135deg, #f97316 0%, #e11d48 100%) !important;
  color: #ffffff;
}

.vb-countdown-sixteen-offer {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(42px, 7vw, 68px);
  line-height: 0.88;
  font-weight: 950;
  letter-spacing: -0.08em;
}

.vb-countdown-sixteen-right p {
  margin: 0 !important;
  color: #fff7ed !important;
  -webkit-text-fill-color: #fff7ed !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 750;
}

.vb-countdown-sixteen-timer {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 9px;
}

.vb-countdown-sixteen-timer div {
  min-width: 0;
  padding: 14px 7px;
  border-radius: 16px 6px 16px 6px;
  background: rgba(255,255,255,0.16);
  border: 1px solid rgba(255,255,255,0.18);
  text-align: center;
}

.vb-countdown-sixteen-timer strong {
  display: block;
  margin-bottom: 5px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(26px, 5vw, 40px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums;
}

.vb-countdown-sixteen-timer span {
  display: block;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 9px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-sixteen-right a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 999px;
  background: #ffffff;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(15, 23, 42, 0.18);
}

@media (max-width: 900px) {
  .vb-countdown-sixteen-coupon {
    grid-template-columns: 1fr;
  }

  .vb-countdown-sixteen-divider {
    min-height: 0;
    height: 2px;
    border-left: 0;
    border-top: 2px dashed rgba(245, 158, 11, 0.40);
  }

  .vb-countdown-sixteen-divider::before,
  .vb-countdown-sixteen-divider::after {
    display: none;
  }
}

@media (max-width: 640px) {
  .vb-countdown-sixteen-left h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-sixteen-code {
    width: 100%;
  }

  .vb-countdown-sixteen-right a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-sixteen-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-sixteen]");
  if (!timer) return;

  const duration = Number(timer.getAttribute("data-duration")) || 28800;
  let remaining = duration;

  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function updateCountdown() {
    if (remaining <= 0) {
      remaining = duration;
    }

    const hours = Math.floor(remaining / 3600);
    const minutes = Math.floor((remaining / 60) % 60);
    const seconds = remaining % 60;

    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    statusEl.textContent = "Coupon expires soon.";

    remaining -= 1;
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-sixteen]");
  if (!timer) return;

  const duration = Number(timer.getAttribute("data-duration")) || 28800;
  let remaining = duration;

  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function updateCountdown() {
    if (remaining &lt;= 0) {
      remaining = duration;
    }

    const hours = Math.floor(remaining / 3600);
    const minutes = Math.floor((remaining / 60) % 60);
    const seconds = remaining % 60;

    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    statusEl.textContent = "Coupon expires soon.";

    remaining -= 1;
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-sixteen-demo"&gt;
  &lt;section class="vb-countdown-sixteen-coupon" data-vb-countdown-sixteen data-duration="28800"&gt;
    &lt;div class="vb-countdown-sixteen-left"&gt;
      &lt;span class="vb-countdown-sixteen-kicker"&gt;Example 16&lt;/span&gt;
      &lt;h3&gt;Coupon Expiry Countdown Timer&lt;/h3&gt;
      &lt;p&gt;Use this countdown timer for coupon codes, checkout discounts, popup offers, cart recovery campaigns, and promotional landing pages.&lt;/p&gt;

      &lt;div class="vb-countdown-sixteen-code"&gt;
        &lt;span&gt;Coupon Code&lt;/span&gt;
        &lt;strong&gt;SAVE30&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-sixteen-divider"&gt;&lt;/div&gt;

    &lt;div class="vb-countdown-sixteen-right"&gt;
      &lt;strong class="vb-countdown-sixteen-offer"&gt;30% OFF&lt;/strong&gt;
      &lt;p data-status&gt;Coupon expires soon.&lt;/p&gt;

      &lt;div class="vb-countdown-sixteen-timer" aria-label="Coupon expiry countdown timer"&gt;
        &lt;div&gt;
          &lt;strong data-hours&gt;00&lt;/strong&gt;
          &lt;span&gt;Hours&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
          &lt;span&gt;Min&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
          &lt;span&gt;Sec&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;a href="#coupon-offer"&gt;Use Coupon&lt;/a&gt;
    &lt;/div&gt;
  &lt;/section&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-sixteen-demo,
.vb-countdown-sixteen-demo * {
  box-sizing: border-box;
}

.vb-countdown-sixteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 26px;
  background:
    radial-gradient(circle at 15% 20%, rgba(245, 158, 11, 0.16), transparent 34%),
    radial-gradient(circle at 85% 20%, rgba(244, 63, 94, 0.14), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fff1f2 52%, #ffffff 100%) !important;
  border: 1px solid rgba(245, 158, 11, 0.22);
  box-shadow: 0 28px 80px rgba(120, 53, 15, 0.09);
}

.vb-countdown-sixteen-coupon {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) 26px minmax(250px, 360px);
  gap: clamp(16px, 2.6vw, 24px);
  align-items: stretch;
  max-width: 1120px;
  margin: 0 auto;
  padding: clamp(18px, 3vw, 26px);
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 2px dashed rgba(245, 158, 11, 0.42);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-countdown-sixteen-coupon::before,
.vb-countdown-sixteen-coupon::after {
  content: "";
  position: absolute;
  top: 50%;
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: #fffbeb;
  border: 1px solid rgba(245, 158, 11, 0.20);
  transform: translateY(-50%);
  z-index: 3;
}

.vb-countdown-sixteen-coupon::before {
  left: -22px;
}

.vb-countdown-sixteen-coupon::after {
  right: -22px;
}

.vb-countdown-sixteen-left,
.vb-countdown-sixteen-right {
  min-width: 0;
}

.vb-countdown-sixteen-left {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(18px, 3vw, 28px);
}

.vb-countdown-sixteen-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px 999px 4px 999px;
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-sixteen-left h3 {
  max-width: 740px;
  margin: 0 0 16px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5.8vw, 76px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
  overflow-wrap: anywhere;
}

.vb-countdown-sixteen-left p {
  max-width: 650px;
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.72;
  font-weight: 650;
}

.vb-countdown-sixteen-code {
  display: inline-grid;
  gap: 6px;
  align-self: flex-start;
  max-width: 100%;
  padding: 16px 20px;
  border-radius: 18px 6px 18px 6px;
  background: #0f172a;
  box-shadow: 0 16px 34px rgba(15, 23, 42, 0.16);
}

.vb-countdown-sixteen-code span {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-sixteen-code strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 5vw, 42px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: 0.08em;
}

.vb-countdown-sixteen-divider {
  position: relative;
  min-height: 100%;
  border-left: 2px dashed rgba(245, 158, 11, 0.40);
}

.vb-countdown-sixteen-divider::before,
.vb-countdown-sixteen-divider::after {
  content: "";
  position: absolute;
  left: -14px;
  width: 26px;
  height: 26px;
  border-radius: 999px;
  background: #fffbeb;
  border: 1px solid rgba(245, 158, 11, 0.20);
}

.vb-countdown-sixteen-divider::before {
  top: -28px;
}

.vb-countdown-sixteen-divider::after {
  bottom: -28px;
}

.vb-countdown-sixteen-right {
  display: grid;
  align-content: center;
  gap: 16px;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 22px;
  background:
    radial-gradient(circle at 20% 18%, rgba(255,255,255,0.20), transparent 34%),
    linear-gradient(135deg, #f97316 0%, #e11d48 100%) !important;
  color: #ffffff;
}

.vb-countdown-sixteen-offer {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(42px, 7vw, 68px);
  line-height: 0.88;
  font-weight: 950;
  letter-spacing: -0.08em;
}

.vb-countdown-sixteen-right p {
  margin: 0 !important;
  color: #fff7ed !important;
  -webkit-text-fill-color: #fff7ed !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 750;
}

.vb-countdown-sixteen-timer {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 9px;
}

.vb-countdown-sixteen-timer div {
  min-width: 0;
  padding: 14px 7px;
  border-radius: 16px 6px 16px 6px;
  background: rgba(255,255,255,0.16);
  border: 1px solid rgba(255,255,255,0.18);
  text-align: center;
}

.vb-countdown-sixteen-timer strong {
  display: block;
  margin-bottom: 5px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(26px, 5vw, 40px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums;
}

.vb-countdown-sixteen-timer span {
  display: block;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 9px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-sixteen-right a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 999px;
  background: #ffffff;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(15, 23, 42, 0.18);
}

@media (max-width: 900px) {
  .vb-countdown-sixteen-coupon {
    grid-template-columns: 1fr;
  }

  .vb-countdown-sixteen-divider {
    min-height: 0;
    height: 2px;
    border-left: 0;
    border-top: 2px dashed rgba(245, 158, 11, 0.40);
  }

  .vb-countdown-sixteen-divider::before,
  .vb-countdown-sixteen-divider::after {
    display: none;
  }
}

@media (max-width: 640px) {
  .vb-countdown-sixteen-left h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-sixteen-code {
    width: 100%;
  }

  .vb-countdown-sixteen-right a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-sixteen-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This coupon expiry countdown timer is useful for ecommerce coupon codes, checkout discounts, popup offers, cart recovery campaigns, email campaign landing pages, and limited-time promotional banners.</p>



<h2 class="wp-block-heading">17. Course Enrollment Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A course enrollment countdown timer</strong> is useful for online course pages, academy websites, coaching programs, learning platforms, cohort-based courses, early-bird enrollment campaigns, and training landing pages. It helps show when enrollment closes and encourages visitors to join before the deadline.</p>



<p class="wp-block-paragraph">This example uses a clean course landing page style with a lesson preview card, enrollment badge, instructor-style information block, countdown modules, and a course CTA button. The JavaScript uses a repeating 14-day enrollment cycle, so the demo keeps working over time and never stays stopped at zero.</p>



<ul class="wp-block-list">
<li>Course enrollment countdown timer</li>
<li>Online course landing page layout</li>
<li>Days, hours, minutes, and seconds</li>
<li>Repeating enrollment cycle</li>
<li>Responsive course CTA section</li>
</ul>



<div class="vb-countdown-seventeen-demo">
  <section class="vb-countdown-seventeen-course" data-vb-countdown-seventeen data-cycle-days="14">
    <div class="vb-countdown-seventeen-preview">
      <span class="vb-countdown-seventeen-tag">Example 17</span>

      <div class="vb-countdown-seventeen-screen">
        <div class="vb-countdown-seventeen-screen-top">
          <i></i>
          <i></i>
          <i></i>
        </div>
        <div class="vb-countdown-seventeen-lines">
          <span></span>
          <span></span>
          <span></span>
        </div>
      </div>

      <div class="vb-countdown-seventeen-module">
        <strong>12 modules</strong>
        <span>Enrollment open</span>
      </div>
    </div>

    <div class="vb-countdown-seventeen-content">
      <span class="vb-countdown-seventeen-kicker">Online Course</span>
      <h3>Course Enrollment Countdown Timer</h3>
      <p>Use this countdown timer for online course launches, cohort-based programs, academy pages, training campaigns, and enrollment deadline sections.</p>

      <div class="vb-countdown-seventeen-meta">
        <span>Beginner friendly</span>
        <span>Certificate included</span>
        <span data-next-enrollment>Enrollment window loading</span>
      </div>

      <div class="vb-countdown-seventeen-timer" aria-label="Course enrollment countdown timer">
        <div>
          <strong data-days>00</strong>
          <span>Days</span>
        </div>

        <div>
          <strong data-hours>00</strong>
          <span>Hours</span>
        </div>

        <div>
          <strong data-minutes>00</strong>
          <span>Min</span>
        </div>

        <div>
          <strong data-seconds>00</strong>
          <span>Sec</span>
        </div>
      </div>

      <p class="vb-countdown-seventeen-status" data-status>Enrollment is open for the next course window.</p>

      <a href="#course-enrollment">Enroll Now</a>
    </div>
  </section>
</div>

<style>
.vb-countdown-seventeen-demo,
.vb-countdown-seventeen-demo * {
  box-sizing: border-box;
}

.vb-countdown-seventeen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 56px 18px 18px 56px;
  background:
    radial-gradient(circle at 14% 18%, rgba(59, 130, 246, 0.17), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(16, 185, 129, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 54%, #ffffff 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.20);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-countdown-seventeen-course {
  display: grid;
  grid-template-columns: minmax(260px, 0.82fr) minmax(0, 1.18fr);
  gap: clamp(22px, 4vw, 38px);
  align-items: center;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 42px 12px 12px 42px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-countdown-seventeen-preview {
  position: relative;
  min-width: 0;
  min-height: clamp(330px, 42vw, 480px);
  overflow: hidden;
  border-radius: 34px 10px 10px 34px;
  background:
    radial-gradient(circle at 28% 20%, rgba(255,255,255,0.30), transparent 34%),
    linear-gradient(135deg, #1e3a8a 0%, #2563eb 52%, #10b981 100%) !important;
}

.vb-countdown-seventeen-tag {
  position: absolute;
  left: 18px;
  top: 18px;
  z-index: 4;
  display: inline-flex;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  border: 1px solid rgba(255,255,255,0.22);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-seventeen-screen {
  position: absolute;
  left: 50%;
  top: 48%;
  width: min(78%, 310px);
  min-height: 230px;
  transform: translate(-50%, -50%) rotate(-4deg);
  border-radius: 24px;
  background: rgba(255,255,255,0.92);
  box-shadow: 0 28px 76px rgba(15, 23, 42, 0.22);
  overflow: hidden;
}

.vb-countdown-seventeen-screen-top {
  display: flex;
  gap: 7px;
  padding: 14px;
  background: #0f172a;
}

.vb-countdown-seventeen-screen-top i {
  width: 10px;
  height: 10px;
  border-radius: 999px;
  background: #60a5fa;
}

.vb-countdown-seventeen-screen-top i:nth-child(2) {
  background: #34d399;
}

.vb-countdown-seventeen-screen-top i:nth-child(3) {
  background: #facc15;
}

.vb-countdown-seventeen-lines {
  display: grid;
  gap: 14px;
  padding: 24px;
}

.vb-countdown-seventeen-lines span {
  display: block;
  height: 18px;
  border-radius: 999px;
  background: #dbeafe;
}

.vb-countdown-seventeen-lines span:nth-child(1) {
  width: 84%;
}

.vb-countdown-seventeen-lines span:nth-child(2) {
  width: 62%;
  background: #bbf7d0;
}

.vb-countdown-seventeen-lines span:nth-child(3) {
  width: 74%;
  background: #e0e7ff;
}

.vb-countdown-seventeen-module {
  position: absolute;
  left: 24px;
  right: 24px;
  bottom: 24px;
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: center;
  padding: 16px;
  border-radius: 22px;
  background: rgba(15, 23, 42, 0.72);
  border: 1px solid rgba(255,255,255,0.14);
  backdrop-filter: blur(12px);
}

.vb-countdown-seventeen-module strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-countdown-seventeen-module span {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-seventeen-content {
  min-width: 0;
  padding: clamp(10px, 2vw, 18px);
}

.vb-countdown-seventeen-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px 999px 999px 4px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-seventeen-content h3 {
  max-width: 760px;
  margin: 0 0 16px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5.8vw, 76px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
  overflow-wrap: anywhere;
}

.vb-countdown-seventeen-content p {
  max-width: 680px;
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-seventeen-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 18px;
}

.vb-countdown-seventeen-meta span {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: #f1f5f9;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-seventeen-timer {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(8px, 1.4vw, 12px);
  margin-bottom: 18px;
}

.vb-countdown-seventeen-timer div {
  min-width: 0;
  padding: clamp(15px, 2.4vw, 20px) 8px;
  border-radius: 10px 24px 10px 24px;
  background: #0f172a;
  text-align: center;
  box-shadow: 0 18px 42px rgba(15, 23, 42, 0.16);
}

.vb-countdown-seventeen-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4.5vw, 50px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-seventeen-timer span {
  display: block;
  color: #93c5fd !important;
  -webkit-text-fill-color: #93c5fd !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-seventeen-status {
  margin-bottom: 18px !important;
}

.vb-countdown-seventeen-content a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 14px 20px;
  border-radius: 999px 999px 999px 8px;
  background: linear-gradient(135deg, #2563eb, #10b981);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(37, 99, 235, 0.22);
}

@media (max-width: 920px) {
  .vb-countdown-seventeen-course {
    grid-template-columns: 1fr;
  }

  .vb-countdown-seventeen-preview {
    border-radius: 30px 10px 10px 30px;
  }
}

@media (max-width: 640px) {
  .vb-countdown-seventeen-demo {
    border-radius: 34px 12px 12px 34px;
  }

  .vb-countdown-seventeen-course {
    border-radius: 28px 10px 10px 28px;
  }

  .vb-countdown-seventeen-content h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-seventeen-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-seventeen-timer strong {
    font-size: clamp(30px, 13vw, 46px);
  }

  .vb-countdown-seventeen-content a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-seventeen-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-seventeen]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 14;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-08T11:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextEnrollmentEl = timer.querySelector("[data-next-enrollment]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextEnrollmentEnd(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextEnd = getNextEnrollmentEnd(now);
    let remaining = nextEnd - now;

    if (remaining <= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(nextEnd).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextEnrollmentEl.textContent = "Enrollment closes " + dateText;
    statusEl.textContent = "Enrollment is open for the next course window.";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-seventeen]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 14;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-08T11:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextEnrollmentEl = timer.querySelector("[data-next-enrollment]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextEnrollmentEnd(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextEnd = getNextEnrollmentEnd(now);
    let remaining = nextEnd - now;

    if (remaining &lt;= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(nextEnd).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextEnrollmentEl.textContent = "Enrollment closes " + dateText;
    statusEl.textContent = "Enrollment is open for the next course window.";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-seventeen-demo"&gt;
  &lt;section class="vb-countdown-seventeen-course" data-vb-countdown-seventeen data-cycle-days="14"&gt;
    &lt;div class="vb-countdown-seventeen-preview"&gt;
      &lt;span class="vb-countdown-seventeen-tag"&gt;Example 17&lt;/span&gt;

      &lt;div class="vb-countdown-seventeen-screen"&gt;
        &lt;div class="vb-countdown-seventeen-screen-top"&gt;
          &lt;i&gt;&lt;/i&gt;
          &lt;i&gt;&lt;/i&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/div&gt;
        &lt;div class="vb-countdown-seventeen-lines"&gt;
          &lt;span&gt;&lt;/span&gt;
          &lt;span&gt;&lt;/span&gt;
          &lt;span&gt;&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-seventeen-module"&gt;
        &lt;strong&gt;12 modules&lt;/strong&gt;
        &lt;span&gt;Enrollment open&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-seventeen-content"&gt;
      &lt;span class="vb-countdown-seventeen-kicker"&gt;Online Course&lt;/span&gt;
      &lt;h3&gt;Course Enrollment Countdown Timer&lt;/h3&gt;
      &lt;p&gt;Use this countdown timer for online course launches, cohort-based programs, academy pages, training campaigns, and enrollment deadline sections.&lt;/p&gt;

      &lt;div class="vb-countdown-seventeen-meta"&gt;
        &lt;span&gt;Beginner friendly&lt;/span&gt;
        &lt;span&gt;Certificate included&lt;/span&gt;
        &lt;span data-next-enrollment&gt;Enrollment window loading&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-seventeen-timer" aria-label="Course enrollment countdown timer"&gt;
        &lt;div&gt;
          &lt;strong data-days&gt;00&lt;/strong&gt;
          &lt;span&gt;Days&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-hours&gt;00&lt;/strong&gt;
          &lt;span&gt;Hours&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
          &lt;span&gt;Min&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
          &lt;span&gt;Sec&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;p class="vb-countdown-seventeen-status" data-status&gt;Enrollment is open for the next course window.&lt;/p&gt;

      &lt;a href="#course-enrollment"&gt;Enroll Now&lt;/a&gt;
    &lt;/div&gt;
  &lt;/section&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-seventeen-demo,
.vb-countdown-seventeen-demo * {
  box-sizing: border-box;
}

.vb-countdown-seventeen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 56px 18px 18px 56px;
  background:
    radial-gradient(circle at 14% 18%, rgba(59, 130, 246, 0.17), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(16, 185, 129, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 54%, #ffffff 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.20);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-countdown-seventeen-course {
  display: grid;
  grid-template-columns: minmax(260px, 0.82fr) minmax(0, 1.18fr);
  gap: clamp(22px, 4vw, 38px);
  align-items: center;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 42px 12px 12px 42px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-countdown-seventeen-preview {
  position: relative;
  min-width: 0;
  min-height: clamp(330px, 42vw, 480px);
  overflow: hidden;
  border-radius: 34px 10px 10px 34px;
  background:
    radial-gradient(circle at 28% 20%, rgba(255,255,255,0.30), transparent 34%),
    linear-gradient(135deg, #1e3a8a 0%, #2563eb 52%, #10b981 100%) !important;
}

.vb-countdown-seventeen-tag {
  position: absolute;
  left: 18px;
  top: 18px;
  z-index: 4;
  display: inline-flex;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  border: 1px solid rgba(255,255,255,0.22);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-seventeen-screen {
  position: absolute;
  left: 50%;
  top: 48%;
  width: min(78%, 310px);
  min-height: 230px;
  transform: translate(-50%, -50%) rotate(-4deg);
  border-radius: 24px;
  background: rgba(255,255,255,0.92);
  box-shadow: 0 28px 76px rgba(15, 23, 42, 0.22);
  overflow: hidden;
}

.vb-countdown-seventeen-screen-top {
  display: flex;
  gap: 7px;
  padding: 14px;
  background: #0f172a;
}

.vb-countdown-seventeen-screen-top i {
  width: 10px;
  height: 10px;
  border-radius: 999px;
  background: #60a5fa;
}

.vb-countdown-seventeen-screen-top i:nth-child(2) {
  background: #34d399;
}

.vb-countdown-seventeen-screen-top i:nth-child(3) {
  background: #facc15;
}

.vb-countdown-seventeen-lines {
  display: grid;
  gap: 14px;
  padding: 24px;
}

.vb-countdown-seventeen-lines span {
  display: block;
  height: 18px;
  border-radius: 999px;
  background: #dbeafe;
}

.vb-countdown-seventeen-lines span:nth-child(1) {
  width: 84%;
}

.vb-countdown-seventeen-lines span:nth-child(2) {
  width: 62%;
  background: #bbf7d0;
}

.vb-countdown-seventeen-lines span:nth-child(3) {
  width: 74%;
  background: #e0e7ff;
}

.vb-countdown-seventeen-module {
  position: absolute;
  left: 24px;
  right: 24px;
  bottom: 24px;
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: center;
  padding: 16px;
  border-radius: 22px;
  background: rgba(15, 23, 42, 0.72);
  border: 1px solid rgba(255,255,255,0.14);
  backdrop-filter: blur(12px);
}

.vb-countdown-seventeen-module strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-countdown-seventeen-module span {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-seventeen-content {
  min-width: 0;
  padding: clamp(10px, 2vw, 18px);
}

.vb-countdown-seventeen-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px 999px 999px 4px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-seventeen-content h3 {
  max-width: 760px;
  margin: 0 0 16px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5.8vw, 76px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
  overflow-wrap: anywhere;
}

.vb-countdown-seventeen-content p {
  max-width: 680px;
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-seventeen-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 18px;
}

.vb-countdown-seventeen-meta span {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: #f1f5f9;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-seventeen-timer {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(8px, 1.4vw, 12px);
  margin-bottom: 18px;
}

.vb-countdown-seventeen-timer div {
  min-width: 0;
  padding: clamp(15px, 2.4vw, 20px) 8px;
  border-radius: 10px 24px 10px 24px;
  background: #0f172a;
  text-align: center;
  box-shadow: 0 18px 42px rgba(15, 23, 42, 0.16);
}

.vb-countdown-seventeen-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4.5vw, 50px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-seventeen-timer span {
  display: block;
  color: #93c5fd !important;
  -webkit-text-fill-color: #93c5fd !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-seventeen-status {
  margin-bottom: 18px !important;
}

.vb-countdown-seventeen-content a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 14px 20px;
  border-radius: 999px 999px 999px 8px;
  background: linear-gradient(135deg, #2563eb, #10b981);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(37, 99, 235, 0.22);
}

@media (max-width: 920px) {
  .vb-countdown-seventeen-course {
    grid-template-columns: 1fr;
  }

  .vb-countdown-seventeen-preview {
    border-radius: 30px 10px 10px 30px;
  }
}

@media (max-width: 640px) {
  .vb-countdown-seventeen-demo {
    border-radius: 34px 12px 12px 34px;
  }

  .vb-countdown-seventeen-course {
    border-radius: 28px 10px 10px 28px;
  }

  .vb-countdown-seventeen-content h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-seventeen-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-seventeen-timer strong {
    font-size: clamp(30px, 13vw, 46px);
  }

  .vb-countdown-seventeen-content a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-seventeen-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This course enrollment countdown timer is useful for online course landing pages, academy websites, cohort launches, coaching programs, training pages, course discounts, and enrollment deadline sections.</p>



<h2 class="wp-block-heading">18. Booking Deadline Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A booking deadline countdown timer</strong> is useful for hotel bookings, appointment pages, travel packages, event reservations, restaurant bookings, consultation pages, service businesses, and limited booking windows where visitors need to reserve before a deadline.</p>



<p class="wp-block-paragraph">This example uses a booking-focused layout with a calendar-inspired side panel, deadline notice, availability cards, countdown display, and reservation button. The JavaScript uses a repeating 72-hour booking window, so the demo keeps working and never remains expired.</p>



<ul class="wp-block-list">
<li>Booking deadline countdown timer</li>
<li>Reservation and availability layout</li>
<li>Days, hours, minutes, and seconds</li>
<li>Repeating booking deadline window</li>
<li>Responsive service booking section</li>
</ul>



<div class="vb-countdown-eighteen-demo">
  <section class="vb-countdown-eighteen-booking" data-vb-countdown-eighteen data-duration="259200">
    <div class="vb-countdown-eighteen-calendar">
      <span>Example 18</span>
      <strong data-calendar-day>--</strong>
      <small data-calendar-month>Booking</small>
    </div>

    <div class="vb-countdown-eighteen-content">
      <div class="vb-countdown-eighteen-label">Reservation Deadline</div>
      <h3>Booking Deadline Countdown Timer</h3>
      <p>Use this countdown timer for appointments, hotel bookings, travel deals, restaurant reservations, event bookings, and service-based landing pages.</p>

      <div class="vb-countdown-eighteen-availability">
        <div>
          <strong>6 slots</strong>
          <span>Available today</span>
        </div>
        <div>
          <strong>24h</strong>
          <span>Response time</span>
        </div>
      </div>
    </div>

    <aside class="vb-countdown-eighteen-panel">
      <span data-status>Booking deadline active</span>

      <div class="vb-countdown-eighteen-timer" aria-label="Booking deadline countdown timer">
        <div>
          <strong data-days>00</strong>
          <span>Days</span>
        </div>

        <div>
          <strong data-hours>00</strong>
          <span>Hours</span>
        </div>

        <div>
          <strong data-minutes>00</strong>
          <span>Min</span>
        </div>

        <div>
          <strong data-seconds>00</strong>
          <span>Sec</span>
        </div>
      </div>

      <a href="#booking-deadline">Reserve Booking</a>
    </aside>
  </section>
</div>

<style>
.vb-countdown-eighteen-demo,
.vb-countdown-eighteen-demo * {
  box-sizing: border-box;
}

.vb-countdown-eighteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 14px 50px 50px 14px;
  background:
    radial-gradient(circle at 16% 20%, rgba(14, 165, 233, 0.16), transparent 34%),
    radial-gradient(circle at 88% 24%, rgba(245, 158, 11, 0.14), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #fffbeb 52%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.20);
  box-shadow: 0 28px 80px rgba(3, 105, 161, 0.09);
}

.vb-countdown-eighteen-booking {
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr) minmax(260px, 360px);
  gap: clamp(18px, 3vw, 26px);
  align-items: stretch;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(14px, 2vw, 18px);
  border-radius: 10px 38px 38px 10px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-countdown-eighteen-calendar {
  display: grid;
  place-items: center;
  align-content: center;
  gap: 10px;
  min-width: 0;
  min-height: 340px;
  border-radius: 8px 28px 28px 8px;
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.25), transparent 34%),
    linear-gradient(135deg, #0369a1 0%, #0ea5e9 52%, #f59e0b 100%) !important;
  color: #ffffff;
}

.vb-countdown-eighteen-calendar span {
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-eighteen-calendar strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(54px, 8vw, 88px);
  line-height: 0.85;
  font-weight: 950;
  letter-spacing: -0.07em;
  font-variant-numeric: tabular-nums;
}

.vb-countdown-eighteen-calendar small {
  color: #fff7ed !important;
  -webkit-text-fill-color: #fff7ed !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-countdown-eighteen-content {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
  padding: clamp(18px, 3vw, 28px) 6px;
}

.vb-countdown-eighteen-label {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 8px 999px 999px 8px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-eighteen-content h3 {
  max-width: 740px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5.5vw, 70px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-countdown-eighteen-content p {
  max-width: 680px;
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.72;
  font-weight: 650;
}

.vb-countdown-eighteen-availability {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 180px));
  gap: 12px;
}

.vb-countdown-eighteen-availability div {
  min-width: 0;
  padding: 16px;
  border-radius: 20px 8px 20px 8px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.18);
}

.vb-countdown-eighteen-availability strong {
  display: block;
  margin-bottom: 6px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 28px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-countdown-eighteen-availability span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-eighteen-panel {
  display: grid;
  align-content: center;
  gap: 16px;
  min-width: 0;
  padding: clamp(20px, 3vw, 26px);
  border-radius: 32px;
  background:
    radial-gradient(circle at 24% 16%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #075985 54%, #0c4a6e 100%) !important;
  box-shadow: 0 24px 70px rgba(3, 105, 161, 0.18);
}

.vb-countdown-eighteen-panel > span {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-eighteen-timer {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.vb-countdown-eighteen-timer div {
  min-width: 0;
  padding: 16px 8px;
  border-radius: 20px 6px 20px 6px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.13);
  text-align: center;
}

.vb-countdown-eighteen-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 6vw, 48px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-eighteen-timer span {
  display: block;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-eighteen-panel a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #0ea5e9, #f59e0b);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(14, 165, 233, 0.22);
}

@media (max-width: 980px) {
  .vb-countdown-eighteen-booking {
    grid-template-columns: 130px minmax(0, 1fr);
  }

  .vb-countdown-eighteen-panel {
    grid-column: 1 / -1;
  }

  .vb-countdown-eighteen-timer {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (max-width: 700px) {
  .vb-countdown-eighteen-booking {
    grid-template-columns: 1fr;
  }

  .vb-countdown-eighteen-calendar {
    min-height: 190px;
    border-radius: 8px 24px 24px 8px;
  }

  .vb-countdown-eighteen-content h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-eighteen-availability {
    grid-template-columns: 1fr;
  }

  .vb-countdown-eighteen-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-eighteen-panel a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-eighteen-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-eighteen]");
  if (!timer) return;

  const duration = Number(timer.getAttribute("data-duration")) || 259200;
  let remaining = duration;

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");
  const calendarDayEl = timer.querySelector("[data-calendar-day]");
  const calendarMonthEl = timer.querySelector("[data-calendar-month]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function updateCalendarPreview() {
    const deadline = new Date(Date.now() + remaining * 1000);
    calendarDayEl.textContent = formatNumber(deadline.getDate());
    calendarMonthEl.textContent = deadline.toLocaleString("en-US", { month: "short" });
  }

  function updateCountdown() {
    if (remaining <= 0) {
      remaining = duration;
    }

    const days = Math.floor(remaining / 86400);
    const hours = Math.floor((remaining / 3600) % 24);
    const minutes = Math.floor((remaining / 60) % 60);
    const seconds = remaining % 60;

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    statusEl.textContent = "Booking deadline active";

    updateCalendarPreview();
    remaining -= 1;
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-eighteen]");
  if (!timer) return;

  const duration = Number(timer.getAttribute("data-duration")) || 259200;
  let remaining = duration;

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");
  const calendarDayEl = timer.querySelector("[data-calendar-day]");
  const calendarMonthEl = timer.querySelector("[data-calendar-month]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function updateCalendarPreview() {
    const deadline = new Date(Date.now() + remaining * 1000);
    calendarDayEl.textContent = formatNumber(deadline.getDate());
    calendarMonthEl.textContent = deadline.toLocaleString("en-US", { month: "short" });
  }

  function updateCountdown() {
    if (remaining &lt;= 0) {
      remaining = duration;
    }

    const days = Math.floor(remaining / 86400);
    const hours = Math.floor((remaining / 3600) % 24);
    const minutes = Math.floor((remaining / 60) % 60);
    const seconds = remaining % 60;

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    statusEl.textContent = "Booking deadline active";

    updateCalendarPreview();
    remaining -= 1;
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-eighteen-demo"&gt;
  &lt;section class="vb-countdown-eighteen-booking" data-vb-countdown-eighteen data-duration="259200"&gt;
    &lt;div class="vb-countdown-eighteen-calendar"&gt;
      &lt;span&gt;Example 18&lt;/span&gt;
      &lt;strong data-calendar-day&gt;--&lt;/strong&gt;
      &lt;small data-calendar-month&gt;Booking&lt;/small&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-eighteen-content"&gt;
      &lt;div class="vb-countdown-eighteen-label"&gt;Reservation Deadline&lt;/div&gt;
      &lt;h3&gt;Booking Deadline Countdown Timer&lt;/h3&gt;
      &lt;p&gt;Use this countdown timer for appointments, hotel bookings, travel deals, restaurant reservations, event bookings, and service-based landing pages.&lt;/p&gt;

      &lt;div class="vb-countdown-eighteen-availability"&gt;
        &lt;div&gt;
          &lt;strong&gt;6 slots&lt;/strong&gt;
          &lt;span&gt;Available today&lt;/span&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;strong&gt;24h&lt;/strong&gt;
          &lt;span&gt;Response time&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;aside class="vb-countdown-eighteen-panel"&gt;
      &lt;span data-status&gt;Booking deadline active&lt;/span&gt;

      &lt;div class="vb-countdown-eighteen-timer" aria-label="Booking deadline countdown timer"&gt;
        &lt;div&gt;
          &lt;strong data-days&gt;00&lt;/strong&gt;
          &lt;span&gt;Days&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-hours&gt;00&lt;/strong&gt;
          &lt;span&gt;Hours&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
          &lt;span&gt;Min&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
          &lt;span&gt;Sec&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;a href="#booking-deadline"&gt;Reserve Booking&lt;/a&gt;
    &lt;/aside&gt;
  &lt;/section&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-eighteen-demo,
.vb-countdown-eighteen-demo * {
  box-sizing: border-box;
}

.vb-countdown-eighteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 14px 50px 50px 14px;
  background:
    radial-gradient(circle at 16% 20%, rgba(14, 165, 233, 0.16), transparent 34%),
    radial-gradient(circle at 88% 24%, rgba(245, 158, 11, 0.14), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #fffbeb 52%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.20);
  box-shadow: 0 28px 80px rgba(3, 105, 161, 0.09);
}

.vb-countdown-eighteen-booking {
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr) minmax(260px, 360px);
  gap: clamp(18px, 3vw, 26px);
  align-items: stretch;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(14px, 2vw, 18px);
  border-radius: 10px 38px 38px 10px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-countdown-eighteen-calendar {
  display: grid;
  place-items: center;
  align-content: center;
  gap: 10px;
  min-width: 0;
  min-height: 340px;
  border-radius: 8px 28px 28px 8px;
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.25), transparent 34%),
    linear-gradient(135deg, #0369a1 0%, #0ea5e9 52%, #f59e0b 100%) !important;
  color: #ffffff;
}

.vb-countdown-eighteen-calendar span {
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-eighteen-calendar strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(54px, 8vw, 88px);
  line-height: 0.85;
  font-weight: 950;
  letter-spacing: -0.07em;
  font-variant-numeric: tabular-nums;
}

.vb-countdown-eighteen-calendar small {
  color: #fff7ed !important;
  -webkit-text-fill-color: #fff7ed !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-countdown-eighteen-content {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-width: 0;
  padding: clamp(18px, 3vw, 28px) 6px;
}

.vb-countdown-eighteen-label {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 8px 999px 999px 8px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-eighteen-content h3 {
  max-width: 740px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5.5vw, 70px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-countdown-eighteen-content p {
  max-width: 680px;
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.72;
  font-weight: 650;
}

.vb-countdown-eighteen-availability {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 180px));
  gap: 12px;
}

.vb-countdown-eighteen-availability div {
  min-width: 0;
  padding: 16px;
  border-radius: 20px 8px 20px 8px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.18);
}

.vb-countdown-eighteen-availability strong {
  display: block;
  margin-bottom: 6px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 28px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-countdown-eighteen-availability span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-eighteen-panel {
  display: grid;
  align-content: center;
  gap: 16px;
  min-width: 0;
  padding: clamp(20px, 3vw, 26px);
  border-radius: 32px;
  background:
    radial-gradient(circle at 24% 16%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #075985 54%, #0c4a6e 100%) !important;
  box-shadow: 0 24px 70px rgba(3, 105, 161, 0.18);
}

.vb-countdown-eighteen-panel > span {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-eighteen-timer {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.vb-countdown-eighteen-timer div {
  min-width: 0;
  padding: 16px 8px;
  border-radius: 20px 6px 20px 6px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.13);
  text-align: center;
}

.vb-countdown-eighteen-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 6vw, 48px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-eighteen-timer span {
  display: block;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-eighteen-panel a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #0ea5e9, #f59e0b);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(14, 165, 233, 0.22);
}

@media (max-width: 980px) {
  .vb-countdown-eighteen-booking {
    grid-template-columns: 130px minmax(0, 1fr);
  }

  .vb-countdown-eighteen-panel {
    grid-column: 1 / -1;
  }

  .vb-countdown-eighteen-timer {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (max-width: 700px) {
  .vb-countdown-eighteen-booking {
    grid-template-columns: 1fr;
  }

  .vb-countdown-eighteen-calendar {
    min-height: 190px;
    border-radius: 8px 24px 24px 8px;
  }

  .vb-countdown-eighteen-content h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-eighteen-availability {
    grid-template-columns: 1fr;
  }

  .vb-countdown-eighteen-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-eighteen-panel a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-eighteen-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This booking deadline countdown timer is useful for appointment booking pages, hotel deals, restaurant reservation sections, travel packages, event booking pages, service websites, and limited reservation campaigns.</p>



<h2 class="wp-block-heading">19. Auction Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>An auction countdown timer</strong> is useful for bidding pages, marketplace auctions, NFT-style listings, collectible sales, product auctions, ticket auctions, and limited bidding windows where visitors need to place a bid before time runs out.</p>



<p class="wp-block-paragraph">This example uses a bidding-focused auction layout with a current bid panel, bidder activity cards, countdown blocks, and a strong bid CTA. The JavaScript uses a repeating 48-hour auction window, so the demo keeps working and never remains stopped at zero.</p>



<ul class="wp-block-list">
<li>Auction countdown timer</li>
<li>Current bid and bidder layout</li>
<li>Days, hours, minutes, and seconds</li>
<li>Repeating auction window</li>
<li>Responsive marketplace auction section</li>
</ul>



<div class="vb-countdown-nineteen-demo">
  <section class="vb-countdown-nineteen-auction" data-vb-countdown-nineteen data-duration="172800">
    <div class="vb-countdown-nineteen-item">
      <span class="vb-countdown-nineteen-kicker">Example 19</span>
      <h3>Auction Countdown Timer</h3>
      <p>Use this countdown timer for auction listings, bidding pages, marketplace offers, collectible drops, limited product auctions, and high-value sale pages.</p>

      <div class="vb-countdown-nineteen-bid">
        <span>Current Bid</span>
        <strong>€1,240</strong>
        <small>18 active bidders</small>
      </div>
    </div>

    <div class="vb-countdown-nineteen-activity">
      <div>
        <span>Top Bidder</span>
        <strong>Buyer #482</strong>
      </div>
      <div>
        <span>Bid Step</span>
        <strong>€25</strong>
      </div>
      <div>
        <span data-status>Live auction active</span>
        <strong>Place your bid</strong>
      </div>
    </div>

    <aside class="vb-countdown-nineteen-panel">
      <strong class="vb-countdown-nineteen-panel-title">Auction ends in</strong>

      <div class="vb-countdown-nineteen-timer" aria-label="Auction countdown timer">
        <div>
          <strong data-days>00</strong>
          <span>Days</span>
        </div>

        <div>
          <strong data-hours>00</strong>
          <span>Hours</span>
        </div>

        <div>
          <strong data-minutes>00</strong>
          <span>Min</span>
        </div>

        <div>
          <strong data-seconds>00</strong>
          <span>Sec</span>
        </div>
      </div>

      <a href="#auction-bid">Place Bid</a>
    </aside>
  </section>
</div>

<style>
.vb-countdown-nineteen-demo,
.vb-countdown-nineteen-demo * {
  box-sizing: border-box;
}

.vb-countdown-nineteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 12px 54px 12px 54px;
  background:
    radial-gradient(circle at 14% 18%, rgba(168, 85, 247, 0.16), transparent 34%),
    radial-gradient(circle at 88% 24%, rgba(251, 191, 36, 0.15), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #fffbeb 54%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.20);
  box-shadow: 0 28px 80px rgba(88, 28, 135, 0.09);
}

.vb-countdown-nineteen-auction {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(220px, 300px) minmax(260px, 340px);
  gap: clamp(18px, 3vw, 26px);
  align-items: stretch;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 10px 42px 10px 42px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.12), transparent 34%),
    linear-gradient(135deg, #1e1b4b 0%, #3b0764 50%, #111827 100%) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
}

.vb-countdown-nineteen-item,
.vb-countdown-nineteen-activity,
.vb-countdown-nineteen-panel {
  min-width: 0;
}

.vb-countdown-nineteen-item {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(18px, 3vw, 28px);
}

.vb-countdown-nineteen-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px 999px 4px 999px;
  background: rgba(251, 191, 36, 0.14);
  border: 1px solid rgba(253, 224, 71, 0.22);
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-nineteen-item h3 {
  max-width: 760px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5.8vw, 78px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
  overflow-wrap: anywhere;
}

.vb-countdown-nineteen-item p {
  max-width: 680px;
  margin: 0 0 22px !important;
  color: #e9d5ff !important;
  -webkit-text-fill-color: #e9d5ff !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-nineteen-bid {
  display: inline-grid;
  gap: 5px;
  align-self: flex-start;
  padding: 18px 20px;
  border-radius: 24px 6px 24px 6px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-countdown-nineteen-bid span,
.vb-countdown-nineteen-bid small {
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 12px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-nineteen-bid strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 48px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vb-countdown-nineteen-activity {
  display: grid;
  gap: 12px;
  align-content: center;
}

.vb-countdown-nineteen-activity div {
  padding: 18px;
  border-radius: 8px 26px 8px 26px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-countdown-nineteen-activity span {
  display: block;
  margin-bottom: 7px;
  color: #c4b5fd !important;
  -webkit-text-fill-color: #c4b5fd !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-nineteen-activity strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(20px, 3vw, 28px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-countdown-nineteen-panel {
  display: grid;
  align-content: center;
  gap: 16px;
  padding: clamp(20px, 3vw, 26px);
  border-radius: 36px 8px 36px 8px;
  background: #ffffff;
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.20);
}

.vb-countdown-nineteen-panel-title {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 24px;
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-countdown-nineteen-timer {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.vb-countdown-nineteen-timer div {
  min-width: 0;
  padding: 16px 8px;
  border-radius: 18px 6px 18px 6px;
  background: #f5f3ff;
  border: 1px solid rgba(168, 85, 247, 0.16);
  text-align: center;
}

.vb-countdown-nineteen-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 5px;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: clamp(30px, 6vw, 48px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-nineteen-timer span {
  display: block;
  color: #7c3aed !important;
  -webkit-text-fill-color: #7c3aed !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-nineteen-panel a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #7c3aed, #f59e0b);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(124, 58, 237, 0.22);
}

@media (max-width: 1050px) {
  .vb-countdown-nineteen-auction {
    grid-template-columns: 1fr 1fr;
  }

  .vb-countdown-nineteen-panel {
    grid-column: 1 / -1;
  }

  .vb-countdown-nineteen-timer {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (max-width: 700px) {
  .vb-countdown-nineteen-auction {
    grid-template-columns: 1fr;
  }

  .vb-countdown-nineteen-item h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-nineteen-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-nineteen-panel a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-nineteen-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-nineteen]");
  if (!timer) return;

  const duration = Number(timer.getAttribute("data-duration")) || 172800;
  let remaining = duration;

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function updateCountdown() {
    if (remaining <= 0) {
      remaining = duration;
    }

    const days = Math.floor(remaining / 86400);
    const hours = Math.floor((remaining / 3600) % 24);
    const minutes = Math.floor((remaining / 60) % 60);
    const seconds = remaining % 60;

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    statusEl.textContent = "Live auction active";

    remaining -= 1;
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-nineteen]");
  if (!timer) return;

  const duration = Number(timer.getAttribute("data-duration")) || 172800;
  let remaining = duration;

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function updateCountdown() {
    if (remaining &lt;= 0) {
      remaining = duration;
    }

    const days = Math.floor(remaining / 86400);
    const hours = Math.floor((remaining / 3600) % 24);
    const minutes = Math.floor((remaining / 60) % 60);
    const seconds = remaining % 60;

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    statusEl.textContent = "Live auction active";

    remaining -= 1;
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-nineteen-demo"&gt;
  &lt;section class="vb-countdown-nineteen-auction" data-vb-countdown-nineteen data-duration="172800"&gt;
    &lt;div class="vb-countdown-nineteen-item"&gt;
      &lt;span class="vb-countdown-nineteen-kicker"&gt;Example 19&lt;/span&gt;
      &lt;h3&gt;Auction Countdown Timer&lt;/h3&gt;
      &lt;p&gt;Use this countdown timer for auction listings, bidding pages, marketplace offers, collectible drops, limited product auctions, and high-value sale pages.&lt;/p&gt;

      &lt;div class="vb-countdown-nineteen-bid"&gt;
        &lt;span&gt;Current Bid&lt;/span&gt;
        &lt;strong&gt;€1,240&lt;/strong&gt;
        &lt;small&gt;18 active bidders&lt;/small&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-nineteen-activity"&gt;
      &lt;div&gt;
        &lt;span&gt;Top Bidder&lt;/span&gt;
        &lt;strong&gt;Buyer #482&lt;/strong&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;span&gt;Bid Step&lt;/span&gt;
        &lt;strong&gt;€25&lt;/strong&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;span data-status&gt;Live auction active&lt;/span&gt;
        &lt;strong&gt;Place your bid&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;aside class="vb-countdown-nineteen-panel"&gt;
      &lt;strong class="vb-countdown-nineteen-panel-title"&gt;Auction ends in&lt;/strong&gt;

      &lt;div class="vb-countdown-nineteen-timer" aria-label="Auction countdown timer"&gt;
        &lt;div&gt;
          &lt;strong data-days&gt;00&lt;/strong&gt;
          &lt;span&gt;Days&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-hours&gt;00&lt;/strong&gt;
          &lt;span&gt;Hours&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
          &lt;span&gt;Min&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
          &lt;span&gt;Sec&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;a href="#auction-bid"&gt;Place Bid&lt;/a&gt;
    &lt;/aside&gt;
  &lt;/section&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-nineteen-demo,
.vb-countdown-nineteen-demo * {
  box-sizing: border-box;
}

.vb-countdown-nineteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 12px 54px 12px 54px;
  background:
    radial-gradient(circle at 14% 18%, rgba(168, 85, 247, 0.16), transparent 34%),
    radial-gradient(circle at 88% 24%, rgba(251, 191, 36, 0.15), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #fffbeb 54%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.20);
  box-shadow: 0 28px 80px rgba(88, 28, 135, 0.09);
}

.vb-countdown-nineteen-auction {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(220px, 300px) minmax(260px, 340px);
  gap: clamp(18px, 3vw, 26px);
  align-items: stretch;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 10px 42px 10px 42px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.12), transparent 34%),
    linear-gradient(135deg, #1e1b4b 0%, #3b0764 50%, #111827 100%) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
}

.vb-countdown-nineteen-item,
.vb-countdown-nineteen-activity,
.vb-countdown-nineteen-panel {
  min-width: 0;
}

.vb-countdown-nineteen-item {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(18px, 3vw, 28px);
}

.vb-countdown-nineteen-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px 999px 4px 999px;
  background: rgba(251, 191, 36, 0.14);
  border: 1px solid rgba(253, 224, 71, 0.22);
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-nineteen-item h3 {
  max-width: 760px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5.8vw, 78px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
  overflow-wrap: anywhere;
}

.vb-countdown-nineteen-item p {
  max-width: 680px;
  margin: 0 0 22px !important;
  color: #e9d5ff !important;
  -webkit-text-fill-color: #e9d5ff !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-nineteen-bid {
  display: inline-grid;
  gap: 5px;
  align-self: flex-start;
  padding: 18px 20px;
  border-radius: 24px 6px 24px 6px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-countdown-nineteen-bid span,
.vb-countdown-nineteen-bid small {
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 12px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-nineteen-bid strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 48px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vb-countdown-nineteen-activity {
  display: grid;
  gap: 12px;
  align-content: center;
}

.vb-countdown-nineteen-activity div {
  padding: 18px;
  border-radius: 8px 26px 8px 26px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-countdown-nineteen-activity span {
  display: block;
  margin-bottom: 7px;
  color: #c4b5fd !important;
  -webkit-text-fill-color: #c4b5fd !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-nineteen-activity strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(20px, 3vw, 28px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-countdown-nineteen-panel {
  display: grid;
  align-content: center;
  gap: 16px;
  padding: clamp(20px, 3vw, 26px);
  border-radius: 36px 8px 36px 8px;
  background: #ffffff;
  box-shadow: 0 24px 70px rgba(0, 0, 0, 0.20);
}

.vb-countdown-nineteen-panel-title {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 24px;
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-countdown-nineteen-timer {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.vb-countdown-nineteen-timer div {
  min-width: 0;
  padding: 16px 8px;
  border-radius: 18px 6px 18px 6px;
  background: #f5f3ff;
  border: 1px solid rgba(168, 85, 247, 0.16);
  text-align: center;
}

.vb-countdown-nineteen-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 5px;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: clamp(30px, 6vw, 48px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-nineteen-timer span {
  display: block;
  color: #7c3aed !important;
  -webkit-text-fill-color: #7c3aed !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-nineteen-panel a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #7c3aed, #f59e0b);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(124, 58, 237, 0.22);
}

@media (max-width: 1050px) {
  .vb-countdown-nineteen-auction {
    grid-template-columns: 1fr 1fr;
  }

  .vb-countdown-nineteen-panel {
    grid-column: 1 / -1;
  }

  .vb-countdown-nineteen-timer {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (max-width: 700px) {
  .vb-countdown-nineteen-auction {
    grid-template-columns: 1fr;
  }

  .vb-countdown-nineteen-item h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-nineteen-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-nineteen-panel a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-nineteen-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This auction countdown timer is useful for bidding pages, marketplace listings, product auctions, collectible sales, event ticket auctions, NFT-style drops, and limited bidding campaigns.</p>



<h2 class="wp-block-heading">20. Donation Campaign Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A donation campaign countdown timer</strong> is useful for nonprofit campaigns, fundraising pages, charity events, community projects, donation drives, awareness campaigns, and goal-based landing pages where supporters need to donate before a campaign deadline.</p>



<p class="wp-block-paragraph">This example uses a donation-focused campaign layout with a fundraising progress bar, goal cards, donor message area, deadline countdown, and donation CTA. The JavaScript uses a repeating 30-day campaign cycle, so the timer keeps working instead of remaining expired.</p>



<ul class="wp-block-list">
<li>Donation campaign countdown timer</li>
<li>Fundraising progress bar</li>
<li>Days, hours, minutes, and seconds</li>
<li>Repeating campaign cycle</li>
<li>Responsive nonprofit landing page section</li>
</ul>



<div class="vb-countdown-twenty-demo">
  <section class="vb-countdown-twenty-donation" data-vb-countdown-twenty data-cycle-days="30">
    <div class="vb-countdown-twenty-content">
      <span class="vb-countdown-twenty-kicker">Example 20</span>
      <h3>Donation Campaign Countdown Timer</h3>
      <p>Use this countdown timer for nonprofit fundraising pages, charity campaigns, donation drives, awareness events, community projects, and goal-based campaign pages.</p>

      <div class="vb-countdown-twenty-progress">
        <div class="vb-countdown-twenty-progress-head">
          <strong>€18,450 raised</strong>
          <span>Goal: €25,000</span>
        </div>
        <div class="vb-countdown-twenty-progress-bar">
          <i></i>
        </div>
      </div>

      <div class="vb-countdown-twenty-stats">
        <div>
          <strong>428</strong>
          <span>Supporters</span>
        </div>
        <div>
          <strong>74%</strong>
          <span>Funded</span>
        </div>
        <div>
          <strong data-next-campaign>Campaign active</strong>
          <span>Deadline</span>
        </div>
      </div>
    </div>

    <aside class="vb-countdown-twenty-panel">
      <span data-status>Donation window active</span>

      <div class="vb-countdown-twenty-timer" aria-label="Donation campaign countdown timer">
        <div>
          <strong data-days>00</strong>
          <span>Days</span>
        </div>

        <div>
          <strong data-hours>00</strong>
          <span>Hours</span>
        </div>

        <div>
          <strong data-minutes>00</strong>
          <span>Min</span>
        </div>

        <div>
          <strong data-seconds>00</strong>
          <span>Sec</span>
        </div>
      </div>

      <p>Every contribution helps move this campaign closer to its goal before the current deadline.</p>
      <a href="#donate-now">Donate Now</a>
    </aside>
  </section>
</div>

<style>
.vb-countdown-twenty-demo,
.vb-countdown-twenty-demo * {
  box-sizing: border-box;
}

.vb-countdown-twenty-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 48px 12px 48px 12px;
  background:
    radial-gradient(circle at 14% 18%, rgba(20, 184, 166, 0.16), transparent 34%),
    radial-gradient(circle at 88% 22%, rgba(34, 197, 94, 0.14), transparent 34%),
    linear-gradient(135deg, #f0fdfa 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.20);
  box-shadow: 0 28px 80px rgba(15, 118, 110, 0.09);
}

.vb-countdown-twenty-donation {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(270px, 380px);
  gap: clamp(20px, 3vw, 30px);
  align-items: stretch;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 38px 10px 38px 10px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-countdown-twenty-content {
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.vb-countdown-twenty-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px 999px 4px 999px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twenty-content h3 {
  max-width: 780px;
  margin: 0 0 16px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5.8vw, 76px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
  overflow-wrap: anywhere;
}

.vb-countdown-twenty-content p {
  max-width: 720px;
  margin: 0 0 24px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-twenty-progress {
  max-width: 720px;
  margin-bottom: 18px;
  padding: 18px;
  border-radius: 24px 8px 24px 8px;
  background: #f0fdfa;
  border: 1px solid rgba(20, 184, 166, 0.18);
}

.vb-countdown-twenty-progress-head {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.vb-countdown-twenty-progress-head strong {
  color: #134e4a !important;
  -webkit-text-fill-color: #134e4a !important;
  font-size: 18px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-countdown-twenty-progress-head span {
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-countdown-twenty-progress-bar {
  overflow: hidden;
  height: 14px;
  border-radius: 999px;
  background: #ccfbf1;
}

.vb-countdown-twenty-progress-bar i {
  display: block;
  width: 74%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #14b8a6, #22c55e) !important;
}

.vb-countdown-twenty-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  max-width: 720px;
}

.vb-countdown-twenty-stats div {
  min-width: 0;
  padding: 16px;
  border-radius: 20px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.18);
}

.vb-countdown-twenty-stats strong {
  display: block;
  margin-bottom: 6px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(20px, 3vw, 30px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
  overflow-wrap: anywhere;
}

.vb-countdown-twenty-stats span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-twenty-panel {
  display: grid;
  align-content: center;
  gap: 16px;
  min-width: 0;
  padding: clamp(20px, 3vw, 26px);
  border-radius: 8px 34px 8px 34px;
  background:
    radial-gradient(circle at 24% 16%, rgba(255,255,255,0.15), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #134e4a 56%, #064e3b 100%) !important;
  box-shadow: 0 24px 70px rgba(15, 118, 110, 0.18);
}

.vb-countdown-twenty-panel > span {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(20, 184, 166, 0.14);
  border: 1px solid rgba(94, 234, 212, 0.20);
  color: #99f6e4 !important;
  -webkit-text-fill-color: #99f6e4 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-twenty-timer {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.vb-countdown-twenty-timer div {
  min-width: 0;
  padding: 16px 8px;
  border-radius: 18px 6px 18px 6px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.13);
  text-align: center;
}

.vb-countdown-twenty-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 6vw, 48px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-twenty-timer span {
  display: block;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-twenty-panel p {
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-countdown-twenty-panel a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #14b8a6, #22c55e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(20, 184, 166, 0.22);
}

@media (max-width: 920px) {
  .vb-countdown-twenty-donation {
    grid-template-columns: 1fr;
  }

  .vb-countdown-twenty-timer {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-countdown-twenty-content h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-twenty-progress-head {
    flex-direction: column;
  }

  .vb-countdown-twenty-stats {
    grid-template-columns: 1fr;
  }

  .vb-countdown-twenty-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-twenty-panel a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-twenty-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-twenty]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 30;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-01T09:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextCampaignEl = timer.querySelector("[data-next-campaign]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextCampaignEnd(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextEnd = getNextCampaignEnd(now);
    let remaining = nextEnd - now;

    if (remaining <= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(nextEnd).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextCampaignEl.textContent = "Ends " + dateText;
    statusEl.textContent = "Donation window active";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-twenty]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 30;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-01T09:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextCampaignEl = timer.querySelector("[data-next-campaign]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextCampaignEnd(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextEnd = getNextCampaignEnd(now);
    let remaining = nextEnd - now;

    if (remaining &lt;= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(nextEnd).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextCampaignEl.textContent = "Ends " + dateText;
    statusEl.textContent = "Donation window active";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-twenty-demo"&gt;
  &lt;section class="vb-countdown-twenty-donation" data-vb-countdown-twenty data-cycle-days="30"&gt;
    &lt;div class="vb-countdown-twenty-content"&gt;
      &lt;span class="vb-countdown-twenty-kicker"&gt;Example 20&lt;/span&gt;
      &lt;h3&gt;Donation Campaign Countdown Timer&lt;/h3&gt;
      &lt;p&gt;Use this countdown timer for nonprofit fundraising pages, charity campaigns, donation drives, awareness events, community projects, and goal-based campaign pages.&lt;/p&gt;

      &lt;div class="vb-countdown-twenty-progress"&gt;
        &lt;div class="vb-countdown-twenty-progress-head"&gt;
          &lt;strong&gt;€18,450 raised&lt;/strong&gt;
          &lt;span&gt;Goal: €25,000&lt;/span&gt;
        &lt;/div&gt;
        &lt;div class="vb-countdown-twenty-progress-bar"&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-twenty-stats"&gt;
        &lt;div&gt;
          &lt;strong&gt;428&lt;/strong&gt;
          &lt;span&gt;Supporters&lt;/span&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;strong&gt;74%&lt;/strong&gt;
          &lt;span&gt;Funded&lt;/span&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;strong data-next-campaign&gt;Campaign active&lt;/strong&gt;
          &lt;span&gt;Deadline&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;aside class="vb-countdown-twenty-panel"&gt;
      &lt;span data-status&gt;Donation window active&lt;/span&gt;

      &lt;div class="vb-countdown-twenty-timer" aria-label="Donation campaign countdown timer"&gt;
        &lt;div&gt;
          &lt;strong data-days&gt;00&lt;/strong&gt;
          &lt;span&gt;Days&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-hours&gt;00&lt;/strong&gt;
          &lt;span&gt;Hours&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
          &lt;span&gt;Min&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
          &lt;span&gt;Sec&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;p&gt;Every contribution helps move this campaign closer to its goal before the current deadline.&lt;/p&gt;
      &lt;a href="#donate-now"&gt;Donate Now&lt;/a&gt;
    &lt;/aside&gt;
  &lt;/section&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-twenty-demo,
.vb-countdown-twenty-demo * {
  box-sizing: border-box;
}

.vb-countdown-twenty-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 48px 12px 48px 12px;
  background:
    radial-gradient(circle at 14% 18%, rgba(20, 184, 166, 0.16), transparent 34%),
    radial-gradient(circle at 88% 22%, rgba(34, 197, 94, 0.14), transparent 34%),
    linear-gradient(135deg, #f0fdfa 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.20);
  box-shadow: 0 28px 80px rgba(15, 118, 110, 0.09);
}

.vb-countdown-twenty-donation {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(270px, 380px);
  gap: clamp(20px, 3vw, 30px);
  align-items: stretch;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 38px 10px 38px 10px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-countdown-twenty-content {
  min-width: 0;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.vb-countdown-twenty-kicker {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px 999px 4px 999px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twenty-content h3 {
  max-width: 780px;
  margin: 0 0 16px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5.8vw, 76px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
  overflow-wrap: anywhere;
}

.vb-countdown-twenty-content p {
  max-width: 720px;
  margin: 0 0 24px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-twenty-progress {
  max-width: 720px;
  margin-bottom: 18px;
  padding: 18px;
  border-radius: 24px 8px 24px 8px;
  background: #f0fdfa;
  border: 1px solid rgba(20, 184, 166, 0.18);
}

.vb-countdown-twenty-progress-head {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 12px;
}

.vb-countdown-twenty-progress-head strong {
  color: #134e4a !important;
  -webkit-text-fill-color: #134e4a !important;
  font-size: 18px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-countdown-twenty-progress-head span {
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-countdown-twenty-progress-bar {
  overflow: hidden;
  height: 14px;
  border-radius: 999px;
  background: #ccfbf1;
}

.vb-countdown-twenty-progress-bar i {
  display: block;
  width: 74%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #14b8a6, #22c55e) !important;
}

.vb-countdown-twenty-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
  max-width: 720px;
}

.vb-countdown-twenty-stats div {
  min-width: 0;
  padding: 16px;
  border-radius: 20px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.18);
}

.vb-countdown-twenty-stats strong {
  display: block;
  margin-bottom: 6px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(20px, 3vw, 30px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
  overflow-wrap: anywhere;
}

.vb-countdown-twenty-stats span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-twenty-panel {
  display: grid;
  align-content: center;
  gap: 16px;
  min-width: 0;
  padding: clamp(20px, 3vw, 26px);
  border-radius: 8px 34px 8px 34px;
  background:
    radial-gradient(circle at 24% 16%, rgba(255,255,255,0.15), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #134e4a 56%, #064e3b 100%) !important;
  box-shadow: 0 24px 70px rgba(15, 118, 110, 0.18);
}

.vb-countdown-twenty-panel > span {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(20, 184, 166, 0.14);
  border: 1px solid rgba(94, 234, 212, 0.20);
  color: #99f6e4 !important;
  -webkit-text-fill-color: #99f6e4 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-twenty-timer {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.vb-countdown-twenty-timer div {
  min-width: 0;
  padding: 16px 8px;
  border-radius: 18px 6px 18px 6px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.13);
  text-align: center;
}

.vb-countdown-twenty-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 6vw, 48px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-twenty-timer span {
  display: block;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-twenty-panel p {
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-countdown-twenty-panel a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #14b8a6, #22c55e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(20, 184, 166, 0.22);
}

@media (max-width: 920px) {
  .vb-countdown-twenty-donation {
    grid-template-columns: 1fr;
  }

  .vb-countdown-twenty-timer {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-countdown-twenty-content h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-twenty-progress-head {
    flex-direction: column;
  }

  .vb-countdown-twenty-stats {
    grid-template-columns: 1fr;
  }

  .vb-countdown-twenty-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-twenty-panel a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-twenty-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This donation campaign countdown timer is useful for nonprofit fundraising pages, charity campaigns, donation drives, community projects, awareness events, goal-based landing pages, and campaign deadline sections.</p>



<h2 class="wp-block-heading">21. Maintenance Mode Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A maintenance mode countdown timer</strong> is useful for websites, SaaS dashboards, web apps, hosting panels, admin areas, product platforms, and service pages that need to show when scheduled maintenance will end.</p>



<p class="wp-block-paragraph">This example uses a technical maintenance layout with warning stripes, a system-status panel, uptime cards, terminal-style details, and a bold countdown display. The JavaScript uses a repeating 4-hour maintenance window, so the demo keeps working and never stays expired.</p>



<ul class="wp-block-list">
<li>Maintenance mode countdown timer</li>
<li>System-status style design</li>
<li>Hours, minutes, and seconds</li>
<li>Repeating maintenance window</li>
<li>Responsive technical UI layout</li>
</ul>



<div class="vb-countdown-twentyone-demo">
  <section class="vb-countdown-twentyone-maintenance" data-vb-countdown-twentyone data-duration="14400">
    <div class="vb-countdown-twentyone-header">
      <span class="vb-countdown-twentyone-kicker">Example 21</span>
      <strong data-status>Scheduled maintenance active</strong>
    </div>

    <div class="vb-countdown-twentyone-main">
      <div class="vb-countdown-twentyone-copy">
        <h3>Maintenance Mode Countdown Timer</h3>
        <p>Use this countdown timer for scheduled maintenance pages, SaaS dashboards, hosting panels, app status pages, and service update screens.</p>

        <div class="vb-countdown-twentyone-terminal">
          <span>System notice</span>
          <code>Maintenance window is currently running.</code>
          <code>Services will return after the countdown ends.</code>
          <code>Automatic demo cycle enabled.</code>
        </div>
      </div>

      <div class="vb-countdown-twentyone-panel">
        <div class="vb-countdown-twentyone-timer" aria-label="Maintenance mode countdown timer">
          <div>
            <strong data-hours>00</strong>
            <span>Hours</span>
          </div>

          <div>
            <strong data-minutes>00</strong>
            <span>Minutes</span>
          </div>

          <div>
            <strong data-seconds>00</strong>
            <span>Seconds</span>
          </div>
        </div>

        <div class="vb-countdown-twentyone-metrics">
          <div>
            <strong>99.9%</strong>
            <span>Target uptime</span>
          </div>

          <div>
            <strong>Live</strong>
            <span>Status monitor</span>
          </div>
        </div>
      </div>
    </div>
  </section>
</div>

<style>
.vb-countdown-twentyone-demo,
.vb-countdown-twentyone-demo * {
  box-sizing: border-box;
}

.vb-countdown-twentyone-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 10px;
  background:
    repeating-linear-gradient(135deg, rgba(250, 204, 21, 0.16) 0 12px, rgba(15, 23, 42, 0.04) 12px 24px),
    linear-gradient(135deg, #f8fafc 0%, #fefce8 52%, #ffffff 100%) !important;
  border: 1px solid rgba(234, 179, 8, 0.26);
  box-shadow: 0 28px 80px rgba(113, 63, 18, 0.10);
}

.vb-countdown-twentyone-maintenance {
  max-width: 1160px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 8px;
  background:
    linear-gradient(90deg, rgba(255,255,255,0.04) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.04) 1px, transparent 1px),
    linear-gradient(135deg, #020617 0%, #111827 58%, #292524 100%) !important;
  background-size: 32px 32px, 32px 32px, auto !important;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 30px 90px rgba(2, 6, 23, 0.40);
}

.vb-countdown-twentyone-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 18px;
  background:
    repeating-linear-gradient(135deg, #facc15 0 14px, #111827 14px 28px) !important;
}

.vb-countdown-twentyone-kicker {
  display: inline-flex;
  padding: 8px 12px;
  border-radius: 4px;
  background: #111827;
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twentyone-header > strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  background: #fef3c7;
  padding: 8px 12px;
  border-radius: 4px;
  font-size: 12px;
  font-weight: 950;
  text-align: right;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-countdown-twentyone-main {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 380px);
  gap: clamp(22px, 4vw, 38px);
  align-items: center;
  padding: clamp(24px, 5vw, 48px);
}

.vb-countdown-twentyone-copy,
.vb-countdown-twentyone-panel {
  min-width: 0;
}

.vb-countdown-twentyone-copy h3 {
  max-width: 760px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 78px) !important;
  line-height: 0.88 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
  overflow-wrap: anywhere;
}

.vb-countdown-twentyone-copy p {
  max-width: 680px;
  margin: 0 0 24px !important;
  color: #d1d5db !important;
  -webkit-text-fill-color: #d1d5db !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-twentyone-terminal {
  display: grid;
  gap: 8px;
  max-width: 680px;
  padding: 18px;
  border-radius: 6px;
  background: #020617;
  border: 1px solid rgba(250, 204, 21, 0.22);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.05);
}

.vb-countdown-twentyone-terminal span {
  color: #facc15 !important;
  -webkit-text-fill-color: #facc15 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-twentyone-terminal code {
  display: block;
  white-space: normal;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 13px;
  line-height: 1.5;
  font-weight: 750;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}

.vb-countdown-twentyone-terminal code::before {
  content: "> ";
  color: #facc15;
  -webkit-text-fill-color: #facc15;
}

.vb-countdown-twentyone-panel {
  display: grid;
  gap: 16px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 8px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-countdown-twentyone-timer {
  display: grid;
  gap: 10px;
}

.vb-countdown-twentyone-timer div {
  display: grid;
  grid-template-columns: 90px minmax(0, 1fr);
  align-items: center;
  gap: 16px;
  min-width: 0;
  padding: 16px;
  border-radius: 4px;
  background: #facc15;
  border-left: 8px solid #111827;
}

.vb-countdown-twentyone-timer strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(34px, 6vw, 52px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-twentyone-timer span {
  color: #292524 !important;
  -webkit-text-fill-color: #292524 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-twentyone-metrics {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.vb-countdown-twentyone-metrics div {
  min-width: 0;
  padding: 16px;
  border-radius: 6px;
  background: #020617;
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-countdown-twentyone-metrics strong {
  display: block;
  margin-bottom: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-countdown-twentyone-metrics span {
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 12px;
  font-weight: 850;
}

@media (max-width: 900px) {
  .vb-countdown-twentyone-main {
    grid-template-columns: 1fr;
  }

  .vb-countdown-twentyone-header {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-countdown-twentyone-header > strong {
    text-align: left;
  }
}

@media (max-width: 640px) {
  .vb-countdown-twentyone-copy h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-twentyone-timer div {
    grid-template-columns: 1fr;
    gap: 8px;
  }

  .vb-countdown-twentyone-metrics {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-twentyone]");
  if (!timer) return;

  const duration = Number(timer.getAttribute("data-duration")) || 14400;
  let remaining = duration;

  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function updateCountdown() {
    if (remaining <= 0) {
      remaining = duration;
    }

    const hours = Math.floor(remaining / 3600);
    const minutes = Math.floor((remaining / 60) % 60);
    const seconds = remaining % 60;

    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    statusEl.textContent = "Scheduled maintenance active";

    remaining -= 1;
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-twentyone]");
  if (!timer) return;

  const duration = Number(timer.getAttribute("data-duration")) || 14400;
  let remaining = duration;

  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function updateCountdown() {
    if (remaining &lt;= 0) {
      remaining = duration;
    }

    const hours = Math.floor(remaining / 3600);
    const minutes = Math.floor((remaining / 60) % 60);
    const seconds = remaining % 60;

    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    statusEl.textContent = "Scheduled maintenance active";

    remaining -= 1;
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-twentyone-demo"&gt;
  &lt;section class="vb-countdown-twentyone-maintenance" data-vb-countdown-twentyone data-duration="14400"&gt;
    &lt;div class="vb-countdown-twentyone-header"&gt;
      &lt;span class="vb-countdown-twentyone-kicker"&gt;Example 21&lt;/span&gt;
      &lt;strong data-status&gt;Scheduled maintenance active&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-twentyone-main"&gt;
      &lt;div class="vb-countdown-twentyone-copy"&gt;
        &lt;h3&gt;Maintenance Mode Countdown Timer&lt;/h3&gt;
        &lt;p&gt;Use this countdown timer for scheduled maintenance pages, SaaS dashboards, hosting panels, app status pages, and service update screens.&lt;/p&gt;

        &lt;div class="vb-countdown-twentyone-terminal"&gt;
          &lt;span&gt;System notice&lt;/span&gt;
          &lt;code&gt;Maintenance window is currently running.&lt;/code&gt;
          &lt;code&gt;Services will return after the countdown ends.&lt;/code&gt;
          &lt;code&gt;Automatic demo cycle enabled.&lt;/code&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-twentyone-panel"&gt;
        &lt;div class="vb-countdown-twentyone-timer" aria-label="Maintenance mode countdown timer"&gt;
          &lt;div&gt;
            &lt;strong data-hours&gt;00&lt;/strong&gt;
            &lt;span&gt;Hours&lt;/span&gt;
          &lt;/div&gt;

          &lt;div&gt;
            &lt;strong data-minutes&gt;00&lt;/strong&gt;
            &lt;span&gt;Minutes&lt;/span&gt;
          &lt;/div&gt;

          &lt;div&gt;
            &lt;strong data-seconds&gt;00&lt;/strong&gt;
            &lt;span&gt;Seconds&lt;/span&gt;
          &lt;/div&gt;
        &lt;/div&gt;

        &lt;div class="vb-countdown-twentyone-metrics"&gt;
          &lt;div&gt;
            &lt;strong&gt;99.9%&lt;/strong&gt;
            &lt;span&gt;Target uptime&lt;/span&gt;
          &lt;/div&gt;

          &lt;div&gt;
            &lt;strong&gt;Live&lt;/strong&gt;
            &lt;span&gt;Status monitor&lt;/span&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/section&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-twentyone-demo,
.vb-countdown-twentyone-demo * {
  box-sizing: border-box;
}

.vb-countdown-twentyone-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 10px;
  background:
    repeating-linear-gradient(135deg, rgba(250, 204, 21, 0.16) 0 12px, rgba(15, 23, 42, 0.04) 12px 24px),
    linear-gradient(135deg, #f8fafc 0%, #fefce8 52%, #ffffff 100%) !important;
  border: 1px solid rgba(234, 179, 8, 0.26);
  box-shadow: 0 28px 80px rgba(113, 63, 18, 0.10);
}

.vb-countdown-twentyone-maintenance {
  max-width: 1160px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 8px;
  background:
    linear-gradient(90deg, rgba(255,255,255,0.04) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.04) 1px, transparent 1px),
    linear-gradient(135deg, #020617 0%, #111827 58%, #292524 100%) !important;
  background-size: 32px 32px, 32px 32px, auto !important;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 30px 90px rgba(2, 6, 23, 0.40);
}

.vb-countdown-twentyone-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 14px 18px;
  background:
    repeating-linear-gradient(135deg, #facc15 0 14px, #111827 14px 28px) !important;
}

.vb-countdown-twentyone-kicker {
  display: inline-flex;
  padding: 8px 12px;
  border-radius: 4px;
  background: #111827;
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twentyone-header > strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  background: #fef3c7;
  padding: 8px 12px;
  border-radius: 4px;
  font-size: 12px;
  font-weight: 950;
  text-align: right;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-countdown-twentyone-main {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 380px);
  gap: clamp(22px, 4vw, 38px);
  align-items: center;
  padding: clamp(24px, 5vw, 48px);
}

.vb-countdown-twentyone-copy,
.vb-countdown-twentyone-panel {
  min-width: 0;
}

.vb-countdown-twentyone-copy h3 {
  max-width: 760px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 78px) !important;
  line-height: 0.88 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
  overflow-wrap: anywhere;
}

.vb-countdown-twentyone-copy p {
  max-width: 680px;
  margin: 0 0 24px !important;
  color: #d1d5db !important;
  -webkit-text-fill-color: #d1d5db !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-twentyone-terminal {
  display: grid;
  gap: 8px;
  max-width: 680px;
  padding: 18px;
  border-radius: 6px;
  background: #020617;
  border: 1px solid rgba(250, 204, 21, 0.22);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.05);
}

.vb-countdown-twentyone-terminal span {
  color: #facc15 !important;
  -webkit-text-fill-color: #facc15 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-twentyone-terminal code {
  display: block;
  white-space: normal;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 13px;
  line-height: 1.5;
  font-weight: 750;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}

.vb-countdown-twentyone-terminal code::before {
  content: "&gt; ";
  color: #facc15;
  -webkit-text-fill-color: #facc15;
}

.vb-countdown-twentyone-panel {
  display: grid;
  gap: 16px;
  padding: clamp(18px, 3vw, 24px);
  border-radius: 8px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-countdown-twentyone-timer {
  display: grid;
  gap: 10px;
}

.vb-countdown-twentyone-timer div {
  display: grid;
  grid-template-columns: 90px minmax(0, 1fr);
  align-items: center;
  gap: 16px;
  min-width: 0;
  padding: 16px;
  border-radius: 4px;
  background: #facc15;
  border-left: 8px solid #111827;
}

.vb-countdown-twentyone-timer strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(34px, 6vw, 52px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-twentyone-timer span {
  color: #292524 !important;
  -webkit-text-fill-color: #292524 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-twentyone-metrics {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.vb-countdown-twentyone-metrics div {
  min-width: 0;
  padding: 16px;
  border-radius: 6px;
  background: #020617;
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-countdown-twentyone-metrics strong {
  display: block;
  margin-bottom: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-countdown-twentyone-metrics span {
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 12px;
  font-weight: 850;
}

@media (max-width: 900px) {
  .vb-countdown-twentyone-main {
    grid-template-columns: 1fr;
  }

  .vb-countdown-twentyone-header {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-countdown-twentyone-header > strong {
    text-align: left;
  }
}

@media (max-width: 640px) {
  .vb-countdown-twentyone-copy h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-twentyone-timer div {
    grid-template-columns: 1fr;
    gap: 8px;
  }

  .vb-countdown-twentyone-metrics {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This maintenance mode countdown timer is useful for website maintenance pages, SaaS status pages, hosting dashboards, update screens, app downtime notices, and scheduled service interruption messages.</p>



<h2 class="wp-block-heading">22. App Download Launch Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>An app download launch countdown timer</strong> is useful for mobile app landing pages, startup launches, app store campaigns, waitlist pages, beta launch pages, product preview pages, and app promotion sections.</p>



<p class="wp-block-paragraph">This example uses a mobile app launch layout with a phone mockup, floating app cards, download buttons, launch badges, and a soft gradient countdown panel. The JavaScript uses a repeating 18-day launch cycle, so the timer keeps working far into the future.</p>



<ul class="wp-block-list">
<li>App download launch countdown timer</li>
<li>Mobile app landing page design</li>
<li>Days, hours, minutes, and seconds</li>
<li>Phone mockup with app UI cards</li>
<li>Responsive app launch section</li>
</ul>



<div class="vb-countdown-twentytwo-demo">
  <section class="vb-countdown-twentytwo-app" data-vb-countdown-twentytwo data-cycle-days="18">
    <div class="vb-countdown-twentytwo-phone-wrap">
      <div class="vb-countdown-twentytwo-phone">
        <div class="vb-countdown-twentytwo-notch"></div>
        <div class="vb-countdown-twentytwo-appicon">A</div>
        <div class="vb-countdown-twentytwo-card vb-countdown-twentytwo-card-one">
          <span>Launch</span>
          <strong>Soon</strong>
        </div>
        <div class="vb-countdown-twentytwo-card vb-countdown-twentytwo-card-two">
          <span>Users</span>
          <strong>24k</strong>
        </div>
        <div class="vb-countdown-twentytwo-bars">
          <i></i>
          <i></i>
          <i></i>
        </div>
      </div>
    </div>

    <div class="vb-countdown-twentytwo-content">
      <span class="vb-countdown-twentytwo-kicker">Example 22</span>
      <h3>App Download Launch Countdown Timer</h3>
      <p>Use this countdown timer for mobile app launch pages, beta release campaigns, app store waitlists, SaaS apps, startup products, and download landing pages.</p>

      <div class="vb-countdown-twentytwo-badges">
        <span>iOS and Android</span>
        <span>Early access</span>
        <span data-next-launch>Next launch loading</span>
      </div>

      <div class="vb-countdown-twentytwo-timer" aria-label="App download launch countdown timer">
        <div>
          <strong data-days>00</strong>
          <span>Days</span>
        </div>

        <div>
          <strong data-hours>00</strong>
          <span>Hours</span>
        </div>

        <div>
          <strong data-minutes>00</strong>
          <span>Min</span>
        </div>

        <div>
          <strong data-seconds>00</strong>
          <span>Sec</span>
        </div>
      </div>

      <p class="vb-countdown-twentytwo-status" data-status>App launch countdown is active.</p>

      <div class="vb-countdown-twentytwo-buttons">
        <a href="#app-store">App Store</a>
        <a href="#google-play">Google Play</a>
      </div>
    </div>
  </section>
</div>

<style>
.vb-countdown-twentytwo-demo,
.vb-countdown-twentytwo-demo * {
  box-sizing: border-box;
}

.vb-countdown-twentytwo-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 60px 60px 18px 18px;
  background:
    radial-gradient(circle at 18% 20%, rgba(236, 72, 153, 0.18), transparent 34%),
    radial-gradient(circle at 84% 20%, rgba(59, 130, 246, 0.18), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #eff6ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(236, 72, 153, 0.18);
  box-shadow: 0 28px 80px rgba(157, 23, 77, 0.09);
}

.vb-countdown-twentytwo-app {
  position: relative;
  display: grid;
  grid-template-columns: minmax(260px, 0.78fr) minmax(0, 1.22fr);
  gap: clamp(24px, 5vw, 46px);
  align-items: center;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(24px, 5vw, 52px);
  overflow: hidden;
  border-radius: 46px 46px 14px 14px;
  background:
    radial-gradient(circle at 20% 20%, rgba(255,255,255,0.22), transparent 34%),
    linear-gradient(135deg, #831843 0%, #4f46e5 52%, #0f172a 100%) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.26);
}

.vb-countdown-twentytwo-app::before {
  content: "";
  position: absolute;
  right: -130px;
  top: -110px;
  width: 360px;
  height: 360px;
  border-radius: 44% 56% 64% 36%;
  background: rgba(147, 197, 253, 0.16);
}

.vb-countdown-twentytwo-app::after {
  content: "";
  position: absolute;
  left: 32%;
  bottom: -140px;
  width: 300px;
  height: 300px;
  border-radius: 70% 30% 48% 52%;
  background: rgba(244, 114, 182, 0.14);
}

.vb-countdown-twentytwo-phone-wrap,
.vb-countdown-twentytwo-content {
  position: relative;
  z-index: 2;
  min-width: 0;
}

.vb-countdown-twentytwo-phone-wrap {
  display: grid;
  place-items: center;
}

.vb-countdown-twentytwo-phone {
  position: relative;
  width: min(100%, 300px);
  aspect-ratio: 0.56 / 1;
  border-radius: 38px;
  background:
    radial-gradient(circle at 50% 16%, rgba(255,255,255,0.18), transparent 28%),
    linear-gradient(160deg, #020617 0%, #111827 48%, #312e81 100%) !important;
  border: 10px solid rgba(255,255,255,0.18);
  box-shadow:
    0 34px 90px rgba(2, 6, 23, 0.40),
    inset 0 1px 0 rgba(255,255,255,0.10);
  transform: rotate(-4deg);
}

.vb-countdown-twentytwo-notch {
  position: absolute;
  left: 50%;
  top: 12px;
  width: 96px;
  height: 24px;
  border-radius: 999px;
  background: #020617;
  transform: translateX(-50%);
}

.vb-countdown-twentytwo-appicon {
  position: absolute;
  left: 50%;
  top: 70px;
  display: grid;
  place-items: center;
  width: 84px;
  height: 84px;
  border-radius: 24px;
  transform: translateX(-50%);
  background: linear-gradient(135deg, #ec4899, #3b82f6);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 42px;
  font-weight: 950;
  box-shadow: 0 20px 44px rgba(236, 72, 153, 0.26);
}

.vb-countdown-twentytwo-card {
  position: absolute;
  display: grid;
  gap: 4px;
  padding: 14px;
  border-radius: 18px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.14);
  backdrop-filter: blur(10px);
}

.vb-countdown-twentytwo-card-one {
  left: 22px;
  right: 22px;
  top: 180px;
}

.vb-countdown-twentytwo-card-two {
  left: 22px;
  right: 22px;
  bottom: 88px;
}

.vb-countdown-twentytwo-card span {
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-twentytwo-card strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 28px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-countdown-twentytwo-bars {
  position: absolute;
  left: 22px;
  right: 22px;
  bottom: 32px;
  display: grid;
  gap: 8px;
}

.vb-countdown-twentytwo-bars i {
  display: block;
  height: 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
}

.vb-countdown-twentytwo-bars i:nth-child(1) {
  width: 86%;
}

.vb-countdown-twentytwo-bars i:nth-child(2) {
  width: 68%;
}

.vb-countdown-twentytwo-bars i:nth-child(3) {
  width: 48%;
}

.vb-countdown-twentytwo-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twentytwo-content h3 {
  max-width: 820px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 82px) !important;
  line-height: 0.88 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
  overflow-wrap: anywhere;
}

.vb-countdown-twentytwo-content p {
  max-width: 690px;
  margin: 0 0 22px !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-twentytwo-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 18px;
}

.vb-countdown-twentytwo-badges span {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.12);
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-twentytwo-timer {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(8px, 1.4vw, 12px);
  max-width: 720px;
  margin-bottom: 18px;
}

.vb-countdown-twentytwo-timer div {
  min-width: 0;
  padding: clamp(15px, 2.5vw, 22px) 8px;
  border-radius: 999px 999px 22px 22px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.14);
  text-align: center;
}

.vb-countdown-twentytwo-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4.6vw, 54px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-twentytwo-timer span {
  display: block;
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-twentytwo-status {
  margin-bottom: 18px !important;
}

.vb-countdown-twentytwo-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.vb-countdown-twentytwo-buttons a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 14px 20px;
  border-radius: 18px;
  background: #ffffff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(15, 23, 42, 0.18);
}

.vb-countdown-twentytwo-buttons a:nth-child(2) {
  background: rgba(255,255,255,0.12);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  border: 1px solid rgba(255,255,255,0.16);
}

@media (max-width: 920px) {
  .vb-countdown-twentytwo-app {
    grid-template-columns: 1fr;
  }

  .vb-countdown-twentytwo-phone {
    max-width: 260px;
  }
}

@media (max-width: 640px) {
  .vb-countdown-twentytwo-demo {
    border-radius: 38px 38px 12px 12px;
  }

  .vb-countdown-twentytwo-app {
    border-radius: 30px 30px 10px 10px;
  }

  .vb-countdown-twentytwo-content h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-twentytwo-phone {
    transform: none;
  }

  .vb-countdown-twentytwo-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-twentytwo-timer strong {
    font-size: clamp(30px, 13vw, 46px);
  }

  .vb-countdown-twentytwo-buttons a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-twentytwo-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-twentytwo]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 18;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-06T10:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextLaunchEl = timer.querySelector("[data-next-launch]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextLaunch(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextLaunch = getNextLaunch(now);
    let remaining = nextLaunch - now;

    if (remaining <= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(nextLaunch).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextLaunchEl.textContent = "Launch window: " + dateText;
    statusEl.textContent = "App launch countdown is active.";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-twentytwo]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 18;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-06T10:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextLaunchEl = timer.querySelector("[data-next-launch]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextLaunch(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextLaunch = getNextLaunch(now);
    let remaining = nextLaunch - now;

    if (remaining &lt;= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(nextLaunch).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextLaunchEl.textContent = "Launch window: " + dateText;
    statusEl.textContent = "App launch countdown is active.";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-twentytwo-demo"&gt;
  &lt;section class="vb-countdown-twentytwo-app" data-vb-countdown-twentytwo data-cycle-days="18"&gt;
    &lt;div class="vb-countdown-twentytwo-phone-wrap"&gt;
      &lt;div class="vb-countdown-twentytwo-phone"&gt;
        &lt;div class="vb-countdown-twentytwo-notch"&gt;&lt;/div&gt;
        &lt;div class="vb-countdown-twentytwo-appicon"&gt;A&lt;/div&gt;
        &lt;div class="vb-countdown-twentytwo-card vb-countdown-twentytwo-card-one"&gt;
          &lt;span&gt;Launch&lt;/span&gt;
          &lt;strong&gt;Soon&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div class="vb-countdown-twentytwo-card vb-countdown-twentytwo-card-two"&gt;
          &lt;span&gt;Users&lt;/span&gt;
          &lt;strong&gt;24k&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div class="vb-countdown-twentytwo-bars"&gt;
          &lt;i&gt;&lt;/i&gt;
          &lt;i&gt;&lt;/i&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-twentytwo-content"&gt;
      &lt;span class="vb-countdown-twentytwo-kicker"&gt;Example 22&lt;/span&gt;
      &lt;h3&gt;App Download Launch Countdown Timer&lt;/h3&gt;
      &lt;p&gt;Use this countdown timer for mobile app launch pages, beta release campaigns, app store waitlists, SaaS apps, startup products, and download landing pages.&lt;/p&gt;

      &lt;div class="vb-countdown-twentytwo-badges"&gt;
        &lt;span&gt;iOS and Android&lt;/span&gt;
        &lt;span&gt;Early access&lt;/span&gt;
        &lt;span data-next-launch&gt;Next launch loading&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-twentytwo-timer" aria-label="App download launch countdown timer"&gt;
        &lt;div&gt;
          &lt;strong data-days&gt;00&lt;/strong&gt;
          &lt;span&gt;Days&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-hours&gt;00&lt;/strong&gt;
          &lt;span&gt;Hours&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
          &lt;span&gt;Min&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
          &lt;span&gt;Sec&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;p class="vb-countdown-twentytwo-status" data-status&gt;App launch countdown is active.&lt;/p&gt;

      &lt;div class="vb-countdown-twentytwo-buttons"&gt;
        &lt;a href="#app-store"&gt;App Store&lt;/a&gt;
        &lt;a href="#google-play"&gt;Google Play&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/section&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-twentytwo-demo,
.vb-countdown-twentytwo-demo * {
  box-sizing: border-box;
}

.vb-countdown-twentytwo-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 60px 60px 18px 18px;
  background:
    radial-gradient(circle at 18% 20%, rgba(236, 72, 153, 0.18), transparent 34%),
    radial-gradient(circle at 84% 20%, rgba(59, 130, 246, 0.18), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #eff6ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(236, 72, 153, 0.18);
  box-shadow: 0 28px 80px rgba(157, 23, 77, 0.09);
}

.vb-countdown-twentytwo-app {
  position: relative;
  display: grid;
  grid-template-columns: minmax(260px, 0.78fr) minmax(0, 1.22fr);
  gap: clamp(24px, 5vw, 46px);
  align-items: center;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(24px, 5vw, 52px);
  overflow: hidden;
  border-radius: 46px 46px 14px 14px;
  background:
    radial-gradient(circle at 20% 20%, rgba(255,255,255,0.22), transparent 34%),
    linear-gradient(135deg, #831843 0%, #4f46e5 52%, #0f172a 100%) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.26);
}

.vb-countdown-twentytwo-app::before {
  content: "";
  position: absolute;
  right: -130px;
  top: -110px;
  width: 360px;
  height: 360px;
  border-radius: 44% 56% 64% 36%;
  background: rgba(147, 197, 253, 0.16);
}

.vb-countdown-twentytwo-app::after {
  content: "";
  position: absolute;
  left: 32%;
  bottom: -140px;
  width: 300px;
  height: 300px;
  border-radius: 70% 30% 48% 52%;
  background: rgba(244, 114, 182, 0.14);
}

.vb-countdown-twentytwo-phone-wrap,
.vb-countdown-twentytwo-content {
  position: relative;
  z-index: 2;
  min-width: 0;
}

.vb-countdown-twentytwo-phone-wrap {
  display: grid;
  place-items: center;
}

.vb-countdown-twentytwo-phone {
  position: relative;
  width: min(100%, 300px);
  aspect-ratio: 0.56 / 1;
  border-radius: 38px;
  background:
    radial-gradient(circle at 50% 16%, rgba(255,255,255,0.18), transparent 28%),
    linear-gradient(160deg, #020617 0%, #111827 48%, #312e81 100%) !important;
  border: 10px solid rgba(255,255,255,0.18);
  box-shadow:
    0 34px 90px rgba(2, 6, 23, 0.40),
    inset 0 1px 0 rgba(255,255,255,0.10);
  transform: rotate(-4deg);
}

.vb-countdown-twentytwo-notch {
  position: absolute;
  left: 50%;
  top: 12px;
  width: 96px;
  height: 24px;
  border-radius: 999px;
  background: #020617;
  transform: translateX(-50%);
}

.vb-countdown-twentytwo-appicon {
  position: absolute;
  left: 50%;
  top: 70px;
  display: grid;
  place-items: center;
  width: 84px;
  height: 84px;
  border-radius: 24px;
  transform: translateX(-50%);
  background: linear-gradient(135deg, #ec4899, #3b82f6);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 42px;
  font-weight: 950;
  box-shadow: 0 20px 44px rgba(236, 72, 153, 0.26);
}

.vb-countdown-twentytwo-card {
  position: absolute;
  display: grid;
  gap: 4px;
  padding: 14px;
  border-radius: 18px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.14);
  backdrop-filter: blur(10px);
}

.vb-countdown-twentytwo-card-one {
  left: 22px;
  right: 22px;
  top: 180px;
}

.vb-countdown-twentytwo-card-two {
  left: 22px;
  right: 22px;
  bottom: 88px;
}

.vb-countdown-twentytwo-card span {
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-twentytwo-card strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 28px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-countdown-twentytwo-bars {
  position: absolute;
  left: 22px;
  right: 22px;
  bottom: 32px;
  display: grid;
  gap: 8px;
}

.vb-countdown-twentytwo-bars i {
  display: block;
  height: 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
}

.vb-countdown-twentytwo-bars i:nth-child(1) {
  width: 86%;
}

.vb-countdown-twentytwo-bars i:nth-child(2) {
  width: 68%;
}

.vb-countdown-twentytwo-bars i:nth-child(3) {
  width: 48%;
}

.vb-countdown-twentytwo-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twentytwo-content h3 {
  max-width: 820px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 82px) !important;
  line-height: 0.88 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
  overflow-wrap: anywhere;
}

.vb-countdown-twentytwo-content p {
  max-width: 690px;
  margin: 0 0 22px !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-twentytwo-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 18px;
}

.vb-countdown-twentytwo-badges span {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.12);
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-twentytwo-timer {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(8px, 1.4vw, 12px);
  max-width: 720px;
  margin-bottom: 18px;
}

.vb-countdown-twentytwo-timer div {
  min-width: 0;
  padding: clamp(15px, 2.5vw, 22px) 8px;
  border-radius: 999px 999px 22px 22px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.14);
  text-align: center;
}

.vb-countdown-twentytwo-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4.6vw, 54px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-twentytwo-timer span {
  display: block;
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-twentytwo-status {
  margin-bottom: 18px !important;
}

.vb-countdown-twentytwo-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.vb-countdown-twentytwo-buttons a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 14px 20px;
  border-radius: 18px;
  background: #ffffff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(15, 23, 42, 0.18);
}

.vb-countdown-twentytwo-buttons a:nth-child(2) {
  background: rgba(255,255,255,0.12);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  border: 1px solid rgba(255,255,255,0.16);
}

@media (max-width: 920px) {
  .vb-countdown-twentytwo-app {
    grid-template-columns: 1fr;
  }

  .vb-countdown-twentytwo-phone {
    max-width: 260px;
  }
}

@media (max-width: 640px) {
  .vb-countdown-twentytwo-demo {
    border-radius: 38px 38px 12px 12px;
  }

  .vb-countdown-twentytwo-app {
    border-radius: 30px 30px 10px 10px;
  }

  .vb-countdown-twentytwo-content h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-twentytwo-phone {
    transform: none;
  }

  .vb-countdown-twentytwo-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-twentytwo-timer strong {
    font-size: clamp(30px, 13vw, 46px);
  }

  .vb-countdown-twentytwo-buttons a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-twentytwo-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This app download launch countdown timer is useful for mobile app landing pages, app store waitlists, startup product launches, beta access campaigns, SaaS app releases, and download promotion sections.</p>



<h2 class="wp-block-heading">23. Preorder Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A preorder countdown timer</strong> is useful for product launch pages, ecommerce preorder campaigns, limited production runs, hardware launches, digital product releases, book launches, and early buyer landing pages. It shows visitors how much time remains before preorder pricing or availability changes.</p>



<p class="wp-block-paragraph">This example uses a premium preorder layout with a product showcase panel, launch badge, price card, preorder benefits, and a large countdown display. The JavaScript uses a repeating 21-day preorder cycle, so the timer keeps working in the future and never stays stopped at zero.</p>



<ul class="wp-block-list">
<li>Preorder countdown timer</li>
<li>Product launch preorder layout</li>
<li>Days, hours, minutes, and seconds</li>
<li>Repeating preorder cycle</li>
<li>Responsive ecommerce launch section</li>
</ul>



<div class="vb-countdown-twentythree-demo">
  <section class="vb-countdown-twentythree-preorder" data-vb-countdown-twentythree data-cycle-days="21">
    <div class="vb-countdown-twentythree-product">
      <span class="vb-countdown-twentythree-tag">Example 23</span>

      <div class="vb-countdown-twentythree-product-card">
        <div class="vb-countdown-twentythree-product-top">
          <i></i>
          <i></i>
        </div>

        <div class="vb-countdown-twentythree-product-shape">
          <span></span>
        </div>

        <div class="vb-countdown-twentythree-price">
          <small>Preorder price</small>
          <strong>€149</strong>
        </div>
      </div>
    </div>

    <div class="vb-countdown-twentythree-content">
      <span class="vb-countdown-twentythree-kicker">Preorder Campaign</span>
      <h3>Preorder Countdown Timer</h3>
      <p>Use this countdown timer for product preorder pages, ecommerce launch campaigns, limited production drops, digital releases, and early buyer offers.</p>

      <div class="vb-countdown-twentythree-benefits">
        <div>
          <strong>Early price</strong>
          <span>Preorder discount active</span>
        </div>

        <div>
          <strong>Limited batch</strong>
          <span>First release quantity</span>
        </div>

        <div>
          <strong data-next-preorder>Next preorder window loading</strong>
          <span>Campaign deadline</span>
        </div>
      </div>

      <div class="vb-countdown-twentythree-timer" aria-label="Preorder countdown timer">
        <div>
          <strong data-days>00</strong>
          <span>Days</span>
        </div>

        <div>
          <strong data-hours>00</strong>
          <span>Hours</span>
        </div>

        <div>
          <strong data-minutes>00</strong>
          <span>Min</span>
        </div>

        <div>
          <strong data-seconds>00</strong>
          <span>Sec</span>
        </div>
      </div>

      <p class="vb-countdown-twentythree-status" data-status>Preorder window is active.</p>

      <a href="#preorder-now">Preorder Now</a>
    </div>
  </section>
</div>

<style>
.vb-countdown-twentythree-demo,
.vb-countdown-twentythree-demo * {
  box-sizing: border-box;
}

.vb-countdown-twentythree-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 18px 18px 62px 18px;
  background:
    radial-gradient(circle at 14% 18%, rgba(251, 146, 60, 0.18), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #eef2ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(251, 146, 60, 0.22);
  box-shadow: 0 28px 80px rgba(124, 45, 18, 0.09);
}

.vb-countdown-twentythree-preorder {
  position: relative;
  display: grid;
  grid-template-columns: minmax(260px, 0.78fr) minmax(0, 1.22fr);
  gap: clamp(24px, 5vw, 46px);
  align-items: center;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(24px, 5vw, 52px);
  overflow: hidden;
  border-radius: 12px 12px 48px 12px;
  background:
    radial-gradient(circle at 22% 22%, rgba(255,255,255,0.20), transparent 34%),
    linear-gradient(135deg, #431407 0%, #9a3412 48%, #312e81 100%) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
}

.vb-countdown-twentythree-preorder::before {
  content: "";
  position: absolute;
  left: -130px;
  bottom: -140px;
  width: 360px;
  height: 360px;
  border-radius: 35% 65% 52% 48%;
  background: rgba(251, 146, 60, 0.16);
}

.vb-countdown-twentythree-preorder::after {
  content: "";
  position: absolute;
  right: -120px;
  top: -120px;
  width: 320px;
  height: 320px;
  border-radius: 68% 32% 42% 58%;
  background: rgba(129, 140, 248, 0.14);
}

.vb-countdown-twentythree-product,
.vb-countdown-twentythree-content {
  position: relative;
  z-index: 2;
  min-width: 0;
}

.vb-countdown-twentythree-product {
  display: grid;
  place-items: center;
}

.vb-countdown-twentythree-tag {
  position: absolute;
  left: 10px;
  top: 10px;
  z-index: 4;
  display: inline-flex;
  padding: 8px 12px;
  border-radius: 999px 999px 999px 4px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.18);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twentythree-product-card {
  position: relative;
  width: min(100%, 340px);
  min-height: 430px;
  border-radius: 22px 54px 22px 54px;
  background:
    radial-gradient(circle at 30% 22%, rgba(255,255,255,0.20), transparent 34%),
    linear-gradient(145deg, rgba(255,255,255,0.14), rgba(255,255,255,0.05)) !important;
  border: 1px solid rgba(255,255,255,0.16);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.32);
  backdrop-filter: blur(14px);
  transform: rotate(3deg);
}

.vb-countdown-twentythree-product-top {
  position: absolute;
  left: 24px;
  right: 24px;
  top: 28px;
  display: flex;
  justify-content: space-between;
}

.vb-countdown-twentythree-product-top i {
  display: block;
  width: 54px;
  height: 14px;
  border-radius: 999px;
  background: rgba(255,255,255,0.18);
}

.vb-countdown-twentythree-product-top i:nth-child(2) {
  width: 34px;
}

.vb-countdown-twentythree-product-shape {
  position: absolute;
  left: 50%;
  top: 48%;
  display: grid;
  place-items: center;
  width: 190px;
  height: 230px;
  border-radius: 42px 18px 42px 18px;
  transform: translate(-50%, -50%) rotate(-9deg);
  background:
    radial-gradient(circle at 28% 20%, rgba(255,255,255,0.34), transparent 32%),
    linear-gradient(135deg, #fb923c, #6366f1) !important;
  box-shadow: 0 30px 70px rgba(2, 6, 23, 0.24);
}

.vb-countdown-twentythree-product-shape span {
  display: block;
  width: 76px;
  height: 76px;
  border-radius: 999px;
  background: rgba(255,255,255,0.28);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-countdown-twentythree-price {
  position: absolute;
  left: 24px;
  right: 24px;
  bottom: 24px;
  display: grid;
  gap: 7px;
  padding: 18px;
  border-radius: 20px 8px 20px 8px;
  background: rgba(2, 6, 23, 0.66);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-countdown-twentythree-price small {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-twentythree-price strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 42px;
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vb-countdown-twentythree-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 6px 999px 999px 6px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twentythree-content h3 {
  max-width: 820px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 82px) !important;
  line-height: 0.88 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
  overflow-wrap: anywhere;
}

.vb-countdown-twentythree-content p {
  max-width: 690px;
  margin: 0 0 22px !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-twentythree-benefits {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
  max-width: 760px;
  margin-bottom: 18px;
}

.vb-countdown-twentythree-benefits div {
  min-width: 0;
  padding: 15px;
  border-radius: 18px 6px 18px 6px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-countdown-twentythree-benefits strong {
  display: block;
  margin-bottom: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  line-height: 1.15;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-countdown-twentythree-benefits span {
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 750;
}

.vb-countdown-twentythree-timer {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(8px, 1.4vw, 12px);
  max-width: 760px;
  margin-bottom: 18px;
}

.vb-countdown-twentythree-timer div {
  min-width: 0;
  padding: clamp(15px, 2.5vw, 22px) 8px;
  border-radius: 8px 26px 8px 26px;
  background: #ffffff;
  text-align: center;
  box-shadow: 0 18px 42px rgba(2, 6, 23, 0.18);
}

.vb-countdown-twentythree-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: clamp(28px, 4.6vw, 54px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-twentythree-timer span {
  display: block;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-twentythree-status {
  margin-bottom: 18px !important;
}

.vb-countdown-twentythree-content a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 14px 20px;
  border-radius: 999px 8px 999px 8px;
  background: linear-gradient(135deg, #fb923c, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(251, 146, 60, 0.22);
}

@media (max-width: 920px) {
  .vb-countdown-twentythree-preorder {
    grid-template-columns: 1fr;
  }

  .vb-countdown-twentythree-product-card {
    transform: none;
  }
}

@media (max-width: 640px) {
  .vb-countdown-twentythree-demo {
    border-radius: 12px 12px 38px 12px;
  }

  .vb-countdown-twentythree-preorder {
    border-radius: 10px 10px 30px 10px;
  }

  .vb-countdown-twentythree-content h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-twentythree-benefits {
    grid-template-columns: 1fr;
  }

  .vb-countdown-twentythree-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-twentythree-timer strong {
    font-size: clamp(30px, 13vw, 46px);
  }

  .vb-countdown-twentythree-content a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-twentythree-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-twentythree]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 21;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-05T13:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextPreorderEl = timer.querySelector("[data-next-preorder]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextPreorderEnd(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextEnd = getNextPreorderEnd(now);
    let remaining = nextEnd - now;

    if (remaining <= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(nextEnd).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextPreorderEl.textContent = "Ends " + dateText;
    statusEl.textContent = "Preorder window is active.";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-twentythree]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 21;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-05T13:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextPreorderEl = timer.querySelector("[data-next-preorder]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextPreorderEnd(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextEnd = getNextPreorderEnd(now);
    let remaining = nextEnd - now;

    if (remaining &lt;= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(nextEnd).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextPreorderEl.textContent = "Ends " + dateText;
    statusEl.textContent = "Preorder window is active.";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-twentythree-demo"&gt;
  &lt;section class="vb-countdown-twentythree-preorder" data-vb-countdown-twentythree data-cycle-days="21"&gt;
    &lt;div class="vb-countdown-twentythree-product"&gt;
      &lt;span class="vb-countdown-twentythree-tag"&gt;Example 23&lt;/span&gt;

      &lt;div class="vb-countdown-twentythree-product-card"&gt;
        &lt;div class="vb-countdown-twentythree-product-top"&gt;
          &lt;i&gt;&lt;/i&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/div&gt;

        &lt;div class="vb-countdown-twentythree-product-shape"&gt;
          &lt;span&gt;&lt;/span&gt;
        &lt;/div&gt;

        &lt;div class="vb-countdown-twentythree-price"&gt;
          &lt;small&gt;Preorder price&lt;/small&gt;
          &lt;strong&gt;€149&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-twentythree-content"&gt;
      &lt;span class="vb-countdown-twentythree-kicker"&gt;Preorder Campaign&lt;/span&gt;
      &lt;h3&gt;Preorder Countdown Timer&lt;/h3&gt;
      &lt;p&gt;Use this countdown timer for product preorder pages, ecommerce launch campaigns, limited production drops, digital releases, and early buyer offers.&lt;/p&gt;

      &lt;div class="vb-countdown-twentythree-benefits"&gt;
        &lt;div&gt;
          &lt;strong&gt;Early price&lt;/strong&gt;
          &lt;span&gt;Preorder discount active&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong&gt;Limited batch&lt;/strong&gt;
          &lt;span&gt;First release quantity&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-next-preorder&gt;Next preorder window loading&lt;/strong&gt;
          &lt;span&gt;Campaign deadline&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-twentythree-timer" aria-label="Preorder countdown timer"&gt;
        &lt;div&gt;
          &lt;strong data-days&gt;00&lt;/strong&gt;
          &lt;span&gt;Days&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-hours&gt;00&lt;/strong&gt;
          &lt;span&gt;Hours&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
          &lt;span&gt;Min&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
          &lt;span&gt;Sec&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;p class="vb-countdown-twentythree-status" data-status&gt;Preorder window is active.&lt;/p&gt;

      &lt;a href="#preorder-now"&gt;Preorder Now&lt;/a&gt;
    &lt;/div&gt;
  &lt;/section&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-twentythree-demo,
.vb-countdown-twentythree-demo * {
  box-sizing: border-box;
}

.vb-countdown-twentythree-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 18px 18px 62px 18px;
  background:
    radial-gradient(circle at 14% 18%, rgba(251, 146, 60, 0.18), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #eef2ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(251, 146, 60, 0.22);
  box-shadow: 0 28px 80px rgba(124, 45, 18, 0.09);
}

.vb-countdown-twentythree-preorder {
  position: relative;
  display: grid;
  grid-template-columns: minmax(260px, 0.78fr) minmax(0, 1.22fr);
  gap: clamp(24px, 5vw, 46px);
  align-items: center;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(24px, 5vw, 52px);
  overflow: hidden;
  border-radius: 12px 12px 48px 12px;
  background:
    radial-gradient(circle at 22% 22%, rgba(255,255,255,0.20), transparent 34%),
    linear-gradient(135deg, #431407 0%, #9a3412 48%, #312e81 100%) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
}

.vb-countdown-twentythree-preorder::before {
  content: "";
  position: absolute;
  left: -130px;
  bottom: -140px;
  width: 360px;
  height: 360px;
  border-radius: 35% 65% 52% 48%;
  background: rgba(251, 146, 60, 0.16);
}

.vb-countdown-twentythree-preorder::after {
  content: "";
  position: absolute;
  right: -120px;
  top: -120px;
  width: 320px;
  height: 320px;
  border-radius: 68% 32% 42% 58%;
  background: rgba(129, 140, 248, 0.14);
}

.vb-countdown-twentythree-product,
.vb-countdown-twentythree-content {
  position: relative;
  z-index: 2;
  min-width: 0;
}

.vb-countdown-twentythree-product {
  display: grid;
  place-items: center;
}

.vb-countdown-twentythree-tag {
  position: absolute;
  left: 10px;
  top: 10px;
  z-index: 4;
  display: inline-flex;
  padding: 8px 12px;
  border-radius: 999px 999px 999px 4px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.18);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twentythree-product-card {
  position: relative;
  width: min(100%, 340px);
  min-height: 430px;
  border-radius: 22px 54px 22px 54px;
  background:
    radial-gradient(circle at 30% 22%, rgba(255,255,255,0.20), transparent 34%),
    linear-gradient(145deg, rgba(255,255,255,0.14), rgba(255,255,255,0.05)) !important;
  border: 1px solid rgba(255,255,255,0.16);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.32);
  backdrop-filter: blur(14px);
  transform: rotate(3deg);
}

.vb-countdown-twentythree-product-top {
  position: absolute;
  left: 24px;
  right: 24px;
  top: 28px;
  display: flex;
  justify-content: space-between;
}

.vb-countdown-twentythree-product-top i {
  display: block;
  width: 54px;
  height: 14px;
  border-radius: 999px;
  background: rgba(255,255,255,0.18);
}

.vb-countdown-twentythree-product-top i:nth-child(2) {
  width: 34px;
}

.vb-countdown-twentythree-product-shape {
  position: absolute;
  left: 50%;
  top: 48%;
  display: grid;
  place-items: center;
  width: 190px;
  height: 230px;
  border-radius: 42px 18px 42px 18px;
  transform: translate(-50%, -50%) rotate(-9deg);
  background:
    radial-gradient(circle at 28% 20%, rgba(255,255,255,0.34), transparent 32%),
    linear-gradient(135deg, #fb923c, #6366f1) !important;
  box-shadow: 0 30px 70px rgba(2, 6, 23, 0.24);
}

.vb-countdown-twentythree-product-shape span {
  display: block;
  width: 76px;
  height: 76px;
  border-radius: 999px;
  background: rgba(255,255,255,0.28);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-countdown-twentythree-price {
  position: absolute;
  left: 24px;
  right: 24px;
  bottom: 24px;
  display: grid;
  gap: 7px;
  padding: 18px;
  border-radius: 20px 8px 20px 8px;
  background: rgba(2, 6, 23, 0.66);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-countdown-twentythree-price small {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-countdown-twentythree-price strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 42px;
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vb-countdown-twentythree-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 6px 999px 999px 6px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twentythree-content h3 {
  max-width: 820px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 82px) !important;
  line-height: 0.88 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
  overflow-wrap: anywhere;
}

.vb-countdown-twentythree-content p {
  max-width: 690px;
  margin: 0 0 22px !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-twentythree-benefits {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 10px;
  max-width: 760px;
  margin-bottom: 18px;
}

.vb-countdown-twentythree-benefits div {
  min-width: 0;
  padding: 15px;
  border-radius: 18px 6px 18px 6px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-countdown-twentythree-benefits strong {
  display: block;
  margin-bottom: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  line-height: 1.15;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-countdown-twentythree-benefits span {
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 750;
}

.vb-countdown-twentythree-timer {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(8px, 1.4vw, 12px);
  max-width: 760px;
  margin-bottom: 18px;
}

.vb-countdown-twentythree-timer div {
  min-width: 0;
  padding: clamp(15px, 2.5vw, 22px) 8px;
  border-radius: 8px 26px 8px 26px;
  background: #ffffff;
  text-align: center;
  box-shadow: 0 18px 42px rgba(2, 6, 23, 0.18);
}

.vb-countdown-twentythree-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: clamp(28px, 4.6vw, 54px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-twentythree-timer span {
  display: block;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-twentythree-status {
  margin-bottom: 18px !important;
}

.vb-countdown-twentythree-content a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 14px 20px;
  border-radius: 999px 8px 999px 8px;
  background: linear-gradient(135deg, #fb923c, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(251, 146, 60, 0.22);
}

@media (max-width: 920px) {
  .vb-countdown-twentythree-preorder {
    grid-template-columns: 1fr;
  }

  .vb-countdown-twentythree-product-card {
    transform: none;
  }
}

@media (max-width: 640px) {
  .vb-countdown-twentythree-demo {
    border-radius: 12px 12px 38px 12px;
  }

  .vb-countdown-twentythree-preorder {
    border-radius: 10px 10px 30px 10px;
  }

  .vb-countdown-twentythree-content h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-twentythree-benefits {
    grid-template-columns: 1fr;
  }

  .vb-countdown-twentythree-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-twentythree-timer strong {
    font-size: clamp(30px, 13vw, 46px);
  }

  .vb-countdown-twentythree-content a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-twentythree-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This preorder countdown timer is useful for ecommerce preorder campaigns, product launch pages, hardware releases, book launches, limited production runs, digital product releases, and early buyer landing pages.</p>



<h2 class="wp-block-heading">24. Newsletter Offer Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A newsletter offer countdown timer</strong> is useful for email signup sections, lead magnet pages, newsletter popups, content upgrade blocks, creator landing pages, marketing funnels, and limited-time subscriber offers.</p>



<p class="wp-block-paragraph">This example uses an editorial newsletter layout with a paper-style signup card, stamp badge, email input, subscriber benefit list, and compact countdown strip. The JavaScript uses a repeating 36-hour signup offer window, so the demo keeps running and never stays expired.</p>



<ul class="wp-block-list">
<li>Newsletter offer countdown timer</li>
<li>Email signup and lead magnet layout</li>
<li>Hours, minutes, and seconds</li>
<li>Repeating signup offer window</li>
<li>Responsive newsletter CTA design</li>
</ul>



<div class="vb-countdown-twentyfour-demo">
  <section class="vb-countdown-twentyfour-newsletter" data-vb-countdown-twentyfour data-duration="129600">
    <div class="vb-countdown-twentyfour-paper">
      <div class="vb-countdown-twentyfour-stamp">Example 24</div>

      <div class="vb-countdown-twentyfour-paper-head">
        <span>Weekly Web Design Notes</span>
        <strong>Newsletter Offer Countdown Timer</strong>
      </div>

      <p>Use this timer for newsletter signup offers, lead magnets, content upgrades, free download campaigns, and email marketing landing pages.</p>

      <form class="vb-countdown-twentyfour-form">
        <input type="email" placeholder="Enter your email" aria-label="Email address">
        <button type="button">Subscribe</button>
      </form>

      <div class="vb-countdown-twentyfour-list">
        <span>Free resource included</span>
        <span>No spam</span>
        <span>Weekly tips</span>
      </div>
    </div>

    <aside class="vb-countdown-twentyfour-side">
      <span class="vb-countdown-twentyfour-kicker">Subscriber bonus</span>
      <h3>Newsletter Offer Countdown Timer</h3>
      <p data-status>Signup offer is active.</p>

      <div class="vb-countdown-twentyfour-timer" aria-label="Newsletter offer countdown timer">
        <div>
          <strong data-hours>00</strong>
          <span>Hours</span>
        </div>

        <div>
          <strong data-minutes>00</strong>
          <span>Min</span>
        </div>

        <div>
          <strong data-seconds>00</strong>
          <span>Sec</span>
        </div>
      </div>

      <small>Offer automatically refreshes for demo use.</small>
    </aside>
  </section>
</div>

<style>
.vb-countdown-twentyfour-demo,
.vb-countdown-twentyfour-demo * {
  box-sizing: border-box;
}

.vb-countdown-twentyfour-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 14px 48px 14px 48px;
  background:
    radial-gradient(circle at 16% 18%, rgba(15, 23, 42, 0.08), transparent 34%),
    radial-gradient(circle at 84% 22%, rgba(20, 184, 166, 0.14), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #ecfeff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.20);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-countdown-twentyfour-newsletter {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 360px);
  gap: clamp(22px, 4vw, 34px);
  align-items: stretch;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-countdown-twentyfour-paper {
  position: relative;
  min-width: 0;
  padding: clamp(28px, 5vw, 54px);
  border-radius: 8px;
  background:
    linear-gradient(90deg, rgba(15, 23, 42, 0.045) 1px, transparent 1px),
    linear-gradient(#ffffff, #fffaf0) !important;
  background-size: 28px 28px, auto !important;
  border: 1px solid rgba(120, 113, 108, 0.24);
  box-shadow:
    0 28px 80px rgba(15, 23, 42, 0.12),
    inset 0 1px 0 rgba(255,255,255,0.8);
}

.vb-countdown-twentyfour-paper::before {
  content: "";
  position: absolute;
  left: 26px;
  top: 0;
  bottom: 0;
  width: 3px;
  background: repeating-linear-gradient(to bottom, #14b8a6 0 14px, transparent 14px 24px);
  opacity: 0.7;
}

.vb-countdown-twentyfour-stamp {
  position: absolute;
  right: clamp(18px, 3vw, 30px);
  top: clamp(18px, 3vw, 30px);
  display: grid;
  place-items: center;
  width: 96px;
  height: 96px;
  border-radius: 999px;
  border: 2px dashed rgba(20, 184, 166, 0.70);
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 11px;
  line-height: 1.2;
  font-weight: 950;
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 0.10em;
  transform: rotate(9deg);
}

.vb-countdown-twentyfour-paper-head {
  display: grid;
  gap: 12px;
  max-width: 720px;
  padding-right: 110px;
  margin-bottom: 18px;
}

.vb-countdown-twentyfour-paper-head span {
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.vb-countdown-twentyfour-paper-head strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5.8vw, 74px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.08em;
  overflow-wrap: anywhere;
}

.vb-countdown-twentyfour-paper p {
  max-width: 690px;
  margin: 0 0 24px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: clamp(15px, 1.8vw, 17px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-twentyfour-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 150px;
  gap: 10px;
  max-width: 620px;
  margin-bottom: 18px;
}

.vb-countdown-twentyfour-form input {
  min-width: 0;
  min-height: 54px;
  padding: 0 16px;
  border-radius: 6px;
  border: 1px solid rgba(100, 116, 139, 0.24);
  background: #ffffff;
  outline: none;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-countdown-twentyfour-form button {
  min-height: 54px;
  border: 0;
  border-radius: 6px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 14px 30px rgba(15, 23, 42, 0.18);
}

.vb-countdown-twentyfour-list {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.vb-countdown-twentyfour-list span {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 6px;
  background: #ecfeff;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-twentyfour-side {
  display: grid;
  align-content: center;
  gap: 16px;
  min-width: 0;
  padding: clamp(20px, 3vw, 28px);
  border-radius: 36px 8px 36px 8px;
  background:
    radial-gradient(circle at 22% 16%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #164e63 58%, #134e4a 100%) !important;
  box-shadow: 0 26px 76px rgba(15, 23, 42, 0.18);
}

.vb-countdown-twentyfour-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(20, 184, 166, 0.14);
  border: 1px solid rgba(94, 234, 212, 0.20);
  color: #99f6e4 !important;
  -webkit-text-fill-color: #99f6e4 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

.vb-countdown-twentyfour-side h3 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4vw, 42px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.065em;
  overflow-wrap: anywhere;
}

.vb-countdown-twentyfour-side p {
  margin: 0 !important;
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

.vb-countdown-twentyfour-timer {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
}

.vb-countdown-twentyfour-timer div {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  min-width: 0;
  padding: 15px 16px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-countdown-twentyfour-timer strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 6vw, 46px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums;
}

.vb-countdown-twentyfour-timer span {
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-twentyfour-side small {
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 12px;
  line-height: 1.45;
  font-weight: 750;
}

@media (max-width: 900px) {
  .vb-countdown-twentyfour-newsletter {
    grid-template-columns: 1fr;
  }

  .vb-countdown-twentyfour-timer {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .vb-countdown-twentyfour-timer div {
    display: grid;
    place-items: center;
    text-align: center;
  }
}

@media (max-width: 640px) {
  .vb-countdown-twentyfour-demo {
    border-radius: 12px 34px 12px 34px;
  }

  .vb-countdown-twentyfour-stamp {
    position: static;
    width: auto;
    height: auto;
    justify-self: start;
    margin-bottom: 16px;
    padding: 10px 12px;
    transform: none;
  }

  .vb-countdown-twentyfour-paper-head {
    padding-right: 0;
  }

  .vb-countdown-twentyfour-paper-head strong {
    font-size: 38px;
    letter-spacing: -0.06em;
  }

  .vb-countdown-twentyfour-form {
    grid-template-columns: 1fr;
  }

  .vb-countdown-twentyfour-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-twentyfour]");
  if (!timer) return;

  const duration = Number(timer.getAttribute("data-duration")) || 129600;
  let remaining = duration;

  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function updateCountdown() {
    if (remaining <= 0) {
      remaining = duration;
    }

    const hours = Math.floor(remaining / 3600);
    const minutes = Math.floor((remaining / 60) % 60);
    const seconds = remaining % 60;

    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    statusEl.textContent = "Signup offer is active.";

    remaining -= 1;
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-twentyfour]");
  if (!timer) return;

  const duration = Number(timer.getAttribute("data-duration")) || 129600;
  let remaining = duration;

  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function updateCountdown() {
    if (remaining &lt;= 0) {
      remaining = duration;
    }

    const hours = Math.floor(remaining / 3600);
    const minutes = Math.floor((remaining / 60) % 60);
    const seconds = remaining % 60;

    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    statusEl.textContent = "Signup offer is active.";

    remaining -= 1;
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-twentyfour-demo"&gt;
  &lt;section class="vb-countdown-twentyfour-newsletter" data-vb-countdown-twentyfour data-duration="129600"&gt;
    &lt;div class="vb-countdown-twentyfour-paper"&gt;
      &lt;div class="vb-countdown-twentyfour-stamp"&gt;Example 24&lt;/div&gt;

      &lt;div class="vb-countdown-twentyfour-paper-head"&gt;
        &lt;span&gt;Weekly Web Design Notes&lt;/span&gt;
        &lt;strong&gt;Newsletter Offer Countdown Timer&lt;/strong&gt;
      &lt;/div&gt;

      &lt;p&gt;Use this timer for newsletter signup offers, lead magnets, content upgrades, free download campaigns, and email marketing landing pages.&lt;/p&gt;

      &lt;form class="vb-countdown-twentyfour-form"&gt;
        &lt;input type="email" placeholder="Enter your email" aria-label="Email address"&gt;
        &lt;button type="button"&gt;Subscribe&lt;/button&gt;
      &lt;/form&gt;

      &lt;div class="vb-countdown-twentyfour-list"&gt;
        &lt;span&gt;Free resource included&lt;/span&gt;
        &lt;span&gt;No spam&lt;/span&gt;
        &lt;span&gt;Weekly tips&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;aside class="vb-countdown-twentyfour-side"&gt;
      &lt;span class="vb-countdown-twentyfour-kicker"&gt;Subscriber bonus&lt;/span&gt;
      &lt;h3&gt;Newsletter Offer Countdown Timer&lt;/h3&gt;
      &lt;p data-status&gt;Signup offer is active.&lt;/p&gt;

      &lt;div class="vb-countdown-twentyfour-timer" aria-label="Newsletter offer countdown timer"&gt;
        &lt;div&gt;
          &lt;strong data-hours&gt;00&lt;/strong&gt;
          &lt;span&gt;Hours&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
          &lt;span&gt;Min&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
          &lt;span&gt;Sec&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;small&gt;Offer automatically refreshes for demo use.&lt;/small&gt;
    &lt;/aside&gt;
  &lt;/section&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-twentyfour-demo,
.vb-countdown-twentyfour-demo * {
  box-sizing: border-box;
}

.vb-countdown-twentyfour-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 14px 48px 14px 48px;
  background:
    radial-gradient(circle at 16% 18%, rgba(15, 23, 42, 0.08), transparent 34%),
    radial-gradient(circle at 84% 22%, rgba(20, 184, 166, 0.14), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #ecfeff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.20);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-countdown-twentyfour-newsletter {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 360px);
  gap: clamp(22px, 4vw, 34px);
  align-items: stretch;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-countdown-twentyfour-paper {
  position: relative;
  min-width: 0;
  padding: clamp(28px, 5vw, 54px);
  border-radius: 8px;
  background:
    linear-gradient(90deg, rgba(15, 23, 42, 0.045) 1px, transparent 1px),
    linear-gradient(#ffffff, #fffaf0) !important;
  background-size: 28px 28px, auto !important;
  border: 1px solid rgba(120, 113, 108, 0.24);
  box-shadow:
    0 28px 80px rgba(15, 23, 42, 0.12),
    inset 0 1px 0 rgba(255,255,255,0.8);
}

.vb-countdown-twentyfour-paper::before {
  content: "";
  position: absolute;
  left: 26px;
  top: 0;
  bottom: 0;
  width: 3px;
  background: repeating-linear-gradient(to bottom, #14b8a6 0 14px, transparent 14px 24px);
  opacity: 0.7;
}

.vb-countdown-twentyfour-stamp {
  position: absolute;
  right: clamp(18px, 3vw, 30px);
  top: clamp(18px, 3vw, 30px);
  display: grid;
  place-items: center;
  width: 96px;
  height: 96px;
  border-radius: 999px;
  border: 2px dashed rgba(20, 184, 166, 0.70);
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 11px;
  line-height: 1.2;
  font-weight: 950;
  text-align: center;
  text-transform: uppercase;
  letter-spacing: 0.10em;
  transform: rotate(9deg);
}

.vb-countdown-twentyfour-paper-head {
  display: grid;
  gap: 12px;
  max-width: 720px;
  padding-right: 110px;
  margin-bottom: 18px;
}

.vb-countdown-twentyfour-paper-head span {
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.vb-countdown-twentyfour-paper-head strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5.8vw, 74px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.08em;
  overflow-wrap: anywhere;
}

.vb-countdown-twentyfour-paper p {
  max-width: 690px;
  margin: 0 0 24px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: clamp(15px, 1.8vw, 17px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-twentyfour-form {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 150px;
  gap: 10px;
  max-width: 620px;
  margin-bottom: 18px;
}

.vb-countdown-twentyfour-form input {
  min-width: 0;
  min-height: 54px;
  padding: 0 16px;
  border-radius: 6px;
  border: 1px solid rgba(100, 116, 139, 0.24);
  background: #ffffff;
  outline: none;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-countdown-twentyfour-form button {
  min-height: 54px;
  border: 0;
  border-radius: 6px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 14px 30px rgba(15, 23, 42, 0.18);
}

.vb-countdown-twentyfour-list {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.vb-countdown-twentyfour-list span {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 6px;
  background: #ecfeff;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-twentyfour-side {
  display: grid;
  align-content: center;
  gap: 16px;
  min-width: 0;
  padding: clamp(20px, 3vw, 28px);
  border-radius: 36px 8px 36px 8px;
  background:
    radial-gradient(circle at 22% 16%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #164e63 58%, #134e4a 100%) !important;
  box-shadow: 0 26px 76px rgba(15, 23, 42, 0.18);
}

.vb-countdown-twentyfour-kicker {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(20, 184, 166, 0.14);
  border: 1px solid rgba(94, 234, 212, 0.20);
  color: #99f6e4 !important;
  -webkit-text-fill-color: #99f6e4 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

.vb-countdown-twentyfour-side h3 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4vw, 42px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.065em;
  overflow-wrap: anywhere;
}

.vb-countdown-twentyfour-side p {
  margin: 0 !important;
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

.vb-countdown-twentyfour-timer {
  display: grid;
  grid-template-columns: 1fr;
  gap: 10px;
}

.vb-countdown-twentyfour-timer div {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  min-width: 0;
  padding: 15px 16px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-countdown-twentyfour-timer strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 6vw, 46px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums;
}

.vb-countdown-twentyfour-timer span {
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-twentyfour-side small {
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 12px;
  line-height: 1.45;
  font-weight: 750;
}

@media (max-width: 900px) {
  .vb-countdown-twentyfour-newsletter {
    grid-template-columns: 1fr;
  }

  .vb-countdown-twentyfour-timer {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .vb-countdown-twentyfour-timer div {
    display: grid;
    place-items: center;
    text-align: center;
  }
}

@media (max-width: 640px) {
  .vb-countdown-twentyfour-demo {
    border-radius: 12px 34px 12px 34px;
  }

  .vb-countdown-twentyfour-stamp {
    position: static;
    width: auto;
    height: auto;
    justify-self: start;
    margin-bottom: 16px;
    padding: 10px 12px;
    transform: none;
  }

  .vb-countdown-twentyfour-paper-head {
    padding-right: 0;
  }

  .vb-countdown-twentyfour-paper-head strong {
    font-size: 38px;
    letter-spacing: -0.06em;
  }

  .vb-countdown-twentyfour-form {
    grid-template-columns: 1fr;
  }

  .vb-countdown-twentyfour-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This newsletter offer countdown timer is useful for email signup sections, lead magnet pages, creator newsletters, popup offers, content upgrade blocks, subscriber campaigns, and marketing funnel landing pages.</p>



<h2 class="wp-block-heading">25. Dashboard Task Deadline Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A dashboard task deadline countdown timer</strong> is useful for admin dashboards, project management apps, SaaS panels, task boards, client portals, productivity tools, and internal systems where users need to complete an action before a deadline.</p>



<p class="wp-block-paragraph">This example uses a dashboard-style layout with task cards, priority labels, progress indicators, a deadline panel, and a compact countdown module. The JavaScript uses a repeating 5-day task deadline cycle, so the demo keeps working over time and never remains expired.</p>



<ul class="wp-block-list">
<li>Dashboard task deadline countdown timer</li>
<li>Project management dashboard layout</li>
<li>Days, hours, minutes, and seconds</li>
<li>Task cards and progress indicators</li>
<li>Responsive SaaS dashboard section</li>
</ul>



<div class="vb-countdown-twentyfive-demo">
  <section class="vb-countdown-twentyfive-dashboard" data-vb-countdown-twentyfive data-cycle-days="5">
    <div class="vb-countdown-twentyfive-sidebar">
      <span class="vb-countdown-twentyfive-logo">D</span>

      <div class="vb-countdown-twentyfive-nav">
        <i></i>
        <i></i>
        <i></i>
      </div>
    </div>

    <div class="vb-countdown-twentyfive-main">
      <div class="vb-countdown-twentyfive-title">
        <span>Example 25</span>
        <h3>Dashboard Task Deadline Countdown Timer</h3>
        <p>Use this countdown timer for task dashboards, SaaS panels, project boards, client portals, admin screens, and productivity apps.</p>
      </div>

      <div class="vb-countdown-twentyfive-tasks">
        <div>
          <span>High Priority</span>
          <strong>Landing page review</strong>
          <small>Design approval needed</small>
        </div>

        <div>
          <span>In Progress</span>
          <strong>Campaign assets</strong>
          <small>Final files pending</small>
        </div>

        <div>
          <span data-next-task>Deadline loading</span>
          <strong>Task deadline</strong>
          <small data-status>Deadline countdown active</small>
        </div>
      </div>
    </div>

    <aside class="vb-countdown-twentyfive-panel">
      <span>Deadline Timer</span>

      <div class="vb-countdown-twentyfive-timer" aria-label="Dashboard task deadline countdown timer">
        <div>
          <strong data-days>00</strong>
          <span>Days</span>
        </div>

        <div>
          <strong data-hours>00</strong>
          <span>Hours</span>
        </div>

        <div>
          <strong data-minutes>00</strong>
          <span>Min</span>
        </div>

        <div>
          <strong data-seconds>00</strong>
          <span>Sec</span>
        </div>
      </div>

      <div class="vb-countdown-twentyfive-progress">
        <strong>Task progress</strong>
        <div><i></i></div>
      </div>

      <a href="#dashboard-task">Open Task</a>
    </aside>
  </section>
</div>

<style>
.vb-countdown-twentyfive-demo,
.vb-countdown-twentyfive-demo * {
  box-sizing: border-box;
}

.vb-countdown-twentyfive-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 26px 8px 26px 8px;
  background:
    radial-gradient(circle at 14% 18%, rgba(99, 102, 241, 0.14), transparent 34%),
    radial-gradient(circle at 88% 24%, rgba(14, 165, 233, 0.14), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.18);
  box-shadow: 0 28px 80px rgba(49, 46, 129, 0.09);
}

.vb-countdown-twentyfive-dashboard {
  display: grid;
  grid-template-columns: 76px minmax(0, 1fr) minmax(270px, 350px);
  gap: clamp(16px, 3vw, 24px);
  align-items: stretch;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(14px, 2vw, 18px);
  border-radius: 22px 6px 22px 6px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-countdown-twentyfive-sidebar {
  display: grid;
  justify-items: center;
  align-content: start;
  gap: 22px;
  padding: 16px 10px;
  border-radius: 16px 4px 16px 4px;
  background: #0f172a;
}

.vb-countdown-twentyfive-logo {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 14px 4px 14px 4px;
  background: linear-gradient(135deg, #6366f1, #0ea5e9);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-countdown-twentyfive-nav {
  display: grid;
  gap: 12px;
}

.vb-countdown-twentyfive-nav i {
  display: block;
  width: 34px;
  height: 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.18);
}

.vb-countdown-twentyfive-nav i:nth-child(2) {
  background: rgba(96, 165, 250, 0.42);
}

.vb-countdown-twentyfive-main {
  min-width: 0;
  display: grid;
  align-content: center;
  gap: 20px;
  padding: clamp(20px, 3vw, 32px);
  border-radius: 18px 6px 18px 6px;
  background:
    linear-gradient(90deg, rgba(15, 23, 42, 0.035) 1px, transparent 1px),
    linear-gradient(0deg, rgba(15, 23, 42, 0.035) 1px, transparent 1px),
    #f8fafc !important;
  background-size: 28px 28px, 28px 28px, auto !important;
}

.vb-countdown-twentyfive-title span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 6px;
  background: #eef2ff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twentyfive-title h3 {
  max-width: 780px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5.6vw, 72px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
  overflow-wrap: anywhere;
}

.vb-countdown-twentyfive-title p {
  max-width: 720px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.72;
  font-weight: 650;
}

.vb-countdown-twentyfive-tasks {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-countdown-twentyfive-tasks div {
  min-width: 0;
  padding: 16px;
  border-radius: 18px 6px 18px 6px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-countdown-twentyfive-tasks span {
  display: inline-flex;
  margin-bottom: 8px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.vb-countdown-twentyfive-tasks div:nth-child(1) span {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-countdown-twentyfive-tasks div:nth-child(2) span {
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
}

.vb-countdown-twentyfive-tasks strong {
  display: block;
  margin-bottom: 6px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  line-height: 1.15;
  font-weight: 950;
  letter-spacing: -0.045em;
}

.vb-countdown-twentyfive-tasks small {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.4;
  font-weight: 750;
}

.vb-countdown-twentyfive-panel {
  display: grid;
  align-content: center;
  gap: 16px;
  min-width: 0;
  padding: clamp(20px, 3vw, 26px);
  border-radius: 6px 22px 6px 22px;
  background:
    radial-gradient(circle at 24% 16%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #1e1b4b 0%, #3730a3 58%, #0f172a 100%) !important;
}

.vb-countdown-twentyfive-panel > span {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

.vb-countdown-twentyfive-timer {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.vb-countdown-twentyfive-timer div {
  min-width: 0;
  padding: 16px 8px;
  border-radius: 16px 4px 16px 4px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.13);
  text-align: center;
}

.vb-countdown-twentyfive-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 6vw, 48px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-twentyfive-timer span {
  display: block;
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-twentyfive-progress {
  display: grid;
  gap: 9px;
}

.vb-countdown-twentyfive-progress strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-countdown-twentyfive-progress div {
  overflow: hidden;
  height: 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
}

.vb-countdown-twentyfive-progress i {
  display: block;
  width: 68%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #60a5fa, #a78bfa) !important;
}

.vb-countdown-twentyfive-panel a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 999px;
  background: #ffffff;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(15, 23, 42, 0.20);
}

@media (max-width: 1050px) {
  .vb-countdown-twentyfive-dashboard {
    grid-template-columns: 76px minmax(0, 1fr);
  }

  .vb-countdown-twentyfive-panel {
    grid-column: 1 / -1;
  }

  .vb-countdown-twentyfive-timer {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (max-width: 760px) {
  .vb-countdown-twentyfive-dashboard {
    grid-template-columns: 1fr;
  }

  .vb-countdown-twentyfive-sidebar {
    display: none;
  }

  .vb-countdown-twentyfive-title h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-twentyfive-tasks {
    grid-template-columns: 1fr;
  }

  .vb-countdown-twentyfive-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-twentyfive-panel a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-twentyfive-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-twentyfive]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 5;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-09T15:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextTaskEl = timer.querySelector("[data-next-task]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextTaskDeadline(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextDeadline = getNextTaskDeadline(now);
    let remaining = nextDeadline - now;

    if (remaining <= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(nextDeadline).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextTaskEl.textContent = "Due " + dateText;
    statusEl.textContent = "Deadline countdown active";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-twentyfive]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 5;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-09T15:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextTaskEl = timer.querySelector("[data-next-task]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextTaskDeadline(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextDeadline = getNextTaskDeadline(now);
    let remaining = nextDeadline - now;

    if (remaining &lt;= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(nextDeadline).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextTaskEl.textContent = "Due " + dateText;
    statusEl.textContent = "Deadline countdown active";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-twentyfive-demo"&gt;
  &lt;section class="vb-countdown-twentyfive-dashboard" data-vb-countdown-twentyfive data-cycle-days="5"&gt;
    &lt;div class="vb-countdown-twentyfive-sidebar"&gt;
      &lt;span class="vb-countdown-twentyfive-logo"&gt;D&lt;/span&gt;

      &lt;div class="vb-countdown-twentyfive-nav"&gt;
        &lt;i&gt;&lt;/i&gt;
        &lt;i&gt;&lt;/i&gt;
        &lt;i&gt;&lt;/i&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-twentyfive-main"&gt;
      &lt;div class="vb-countdown-twentyfive-title"&gt;
        &lt;span&gt;Example 25&lt;/span&gt;
        &lt;h3&gt;Dashboard Task Deadline Countdown Timer&lt;/h3&gt;
        &lt;p&gt;Use this countdown timer for task dashboards, SaaS panels, project boards, client portals, admin screens, and productivity apps.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-twentyfive-tasks"&gt;
        &lt;div&gt;
          &lt;span&gt;High Priority&lt;/span&gt;
          &lt;strong&gt;Landing page review&lt;/strong&gt;
          &lt;small&gt;Design approval needed&lt;/small&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;span&gt;In Progress&lt;/span&gt;
          &lt;strong&gt;Campaign assets&lt;/strong&gt;
          &lt;small&gt;Final files pending&lt;/small&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;span data-next-task&gt;Deadline loading&lt;/span&gt;
          &lt;strong&gt;Task deadline&lt;/strong&gt;
          &lt;small data-status&gt;Deadline countdown active&lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;aside class="vb-countdown-twentyfive-panel"&gt;
      &lt;span&gt;Deadline Timer&lt;/span&gt;

      &lt;div class="vb-countdown-twentyfive-timer" aria-label="Dashboard task deadline countdown timer"&gt;
        &lt;div&gt;
          &lt;strong data-days&gt;00&lt;/strong&gt;
          &lt;span&gt;Days&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-hours&gt;00&lt;/strong&gt;
          &lt;span&gt;Hours&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
          &lt;span&gt;Min&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
          &lt;span&gt;Sec&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-twentyfive-progress"&gt;
        &lt;strong&gt;Task progress&lt;/strong&gt;
        &lt;div&gt;&lt;i&gt;&lt;/i&gt;&lt;/div&gt;
      &lt;/div&gt;

      &lt;a href="#dashboard-task"&gt;Open Task&lt;/a&gt;
    &lt;/aside&gt;
  &lt;/section&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-twentyfive-demo,
.vb-countdown-twentyfive-demo * {
  box-sizing: border-box;
}

.vb-countdown-twentyfive-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 26px 8px 26px 8px;
  background:
    radial-gradient(circle at 14% 18%, rgba(99, 102, 241, 0.14), transparent 34%),
    radial-gradient(circle at 88% 24%, rgba(14, 165, 233, 0.14), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.18);
  box-shadow: 0 28px 80px rgba(49, 46, 129, 0.09);
}

.vb-countdown-twentyfive-dashboard {
  display: grid;
  grid-template-columns: 76px minmax(0, 1fr) minmax(270px, 350px);
  gap: clamp(16px, 3vw, 24px);
  align-items: stretch;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(14px, 2vw, 18px);
  border-radius: 22px 6px 22px 6px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-countdown-twentyfive-sidebar {
  display: grid;
  justify-items: center;
  align-content: start;
  gap: 22px;
  padding: 16px 10px;
  border-radius: 16px 4px 16px 4px;
  background: #0f172a;
}

.vb-countdown-twentyfive-logo {
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 14px 4px 14px 4px;
  background: linear-gradient(135deg, #6366f1, #0ea5e9);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-countdown-twentyfive-nav {
  display: grid;
  gap: 12px;
}

.vb-countdown-twentyfive-nav i {
  display: block;
  width: 34px;
  height: 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.18);
}

.vb-countdown-twentyfive-nav i:nth-child(2) {
  background: rgba(96, 165, 250, 0.42);
}

.vb-countdown-twentyfive-main {
  min-width: 0;
  display: grid;
  align-content: center;
  gap: 20px;
  padding: clamp(20px, 3vw, 32px);
  border-radius: 18px 6px 18px 6px;
  background:
    linear-gradient(90deg, rgba(15, 23, 42, 0.035) 1px, transparent 1px),
    linear-gradient(0deg, rgba(15, 23, 42, 0.035) 1px, transparent 1px),
    #f8fafc !important;
  background-size: 28px 28px, 28px 28px, auto !important;
}

.vb-countdown-twentyfive-title span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 6px;
  background: #eef2ff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twentyfive-title h3 {
  max-width: 780px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5.6vw, 72px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
  overflow-wrap: anywhere;
}

.vb-countdown-twentyfive-title p {
  max-width: 720px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.72;
  font-weight: 650;
}

.vb-countdown-twentyfive-tasks {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-countdown-twentyfive-tasks div {
  min-width: 0;
  padding: 16px;
  border-radius: 18px 6px 18px 6px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-countdown-twentyfive-tasks span {
  display: inline-flex;
  margin-bottom: 8px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.vb-countdown-twentyfive-tasks div:nth-child(1) span {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-countdown-twentyfive-tasks div:nth-child(2) span {
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
}

.vb-countdown-twentyfive-tasks strong {
  display: block;
  margin-bottom: 6px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  line-height: 1.15;
  font-weight: 950;
  letter-spacing: -0.045em;
}

.vb-countdown-twentyfive-tasks small {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.4;
  font-weight: 750;
}

.vb-countdown-twentyfive-panel {
  display: grid;
  align-content: center;
  gap: 16px;
  min-width: 0;
  padding: clamp(20px, 3vw, 26px);
  border-radius: 6px 22px 6px 22px;
  background:
    radial-gradient(circle at 24% 16%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #1e1b4b 0%, #3730a3 58%, #0f172a 100%) !important;
}

.vb-countdown-twentyfive-panel > span {
  display: inline-flex;
  justify-self: start;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

.vb-countdown-twentyfive-timer {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.vb-countdown-twentyfive-timer div {
  min-width: 0;
  padding: 16px 8px;
  border-radius: 16px 4px 16px 4px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.13);
  text-align: center;
}

.vb-countdown-twentyfive-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 6vw, 48px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.045em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-twentyfive-timer span {
  display: block;
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-twentyfive-progress {
  display: grid;
  gap: 9px;
}

.vb-countdown-twentyfive-progress strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-countdown-twentyfive-progress div {
  overflow: hidden;
  height: 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
}

.vb-countdown-twentyfive-progress i {
  display: block;
  width: 68%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #60a5fa, #a78bfa) !important;
}

.vb-countdown-twentyfive-panel a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 999px;
  background: #ffffff;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(15, 23, 42, 0.20);
}

@media (max-width: 1050px) {
  .vb-countdown-twentyfive-dashboard {
    grid-template-columns: 76px minmax(0, 1fr);
  }

  .vb-countdown-twentyfive-panel {
    grid-column: 1 / -1;
  }

  .vb-countdown-twentyfive-timer {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

@media (max-width: 760px) {
  .vb-countdown-twentyfive-dashboard {
    grid-template-columns: 1fr;
  }

  .vb-countdown-twentyfive-sidebar {
    display: none;
  }

  .vb-countdown-twentyfive-title h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-twentyfive-tasks {
    grid-template-columns: 1fr;
  }

  .vb-countdown-twentyfive-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-twentyfive-panel a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-twentyfive-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This dashboard task deadline countdown timer is useful for SaaS dashboards, project management apps, task boards, admin panels, client portals, productivity apps, and deadline-focused workflow sections.</p>



<h2 class="wp-block-heading">26. Fitness Challenge Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A fitness challenge countdown timer</strong> is useful for gym websites, fitness apps, workout programs, online coaching pages, challenge landing pages, health campaigns, and membership promotions where visitors need to join before the challenge starts.</p>



<p class="wp-block-paragraph">This example uses an energetic fitness campaign design with angled panels, workout stat cards, a challenge badge, bold countdown tiles, and a high-contrast CTA. The JavaScript uses a repeating 30-day fitness challenge cycle, so the demo keeps working and never remains expired.</p>



<ul class="wp-block-list">
<li>Fitness challenge countdown timer</li>
<li>Workout campaign landing page design</li>
<li>Days, hours, minutes, and seconds</li>
<li>Fitness stats and challenge CTA</li>
<li>Responsive health and gym layout</li>
</ul>



<div class="vb-countdown-twentysix-demo">
  <section class="vb-countdown-twentysix-fitness" data-vb-countdown-twentysix data-cycle-days="30">
    <div class="vb-countdown-twentysix-visual">
      <span class="vb-countdown-twentysix-tag">Example 26</span>

      <div class="vb-countdown-twentysix-pulse">
        <i></i>
        <strong>30</strong>
        <span>Day Challenge</span>
      </div>

      <div class="vb-countdown-twentysix-stat vb-countdown-twentysix-stat-one">
        <strong>HIIT</strong>
        <span>Training plan</span>
      </div>

      <div class="vb-countdown-twentysix-stat vb-countdown-twentysix-stat-two">
        <strong>4x</strong>
        <span>Weekly workouts</span>
      </div>
    </div>

    <div class="vb-countdown-twentysix-content">
      <span class="vb-countdown-twentysix-kicker">Fitness Challenge</span>
      <h3>Fitness Challenge Countdown Timer</h3>
      <p>Use this countdown timer for fitness challenge pages, gym promotions, workout apps, coaching launches, health campaigns, and online training programs.</p>

      <div class="vb-countdown-twentysix-timer" aria-label="Fitness challenge countdown timer">
        <div>
          <strong data-days>00</strong>
          <span>Days</span>
        </div>

        <div>
          <strong data-hours>00</strong>
          <span>Hours</span>
        </div>

        <div>
          <strong data-minutes>00</strong>
          <span>Min</span>
        </div>

        <div>
          <strong data-seconds>00</strong>
          <span>Sec</span>
        </div>
      </div>

      <div class="vb-countdown-twentysix-info">
        <span data-next-challenge>Next challenge loading</span>
        <strong data-status>Challenge countdown active</strong>
      </div>

      <a href="#join-fitness-challenge">Join Challenge</a>
    </div>
  </section>
</div>

<style>
.vb-countdown-twentysix-demo,
.vb-countdown-twentysix-demo * {
  box-sizing: border-box;
}

.vb-countdown-twentysix-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 8px 70px 8px 70px;
  background:
    radial-gradient(circle at 16% 18%, rgba(239, 68, 68, 0.16), transparent 34%),
    radial-gradient(circle at 88% 22%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(239, 68, 68, 0.18);
  box-shadow: 0 28px 80px rgba(127, 29, 29, 0.09);
}

.vb-countdown-twentysix-fitness {
  position: relative;
  display: grid;
  grid-template-columns: minmax(260px, 0.8fr) minmax(0, 1.2fr);
  gap: clamp(24px, 5vw, 46px);
  align-items: center;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(24px, 5vw, 52px);
  overflow: hidden;
  border-radius: 6px 54px 6px 54px;
  background:
    repeating-linear-gradient(-12deg, rgba(255,255,255,0.035) 0 10px, transparent 10px 22px),
    linear-gradient(135deg, #111827 0%, #7f1d1d 48%, #14532d 100%) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.30);
}

.vb-countdown-twentysix-fitness::before {
  content: "";
  position: absolute;
  left: -120px;
  top: -120px;
  width: 340px;
  height: 340px;
  border-radius: 999px;
  background: rgba(239, 68, 68, 0.15);
}

.vb-countdown-twentysix-fitness::after {
  content: "";
  position: absolute;
  right: -140px;
  bottom: -140px;
  width: 380px;
  height: 380px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.14);
}

.vb-countdown-twentysix-visual,
.vb-countdown-twentysix-content {
  position: relative;
  z-index: 2;
  min-width: 0;
}

.vb-countdown-twentysix-visual {
  min-height: clamp(340px, 43vw, 500px);
  border-radius: 6px 44px 6px 44px;
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, rgba(255,255,255,0.12), rgba(255,255,255,0.04)) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 30px 80px rgba(2, 6, 23, 0.24);
  overflow: hidden;
}

.vb-countdown-twentysix-tag {
  position: absolute;
  left: 18px;
  top: 18px;
  z-index: 3;
  display: inline-flex;
  padding: 8px 12px;
  border-radius: 999px 999px 999px 4px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
  color: #fecaca !important;
  -webkit-text-fill-color: #fecaca !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twentysix-pulse {
  position: absolute;
  left: 50%;
  top: 46%;
  display: grid;
  place-items: center;
  width: clamp(190px, 28vw, 270px);
  height: clamp(190px, 28vw, 270px);
  border-radius: 999px;
  transform: translate(-50%, -50%);
  background:
    radial-gradient(circle, rgba(255,255,255,0.20), rgba(255,255,255,0.06)) !important;
  border: 1px solid rgba(255,255,255,0.16);
}

.vb-countdown-twentysix-pulse i {
  position: absolute;
  inset: 18px;
  border-radius: inherit;
  border: 2px dashed rgba(255,255,255,0.22);
}

.vb-countdown-twentysix-pulse strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(58px, 10vw, 100px);
  line-height: 0.85;
  font-weight: 950;
  letter-spacing: -0.08em;
}

.vb-countdown-twentysix-pulse span {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-twentysix-stat {
  position: absolute;
  display: grid;
  gap: 5px;
  padding: 16px;
  border-radius: 18px 6px 18px 6px;
  background: rgba(2, 6, 23, 0.68);
  border: 1px solid rgba(255,255,255,0.12);
  backdrop-filter: blur(12px);
}

.vb-countdown-twentysix-stat-one {
  left: 24px;
  bottom: 28px;
}

.vb-countdown-twentysix-stat-two {
  right: 24px;
  top: 82px;
}

.vb-countdown-twentysix-stat strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 30px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-countdown-twentysix-stat span {
  color: #fecaca !important;
  -webkit-text-fill-color: #fecaca !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-twentysix-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 6px 999px 999px 6px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twentysix-content h3 {
  max-width: 820px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 82px) !important;
  line-height: 0.88 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
  overflow-wrap: anywhere;
}

.vb-countdown-twentysix-content p {
  max-width: 690px;
  margin: 0 0 22px !important;
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-twentysix-timer {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(8px, 1.4vw, 12px);
  max-width: 760px;
  margin-bottom: 18px;
}

.vb-countdown-twentysix-timer div {
  min-width: 0;
  padding: clamp(15px, 2.5vw, 22px) 8px;
  border-radius: 6px 28px 6px 28px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.14);
  text-align: center;
}

.vb-countdown-twentysix-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4.6vw, 54px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-twentysix-timer span {
  display: block;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-twentysix-info {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 18px;
}

.vb-countdown-twentysix-info span,
.vb-countdown-twentysix-info strong {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.12);
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-twentysix-content a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 14px 20px;
  border-radius: 999px 8px 999px 8px;
  background: linear-gradient(135deg, #ef4444, #22c55e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(239, 68, 68, 0.22);
}

@media (max-width: 920px) {
  .vb-countdown-twentysix-fitness {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-countdown-twentysix-demo {
    border-radius: 8px 38px 8px 38px;
  }

  .vb-countdown-twentysix-fitness {
    border-radius: 6px 30px 6px 30px;
  }

  .vb-countdown-twentysix-content h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-twentysix-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-twentysix-timer strong {
    font-size: clamp(30px, 13vw, 46px);
  }

  .vb-countdown-twentysix-stat {
    position: static;
    margin: 12px;
  }

  .vb-countdown-twentysix-pulse {
    top: 42%;
  }

  .vb-countdown-twentysix-content a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-twentysix-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-twentysix]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 30;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-10T07:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextChallengeEl = timer.querySelector("[data-next-challenge]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextChallengeStart(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextStart = getNextChallengeStart(now);
    let remaining = nextStart - now;

    if (remaining <= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(nextStart).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextChallengeEl.textContent = "Starts " + dateText;
    statusEl.textContent = "Challenge countdown active";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-twentysix]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 30;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-10T07:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextChallengeEl = timer.querySelector("[data-next-challenge]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextChallengeStart(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function updateCountdown() {
    const now = Date.now();
    const nextStart = getNextChallengeStart(now);
    let remaining = nextStart - now;

    if (remaining &lt;= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(nextStart).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    nextChallengeEl.textContent = "Starts " + dateText;
    statusEl.textContent = "Challenge countdown active";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-twentysix-demo"&gt;
  &lt;section class="vb-countdown-twentysix-fitness" data-vb-countdown-twentysix data-cycle-days="30"&gt;
    &lt;div class="vb-countdown-twentysix-visual"&gt;
      &lt;span class="vb-countdown-twentysix-tag"&gt;Example 26&lt;/span&gt;

      &lt;div class="vb-countdown-twentysix-pulse"&gt;
        &lt;i&gt;&lt;/i&gt;
        &lt;strong&gt;30&lt;/strong&gt;
        &lt;span&gt;Day Challenge&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-twentysix-stat vb-countdown-twentysix-stat-one"&gt;
        &lt;strong&gt;HIIT&lt;/strong&gt;
        &lt;span&gt;Training plan&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-twentysix-stat vb-countdown-twentysix-stat-two"&gt;
        &lt;strong&gt;4x&lt;/strong&gt;
        &lt;span&gt;Weekly workouts&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-twentysix-content"&gt;
      &lt;span class="vb-countdown-twentysix-kicker"&gt;Fitness Challenge&lt;/span&gt;
      &lt;h3&gt;Fitness Challenge Countdown Timer&lt;/h3&gt;
      &lt;p&gt;Use this countdown timer for fitness challenge pages, gym promotions, workout apps, coaching launches, health campaigns, and online training programs.&lt;/p&gt;

      &lt;div class="vb-countdown-twentysix-timer" aria-label="Fitness challenge countdown timer"&gt;
        &lt;div&gt;
          &lt;strong data-days&gt;00&lt;/strong&gt;
          &lt;span&gt;Days&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-hours&gt;00&lt;/strong&gt;
          &lt;span&gt;Hours&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
          &lt;span&gt;Min&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
          &lt;span&gt;Sec&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-twentysix-info"&gt;
        &lt;span data-next-challenge&gt;Next challenge loading&lt;/span&gt;
        &lt;strong data-status&gt;Challenge countdown active&lt;/strong&gt;
      &lt;/div&gt;

      &lt;a href="#join-fitness-challenge"&gt;Join Challenge&lt;/a&gt;
    &lt;/div&gt;
  &lt;/section&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-twentysix-demo,
.vb-countdown-twentysix-demo * {
  box-sizing: border-box;
}

.vb-countdown-twentysix-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 8px 70px 8px 70px;
  background:
    radial-gradient(circle at 16% 18%, rgba(239, 68, 68, 0.16), transparent 34%),
    radial-gradient(circle at 88% 22%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(239, 68, 68, 0.18);
  box-shadow: 0 28px 80px rgba(127, 29, 29, 0.09);
}

.vb-countdown-twentysix-fitness {
  position: relative;
  display: grid;
  grid-template-columns: minmax(260px, 0.8fr) minmax(0, 1.2fr);
  gap: clamp(24px, 5vw, 46px);
  align-items: center;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(24px, 5vw, 52px);
  overflow: hidden;
  border-radius: 6px 54px 6px 54px;
  background:
    repeating-linear-gradient(-12deg, rgba(255,255,255,0.035) 0 10px, transparent 10px 22px),
    linear-gradient(135deg, #111827 0%, #7f1d1d 48%, #14532d 100%) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.30);
}

.vb-countdown-twentysix-fitness::before {
  content: "";
  position: absolute;
  left: -120px;
  top: -120px;
  width: 340px;
  height: 340px;
  border-radius: 999px;
  background: rgba(239, 68, 68, 0.15);
}

.vb-countdown-twentysix-fitness::after {
  content: "";
  position: absolute;
  right: -140px;
  bottom: -140px;
  width: 380px;
  height: 380px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.14);
}

.vb-countdown-twentysix-visual,
.vb-countdown-twentysix-content {
  position: relative;
  z-index: 2;
  min-width: 0;
}

.vb-countdown-twentysix-visual {
  min-height: clamp(340px, 43vw, 500px);
  border-radius: 6px 44px 6px 44px;
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, rgba(255,255,255,0.12), rgba(255,255,255,0.04)) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 30px 80px rgba(2, 6, 23, 0.24);
  overflow: hidden;
}

.vb-countdown-twentysix-tag {
  position: absolute;
  left: 18px;
  top: 18px;
  z-index: 3;
  display: inline-flex;
  padding: 8px 12px;
  border-radius: 999px 999px 999px 4px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
  color: #fecaca !important;
  -webkit-text-fill-color: #fecaca !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twentysix-pulse {
  position: absolute;
  left: 50%;
  top: 46%;
  display: grid;
  place-items: center;
  width: clamp(190px, 28vw, 270px);
  height: clamp(190px, 28vw, 270px);
  border-radius: 999px;
  transform: translate(-50%, -50%);
  background:
    radial-gradient(circle, rgba(255,255,255,0.20), rgba(255,255,255,0.06)) !important;
  border: 1px solid rgba(255,255,255,0.16);
}

.vb-countdown-twentysix-pulse i {
  position: absolute;
  inset: 18px;
  border-radius: inherit;
  border: 2px dashed rgba(255,255,255,0.22);
}

.vb-countdown-twentysix-pulse strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(58px, 10vw, 100px);
  line-height: 0.85;
  font-weight: 950;
  letter-spacing: -0.08em;
}

.vb-countdown-twentysix-pulse span {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-twentysix-stat {
  position: absolute;
  display: grid;
  gap: 5px;
  padding: 16px;
  border-radius: 18px 6px 18px 6px;
  background: rgba(2, 6, 23, 0.68);
  border: 1px solid rgba(255,255,255,0.12);
  backdrop-filter: blur(12px);
}

.vb-countdown-twentysix-stat-one {
  left: 24px;
  bottom: 28px;
}

.vb-countdown-twentysix-stat-two {
  right: 24px;
  top: 82px;
}

.vb-countdown-twentysix-stat strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 30px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-countdown-twentysix-stat span {
  color: #fecaca !important;
  -webkit-text-fill-color: #fecaca !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-twentysix-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 6px 999px 999px 6px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twentysix-content h3 {
  max-width: 820px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 82px) !important;
  line-height: 0.88 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
  overflow-wrap: anywhere;
}

.vb-countdown-twentysix-content p {
  max-width: 690px;
  margin: 0 0 22px !important;
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-twentysix-timer {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(8px, 1.4vw, 12px);
  max-width: 760px;
  margin-bottom: 18px;
}

.vb-countdown-twentysix-timer div {
  min-width: 0;
  padding: clamp(15px, 2.5vw, 22px) 8px;
  border-radius: 6px 28px 6px 28px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.14);
  text-align: center;
}

.vb-countdown-twentysix-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4.6vw, 54px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-twentysix-timer span {
  display: block;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-twentysix-info {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 18px;
}

.vb-countdown-twentysix-info span,
.vb-countdown-twentysix-info strong {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.12);
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-twentysix-content a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 14px 20px;
  border-radius: 999px 8px 999px 8px;
  background: linear-gradient(135deg, #ef4444, #22c55e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(239, 68, 68, 0.22);
}

@media (max-width: 920px) {
  .vb-countdown-twentysix-fitness {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-countdown-twentysix-demo {
    border-radius: 8px 38px 8px 38px;
  }

  .vb-countdown-twentysix-fitness {
    border-radius: 6px 30px 6px 30px;
  }

  .vb-countdown-twentysix-content h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-twentysix-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-twentysix-timer strong {
    font-size: clamp(30px, 13vw, 46px);
  }

  .vb-countdown-twentysix-stat {
    position: static;
    margin: 12px;
  }

  .vb-countdown-twentysix-pulse {
    top: 42%;
  }

  .vb-countdown-twentysix-content a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-twentysix-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This fitness challenge countdown timer is useful for gym landing pages, fitness app campaigns, online coaching programs, workout challenges, health promotions, personal trainer pages, and membership offer sections.</p>



<h2 class="wp-block-heading">27. Multi-Timezone Event Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A multi-timezone event countdown timer</strong> is useful for webinars, online conferences, product launches, livestreams, virtual events, global workshops, and international campaigns where visitors may join from different locations.</p>



<p class="wp-block-paragraph">This example uses a global event layout with timezone cards, a world-style grid background, event details, and a countdown that keeps cycling forward. The JavaScript uses a repeating 14-day global event cycle and also displays example event times for New York, London, and Tokyo.</p>



<ul class="wp-block-list">
<li>Multi-timezone event countdown timer</li>
<li>Global webinar and event layout</li>
<li>Days, hours, minutes, and seconds</li>
<li>Timezone cards for different cities</li>
<li>Responsive international event section</li>
</ul>



<div class="vb-countdown-twentyseven-demo">
  <section class="vb-countdown-twentyseven-event" data-vb-countdown-twentyseven data-cycle-days="14">
    <div class="vb-countdown-twentyseven-map">
      <span class="vb-countdown-twentyseven-tag">Example 27</span>

      <div class="vb-countdown-twentyseven-orbit">
        <i></i>
        <i></i>
        <i></i>
        <strong>GLOBAL</strong>
      </div>

      <div class="vb-countdown-twentyseven-zone vb-countdown-twentyseven-zone-one">
        <span>New York</span>
        <strong data-ny-time>Loading</strong>
      </div>

      <div class="vb-countdown-twentyseven-zone vb-countdown-twentyseven-zone-two">
        <span>London</span>
        <strong data-london-time>Loading</strong>
      </div>

      <div class="vb-countdown-twentyseven-zone vb-countdown-twentyseven-zone-three">
        <span>Tokyo</span>
        <strong data-tokyo-time>Loading</strong>
      </div>
    </div>

    <div class="vb-countdown-twentyseven-content">
      <span class="vb-countdown-twentyseven-kicker">Global Event</span>
      <h3>Multi-Timezone Event Countdown Timer</h3>
      <p>Use this countdown timer for international webinars, online conferences, global launches, livestream events, workshops, and worldwide campaign pages.</p>

      <div class="vb-countdown-twentyseven-timer" aria-label="Multi-timezone event countdown timer">
        <div>
          <strong data-days>00</strong>
          <span>Days</span>
        </div>

        <div>
          <strong data-hours>00</strong>
          <span>Hours</span>
        </div>

        <div>
          <strong data-minutes>00</strong>
          <span>Min</span>
        </div>

        <div>
          <strong data-seconds>00</strong>
          <span>Sec</span>
        </div>
      </div>

      <div class="vb-countdown-twentyseven-meta">
        <span data-next-event>Next event loading</span>
        <strong data-status>Global event countdown active</strong>
      </div>

      <a href="#global-event-registration">Register for Event</a>
    </div>
  </section>
</div>

<style>
.vb-countdown-twentyseven-demo,
.vb-countdown-twentyseven-demo * {
  box-sizing: border-box;
}

.vb-countdown-twentyseven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 40px 8px 40px 8px;
  background:
    radial-gradient(circle at 16% 18%, rgba(14, 165, 233, 0.17), transparent 34%),
    radial-gradient(circle at 88% 22%, rgba(168, 85, 247, 0.15), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #faf5ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.20);
  box-shadow: 0 28px 80px rgba(3, 105, 161, 0.09);
}

.vb-countdown-twentyseven-event {
  position: relative;
  display: grid;
  grid-template-columns: minmax(260px, 0.88fr) minmax(0, 1.12fr);
  gap: clamp(24px, 5vw, 46px);
  align-items: center;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(24px, 5vw, 52px);
  overflow: hidden;
  border-radius: 32px 6px 32px 6px;
  background:
    linear-gradient(90deg, rgba(255,255,255,0.05) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.05) 1px, transparent 1px),
    radial-gradient(circle at 20% 20%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #075985 48%, #581c87 100%) !important;
  background-size: 34px 34px, 34px 34px, auto, auto !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.30);
}

.vb-countdown-twentyseven-event::before {
  content: "";
  position: absolute;
  right: -140px;
  top: -130px;
  width: 390px;
  height: 390px;
  border-radius: 999px;
  background: rgba(125, 211, 252, 0.13);
}

.vb-countdown-twentyseven-event::after {
  content: "";
  position: absolute;
  left: -140px;
  bottom: -160px;
  width: 390px;
  height: 390px;
  border-radius: 999px;
  background: rgba(192, 132, 252, 0.13);
}

.vb-countdown-twentyseven-map,
.vb-countdown-twentyseven-content {
  position: relative;
  z-index: 2;
  min-width: 0;
}

.vb-countdown-twentyseven-map {
  min-height: clamp(360px, 44vw, 520px);
  border-radius: 28px 6px 28px 6px;
  background:
    radial-gradient(circle at 50% 50%, rgba(255,255,255,0.13), transparent 34%),
    linear-gradient(135deg, rgba(255,255,255,0.12), rgba(255,255,255,0.04)) !important;
  border: 1px solid rgba(255,255,255,0.14);
  overflow: hidden;
  box-shadow: 0 30px 80px rgba(2, 6, 23, 0.24);
}

.vb-countdown-twentyseven-tag {
  position: absolute;
  left: 18px;
  top: 18px;
  z-index: 4;
  display: inline-flex;
  padding: 8px 12px;
  border-radius: 6px 999px 999px 6px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twentyseven-orbit {
  position: absolute;
  left: 50%;
  top: 48%;
  display: grid;
  place-items: center;
  width: clamp(190px, 30vw, 300px);
  height: clamp(190px, 30vw, 300px);
  border-radius: 999px;
  transform: translate(-50%, -50%);
  background:
    radial-gradient(circle, rgba(255,255,255,0.17), rgba(255,255,255,0.045)) !important;
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-countdown-twentyseven-orbit i {
  position: absolute;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,0.18);
}

.vb-countdown-twentyseven-orbit i:nth-child(1) {
  inset: 18px;
}

.vb-countdown-twentyseven-orbit i:nth-child(2) {
  inset: 42px;
}

.vb-countdown-twentyseven-orbit i:nth-child(3) {
  inset: 70px;
}

.vb-countdown-twentyseven-orbit strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(24px, 4vw, 42px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: 0.12em;
}

.vb-countdown-twentyseven-zone {
  position: absolute;
  display: grid;
  gap: 5px;
  min-width: 138px;
  padding: 14px;
  border-radius: 18px 6px 18px 6px;
  background: rgba(2, 6, 23, 0.68);
  border: 1px solid rgba(255,255,255,0.12);
  backdrop-filter: blur(12px);
}

.vb-countdown-twentyseven-zone-one {
  left: 22px;
  bottom: 30px;
}

.vb-countdown-twentyseven-zone-two {
  right: 22px;
  top: 82px;
}

.vb-countdown-twentyseven-zone-three {
  right: 36px;
  bottom: 34px;
}

.vb-countdown-twentyseven-zone span {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-twentyseven-zone strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.03em;
}

.vb-countdown-twentyseven-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px 6px 999px 6px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
  color: #e9d5ff !important;
  -webkit-text-fill-color: #e9d5ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twentyseven-content h3 {
  max-width: 820px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 82px) !important;
  line-height: 0.88 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
  overflow-wrap: anywhere;
}

.vb-countdown-twentyseven-content p {
  max-width: 700px;
  margin: 0 0 22px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-twentyseven-timer {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(8px, 1.4vw, 12px);
  max-width: 760px;
  margin-bottom: 18px;
}

.vb-countdown-twentyseven-timer div {
  min-width: 0;
  padding: clamp(15px, 2.5vw, 22px) 8px;
  border-radius: 999px 999px 8px 8px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.14);
  text-align: center;
}

.vb-countdown-twentyseven-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4.6vw, 54px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-twentyseven-timer span {
  display: block;
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-twentyseven-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 18px;
}

.vb-countdown-twentyseven-meta span,
.vb-countdown-twentyseven-meta strong {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.12);
  color: #e9d5ff !important;
  -webkit-text-fill-color: #e9d5ff !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-twentyseven-content a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 14px 20px;
  border-radius: 8px 999px 8px 999px;
  background: linear-gradient(135deg, #0ea5e9, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(14, 165, 233, 0.22);
}

@media (max-width: 920px) {
  .vb-countdown-twentyseven-event {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-countdown-twentyseven-demo {
    border-radius: 28px 6px 28px 6px;
  }

  .vb-countdown-twentyseven-event {
    border-radius: 24px 6px 24px 6px;
  }

  .vb-countdown-twentyseven-content h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-twentyseven-zone {
    position: static;
    margin: 10px;
  }

  .vb-countdown-twentyseven-orbit {
    top: 36%;
  }

  .vb-countdown-twentyseven-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-twentyseven-timer strong {
    font-size: clamp(30px, 13vw, 46px);
  }

  .vb-countdown-twentyseven-content a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-twentyseven-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-twentyseven]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 14;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-12T16:00:00Z").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextEventEl = timer.querySelector("[data-next-event]");
  const statusEl = timer.querySelector("[data-status]");
  const nyTimeEl = timer.querySelector("[data-ny-time]");
  const londonTimeEl = timer.querySelector("[data-london-time]");
  const tokyoTimeEl = timer.querySelector("[data-tokyo-time]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextEvent(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function formatTime(timestamp, timeZone) {
    return new Date(timestamp).toLocaleTimeString("en-US", {
      timeZone: timeZone,
      hour: "2-digit",
      minute: "2-digit"
    });
  }

  function updateCountdown() {
    const now = Date.now();
    const nextEvent = getNextEvent(now);
    let remaining = nextEvent - now;

    if (remaining <= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(nextEvent).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);

    nyTimeEl.textContent = formatTime(nextEvent, "America/New_York");
    londonTimeEl.textContent = formatTime(nextEvent, "Europe/London");
    tokyoTimeEl.textContent = formatTime(nextEvent, "Asia/Tokyo");

    nextEventEl.textContent = "Next event: " + dateText;
    statusEl.textContent = "Global event countdown active";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-twentyseven]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 14;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-12T16:00:00Z").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextEventEl = timer.querySelector("[data-next-event]");
  const statusEl = timer.querySelector("[data-status]");
  const nyTimeEl = timer.querySelector("[data-ny-time]");
  const londonTimeEl = timer.querySelector("[data-london-time]");
  const tokyoTimeEl = timer.querySelector("[data-tokyo-time]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getNextEvent(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return baseDate + (cyclesPassed + 1) * cycleMs;
  }

  function formatTime(timestamp, timeZone) {
    return new Date(timestamp).toLocaleTimeString("en-US", {
      timeZone: timeZone,
      hour: "2-digit",
      minute: "2-digit"
    });
  }

  function updateCountdown() {
    const now = Date.now();
    const nextEvent = getNextEvent(now);
    let remaining = nextEvent - now;

    if (remaining &lt;= 0) {
      remaining = cycleMs;
    }

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(nextEvent).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);

    nyTimeEl.textContent = formatTime(nextEvent, "America/New_York");
    londonTimeEl.textContent = formatTime(nextEvent, "Europe/London");
    tokyoTimeEl.textContent = formatTime(nextEvent, "Asia/Tokyo");

    nextEventEl.textContent = "Next event: " + dateText;
    statusEl.textContent = "Global event countdown active";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-twentyseven-demo"&gt;
  &lt;section class="vb-countdown-twentyseven-event" data-vb-countdown-twentyseven data-cycle-days="14"&gt;
    &lt;div class="vb-countdown-twentyseven-map"&gt;
      &lt;span class="vb-countdown-twentyseven-tag"&gt;Example 27&lt;/span&gt;

      &lt;div class="vb-countdown-twentyseven-orbit"&gt;
        &lt;i&gt;&lt;/i&gt;
        &lt;i&gt;&lt;/i&gt;
        &lt;i&gt;&lt;/i&gt;
        &lt;strong&gt;GLOBAL&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-twentyseven-zone vb-countdown-twentyseven-zone-one"&gt;
        &lt;span&gt;New York&lt;/span&gt;
        &lt;strong data-ny-time&gt;Loading&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-twentyseven-zone vb-countdown-twentyseven-zone-two"&gt;
        &lt;span&gt;London&lt;/span&gt;
        &lt;strong data-london-time&gt;Loading&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-twentyseven-zone vb-countdown-twentyseven-zone-three"&gt;
        &lt;span&gt;Tokyo&lt;/span&gt;
        &lt;strong data-tokyo-time&gt;Loading&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-twentyseven-content"&gt;
      &lt;span class="vb-countdown-twentyseven-kicker"&gt;Global Event&lt;/span&gt;
      &lt;h3&gt;Multi-Timezone Event Countdown Timer&lt;/h3&gt;
      &lt;p&gt;Use this countdown timer for international webinars, online conferences, global launches, livestream events, workshops, and worldwide campaign pages.&lt;/p&gt;

      &lt;div class="vb-countdown-twentyseven-timer" aria-label="Multi-timezone event countdown timer"&gt;
        &lt;div&gt;
          &lt;strong data-days&gt;00&lt;/strong&gt;
          &lt;span&gt;Days&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-hours&gt;00&lt;/strong&gt;
          &lt;span&gt;Hours&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
          &lt;span&gt;Min&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
          &lt;span&gt;Sec&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-twentyseven-meta"&gt;
        &lt;span data-next-event&gt;Next event loading&lt;/span&gt;
        &lt;strong data-status&gt;Global event countdown active&lt;/strong&gt;
      &lt;/div&gt;

      &lt;a href="#global-event-registration"&gt;Register for Event&lt;/a&gt;
    &lt;/div&gt;
  &lt;/section&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-twentyseven-demo,
.vb-countdown-twentyseven-demo * {
  box-sizing: border-box;
}

.vb-countdown-twentyseven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 40px 8px 40px 8px;
  background:
    radial-gradient(circle at 16% 18%, rgba(14, 165, 233, 0.17), transparent 34%),
    radial-gradient(circle at 88% 22%, rgba(168, 85, 247, 0.15), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #faf5ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.20);
  box-shadow: 0 28px 80px rgba(3, 105, 161, 0.09);
}

.vb-countdown-twentyseven-event {
  position: relative;
  display: grid;
  grid-template-columns: minmax(260px, 0.88fr) minmax(0, 1.12fr);
  gap: clamp(24px, 5vw, 46px);
  align-items: center;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(24px, 5vw, 52px);
  overflow: hidden;
  border-radius: 32px 6px 32px 6px;
  background:
    linear-gradient(90deg, rgba(255,255,255,0.05) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.05) 1px, transparent 1px),
    radial-gradient(circle at 20% 20%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #075985 48%, #581c87 100%) !important;
  background-size: 34px 34px, 34px 34px, auto, auto !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.30);
}

.vb-countdown-twentyseven-event::before {
  content: "";
  position: absolute;
  right: -140px;
  top: -130px;
  width: 390px;
  height: 390px;
  border-radius: 999px;
  background: rgba(125, 211, 252, 0.13);
}

.vb-countdown-twentyseven-event::after {
  content: "";
  position: absolute;
  left: -140px;
  bottom: -160px;
  width: 390px;
  height: 390px;
  border-radius: 999px;
  background: rgba(192, 132, 252, 0.13);
}

.vb-countdown-twentyseven-map,
.vb-countdown-twentyseven-content {
  position: relative;
  z-index: 2;
  min-width: 0;
}

.vb-countdown-twentyseven-map {
  min-height: clamp(360px, 44vw, 520px);
  border-radius: 28px 6px 28px 6px;
  background:
    radial-gradient(circle at 50% 50%, rgba(255,255,255,0.13), transparent 34%),
    linear-gradient(135deg, rgba(255,255,255,0.12), rgba(255,255,255,0.04)) !important;
  border: 1px solid rgba(255,255,255,0.14);
  overflow: hidden;
  box-shadow: 0 30px 80px rgba(2, 6, 23, 0.24);
}

.vb-countdown-twentyseven-tag {
  position: absolute;
  left: 18px;
  top: 18px;
  z-index: 4;
  display: inline-flex;
  padding: 8px 12px;
  border-radius: 6px 999px 999px 6px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twentyseven-orbit {
  position: absolute;
  left: 50%;
  top: 48%;
  display: grid;
  place-items: center;
  width: clamp(190px, 30vw, 300px);
  height: clamp(190px, 30vw, 300px);
  border-radius: 999px;
  transform: translate(-50%, -50%);
  background:
    radial-gradient(circle, rgba(255,255,255,0.17), rgba(255,255,255,0.045)) !important;
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-countdown-twentyseven-orbit i {
  position: absolute;
  border-radius: 999px;
  border: 1px solid rgba(255,255,255,0.18);
}

.vb-countdown-twentyseven-orbit i:nth-child(1) {
  inset: 18px;
}

.vb-countdown-twentyseven-orbit i:nth-child(2) {
  inset: 42px;
}

.vb-countdown-twentyseven-orbit i:nth-child(3) {
  inset: 70px;
}

.vb-countdown-twentyseven-orbit strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(24px, 4vw, 42px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: 0.12em;
}

.vb-countdown-twentyseven-zone {
  position: absolute;
  display: grid;
  gap: 5px;
  min-width: 138px;
  padding: 14px;
  border-radius: 18px 6px 18px 6px;
  background: rgba(2, 6, 23, 0.68);
  border: 1px solid rgba(255,255,255,0.12);
  backdrop-filter: blur(12px);
}

.vb-countdown-twentyseven-zone-one {
  left: 22px;
  bottom: 30px;
}

.vb-countdown-twentyseven-zone-two {
  right: 22px;
  top: 82px;
}

.vb-countdown-twentyseven-zone-three {
  right: 36px;
  bottom: 34px;
}

.vb-countdown-twentyseven-zone span {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-twentyseven-zone strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.03em;
}

.vb-countdown-twentyseven-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px 6px 999px 6px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
  color: #e9d5ff !important;
  -webkit-text-fill-color: #e9d5ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twentyseven-content h3 {
  max-width: 820px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 82px) !important;
  line-height: 0.88 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
  overflow-wrap: anywhere;
}

.vb-countdown-twentyseven-content p {
  max-width: 700px;
  margin: 0 0 22px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-twentyseven-timer {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(8px, 1.4vw, 12px);
  max-width: 760px;
  margin-bottom: 18px;
}

.vb-countdown-twentyseven-timer div {
  min-width: 0;
  padding: clamp(15px, 2.5vw, 22px) 8px;
  border-radius: 999px 999px 8px 8px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.14);
  text-align: center;
}

.vb-countdown-twentyseven-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4.6vw, 54px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-twentyseven-timer span {
  display: block;
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-twentyseven-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 18px;
}

.vb-countdown-twentyseven-meta span,
.vb-countdown-twentyseven-meta strong {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.12);
  color: #e9d5ff !important;
  -webkit-text-fill-color: #e9d5ff !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-twentyseven-content a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 14px 20px;
  border-radius: 8px 999px 8px 999px;
  background: linear-gradient(135deg, #0ea5e9, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(14, 165, 233, 0.22);
}

@media (max-width: 920px) {
  .vb-countdown-twentyseven-event {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-countdown-twentyseven-demo {
    border-radius: 28px 6px 28px 6px;
  }

  .vb-countdown-twentyseven-event {
    border-radius: 24px 6px 24px 6px;
  }

  .vb-countdown-twentyseven-content h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-twentyseven-zone {
    position: static;
    margin: 10px;
  }

  .vb-countdown-twentyseven-orbit {
    top: 36%;
  }

  .vb-countdown-twentyseven-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-twentyseven-timer strong {
    font-size: clamp(30px, 13vw, 46px);
  }

  .vb-countdown-twentyseven-content a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-twentyseven-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This multi-timezone event countdown timer is useful for global webinars, virtual conferences, livestream pages, online workshops, international product launches, and event registration landing pages.</p>



<h2 class="wp-block-heading">28. Countdown Timer with Progress Bar</h2>



<p class="wp-block-paragraph"><strong>A countdown timer with progress bar</strong> is useful for sale campaigns, checkout timers, onboarding steps, course enrollment windows, event deadlines, dashboard alerts, product launches, and landing page offers where visitors should see both remaining time and campaign progress.</p>



<p class="wp-block-paragraph">This example uses a progress-focused layout with a large horizontal progress bar, percentage indicator, timer chips, status text, and CTA button. The JavaScript uses a repeating 7-day cycle and updates both the countdown numbers and the visual progress bar.</p>



<ul class="wp-block-list">
<li>Countdown timer with progress bar</li>
<li>Dynamic progress percentage</li>
<li>Days, hours, minutes, and seconds</li>
<li>Repeating campaign cycle</li>
<li>Responsive progress timer layout</li>
</ul>



<div class="vb-countdown-twentyeight-demo">
  <section class="vb-countdown-twentyeight-progress" data-vb-countdown-twentyeight data-cycle-days="7">
    <div class="vb-countdown-twentyeight-top">
      <div>
        <span class="vb-countdown-twentyeight-kicker">Example 28</span>
        <h3>Countdown Timer with Progress Bar</h3>
        <p>Use this countdown timer with a progress bar for campaigns, checkout holds, sales, onboarding flows, course deadlines, dashboard alerts, and launch pages.</p>
      </div>

      <div class="vb-countdown-twentyeight-percent">
        <strong data-percent>0%</strong>
        <span>Time used</span>
      </div>
    </div>

    <div class="vb-countdown-twentyeight-bar-wrap">
      <div class="vb-countdown-twentyeight-bar">
        <i data-progress-bar></i>
      </div>
      <div class="vb-countdown-twentyeight-bar-labels">
        <span>Campaign started</span>
        <strong data-next-cycle>Deadline loading</strong>
      </div>
    </div>

    <div class="vb-countdown-twentyeight-bottom">
      <div class="vb-countdown-twentyeight-timer" aria-label="Countdown timer with progress bar">
        <div>
          <strong data-days>00</strong>
          <span>Days</span>
        </div>

        <div>
          <strong data-hours>00</strong>
          <span>Hours</span>
        </div>

        <div>
          <strong data-minutes>00</strong>
          <span>Min</span>
        </div>

        <div>
          <strong data-seconds>00</strong>
          <span>Sec</span>
        </div>
      </div>

      <div class="vb-countdown-twentyeight-action">
        <p data-status>Progress countdown is active.</p>
        <a href="#progress-countdown-offer">Continue Before Deadline</a>
      </div>
    </div>
  </section>
</div>

<style>
.vb-countdown-twentyeight-demo,
.vb-countdown-twentyeight-demo * {
  box-sizing: border-box;
}

.vb-countdown-twentyeight-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 22px 22px 6px 60px;
  background:
    radial-gradient(circle at 14% 18%, rgba(34, 197, 94, 0.15), transparent 34%),
    radial-gradient(circle at 88% 22%, rgba(59, 130, 246, 0.14), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #eff6ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.20);
  box-shadow: 0 28px 80px rgba(21, 128, 61, 0.09);
}

.vb-countdown-twentyeight-progress {
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(24px, 5vw, 52px);
  overflow: hidden;
  border-radius: 18px 18px 6px 46px;
  background:
    radial-gradient(circle at 24% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #052e16 0%, #14532d 52%, #1e3a8a 100%) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
}

.vb-countdown-twentyeight-top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(160px, 220px);
  gap: clamp(18px, 3vw, 28px);
  align-items: end;
  margin-bottom: clamp(22px, 4vw, 34px);
}

.vb-countdown-twentyeight-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px 999px 999px 6px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twentyeight-top h3 {
  max-width: 860px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 84px) !important;
  line-height: 0.88 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
  overflow-wrap: anywhere;
}

.vb-countdown-twentyeight-top p {
  max-width: 760px;
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-twentyeight-percent {
  min-width: 0;
  padding: 22px;
  border-radius: 28px 8px 28px 8px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.15);
  text-align: center;
}

.vb-countdown-twentyeight-percent strong {
  display: block;
  margin-bottom: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(42px, 7vw, 70px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.08em;
  font-variant-numeric: tabular-nums;
}

.vb-countdown-twentyeight-percent span {
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-twentyeight-bar-wrap {
  margin-bottom: clamp(22px, 4vw, 34px);
  padding: clamp(16px, 3vw, 22px);
  border-radius: 26px 8px 26px 8px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-countdown-twentyeight-bar {
  overflow: hidden;
  height: clamp(22px, 4vw, 34px);
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.12);
}

.vb-countdown-twentyeight-bar i {
  display: block;
  width: 0%;
  height: 100%;
  border-radius: inherit;
  background:
    linear-gradient(90deg, #22c55e, #0ea5e9, #a855f7) !important;
  box-shadow: 0 0 26px rgba(34, 197, 94, 0.35);
  transition: width 0.4s ease;
}

.vb-countdown-twentyeight-bar-labels {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-top: 12px;
}

.vb-countdown-twentyeight-bar-labels span,
.vb-countdown-twentyeight-bar-labels strong {
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 850;
}

.vb-countdown-twentyeight-bottom {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(250px, 340px);
  gap: clamp(18px, 3vw, 26px);
  align-items: stretch;
}

.vb-countdown-twentyeight-timer {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(8px, 1.4vw, 12px);
}

.vb-countdown-twentyeight-timer div {
  min-width: 0;
  padding: clamp(16px, 2.6vw, 24px) 8px;
  border-radius: 8px 28px 8px 28px;
  background: #ffffff;
  text-align: center;
  box-shadow: 0 18px 42px rgba(2, 6, 23, 0.18);
}

.vb-countdown-twentyeight-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 7px;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: clamp(28px, 4.6vw, 54px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-twentyeight-timer span {
  display: block;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-twentyeight-action {
  display: grid;
  align-content: center;
  gap: 14px;
  min-width: 0;
  padding: 22px;
  border-radius: 28px 8px 28px 8px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-countdown-twentyeight-action p {
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 750;
}

.vb-countdown-twentyeight-action a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22c55e, #0ea5e9);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(34, 197, 94, 0.22);
}

@media (max-width: 920px) {
  .vb-countdown-twentyeight-top,
  .vb-countdown-twentyeight-bottom {
    grid-template-columns: 1fr;
  }

  .vb-countdown-twentyeight-percent {
    text-align: left;
  }
}

@media (max-width: 640px) {
  .vb-countdown-twentyeight-demo {
    border-radius: 18px 18px 6px 38px;
  }

  .vb-countdown-twentyeight-progress {
    border-radius: 14px 14px 6px 30px;
  }

  .vb-countdown-twentyeight-top h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-twentyeight-bar-labels {
    flex-direction: column;
  }

  .vb-countdown-twentyeight-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-twentyeight-timer strong {
    font-size: clamp(30px, 13vw, 46px);
  }

  .vb-countdown-twentyeight-action a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-twentyeight-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-twentyeight]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 7;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-07T09:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const percentEl = timer.querySelector("[data-percent]");
  const progressBarEl = timer.querySelector("[data-progress-bar]");
  const nextCycleEl = timer.querySelector("[data-next-cycle]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getCycleData(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    const currentStart = baseDate + cyclesPassed * cycleMs;
    const nextEnd = baseDate + (cyclesPassed + 1) * cycleMs;

    return {
      currentStart: currentStart,
      nextEnd: nextEnd
    };
  }

  function updateCountdown() {
    const now = Date.now();
    const cycleData = getCycleData(now);
    let remaining = cycleData.nextEnd - now;

    if (remaining <= 0) {
      remaining = cycleMs;
    }

    const elapsed = cycleMs - remaining;
    const progress = Math.min(100, Math.max(0, Math.round((elapsed / cycleMs) * 100)));

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(cycleData.nextEnd).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);

    percentEl.textContent = progress + "%";
    progressBarEl.style.width = progress + "%";
    nextCycleEl.textContent = "Ends " + dateText;
    statusEl.textContent = "Progress countdown is active.";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-twentyeight]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 7;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-07T09:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const percentEl = timer.querySelector("[data-percent]");
  const progressBarEl = timer.querySelector("[data-progress-bar]");
  const nextCycleEl = timer.querySelector("[data-next-cycle]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getCycleData(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    const currentStart = baseDate + cyclesPassed * cycleMs;
    const nextEnd = baseDate + (cyclesPassed + 1) * cycleMs;

    return {
      currentStart: currentStart,
      nextEnd: nextEnd
    };
  }

  function updateCountdown() {
    const now = Date.now();
    const cycleData = getCycleData(now);
    let remaining = cycleData.nextEnd - now;

    if (remaining &lt;= 0) {
      remaining = cycleMs;
    }

    const elapsed = cycleMs - remaining;
    const progress = Math.min(100, Math.max(0, Math.round((elapsed / cycleMs) * 100)));

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(cycleData.nextEnd).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);

    percentEl.textContent = progress + "%";
    progressBarEl.style.width = progress + "%";
    nextCycleEl.textContent = "Ends " + dateText;
    statusEl.textContent = "Progress countdown is active.";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-twentyeight-demo"&gt;
  &lt;section class="vb-countdown-twentyeight-progress" data-vb-countdown-twentyeight data-cycle-days="7"&gt;
    &lt;div class="vb-countdown-twentyeight-top"&gt;
      &lt;div&gt;
        &lt;span class="vb-countdown-twentyeight-kicker"&gt;Example 28&lt;/span&gt;
        &lt;h3&gt;Countdown Timer with Progress Bar&lt;/h3&gt;
        &lt;p&gt;Use this countdown timer with a progress bar for campaigns, checkout holds, sales, onboarding flows, course deadlines, dashboard alerts, and launch pages.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-twentyeight-percent"&gt;
        &lt;strong data-percent&gt;0%&lt;/strong&gt;
        &lt;span&gt;Time used&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-twentyeight-bar-wrap"&gt;
      &lt;div class="vb-countdown-twentyeight-bar"&gt;
        &lt;i data-progress-bar&gt;&lt;/i&gt;
      &lt;/div&gt;
      &lt;div class="vb-countdown-twentyeight-bar-labels"&gt;
        &lt;span&gt;Campaign started&lt;/span&gt;
        &lt;strong data-next-cycle&gt;Deadline loading&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-twentyeight-bottom"&gt;
      &lt;div class="vb-countdown-twentyeight-timer" aria-label="Countdown timer with progress bar"&gt;
        &lt;div&gt;
          &lt;strong data-days&gt;00&lt;/strong&gt;
          &lt;span&gt;Days&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-hours&gt;00&lt;/strong&gt;
          &lt;span&gt;Hours&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
          &lt;span&gt;Min&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
          &lt;span&gt;Sec&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-twentyeight-action"&gt;
        &lt;p data-status&gt;Progress countdown is active.&lt;/p&gt;
        &lt;a href="#progress-countdown-offer"&gt;Continue Before Deadline&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/section&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-twentyeight-demo,
.vb-countdown-twentyeight-demo * {
  box-sizing: border-box;
}

.vb-countdown-twentyeight-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 22px 22px 6px 60px;
  background:
    radial-gradient(circle at 14% 18%, rgba(34, 197, 94, 0.15), transparent 34%),
    radial-gradient(circle at 88% 22%, rgba(59, 130, 246, 0.14), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #eff6ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.20);
  box-shadow: 0 28px 80px rgba(21, 128, 61, 0.09);
}

.vb-countdown-twentyeight-progress {
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(24px, 5vw, 52px);
  overflow: hidden;
  border-radius: 18px 18px 6px 46px;
  background:
    radial-gradient(circle at 24% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #052e16 0%, #14532d 52%, #1e3a8a 100%) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
}

.vb-countdown-twentyeight-top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(160px, 220px);
  gap: clamp(18px, 3vw, 28px);
  align-items: end;
  margin-bottom: clamp(22px, 4vw, 34px);
}

.vb-countdown-twentyeight-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px 999px 999px 6px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twentyeight-top h3 {
  max-width: 860px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 6vw, 84px) !important;
  line-height: 0.88 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
  overflow-wrap: anywhere;
}

.vb-countdown-twentyeight-top p {
  max-width: 760px;
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: clamp(15px, 1.8vw, 16px);
  line-height: 1.75;
  font-weight: 650;
}

.vb-countdown-twentyeight-percent {
  min-width: 0;
  padding: 22px;
  border-radius: 28px 8px 28px 8px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.15);
  text-align: center;
}

.vb-countdown-twentyeight-percent strong {
  display: block;
  margin-bottom: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(42px, 7vw, 70px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.08em;
  font-variant-numeric: tabular-nums;
}

.vb-countdown-twentyeight-percent span {
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-twentyeight-bar-wrap {
  margin-bottom: clamp(22px, 4vw, 34px);
  padding: clamp(16px, 3vw, 22px);
  border-radius: 26px 8px 26px 8px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-countdown-twentyeight-bar {
  overflow: hidden;
  height: clamp(22px, 4vw, 34px);
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.12);
}

.vb-countdown-twentyeight-bar i {
  display: block;
  width: 0%;
  height: 100%;
  border-radius: inherit;
  background:
    linear-gradient(90deg, #22c55e, #0ea5e9, #a855f7) !important;
  box-shadow: 0 0 26px rgba(34, 197, 94, 0.35);
  transition: width 0.4s ease;
}

.vb-countdown-twentyeight-bar-labels {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  margin-top: 12px;
}

.vb-countdown-twentyeight-bar-labels span,
.vb-countdown-twentyeight-bar-labels strong {
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 850;
}

.vb-countdown-twentyeight-bottom {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(250px, 340px);
  gap: clamp(18px, 3vw, 26px);
  align-items: stretch;
}

.vb-countdown-twentyeight-timer {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(8px, 1.4vw, 12px);
}

.vb-countdown-twentyeight-timer div {
  min-width: 0;
  padding: clamp(16px, 2.6vw, 24px) 8px;
  border-radius: 8px 28px 8px 28px;
  background: #ffffff;
  text-align: center;
  box-shadow: 0 18px 42px rgba(2, 6, 23, 0.18);
}

.vb-countdown-twentyeight-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 7px;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: clamp(28px, 4.6vw, 54px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-twentyeight-timer span {
  display: block;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-countdown-twentyeight-action {
  display: grid;
  align-content: center;
  gap: 14px;
  min-width: 0;
  padding: 22px;
  border-radius: 28px 8px 28px 8px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-countdown-twentyeight-action p {
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 750;
}

.vb-countdown-twentyeight-action a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22c55e, #0ea5e9);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(34, 197, 94, 0.22);
}

@media (max-width: 920px) {
  .vb-countdown-twentyeight-top,
  .vb-countdown-twentyeight-bottom {
    grid-template-columns: 1fr;
  }

  .vb-countdown-twentyeight-percent {
    text-align: left;
  }
}

@media (max-width: 640px) {
  .vb-countdown-twentyeight-demo {
    border-radius: 18px 18px 6px 38px;
  }

  .vb-countdown-twentyeight-progress {
    border-radius: 14px 14px 6px 30px;
  }

  .vb-countdown-twentyeight-top h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-twentyeight-bar-labels {
    flex-direction: column;
  }

  .vb-countdown-twentyeight-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-twentyeight-timer strong {
    font-size: clamp(30px, 13vw, 46px);
  }

  .vb-countdown-twentyeight-action a {
    width: 100%;
  }
}

@media (max-width: 360px) {
  .vb-countdown-twentyeight-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This countdown timer with progress bar is useful for sale campaigns, checkout reservation timers, launch pages, course enrollment windows, onboarding deadlines, dashboard alerts, and time-sensitive landing page offers.</p>



<h2 class="wp-block-heading">29. Compact Mobile Countdown Timer</h2>



<p class="wp-block-paragraph"><strong>A compact mobile countdown timer</strong> is useful for mobile landing pages, sticky offer cards, app screens, small checkout notices, limited mobile deals, product pages, and narrow website sections where the countdown must stay readable without taking too much space.</p>



<p class="wp-block-paragraph">This example uses a mobile-first vertical card with a compact header, stacked timer rows, small status badge, offer text, and thumb-friendly CTA button. The JavaScript uses a repeating 24-hour mobile offer cycle, so the demo keeps working and never stays expired.</p>



<ul class="wp-block-list">
<li>Compact mobile countdown timer</li>
<li>Mobile-first narrow card layout</li>
<li>Hours, minutes, and seconds</li>
<li>Repeating mobile offer cycle</li>
<li>Responsive small-screen CTA design</li>
</ul>



<div class="vb-countdown-twentynine-demo">
  <section class="vb-countdown-twentynine-mobile" data-vb-countdown-twentynine data-duration="86400">
    <div class="vb-countdown-twentynine-phone-card">
      <div class="vb-countdown-twentynine-top">
        <span>Example 29</span>
        <strong data-status>Mobile offer active</strong>
      </div>

      <div class="vb-countdown-twentynine-content">
        <span class="vb-countdown-twentynine-kicker">Mobile Deal</span>
        <h3>Compact Mobile Countdown Timer</h3>
        <p>Use this compact countdown timer for mobile offers, checkout reminders, app campaigns, narrow landing page CTAs, and product page promo cards.</p>
      </div>

      <div class="vb-countdown-twentynine-timer" aria-label="Compact mobile countdown timer">
        <div>
          <span>Hours</span>
          <strong data-hours>00</strong>
        </div>

        <div>
          <span>Minutes</span>
          <strong data-minutes>00</strong>
        </div>

        <div>
          <span>Seconds</span>
          <strong data-seconds>00</strong>
        </div>
      </div>

      <div class="vb-countdown-twentynine-offer">
        <small>Mobile-only bonus</small>
        <strong>Save 15% before the timer resets</strong>
      </div>

      <a href="#mobile-countdown-offer">Claim Mobile Offer</a>
    </div>
  </section>
</div>

<style>
.vb-countdown-twentynine-demo,
.vb-countdown-twentynine-demo * {
  box-sizing: border-box;
}

.vb-countdown-twentynine-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 18% 18%, rgba(244, 63, 94, 0.14), transparent 34%),
    radial-gradient(circle at 84% 18%, rgba(99, 102, 241, 0.15), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #eef2ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(244, 63, 94, 0.18);
  box-shadow: 0 28px 80px rgba(136, 19, 55, 0.08);
}

.vb-countdown-twentynine-mobile {
  display: grid;
  place-items: center;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 28px;
  background:
    radial-gradient(circle at 50% 12%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #111827 0%, #4c0519 52%, #312e81 100%) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
}

.vb-countdown-twentynine-phone-card {
  width: min(100%, 430px);
  min-width: 0;
  padding: clamp(18px, 5vw, 28px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 26% 14%, rgba(255,255,255,0.20), transparent 34%),
    linear-gradient(145deg, rgba(255,255,255,0.16), rgba(255,255,255,0.06)) !important;
  border: 1px solid rgba(255,255,255,0.16);
  box-shadow:
    0 34px 90px rgba(2, 6, 23, 0.32),
    inset 0 1px 0 rgba(255,255,255,0.12);
  backdrop-filter: blur(14px);
}

.vb-countdown-twentynine-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  margin-bottom: 22px;
}

.vb-countdown-twentynine-top span,
.vb-countdown-twentynine-top strong {
  display: inline-flex;
  padding: 8px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.14);
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  line-height: 1.2;
}

.vb-countdown-twentynine-top strong {
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  text-align: right;
}

.vb-countdown-twentynine-content {
  min-width: 0;
  margin-bottom: 20px;
}

.vb-countdown-twentynine-kicker {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 7px 10px;
  border-radius: 12px 999px 999px 12px;
  background: rgba(244, 114, 182, 0.18);
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twentynine-content h3 {
  margin: 0 0 12px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 8vw, 48px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-countdown-twentynine-content p {
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 14px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-countdown-twentynine-timer {
  display: grid;
  gap: 10px;
  margin-bottom: 18px;
}

.vb-countdown-twentynine-timer div {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 14px;
  align-items: center;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 20px;
  background: #ffffff;
  box-shadow: 0 16px 34px rgba(2, 6, 23, 0.18);
}

.vb-countdown-twentynine-timer span {
  color: #4c0519 !important;
  -webkit-text-fill-color: #4c0519 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-twentynine-timer strong {
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: clamp(30px, 9vw, 48px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
}

.vb-countdown-twentynine-offer {
  display: grid;
  gap: 6px;
  margin-bottom: 18px;
  padding: 15px;
  border-radius: 22px 8px 22px 8px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-countdown-twentynine-offer small {
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

.vb-countdown-twentynine-offer strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  line-height: 1.25;
  font-weight: 900;
}

.vb-countdown-twentynine-phone-card a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 52px;
  padding: 14px 18px;
  border-radius: 18px;
  background: linear-gradient(135deg, #f43f5e, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(244, 63, 94, 0.24);
}

@media (max-width: 520px) {
  .vb-countdown-twentynine-demo {
    border-radius: 24px;
  }

  .vb-countdown-twentynine-mobile {
    border-radius: 22px;
    padding: 14px;
  }

  .vb-countdown-twentynine-phone-card {
    border-radius: 28px;
  }

  .vb-countdown-twentynine-top {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-countdown-twentynine-top strong {
    text-align: left;
  }
}

@media (max-width: 340px) {
  .vb-countdown-twentynine-timer div {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-twentynine]");
  if (!timer) return;

  const duration = Number(timer.getAttribute("data-duration")) || 86400;
  let remaining = duration;

  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function updateCountdown() {
    if (remaining <= 0) {
      remaining = duration;
    }

    const hours = Math.floor(remaining / 3600);
    const minutes = Math.floor((remaining / 60) % 60);
    const seconds = remaining % 60;

    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    statusEl.textContent = "Mobile offer active";

    remaining -= 1;
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-twentynine]");
  if (!timer) return;

  const duration = Number(timer.getAttribute("data-duration")) || 86400;
  let remaining = duration;

  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const statusEl = timer.querySelector("[data-status]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function updateCountdown() {
    if (remaining &lt;= 0) {
      remaining = duration;
    }

    const hours = Math.floor(remaining / 3600);
    const minutes = Math.floor((remaining / 60) % 60);
    const seconds = remaining % 60;

    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);
    statusEl.textContent = "Mobile offer active";

    remaining -= 1;
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-twentynine-demo"&gt;
  &lt;section class="vb-countdown-twentynine-mobile" data-vb-countdown-twentynine data-duration="86400"&gt;
    &lt;div class="vb-countdown-twentynine-phone-card"&gt;
      &lt;div class="vb-countdown-twentynine-top"&gt;
        &lt;span&gt;Example 29&lt;/span&gt;
        &lt;strong data-status&gt;Mobile offer active&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-twentynine-content"&gt;
        &lt;span class="vb-countdown-twentynine-kicker"&gt;Mobile Deal&lt;/span&gt;
        &lt;h3&gt;Compact Mobile Countdown Timer&lt;/h3&gt;
        &lt;p&gt;Use this compact countdown timer for mobile offers, checkout reminders, app campaigns, narrow landing page CTAs, and product page promo cards.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-twentynine-timer" aria-label="Compact mobile countdown timer"&gt;
        &lt;div&gt;
          &lt;span&gt;Hours&lt;/span&gt;
          &lt;strong data-hours&gt;00&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;span&gt;Minutes&lt;/span&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;span&gt;Seconds&lt;/span&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-twentynine-offer"&gt;
        &lt;small&gt;Mobile-only bonus&lt;/small&gt;
        &lt;strong&gt;Save 15% before the timer resets&lt;/strong&gt;
      &lt;/div&gt;

      &lt;a href="#mobile-countdown-offer"&gt;Claim Mobile Offer&lt;/a&gt;
    &lt;/div&gt;
  &lt;/section&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-twentynine-demo,
.vb-countdown-twentynine-demo * {
  box-sizing: border-box;
}

.vb-countdown-twentynine-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 18% 18%, rgba(244, 63, 94, 0.14), transparent 34%),
    radial-gradient(circle at 84% 18%, rgba(99, 102, 241, 0.15), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #eef2ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(244, 63, 94, 0.18);
  box-shadow: 0 28px 80px rgba(136, 19, 55, 0.08);
}

.vb-countdown-twentynine-mobile {
  display: grid;
  place-items: center;
  max-width: 1160px;
  margin: 0 auto;
  padding: clamp(18px, 4vw, 42px);
  border-radius: 28px;
  background:
    radial-gradient(circle at 50% 12%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #111827 0%, #4c0519 52%, #312e81 100%) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
}

.vb-countdown-twentynine-phone-card {
  width: min(100%, 430px);
  min-width: 0;
  padding: clamp(18px, 5vw, 28px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 26% 14%, rgba(255,255,255,0.20), transparent 34%),
    linear-gradient(145deg, rgba(255,255,255,0.16), rgba(255,255,255,0.06)) !important;
  border: 1px solid rgba(255,255,255,0.16);
  box-shadow:
    0 34px 90px rgba(2, 6, 23, 0.32),
    inset 0 1px 0 rgba(255,255,255,0.12);
  backdrop-filter: blur(14px);
}

.vb-countdown-twentynine-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  margin-bottom: 22px;
}

.vb-countdown-twentynine-top span,
.vb-countdown-twentynine-top strong {
  display: inline-flex;
  padding: 8px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.14);
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
  line-height: 1.2;
}

.vb-countdown-twentynine-top strong {
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  text-align: right;
}

.vb-countdown-twentynine-content {
  min-width: 0;
  margin-bottom: 20px;
}

.vb-countdown-twentynine-kicker {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 7px 10px;
  border-radius: 12px 999px 999px 12px;
  background: rgba(244, 114, 182, 0.18);
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-twentynine-content h3 {
  margin: 0 0 12px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 8vw, 48px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
  overflow-wrap: anywhere;
}

.vb-countdown-twentynine-content p {
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 14px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-countdown-twentynine-timer {
  display: grid;
  gap: 10px;
  margin-bottom: 18px;
}

.vb-countdown-twentynine-timer div {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 14px;
  align-items: center;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 20px;
  background: #ffffff;
  box-shadow: 0 16px 34px rgba(2, 6, 23, 0.18);
}

.vb-countdown-twentynine-timer span {
  color: #4c0519 !important;
  -webkit-text-fill-color: #4c0519 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-countdown-twentynine-timer strong {
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: clamp(30px, 9vw, 48px);
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.055em;
  font-variant-numeric: tabular-nums;
}

.vb-countdown-twentynine-offer {
  display: grid;
  gap: 6px;
  margin-bottom: 18px;
  padding: 15px;
  border-radius: 22px 8px 22px 8px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-countdown-twentynine-offer small {
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

.vb-countdown-twentynine-offer strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  line-height: 1.25;
  font-weight: 900;
}

.vb-countdown-twentynine-phone-card a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  min-height: 52px;
  padding: 14px 18px;
  border-radius: 18px;
  background: linear-gradient(135deg, #f43f5e, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(244, 63, 94, 0.24);
}

@media (max-width: 520px) {
  .vb-countdown-twentynine-demo {
    border-radius: 24px;
  }

  .vb-countdown-twentynine-mobile {
    border-radius: 22px;
    padding: 14px;
  }

  .vb-countdown-twentynine-phone-card {
    border-radius: 28px;
  }

  .vb-countdown-twentynine-top {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-countdown-twentynine-top strong {
    text-align: left;
  }
}

@media (max-width: 340px) {
  .vb-countdown-twentynine-timer div {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This compact mobile countdown timer is useful for mobile landing pages, sticky offer cards, checkout notices, app campaigns, narrow product sections, popup offers, and small responsive CTA blocks.</p>



<h2 class="wp-block-heading">30. Complete Responsive Countdown Timer Section</h2>



<p class="wp-block-paragraph"><strong>A complete responsive countdown timer section</strong> is useful for full landing pages, ecommerce campaigns, launch pages, SaaS offers, event promotions, product releases, lead generation pages, and website sections that need a finished hero-style countdown layout.</p>



<p class="wp-block-paragraph">This final example combines a full responsive layout with a large headline, feature cards, countdown timer, progress strip, CTA buttons, trust badges, and a visual side panel. The JavaScript uses a repeating 10-day campaign cycle, so the demo remains active and works long-term.</p>



<ul class="wp-block-list">
<li>Complete responsive countdown section</li>
<li>Full landing page campaign layout</li>
<li>Days, hours, minutes, and seconds</li>
<li>CTA buttons, badges, and visual panel</li>
<li>Responsive desktop, tablet, and mobile design</li>
</ul>



<div class="vb-countdown-thirty-demo">
  <section class="vb-countdown-thirty-section" data-vb-countdown-thirty data-cycle-days="10">
    <div class="vb-countdown-thirty-copy">
      <span class="vb-countdown-thirty-kicker">Example 30</span>
      <h3>Complete Responsive Countdown Timer Section</h3>
      <p>Use this complete countdown section for product launches, ecommerce campaigns, SaaS landing pages, event promotions, lead generation pages, and limited-time website offers.</p>

      <div class="vb-countdown-thirty-timer" aria-label="Complete responsive countdown timer section">
        <div>
          <strong data-days>00</strong>
          <span>Days</span>
        </div>

        <div>
          <strong data-hours>00</strong>
          <span>Hours</span>
        </div>

        <div>
          <strong data-minutes>00</strong>
          <span>Min</span>
        </div>

        <div>
          <strong data-seconds>00</strong>
          <span>Sec</span>
        </div>
      </div>

      <div class="vb-countdown-thirty-actions">
        <a href="#complete-countdown-offer">Start Campaign</a>
        <button type="button">View Details</button>
      </div>

      <div class="vb-countdown-thirty-badges">
        <span data-next-cycle>Next cycle loading</span>
        <span data-status>Countdown active</span>
        <span>No signup required</span>
      </div>
    </div>

    <div class="vb-countdown-thirty-visual">
      <div class="vb-countdown-thirty-card-main">
        <span>Campaign Snapshot</span>
        <strong>Limited offer</strong>
        <div class="vb-countdown-thirty-progress">
          <i data-progress-bar></i>
        </div>
      </div>

      <div class="vb-countdown-thirty-mini vb-countdown-thirty-mini-one">
        <strong>10 days</strong>
        <span>Campaign cycle</span>
      </div>

      <div class="vb-countdown-thirty-mini vb-countdown-thirty-mini-two">
        <strong data-percent>0%</strong>
        <span>Cycle progress</span>
      </div>

      <div class="vb-countdown-thirty-mini vb-countdown-thirty-mini-three">
        <strong>Responsive</strong>
        <span>Mobile ready</span>
      </div>
    </div>
  </section>
</div>

<style>
.vb-countdown-thirty-demo,
.vb-countdown-thirty-demo * {
  box-sizing: border-box;
}

.vb-countdown-thirty-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 44px);
  border-radius: 60px 20px 60px 20px;
  background:
    radial-gradient(circle at 14% 18%, rgba(56, 189, 248, 0.16), transparent 34%),
    radial-gradient(circle at 88% 22%, rgba(217, 70, 239, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #fdf4ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(56, 189, 248, 0.20);
  box-shadow: 0 28px 80px rgba(12, 74, 110, 0.09);
}

.vb-countdown-thirty-section {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.12fr) minmax(280px, 0.88fr);
  gap: clamp(26px, 5vw, 52px);
  align-items: center;
  max-width: 1180px;
  margin: 0 auto;
  padding: clamp(24px, 5vw, 58px);
  overflow: hidden;
  border-radius: 46px 14px 46px 14px;
  background:
    radial-gradient(circle at 20% 18%, rgba(255,255,255,0.20), transparent 34%),
    linear-gradient(135deg, #020617 0%, #0f172a 42%, #581c87 100%) !important;
  box-shadow: 0 34px 96px rgba(15, 23, 42, 0.32);
}

.vb-countdown-thirty-section::before {
  content: "";
  position: absolute;
  left: -160px;
  top: -160px;
  width: 420px;
  height: 420px;
  border-radius: 36% 64% 52% 48%;
  background: rgba(56, 189, 248, 0.14);
}

.vb-countdown-thirty-section::after {
  content: "";
  position: absolute;
  right: -170px;
  bottom: -170px;
  width: 430px;
  height: 430px;
  border-radius: 70% 30% 45% 55%;
  background: rgba(217, 70, 239, 0.14);
}

.vb-countdown-thirty-copy,
.vb-countdown-thirty-visual {
  position: relative;
  z-index: 2;
  min-width: 0;
}

.vb-countdown-thirty-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px 999px 999px 6px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-thirty-copy h3 {
  max-width: 880px;
  margin: 0 0 18px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 6.4vw, 88px) !important;
  line-height: 0.86 !important;
  font-weight: 950 !important;
  letter-spacing: -0.09em;
  overflow-wrap: anywhere;
}

.vb-countdown-thirty-copy p {
  max-width: 760px;
  margin: 0 0 24px !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: clamp(15px, 1.8vw, 17px);
  line-height: 1.78;
  font-weight: 650;
}

.vb-countdown-thirty-timer {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(9px, 1.5vw, 13px);
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-countdown-thirty-timer div {
  min-width: 0;
  padding: clamp(16px, 2.7vw, 24px) 8px;
  border-radius: 26px 8px 26px 8px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.14);
  text-align: center;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.09);
}

.vb-countdown-thirty-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 4.8vw, 58px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.06em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-thirty-timer span {
  display: block;
  color: #f0abfc !important;
  -webkit-text-fill-color: #f0abfc !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.vb-countdown-thirty-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 18px;
}

.vb-countdown-thirty-actions a,
.vb-countdown-thirty-actions button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 52px;
  padding: 14px 20px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-countdown-thirty-actions a {
  background: linear-gradient(135deg, #38bdf8, #d946ef);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  box-shadow: 0 16px 34px rgba(56, 189, 248, 0.22);
}

.vb-countdown-thirty-actions button {
  border: 1px solid rgba(255,255,255,0.18);
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-countdown-thirty-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.vb-countdown-thirty-badges span {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.12);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-thirty-visual {
  min-height: clamp(360px, 46vw, 540px);
  border-radius: 16px 44px 16px 44px;
  background:
    radial-gradient(circle at 34% 20%, rgba(255,255,255,0.19), transparent 34%),
    linear-gradient(145deg, rgba(255,255,255,0.14), rgba(255,255,255,0.04)) !important;
  border: 1px solid rgba(255,255,255,0.15);
  box-shadow: 0 30px 80px rgba(2, 6, 23, 0.26);
  overflow: hidden;
}

.vb-countdown-thirty-card-main {
  position: absolute;
  left: 26px;
  right: 26px;
  top: 32px;
  display: grid;
  gap: 12px;
  padding: 22px;
  border-radius: 26px 8px 26px 8px;
  background: rgba(2, 6, 23, 0.68);
  border: 1px solid rgba(255,255,255,0.12);
  backdrop-filter: blur(12px);
}

.vb-countdown-thirty-card-main span {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

.vb-countdown-thirty-card-main strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 5vw, 48px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.065em;
}

.vb-countdown-thirty-progress {
  overflow: hidden;
  height: 14px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
}

.vb-countdown-thirty-progress i {
  display: block;
  width: 0%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #38bdf8, #d946ef) !important;
  transition: width 0.4s ease;
}

.vb-countdown-thirty-mini {
  position: absolute;
  display: grid;
  gap: 6px;
  min-width: 150px;
  padding: 16px;
  border-radius: 22px 8px 22px 8px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.14);
  backdrop-filter: blur(12px);
}

.vb-countdown-thirty-mini-one {
  left: 34px;
  bottom: 38px;
}

.vb-countdown-thirty-mini-two {
  right: 28px;
  top: 210px;
}

.vb-countdown-thirty-mini-three {
  right: 38px;
  bottom: 64px;
}

.vb-countdown-thirty-mini strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-countdown-thirty-mini span {
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  font-weight: 850;
}

@media (max-width: 960px) {
  .vb-countdown-thirty-section {
    grid-template-columns: 1fr;
  }

  .vb-countdown-thirty-visual {
    min-height: 440px;
  }
}

@media (max-width: 640px) {
  .vb-countdown-thirty-demo {
    border-radius: 38px 14px 38px 14px;
  }

  .vb-countdown-thirty-section {
    border-radius: 30px 10px 30px 10px;
  }

  .vb-countdown-thirty-copy h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-thirty-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-thirty-timer strong {
    font-size: clamp(30px, 13vw, 48px);
  }

  .vb-countdown-thirty-actions a,
  .vb-countdown-thirty-actions button {
    width: 100%;
  }

  .vb-countdown-thirty-visual {
    min-height: auto;
    padding: 20px;
    display: grid;
    gap: 12px;
  }

  .vb-countdown-thirty-card-main,
  .vb-countdown-thirty-mini {
    position: static;
  }
}

@media (max-width: 360px) {
  .vb-countdown-thirty-timer {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const timer = document.querySelector("[data-vb-countdown-thirty]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 10;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-11T10:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextCycleEl = timer.querySelector("[data-next-cycle]");
  const statusEl = timer.querySelector("[data-status]");
  const progressBarEl = timer.querySelector("[data-progress-bar]");
  const percentEl = timer.querySelector("[data-percent]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getCycleData(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return {
      currentStart: baseDate + cyclesPassed * cycleMs,
      nextEnd: baseDate + (cyclesPassed + 1) * cycleMs
    };
  }

  function updateCountdown() {
    const now = Date.now();
    const cycleData = getCycleData(now);
    let remaining = cycleData.nextEnd - now;

    if (remaining <= 0) {
      remaining = cycleMs;
    }

    const elapsed = cycleMs - remaining;
    const progress = Math.min(100, Math.max(0, Math.round((elapsed / cycleMs) * 100)));

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(cycleData.nextEnd).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);

    nextCycleEl.textContent = "Ends " + dateText;
    statusEl.textContent = "Countdown active";
    progressBarEl.style.width = progress + "%";
    percentEl.textContent = progress + "%";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timer = document.querySelector("[data-vb-countdown-thirty]");
  if (!timer) return;

  const cycleDays = Number(timer.getAttribute("data-cycle-days")) || 10;
  const cycleMs = cycleDays * 24 * 60 * 60 * 1000;
  const baseDate = new Date("2026-01-11T10:00:00").getTime();

  const daysEl = timer.querySelector("[data-days]");
  const hoursEl = timer.querySelector("[data-hours]");
  const minutesEl = timer.querySelector("[data-minutes]");
  const secondsEl = timer.querySelector("[data-seconds]");
  const nextCycleEl = timer.querySelector("[data-next-cycle]");
  const statusEl = timer.querySelector("[data-status]");
  const progressBarEl = timer.querySelector("[data-progress-bar]");
  const percentEl = timer.querySelector("[data-percent]");

  function formatNumber(value) {
    return String(value).padStart(2, "0");
  }

  function getCycleData(now) {
    const cyclesPassed = Math.floor((now - baseDate) / cycleMs);
    return {
      currentStart: baseDate + cyclesPassed * cycleMs,
      nextEnd: baseDate + (cyclesPassed + 1) * cycleMs
    };
  }

  function updateCountdown() {
    const now = Date.now();
    const cycleData = getCycleData(now);
    let remaining = cycleData.nextEnd - now;

    if (remaining &lt;= 0) {
      remaining = cycleMs;
    }

    const elapsed = cycleMs - remaining;
    const progress = Math.min(100, Math.max(0, Math.round((elapsed / cycleMs) * 100)));

    const days = Math.floor(remaining / (1000 * 60 * 60 * 24));
    const hours = Math.floor((remaining / (1000 * 60 * 60)) % 24);
    const minutes = Math.floor((remaining / (1000 * 60)) % 60);
    const seconds = Math.floor((remaining / 1000) % 60);

    const dateText = new Date(cycleData.nextEnd).toLocaleDateString("en-US", {
      month: "short",
      day: "numeric"
    });

    daysEl.textContent = formatNumber(days);
    hoursEl.textContent = formatNumber(hours);
    minutesEl.textContent = formatNumber(minutes);
    secondsEl.textContent = formatNumber(seconds);

    nextCycleEl.textContent = "Ends " + dateText;
    statusEl.textContent = "Countdown active";
    progressBarEl.style.width = progress + "%";
    percentEl.textContent = progress + "%";
  }

  updateCountdown();
  setInterval(updateCountdown, 1000);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-countdown-thirty-demo"&gt;
  &lt;section class="vb-countdown-thirty-section" data-vb-countdown-thirty data-cycle-days="10"&gt;
    &lt;div class="vb-countdown-thirty-copy"&gt;
      &lt;span class="vb-countdown-thirty-kicker"&gt;Example 30&lt;/span&gt;
      &lt;h3&gt;Complete Responsive Countdown Timer Section&lt;/h3&gt;
      &lt;p&gt;Use this complete countdown section for product launches, ecommerce campaigns, SaaS landing pages, event promotions, lead generation pages, and limited-time website offers.&lt;/p&gt;

      &lt;div class="vb-countdown-thirty-timer" aria-label="Complete responsive countdown timer section"&gt;
        &lt;div&gt;
          &lt;strong data-days&gt;00&lt;/strong&gt;
          &lt;span&gt;Days&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-hours&gt;00&lt;/strong&gt;
          &lt;span&gt;Hours&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-minutes&gt;00&lt;/strong&gt;
          &lt;span&gt;Min&lt;/span&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;strong data-seconds&gt;00&lt;/strong&gt;
          &lt;span&gt;Sec&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-thirty-actions"&gt;
        &lt;a href="#complete-countdown-offer"&gt;Start Campaign&lt;/a&gt;
        &lt;button type="button"&gt;View Details&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-thirty-badges"&gt;
        &lt;span data-next-cycle&gt;Next cycle loading&lt;/span&gt;
        &lt;span data-status&gt;Countdown active&lt;/span&gt;
        &lt;span&gt;No signup required&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-countdown-thirty-visual"&gt;
      &lt;div class="vb-countdown-thirty-card-main"&gt;
        &lt;span&gt;Campaign Snapshot&lt;/span&gt;
        &lt;strong&gt;Limited offer&lt;/strong&gt;
        &lt;div class="vb-countdown-thirty-progress"&gt;
          &lt;i data-progress-bar&gt;&lt;/i&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-thirty-mini vb-countdown-thirty-mini-one"&gt;
        &lt;strong&gt;10 days&lt;/strong&gt;
        &lt;span&gt;Campaign cycle&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-thirty-mini vb-countdown-thirty-mini-two"&gt;
        &lt;strong data-percent&gt;0%&lt;/strong&gt;
        &lt;span&gt;Cycle progress&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-countdown-thirty-mini vb-countdown-thirty-mini-three"&gt;
        &lt;strong&gt;Responsive&lt;/strong&gt;
        &lt;span&gt;Mobile ready&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/section&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-countdown-thirty-demo,
.vb-countdown-thirty-demo * {
  box-sizing: border-box;
}

.vb-countdown-thirty-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 44px);
  border-radius: 60px 20px 60px 20px;
  background:
    radial-gradient(circle at 14% 18%, rgba(56, 189, 248, 0.16), transparent 34%),
    radial-gradient(circle at 88% 22%, rgba(217, 70, 239, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #fdf4ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(56, 189, 248, 0.20);
  box-shadow: 0 28px 80px rgba(12, 74, 110, 0.09);
}

.vb-countdown-thirty-section {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1.12fr) minmax(280px, 0.88fr);
  gap: clamp(26px, 5vw, 52px);
  align-items: center;
  max-width: 1180px;
  margin: 0 auto;
  padding: clamp(24px, 5vw, 58px);
  overflow: hidden;
  border-radius: 46px 14px 46px 14px;
  background:
    radial-gradient(circle at 20% 18%, rgba(255,255,255,0.20), transparent 34%),
    linear-gradient(135deg, #020617 0%, #0f172a 42%, #581c87 100%) !important;
  box-shadow: 0 34px 96px rgba(15, 23, 42, 0.32);
}

.vb-countdown-thirty-section::before {
  content: "";
  position: absolute;
  left: -160px;
  top: -160px;
  width: 420px;
  height: 420px;
  border-radius: 36% 64% 52% 48%;
  background: rgba(56, 189, 248, 0.14);
}

.vb-countdown-thirty-section::after {
  content: "";
  position: absolute;
  right: -170px;
  bottom: -170px;
  width: 430px;
  height: 430px;
  border-radius: 70% 30% 45% 55%;
  background: rgba(217, 70, 239, 0.14);
}

.vb-countdown-thirty-copy,
.vb-countdown-thirty-visual {
  position: relative;
  z-index: 2;
  min-width: 0;
}

.vb-countdown-thirty-kicker {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px 999px 999px 6px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-countdown-thirty-copy h3 {
  max-width: 880px;
  margin: 0 0 18px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 6.4vw, 88px) !important;
  line-height: 0.86 !important;
  font-weight: 950 !important;
  letter-spacing: -0.09em;
  overflow-wrap: anywhere;
}

.vb-countdown-thirty-copy p {
  max-width: 760px;
  margin: 0 0 24px !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: clamp(15px, 1.8vw, 17px);
  line-height: 1.78;
  font-weight: 650;
}

.vb-countdown-thirty-timer {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: clamp(9px, 1.5vw, 13px);
  max-width: 780px;
  margin-bottom: 22px;
}

.vb-countdown-thirty-timer div {
  min-width: 0;
  padding: clamp(16px, 2.7vw, 24px) 8px;
  border-radius: 26px 8px 26px 8px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.14);
  text-align: center;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.09);
}

.vb-countdown-thirty-timer strong {
  display: block;
  max-width: 100%;
  margin-bottom: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 4.8vw, 58px);
  line-height: 0.92;
  font-weight: 950;
  letter-spacing: -0.06em;
  font-variant-numeric: tabular-nums;
  overflow-wrap: anywhere;
}

.vb-countdown-thirty-timer span {
  display: block;
  color: #f0abfc !important;
  -webkit-text-fill-color: #f0abfc !important;
  font-size: 10px;
  font-weight: 950;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.vb-countdown-thirty-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 18px;
}

.vb-countdown-thirty-actions a,
.vb-countdown-thirty-actions button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 52px;
  padding: 14px 20px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-countdown-thirty-actions a {
  background: linear-gradient(135deg, #38bdf8, #d946ef);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  box-shadow: 0 16px 34px rgba(56, 189, 248, 0.22);
}

.vb-countdown-thirty-actions button {
  border: 1px solid rgba(255,255,255,0.18);
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-countdown-thirty-badges {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.vb-countdown-thirty-badges span {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.12);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-countdown-thirty-visual {
  min-height: clamp(360px, 46vw, 540px);
  border-radius: 16px 44px 16px 44px;
  background:
    radial-gradient(circle at 34% 20%, rgba(255,255,255,0.19), transparent 34%),
    linear-gradient(145deg, rgba(255,255,255,0.14), rgba(255,255,255,0.04)) !important;
  border: 1px solid rgba(255,255,255,0.15);
  box-shadow: 0 30px 80px rgba(2, 6, 23, 0.26);
  overflow: hidden;
}

.vb-countdown-thirty-card-main {
  position: absolute;
  left: 26px;
  right: 26px;
  top: 32px;
  display: grid;
  gap: 12px;
  padding: 22px;
  border-radius: 26px 8px 26px 8px;
  background: rgba(2, 6, 23, 0.68);
  border: 1px solid rgba(255,255,255,0.12);
  backdrop-filter: blur(12px);
}

.vb-countdown-thirty-card-main span {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.11em;
  text-transform: uppercase;
}

.vb-countdown-thirty-card-main strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 5vw, 48px);
  line-height: 0.95;
  font-weight: 950;
  letter-spacing: -0.065em;
}

.vb-countdown-thirty-progress {
  overflow: hidden;
  height: 14px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
}

.vb-countdown-thirty-progress i {
  display: block;
  width: 0%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #38bdf8, #d946ef) !important;
  transition: width 0.4s ease;
}

.vb-countdown-thirty-mini {
  position: absolute;
  display: grid;
  gap: 6px;
  min-width: 150px;
  padding: 16px;
  border-radius: 22px 8px 22px 8px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.14);
  backdrop-filter: blur(12px);
}

.vb-countdown-thirty-mini-one {
  left: 34px;
  bottom: 38px;
}

.vb-countdown-thirty-mini-two {
  right: 28px;
  top: 210px;
}

.vb-countdown-thirty-mini-three {
  right: 38px;
  bottom: 64px;
}

.vb-countdown-thirty-mini strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-countdown-thirty-mini span {
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  font-weight: 850;
}

@media (max-width: 960px) {
  .vb-countdown-thirty-section {
    grid-template-columns: 1fr;
  }

  .vb-countdown-thirty-visual {
    min-height: 440px;
  }
}

@media (max-width: 640px) {
  .vb-countdown-thirty-demo {
    border-radius: 38px 14px 38px 14px;
  }

  .vb-countdown-thirty-section {
    border-radius: 30px 10px 30px 10px;
  }

  .vb-countdown-thirty-copy h3 {
    font-size: 38px !important;
    letter-spacing: -0.06em;
  }

  .vb-countdown-thirty-timer {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-countdown-thirty-timer strong {
    font-size: clamp(30px, 13vw, 48px);
  }

  .vb-countdown-thirty-actions a,
  .vb-countdown-thirty-actions button {
    width: 100%;
  }

  .vb-countdown-thirty-visual {
    min-height: auto;
    padding: 20px;
    display: grid;
    gap: 12px;
  }

  .vb-countdown-thirty-card-main,
  .vb-countdown-thirty-mini {
    position: static;
  }
}

@media (max-width: 360px) {
  .vb-countdown-thirty-timer {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This complete responsive countdown timer section is useful for launch pages, ecommerce campaigns, SaaS offers, product releases, event promotions, lead generation pages, and full-width landing page countdown sections.</p>



<div class="vb24-js-countdown-lower-ad">
  <a class="vb24-countdown-entityschema-banner" href="https://veebilehed24.ee/en/shop/entityschema-pro/" target="_blank" rel="sponsored noopener">
    <div class="vb24-countdown-entityschema-media">
      <img decoding="async" src="https://veebilehed24.ee/wp-content/uploads/2026/03/entityschema-cover-600x400.webp" width="300" height="200" alt="EntitySchema Pro WordPress structured data and entity SEO plugin" loading="lazy">
    </div>

    <div class="vb24-countdown-entityschema-content">
      <span>WordPress SEO Plugin</span>
      <h3>Make Your Website Easier for Google and AI Search to Understand</h3>
      <p>EntitySchema Pro helps website owners add clear entity-based structured data to WordPress pages, posts, products, services, authors, organizations, FAQs, and local business content.</p>

      <div class="vb24-countdown-entityschema-price">
        <small>Limited offer</small>
        <strong>29€</strong>
        <em>Regular price 89€</em>
      </div>

      <b>View EntitySchema Pro</b>
    </div>
  </a>
</div>

<style>
.vb24-js-countdown-lower-ad,
.vb24-js-countdown-lower-ad * {
  box-sizing: border-box;
}

.vb24-js-countdown-lower-ad {
  margin: 42px 0 44px;
}

.vb24-countdown-entityschema-banner {
  display: grid;
  grid-template-columns: 300px minmax(0, 1fr);
  gap: 24px;
  align-items: center;
  padding: clamp(18px, 4vw, 30px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 12% 18%, rgba(34, 211, 238, 0.24), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(236, 72, 153, 0.20), transparent 34%),
    linear-gradient(135deg, #111827 0%, #312e81 52%, #701a75 100%) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  box-shadow: 0 26px 76px rgba(2, 6, 23, 0.28);
  overflow: hidden;
}

.vb24-countdown-entityschema-media {
  overflow: hidden;
  border-radius: 22px;
  border: 1px solid rgba(255,255,255,0.18);
  background: rgba(255,255,255,0.08);
}

.vb24-countdown-entityschema-media img {
  display: block;
  width: 100%;
  height: auto;
}

.vb24-countdown-entityschema-content {
  min-width: 0;
}

.vb24-countdown-entityschema-content > span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 7px 11px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.18);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb24-countdown-entityschema-content h3 {
  margin: 0 0 12px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(28px, 4vw, 46px) !important;
  line-height: 1.02 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb24-countdown-entityschema-content p {
  max-width: 760px;
  margin: 0 0 18px !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb24-countdown-entityschema-price {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin-bottom: 18px;
}

.vb24-countdown-entityschema-price small {
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.18);
  border: 1px solid rgba(74, 222, 128, 0.30);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb24-countdown-entityschema-price strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 36px;
  line-height: 1;
  font-weight: 950;
}

.vb24-countdown-entityschema-price em {
  color: rgba(255,255,255,0.70) !important;
  -webkit-text-fill-color: rgba(255,255,255,0.70) !important;
  font-size: 14px;
  font-style: normal;
  font-weight: 800;
  text-decoration: line-through;
  text-decoration-color: rgba(248, 113, 113, 0.95);
  text-decoration-thickness: 2px;
}

.vb24-countdown-entityschema-content b {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 46px;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22d3ee, #2563eb 55%, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 36px rgba(37, 99, 235, 0.30);
}

@media (max-width: 780px) {
  .vb24-countdown-entityschema-banner {
    grid-template-columns: 1fr;
  }

  .vb24-countdown-entityschema-media {
    max-width: 360px;
  }
}
</style>



<h2 class="wp-block-heading" id="javascript-countdown-timer-best-practices">JavaScript Countdown Timer Best Practices</h2>



<p class="wp-block-paragraph">JavaScript countdown timers work best when they make a real deadline easier to understand. A good countdown timer should be readable, accurate, responsive, and clearly connected to the action on the page, whether that action is joining an event, buying during a sale, reserving a checkout item, downloading an app, registering for a webinar, or waiting for a launch.</p>



<p class="wp-block-paragraph">The most important rule is simple: the timer must support the page goal. Do not add a countdown only because it looks dynamic. Use it when timing matters, when visitors need a deadline, or when a campaign genuinely has a limited window.</p>



<div class="vb24-js-countdown-practice-grid">
  <article>
    <span>01</span>
    <h3>Use a clear deadline</h3>
    <p>Tell users what the countdown is for: a sale end, event start, product launch, booking deadline, checkout hold, or campaign expiry.</p>
  </article>

  <article>
    <span>02</span>
    <h3>Keep time units readable</h3>
    <p>Days, hours, minutes, and seconds should stay readable on desktop, tablet, and mobile screens without overflowing the timer boxes.</p>
  </article>

  <article>
    <span>03</span>
    <h3>Handle the zero state</h3>
    <p>Decide what happens when the timer reaches zero: show expired text, reset the demo cycle, hide the offer, disable a button, or load the next deadline.</p>
  </article>

  <article>
    <span>04</span>
    <h3>Use scoped JavaScript</h3>
    <p>Use unique wrappers and selectors so multiple countdown timers can exist on the same page without conflicting with each other.</p>
  </article>

  <article>
    <span>05</span>
    <h3>Use real campaign copy</h3>
    <p>The timer should explain why the user should care. Strong labels and CTA text are just as important as the countdown numbers.</p>
  </article>

  <article>
    <span>06</span>
    <h3>Test real screen sizes</h3>
    <p>Countdown numbers can become wide. Always test long day values, narrow mobile screens, tablet layouts, and large desktop sections.</p>
  </article>
</div>

<style>
.vb24-js-countdown-practice-grid,
.vb24-js-countdown-practice-grid * {
  box-sizing: border-box;
}

.vb24-js-countdown-practice-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  margin: 26px 0 34px;
}

.vb24-js-countdown-practice-grid article {
  padding: 22px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 16% 12%, rgba(249, 115, 22, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.08);
}

.vb24-js-countdown-practice-grid span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 12px;
  font-weight: 950;
}

.vb24-js-countdown-practice-grid h3 {
  margin: 0 0 10px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 20px !important;
  line-height: 1.2 !important;
  font-weight: 900 !important;
  letter-spacing: -0.035em;
}

.vb24-js-countdown-practice-grid p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb24-js-countdown-practice-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-js-countdown-practice-grid {
    grid-template-columns: 1fr;
  }
}
</style>



<ul class="wp-block-list">
  <li><strong>Use fixed-date timers</strong> for real launches, webinars, events, and booking deadlines.</li>
  <li><strong>Use recurring timers</strong> for daily deals, weekly campaigns, demo examples, and repeated availability windows.</li>
  <li><strong>Use local time carefully</strong> if the campaign is based on the visitor’s local timezone.</li>
  <li><strong>Use UTC or timezone-aware dates</strong> for global events, livestreams, webinars, and international campaigns.</li>
  <li><strong>Keep CTA buttons close to the timer</strong> so users know what to do before the deadline ends.</li>
  <li><strong>Avoid fake urgency</strong> because misleading timers can reduce trust and make a website feel spammy.</li>
</ul>



<h2 class="wp-block-heading" id="responsive-countdown-timer-design-tips">Responsive Countdown Timer Design Tips</h2>



<p class="wp-block-paragraph">Responsive countdown timer design matters because timer numbers can easily become too wide on small screens. A four-column desktop timer may look great on a landing page, but the same layout can break on mobile if the numbers, labels, padding, or borders are too large.</p>



<p class="wp-block-paragraph">For mobile screens, stack timer units into two columns or one column, reduce padding, use fluid font sizes with <code>clamp()</code>, and make sure every number uses <code>minmax(0, 1fr)</code> or similar layout rules so the timer does not overflow the container.</p>



<div class="vb24-js-countdown-responsive-box">
  <div>
    <h3>Desktop countdown sections</h3>
    <p>Use wider layouts, side visuals, horizontal timers, large headlines, progress bars, and strong CTA areas when there is enough space.</p>
  </div>

  <div>
    <h3>Tablet countdown layouts</h3>
    <p>Reduce complex columns, stack visual panels when needed, and keep timer boxes large enough to scan quickly.</p>
  </div>

  <div>
    <h3>Mobile countdown cards</h3>
    <p>Use two-column or stacked timer layouts, full-width buttons, shorter labels, and flexible number sizing for small screens.</p>
  </div>
</div>

<style>
.vb24-js-countdown-responsive-box,
.vb24-js-countdown-responsive-box * {
  box-sizing: border-box;
}

.vb24-js-countdown-responsive-box {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  margin: 26px 0 34px;
  padding: 22px;
  border-radius: 28px;
  background:
    radial-gradient(circle at 16% 18%, rgba(236, 72, 153, 0.14), transparent 34%),
    linear-gradient(135deg, #fff7ed, #fdf2f8) !important;
  border: 1px solid rgba(249, 115, 22, 0.22);
}

.vb24-js-countdown-responsive-box div {
  padding: 20px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb24-js-countdown-responsive-box h3 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px !important;
  line-height: 1.25 !important;
  font-weight: 900 !important;
  letter-spacing: -0.035em;
}

.vb24-js-countdown-responsive-box p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

@media (max-width: 860px) {
  .vb24-js-countdown-responsive-box {
    grid-template-columns: 1fr;
  }
}
</style>



<ul class="wp-block-list">
  <li><strong>Use fluid font sizes</strong> with <code>clamp()</code> for countdown numbers.</li>
  <li><strong>Use flexible grid columns</strong> such as <code>repeat(4, minmax(0, 1fr))</code>.</li>
  <li><strong>Switch to two columns on mobile</strong> for days, hours, minutes, and seconds.</li>
  <li><strong>Use one-column timers</strong> for very narrow mobile cards or sticky offer widgets.</li>
  <li><strong>Keep labels short</strong> when space is limited, such as “Min” and “Sec”.</li>
  <li><strong>Test large values</strong> because “100” days takes more space than “07” days.</li>
</ul>



<h2 class="wp-block-heading" id="common-javascript-countdown-timer-mistakes">Common JavaScript Countdown Timer Mistakes</h2>



<p class="wp-block-paragraph">Common JavaScript countdown timer mistakes usually happen when a timer is built only for the first day it is published. A hardcoded date can become expired, a layout can break on mobile, or the script can stop working when the same page contains multiple countdown components.</p>



<p class="wp-block-paragraph">Most countdown timer problems are easy to avoid if you decide the timer logic first. Before styling the timer, choose whether it should use a fixed date, recurring cycle, local deadline, UTC deadline, expired message, auto-reset demo behavior, or campaign-specific action.</p>



<div class="vb24-js-countdown-mistakes">
  <article>
    <strong>Using expired hardcoded dates</strong>
    <p>A countdown timer that points to an old date will show zero or negative values unless you handle the expired state or use recurring logic.</p>
  </article>

  <article>
    <strong>Forgetting mobile overflow</strong>
    <p>Large timer numbers can break small cards. Use flexible grids, responsive font sizes, and enough width for each timer unit.</p>
  </article>

  <article>
    <strong>Not explaining the deadline</strong>
    <p>Users should know whether the timer is for a sale, product launch, webinar, checkout hold, booking deadline, or event start.</p>
  </article>

  <article>
    <strong>Using global selectors</strong>
    <p>Generic selectors can make one timer update another timer by accident. Scope each script to a unique wrapper.</p>
  </article>

  <article>
    <strong>Ignoring timezone behavior</strong>
    <p>Global webinars, livestreams, and launches need careful timezone handling so visitors in different regions see the correct timing.</p>
  </article>

  <article>
    <strong>Creating fake urgency</strong>
    <p>A timer should be useful and honest. Fake scarcity can make an ecommerce page, service page, or landing page feel untrustworthy.</p>
  </article>
</div>

<style>
.vb24-js-countdown-mistakes,
.vb24-js-countdown-mistakes * {
  box-sizing: border-box;
}

.vb24-js-countdown-mistakes {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  margin: 26px 0 34px;
}

.vb24-js-countdown-mistakes article {
  position: relative;
  padding: 20px 20px 20px 56px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(248, 113, 113, 0.22);
  box-shadow: 0 16px 40px rgba(127, 29, 29, 0.07);
}

.vb24-js-countdown-mistakes article::before {
  content: "!";
  position: absolute;
  left: 18px;
  top: 20px;
  width: 26px;
  height: 26px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 15px;
  font-weight: 950;
}

.vb24-js-countdown-mistakes strong {
  display: block;
  margin-bottom: 7px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 900;
}

.vb24-js-countdown-mistakes p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 720px) {
  .vb24-js-countdown-mistakes {
    grid-template-columns: 1fr;
  }
}
</style>



<ul class="wp-block-list">
  <li><strong>Do not rely only on visual urgency</strong> without explaining the offer or deadline.</li>
  <li><strong>Do not let timers stay at zero</strong> unless an expired state is the intended behavior.</li>
  <li><strong>Do not make countdown labels too small</strong> on mobile screens.</li>
  <li><strong>Do not use the same ID multiple times</strong> when copying several timer examples into one post.</li>
  <li><strong>Do not forget accessibility basics</strong>, including readable contrast and clear CTA text.</li>
</ul>



<h2 class="wp-block-heading" id="javascript-countdown-timer-faq">JavaScript Countdown Timer FAQ</h2>



<p class="wp-block-paragraph">Here are common questions about JavaScript countdown timers for websites, landing pages, ecommerce campaigns, product launches, event pages, webinar registrations, checkout timers, and responsive UI sections.</p>



<div class="vb24-js-countdown-faq-section" data-vb24-js-countdown-faq>
  <section class="vb24-js-countdown-faq-item is-open">
    <button class="vb24-js-countdown-faq-trigger" type="button" aria-expanded="true">
      <span>What is a JavaScript countdown timer?</span>
      <em></em>
    </button>
    <div class="vb24-js-countdown-faq-panel">
      <div class="vb24-js-countdown-faq-content">
        <p>A JavaScript countdown timer is an interactive component that calculates and displays the remaining time until a specific deadline, such as a sale end, event start, product launch, webinar, booking deadline, or checkout reservation expiry.</p>
      </div>
    </div>
  </section>

  <section class="vb24-js-countdown-faq-item">
    <button class="vb24-js-countdown-faq-trigger" type="button" aria-expanded="false">
      <span>Where should I use countdown timers on a website?</span>
      <em></em>
    </button>
    <div class="vb24-js-countdown-faq-panel">
      <div class="vb24-js-countdown-faq-content">
        <p>Countdown timers work well on sale pages, product launch pages, webinar pages, event landing pages, coming soon pages, checkout pages, booking pages, app launch pages, and dashboard deadline widgets.</p>
      </div>
    </div>
  </section>

  <section class="vb24-js-countdown-faq-item">
    <button class="vb24-js-countdown-faq-trigger" type="button" aria-expanded="false">
      <span>Should a countdown timer reset automatically?</span>
      <em></em>
    </button>
    <div class="vb24-js-countdown-faq-panel">
      <div class="vb24-js-countdown-faq-content">
        <p>It depends on the use case. A real event or product launch should usually use a fixed deadline. A daily deal, weekly campaign, or demo example can use recurring logic so the timer continues to work after the first cycle ends.</p>
      </div>
    </div>
  </section>

  <section class="vb24-js-countdown-faq-item">
    <button class="vb24-js-countdown-faq-trigger" type="button" aria-expanded="false">
      <span>How do I make a countdown timer responsive?</span>
      <em></em>
    </button>
    <div class="vb24-js-countdown-faq-panel">
      <div class="vb24-js-countdown-faq-content">
        <p>Use flexible CSS grid columns, responsive font sizes, short labels, enough padding, and media queries that switch four timer units into two columns or one column on smaller screens.</p>
      </div>
    </div>
  </section>

  <section class="vb24-js-countdown-faq-item">
    <button class="vb24-js-countdown-faq-trigger" type="button" aria-expanded="false">
      <span>Can I use these countdown timer examples in WordPress?</span>
      <em></em>
    </button>
    <div class="vb24-js-countdown-faq-panel">
      <div class="vb24-js-countdown-faq-content">
        <p>Yes. These examples use vanilla JavaScript, HTML, and CSS, so they can be pasted into a Gutenberg Custom HTML block. For a live website, repeated CSS and JavaScript should usually be moved into your theme or plugin files.</p>
      </div>
    </div>
  </section>

  <section class="vb24-js-countdown-faq-item">
    <button class="vb24-js-countdown-faq-trigger" type="button" aria-expanded="false">
      <span>What happens when a JavaScript countdown timer reaches zero?</span>
      <em></em>
    </button>
    <div class="vb24-js-countdown-faq-panel">
      <div class="vb24-js-countdown-faq-content">
        <p>You can show an expired message, disable a button, hide the offer, change the CTA, display a new deadline, or reset the timer for a recurring campaign. The right behavior depends on the purpose of the timer.</p>
      </div>
    </div>
  </section>
</div>

<style>
.vb24-js-countdown-faq-section,
.vb24-js-countdown-faq-section * {
  box-sizing: border-box;
}

.vb24-js-countdown-faq-section {
  display: grid;
  gap: 12px;
  margin: 26px 0 36px;
}

.vb24-js-countdown-faq-item {
  overflow: hidden;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.07);
}

.vb24-js-countdown-faq-item.is-open {
  border-color: rgba(249, 115, 22, 0.42);
  box-shadow: 0 24px 64px rgba(249, 115, 22, 0.12);
}

.vb24-js-countdown-faq-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 44px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 76px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb24-js-countdown-faq-trigger span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 19px;
  line-height: 1.25;
  font-weight: 900;
  letter-spacing: -0.035em;
}

.vb24-js-countdown-faq-trigger em {
  position: relative;
  width: 44px;
  height: 44px;
  border-radius: 16px;
  background: #fff7ed;
  border: 1px solid rgba(249, 115, 22, 0.20);
}

.vb24-js-countdown-faq-trigger em::before,
.vb24-js-countdown-faq-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 16px;
  height: 2px;
  border-radius: 999px;
  background: #ea580c;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease;
}

.vb24-js-countdown-faq-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb24-js-countdown-faq-item.is-open .vb24-js-countdown-faq-trigger em {
  background: #ea580c;
}

.vb24-js-countdown-faq-item.is-open .vb24-js-countdown-faq-trigger em::before,
.vb24-js-countdown-faq-item.is-open .vb24-js-countdown-faq-trigger em::after {
  background: #ffffff;
}

.vb24-js-countdown-faq-item.is-open .vb24-js-countdown-faq-trigger em::after {
  opacity: 0;
}

.vb24-js-countdown-faq-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb24-js-countdown-faq-content {
  padding: 0 20px 20px;
}

.vb24-js-countdown-faq-content p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 640px) {
  .vb24-js-countdown-faq-trigger {
    padding: 16px;
    min-height: 70px;
  }

  .vb24-js-countdown-faq-trigger span {
    font-size: 17px;
  }

  .vb24-js-countdown-faq-content {
    padding: 0 16px 16px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb24-js-countdown-faq]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb24-js-countdown-faq-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb24-js-countdown-faq-trigger");
    const panel = item.querySelector(".vb24-js-countdown-faq-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb24-js-countdown-faq-trigger");
    const panel = item.querySelector(".vb24-js-countdown-faq-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb24-js-countdown-faq-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  items.forEach(function (item) {
    if (item.classList.contains("is-open")) {
      openItem(item);
    } else {
      closeItem(item);
    }
  });

  window.addEventListener("resize", function () {
    items.forEach(function (item) {
      if (item.classList.contains("is-open")) {
        const panel = item.querySelector(".vb24-js-countdown-faq-panel");
        panel.style.maxHeight = panel.scrollHeight + "px";
      }
    });
  });
})();
</script>



<h2 class="wp-block-heading" id="javascript-countdown-timer-conclusion">Conclusion</h2>



<p class="wp-block-paragraph">JavaScript countdown timers are useful for websites where timing matters. They can improve sale pages, product launch sections, webinar registrations, event landing pages, checkout flows, coming soon pages, app launch pages, donation campaigns, booking deadlines, dashboard widgets, and full responsive landing page sections.</p>



<p class="wp-block-paragraph">The best countdown timer is not only a set of changing numbers. It has a clear purpose, readable labels, responsive layout, strong call-to-action, honest deadline, and JavaScript logic that handles what happens when time reaches zero. That is what makes a timer useful for real users instead of just decorative animation.</p>



<p class="wp-block-paragraph">You can use the examples in this guide as starting points for ecommerce campaigns, SaaS websites, landing pages, WordPress projects, event websites, online courses, app launches, nonprofit pages, and dashboard interfaces. Customize the colors, spacing, copy, dates, reset logic, and layout to match your own website design.</p>



<h2 class="wp-block-heading" id="related-javascript-and-css-guides">Related JavaScript and CSS Guides</h2>



<p class="wp-block-paragraph">Continue building better website sections and interactive UI components with these related JavaScript and CSS guides. These posts work well together when building full landing pages, product pages, dashboards, forms, filters, menus, and responsive website layouts.</p>



<div class="vb24-js-countdown-related">
  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-accordion-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Accordion Examples</strong>
    <p>FAQ accordions, product toggles, dashboard panels, nested accordions, and responsive content expanders.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-search-filter-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Search Filter Examples</strong>
    <p>Live search, card filters, product filters, FAQ search, dashboard filters, and responsive filtering UI examples.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-dropdown-menu-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Dropdown Menu Examples</strong>
    <p>Custom selects, navigation dropdowns, profile menus, category dropdowns, and responsive menu components.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-slider-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Slider Examples</strong>
    <p>Image sliders, product carousels, testimonial sliders, hero sliders, and content carousel components.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-form-validation-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Form Validation Examples</strong>
    <p>Input validation, signup validation, checkout validation, password checks, and user-friendly form feedback.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-modal-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Modal Examples</strong>
    <p>Popup windows, dialog boxes, overlay components, confirmation modals, and responsive modal UI patterns.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-website-hero-sections/">
    <span>CSS</span>
    <strong>30 Modern Website Hero Sections</strong>
    <p>Responsive hero layouts, landing page headers, CTA sections, gradients, image panels, and modern website intros.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-pricing-tables/">
    <span>CSS</span>
    <strong>30 Modern CSS Pricing Tables</strong>
    <p>Responsive pricing cards, SaaS pricing sections, comparison tables, featured plans, and pricing layouts.</p>
  </a>
</div>

<style>
.vb24-js-countdown-related,
.vb24-js-countdown-related * {
  box-sizing: border-box;
}

.vb24-js-countdown-related {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin: 26px 0 38px;
}

.vb24-js-countdown-related a {
  display: flex;
  flex-direction: column;
  min-height: 100%;
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 16% 12%, rgba(249, 115, 22, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.08);
  text-decoration: none !important;
  transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}

.vb24-js-countdown-related a:hover {
  transform: translateY(-3px);
  border-color: rgba(249, 115, 22, 0.50);
  box-shadow: 0 22px 58px rgba(124, 45, 18, 0.13);
}

.vb24-js-countdown-related span {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 12px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb24-js-countdown-related strong {
  display: block;
  margin-bottom: 9px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 900;
  letter-spacing: -0.035em;
}

.vb24-js-countdown-related p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 1040px) {
  .vb24-js-countdown-related {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-js-countdown-related {
    grid-template-columns: 1fr;
  }
}
</style>
]]></content:encoded>
					
					<wfw:commentRss>https://veebilehed24.ee/en/blog/javascript/javascript-countdown-timer-examples/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>30 JavaScript Fetch API Examples – GET, POST, JSON, Errors &#038; Real API Requests</title>
		<link>https://veebilehed24.ee/en/blog/javascript/javascript-fetch-api-examples/</link>
					<comments>https://veebilehed24.ee/en/blog/javascript/javascript-fetch-api-examples/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sun, 14 Jun 2026 06:42:22 +0000</pubDate>
				<category><![CDATA[Javascript]]></category>
		<guid isPermaLink="false">https://veebilehed24.ee/?p=1735</guid>

					<description><![CDATA[The JavaScript Fetch API is one of the most important tools for building modern interactive websites, dashboards, forms, search interfaces, ecommerce tools, admin panels, and real-time web applications. It lets you request data from APIs, send form data, load JSON, submit POST requests, update records, delete items, handle errors, show loading states, cancel requests, and [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">The JavaScript Fetch API is one of the most important tools for building modern interactive websites, dashboards, forms, search interfaces, ecommerce tools, admin panels, and real-time web applications. It lets you request data from APIs, send form data, load JSON, submit POST requests, update records, delete items, handle errors, show loading states, cancel requests, and connect the frontend to real backend data.</p>



<p class="wp-block-paragraph">In this guide, you will find 30 JavaScript Fetch API examples for real website projects, including GET requests, POST JSON requests, form submissions, PUT updates, PATCH updates, DELETE requests, search requests, debounce search, pagination, load more buttons, infinite scroll, query parameters, async/await, promises, timeout handling, request cancellation, retry logic, authorization headers, FormData uploads, and complete API dashboard patterns.</p>



<p class="wp-block-paragraph">This post focuses on practical Fetch API logic, not only design. Every example uses vanilla JavaScript, visible HTML, visible CSS, and copy-paste-ready code. You will learn how to fetch JSON data, render API results, handle failed requests, prevent broken UI states, work with headers, send data to a server, and build real JavaScript API request patterns. For related JavaScript functionality, you can also explore our <a href="https://veebilehed24.ee/en/blog/javascript/javascript-form-validation-examples/">JavaScript form validation examples</a>, <a href="https://veebilehed24.ee/en/blog/javascript/javascript-search-filter-examples/">JavaScript search filter examples</a>, <a href="https://veebilehed24.ee/en/blog/javascript/javascript-dropdown-menu-examples/">JavaScript dropdown menu examples</a>, and <a href="https://veebilehed24.ee/en/blog/javascript/javascript-calculator-examples/">JavaScript calculator examples</a>.</p>



<div class="vb24-js-fetch-jump-box">
  <a class="vb24-js-fetch-jump-button" href="#javascript-fetch-api-examples">View All 30 JavaScript Fetch API Examples</a>
</div>

<style>
.vb24-js-fetch-jump-box {
  margin: 28px 0 36px;
}

.vb24-js-fetch-jump-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 14px 22px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22c55e, #06b6d4 52%, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 850;
  line-height: 1.2;
  text-decoration: none !important;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.28);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-js-fetch-jump-button::after {
  content: "↓";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.18);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  line-height: 1;
}

.vb24-js-fetch-jump-button:hover {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transform: translateY(-2px);
  filter: saturate(1.08);
  box-shadow: 0 20px 46px rgba(37, 99, 235, 0.36);
}

@media (max-width: 640px) {
  .vb24-js-fetch-jump-button {
    width: 100%;
    padding: 14px 16px;
    font-size: 14px;
  }
}
</style>



<div class="toc-affiliate-wrap vb24-js-fetch-toc-wrap">

  <div class="toc-left vb24-js-fetch-toc-left">

    <div class="vb24-js-fetch-toc-kicker">On this page</div>

    <h2>Table of Contents</h2>

    <ul class="vl24-toc vb24-js-fetch-toc">
      <li><a href="#what-is-the-javascript-fetch-api">What Is the JavaScript Fetch API?</a></li>
      <li><a href="#why-fetch-api-matters">Why Fetch API Matters</a></li>
      <li><a href="#javascript-fetch-api-request-types">JavaScript Fetch API Request Types</a></li>
      <li><a href="#what-should-a-good-fetch-api-example-include">What Should a Good Fetch API Example Include?</a></li>
      <li><a class="vb24-featured-toc-link" href="#javascript-fetch-api-examples">30 JavaScript Fetch API Examples</a></li>
      <li><a href="#javascript-fetch-api-best-practices">JavaScript Fetch API Best Practices</a></li>
      <li><a href="#fetch-api-error-handling-tips">Fetch API Error Handling Tips</a></li>
      <li><a href="#common-fetch-api-mistakes">Common Fetch API Mistakes</a></li>
      <li><a href="#javascript-fetch-api-faq">JavaScript Fetch API FAQ</a></li>
      <li><a href="#javascript-fetch-api-conclusion">Conclusion</a></li>
      <li><a href="#related-javascript-guides">Related JavaScript Guides</a></li>
    </ul>

  </div>

  <div class="toc-right vb24-js-fetch-toc-right">

    <a class="vb24-webdev-ad-card" href="https://veebilehed24.ee/en/website-development/" target="_blank" rel="sponsored noopener">
      <span class="vb24-webdev-ad-badge">Website Development</span>

      <div class="vb24-webdev-ad-visual">
        <div class="vb24-webdev-ad-window">
          <div class="vb24-webdev-ad-dots"><span></span><span></span><span></span></div>
          <div class="vb24-webdev-ad-code">
            <span>fetch(&#8216;/api/services&#8217;)</span>
            <span>.then(res =&gt; res.json())</span>
            <span>.then(data =&gt; render(data))</span>
          </div>
          <div class="vb24-webdev-ad-ui">
            <div></div>
            <div></div>
            <div></div>
          </div>
        </div>
      </div>

      <div class="vb24-webdev-ad-content">
        <h3>Need a Modern Website?</h3>
        <p>Get a fast, responsive and SEO-friendly website with custom forms, API integrations, calculators, dashboards and landing pages.</p>
        <span class="vb24-webdev-ad-button">View Service</span>
      </div>
    </a>

  </div>

</div>

<style>
.vb24-js-fetch-toc-wrap {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 26px;
  align-items: stretch;
  margin: 34px 0 44px;
}

.vb24-js-fetch-toc-left,
.vb24-js-fetch-toc-right {
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 28px;
  background: linear-gradient(135deg, #0f172a 0%, #0f766e 46%, #1e3a8a 100%);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.18);
}

.vb24-js-fetch-toc-left {
  padding: 28px 30px 30px;
}

.vb24-js-fetch-toc-kicker {
  margin-bottom: 10px;
  color: #99f6e4 !important;
  -webkit-text-fill-color: #99f6e4 !important;
  font-size: 13px;
  font-weight: 850;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb24-js-fetch-toc-left h2 {
  margin: 0 0 22px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px !important;
  line-height: 1.15 !important;
  font-weight: 850 !important;
}

.vb24-js-fetch-toc {
  display: grid !important;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px !important;
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb24-js-fetch-toc li {
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb24-js-fetch-toc li::before {
  display: none !important;
  content: none !important;
}

.vb24-js-fetch-toc a {
  display: flex;
  align-items: center;
  min-height: 54px;
  padding: 13px 15px;
  border: 1px solid rgba(148, 163, 184, 0.18);
  border-radius: 15px;
  background: rgba(255, 255, 255, 0.065);
  color: #f3f4f6 !important;
  -webkit-text-fill-color: #f3f4f6 !important;
  font-size: 15px;
  font-weight: 750;
  line-height: 1.35;
  text-decoration: none !important;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.05);
  transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease;
}

.vb24-js-fetch-toc a:hover {
  transform: translateY(-2px);
  border-color: rgba(34, 211, 238, 0.70);
  background: rgba(6, 182, 212, 0.16);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb24-js-fetch-toc .vb24-featured-toc-link {
  border-color: rgba(34, 211, 238, 0.78);
  background: linear-gradient(135deg, rgba(34, 197, 94, 0.30), rgba(6, 182, 212, 0.30), rgba(37, 99, 235, 0.26));
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb24-js-fetch-toc-right {
  display: flex;
  align-items: stretch;
  justify-content: center;
  padding: 16px;
  overflow: hidden;
}

.vb24-webdev-ad-card,
.vb24-webdev-ad-card * {
  box-sizing: border-box;
}

.vb24-webdev-ad-card {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  min-height: 100%;
  padding: 12px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(34, 211, 238, 0.28), transparent 34%),
    radial-gradient(circle at 86% 14%, rgba(34, 197, 94, 0.22), transparent 36%),
    linear-gradient(135deg, #111827 0%, #0f766e 52%, #1d4ed8 100%) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  overflow: hidden;
  box-shadow: 0 20px 56px rgba(2, 6, 23, 0.32);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-webdev-ad-card:hover {
  transform: translateY(-3px);
  filter: saturate(1.08);
  box-shadow: 0 26px 70px rgba(2, 6, 23, 0.42);
}

.vb24-webdev-ad-badge {
  position: absolute;
  z-index: 3;
  top: 18px;
  left: 18px;
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.70);
  border: 1px solid rgba(255,255,255,0.22);
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb24-webdev-ad-visual {
  padding-top: 36px;
}

.vb24-webdev-ad-window {
  overflow: hidden;
  border-radius: 18px;
  background: rgba(15, 23, 42, 0.72);
  border: 1px solid rgba(255,255,255,0.18);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.10);
}

.vb24-webdev-ad-dots {
  display: flex;
  gap: 7px;
  padding: 12px;
  background: rgba(255,255,255,0.08);
}

.vb24-webdev-ad-dots span {
  width: 9px;
  height: 9px;
  border-radius: 999px;
  background: rgba(255,255,255,0.45);
}

.vb24-webdev-ad-code {
  display: grid;
  gap: 8px;
  padding: 16px;
}

.vb24-webdev-ad-code span {
  display: block;
  padding: 8px 10px;
  border-radius: 10px;
  background: rgba(34, 211, 238, 0.10);
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 11px;
  line-height: 1.2;
  font-weight: 800;
  overflow-wrap: anywhere;
}

.vb24-webdev-ad-ui {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 8px;
  padding: 0 16px 16px;
}

.vb24-webdev-ad-ui div {
  min-height: 42px;
  border-radius: 12px;
  background: linear-gradient(135deg, rgba(34, 197, 94, 0.22), rgba(37, 99, 235, 0.25));
  border: 1px solid rgba(255,255,255,0.12);
}

.vb24-webdev-ad-content {
  padding: 15px 8px 4px;
}

.vb24-webdev-ad-content h3 {
  margin: 0 0 8px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 23px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb24-webdev-ad-content p {
  margin: 0 0 14px !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 13px;
  line-height: 1.5;
  font-weight: 650;
}

.vb24-webdev-ad-button {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 43px;
  padding: 12px 14px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22c55e, #06b6d4 55%, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
  box-shadow: 0 14px 34px rgba(37, 99, 235, 0.30);
}

@media (max-width: 900px) {
  .vb24-js-fetch-toc-wrap {
    grid-template-columns: 1fr;
  }

  .vb24-js-fetch-toc-right {
    justify-content: flex-start;
    max-width: 360px;
  }
}

@media (max-width: 640px) {
  .vb24-js-fetch-toc-left {
    padding: 22px 18px;
    border-radius: 22px;
  }

  .vb24-js-fetch-toc-left h2 {
    font-size: 26px !important;
  }

  .vb24-js-fetch-toc {
    grid-template-columns: 1fr;
  }

  .vb24-js-fetch-toc a {
    min-height: 48px;
    font-size: 14px;
  }

  .vb24-js-fetch-toc-right {
    max-width: 100%;
    border-radius: 22px;
  }
}
</style>



<h2 class="wp-block-heading" id="what-is-the-javascript-fetch-api">What Is the JavaScript Fetch API?</h2>



<p class="wp-block-paragraph">The JavaScript Fetch API is a built-in browser feature that allows JavaScript to make HTTP requests. With <code>fetch()</code>, you can request data from an API, load JSON, send form data, post new records, update existing records, delete items, and connect your frontend interface to a backend service.</p>



<p class="wp-block-paragraph">A basic Fetch API request often starts with a URL and returns a <code>Response</code> object. From that response, you can read JSON with <code>response.json()</code>, check if the request succeeded with <code>response.ok</code>, and then use the returned data to update the page. This makes Fetch API useful for search results, product lists, user dashboards, contact forms, checkout forms, admin panels, and interactive web apps.</p>



<p class="wp-block-paragraph">Fetch API is commonly used with <code>async</code> and <code>await</code> because that structure makes asynchronous requests easier to read. It can also be used with <code>.then()</code> and <code>.catch()</code>. Both styles are included in this guide so you can understand real JavaScript API request patterns.</p>



<h2 class="wp-block-heading" id="why-fetch-api-matters">Why Fetch API Matters</h2>



<p class="wp-block-paragraph">Fetch API matters because most modern websites do not only show static content. They load data, submit forms, validate information, update dashboards, search records, filter results, save preferences, refresh product data, connect to third-party services, and communicate with backend APIs without reloading the page.</p>



<ul class="wp-block-list">
  <li><strong>It connects frontend and backend</strong> by allowing JavaScript to request or send data through HTTP.</li>
  <li><strong>It improves user experience</strong> because data can load dynamically without a full page reload.</li>
  <li><strong>It powers real forms</strong> such as contact forms, signup forms, quote forms, checkout forms, support forms, and admin forms.</li>
  <li><strong>It supports modern dashboards</strong> where stats, users, products, messages, orders, and activity feeds update from API data.</li>
  <li><strong>It helps build search and filtering</strong> by requesting results based on user input, categories, pagination, or query parameters.</li>
  <li><strong>It improves JavaScript skills</strong> because it teaches promises, async/await, error handling, JSON parsing, headers, and request states.</li>
</ul>



<p class="wp-block-paragraph">Fetch API is especially important for developers who build WordPress integrations, custom plugins, SaaS dashboards, API-connected landing pages, ecommerce features, admin tools, search interfaces, and JavaScript apps. Even simple website features become more powerful when they can communicate with real API endpoints.</p>



<h2 class="wp-block-heading" id="javascript-fetch-api-request-types">JavaScript Fetch API Request Types</h2>



<p class="wp-block-paragraph">Fetch API can be used for many different request types. A simple <code>GET</code> request loads data. A <code>POST</code> request sends new data. A <code>PUT</code> request usually replaces an existing record. A <code>PATCH</code> request updates part of a record. A <code>DELETE</code> request removes a record. Query parameters can be used for search, filters, pagination, sorting, and API options.</p>



<p class="wp-block-paragraph">The most useful Fetch API examples are not only about calling an endpoint. A real website also needs loading states, error messages, retry buttons, validation, request cancellation, response handling, safe rendering, and clear feedback for users.</p>



<ul class="wp-block-list">
  <li><strong>GET requests</strong> load API data such as users, posts, products, comments, weather, search results, or dashboard stats.</li>
  <li><strong>POST requests</strong> send new data such as form submissions, comments, contact messages, orders, login attempts, or saved settings.</li>
  <li><strong>PUT requests</strong> update an existing resource by replacing the full record with new data.</li>
  <li><strong>PATCH requests</strong> update only specific fields, such as changing a status, title, email, quantity, or preference.</li>
  <li><strong>DELETE requests</strong> remove a resource and usually update the UI after the API confirms success.</li>
  <li><strong>Query parameter requests</strong> send filters, search keywords, page numbers, limits, categories, and sorting options through the URL.</li>
  <li><strong>Authorized requests</strong> include headers such as <code>Authorization</code> when an API requires a token or login session.</li>
  <li><strong>FormData requests</strong> send files or mixed form fields, often used for uploads and multipart forms.</li>
</ul>



<p class="wp-block-paragraph">This guide includes different Fetch API techniques so the examples do not repeat the same request pattern. Some examples focus on rendering data, some focus on request methods, some focus on errors, some focus on performance, and some focus on real UI behavior such as search, pagination, load more, cancel, retry, and dashboard refresh.</p>



<h2 class="wp-block-heading" id="what-should-a-good-fetch-api-example-include">What Should a Good Fetch API Example Include?</h2>



<p class="wp-block-paragraph">A good Fetch API example should show the full request flow: user action, request start, loading state, response handling, error handling, data rendering, and final UI feedback. This is important because real API requests can fail, return empty results, take longer than expected, or return data in a different shape than expected.</p>



<div class="vb24-js-fetch-checklist">
  <div class="vb24-js-fetch-check-item">
    <h3>Clear request purpose</h3>
    <p>The example should show what the request is doing, such as loading posts, submitting a form, updating a user, deleting a record, or searching API data.</p>
  </div>

  <div class="vb24-js-fetch-check-item">
    <h3>Loading and empty states</h3>
    <p>Users should know when data is loading, when no results are found, and when a request completed successfully.</p>
  </div>

  <div class="vb24-js-fetch-check-item">
    <h3>Error handling</h3>
    <p>The code should check <code>response.ok</code>, catch failed requests, and show useful messages instead of leaving the UI broken.</p>
  </div>

  <div class="vb24-js-fetch-check-item">
    <h3>Safe data rendering</h3>
    <p>API data should be rendered carefully with clean DOM updates, readable formatting, and fallback values for missing fields.</p>
  </div>
</div>

<style>
.vb24-js-fetch-checklist {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 30px;
}

.vb24-js-fetch-check-item {
  min-width: 0;
  padding: 20px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 22px;
  background:
    radial-gradient(circle at 18% 10%, rgba(6, 182, 212, 0.10), transparent 32%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb24-js-fetch-check-item h3 {
  margin: 0 0 10px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 850;
}

.vb24-js-fetch-check-item p {
  margin: 0;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb24-js-fetch-checklist {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-js-fetch-checklist {
    grid-template-columns: 1fr;
  }

  .vb24-js-fetch-check-item {
    padding: 18px;
    border-radius: 20px;
  }
}
</style>



<p class="wp-block-paragraph">Before building a Fetch API feature, decide what endpoint you need, which HTTP method is correct, what data should be sent, what response you expect, what should happen while loading, and what the user should see if the request fails. This planning prevents many common API bugs.</p>



<ul class="wp-block-list">
  <li><strong>Use <code>async/await</code> for readable request logic</strong> when the example has multiple request steps.</li>
  <li><strong>Check <code>response.ok</code></strong> because Fetch API does not automatically throw an error for HTTP status codes like 404 or 500.</li>
  <li><strong>Use <code>try/catch</code></strong> to catch network errors, failed JSON parsing, aborted requests, and unexpected failures.</li>
  <li><strong>Show loading states</strong> so users know that the request is in progress.</li>
  <li><strong>Show empty states</strong> when a request succeeds but returns no results.</li>
  <li><strong>Use query parameters safely</strong> with <code>URLSearchParams</code> instead of manually building long URLs.</li>
  <li><strong>Use headers correctly</strong> for JSON requests, authorization tokens, and content type requirements.</li>
  <li><strong>Use <code>AbortController</code></strong> for timeout logic and cancel buttons when needed.</li>
  <li><strong>Do not expose real private API keys</strong> in frontend JavaScript. Use demo tokens or server-side proxy endpoints.</li>
  <li><strong>Keep each demo scoped</strong> so multiple Fetch API examples can run on the same page without conflicts.</li>
</ul>



<p class="wp-block-paragraph">You can combine Fetch API with many other JavaScript patterns. A form validation script can validate data before sending a POST request. A search filter can request matching results from an API. A dropdown menu can change request parameters. A calculator can submit quote data to a backend. A dashboard can refresh API data on button click or interval. For more practical JavaScript UI logic, see our <a href="https://veebilehed24.ee/en/blog/javascript/javascript-form-validation-examples/">JavaScript form validation examples</a>, <a href="https://veebilehed24.ee/en/blog/javascript/javascript-search-filter-examples/">JavaScript search filter examples</a>, and <a href="https://veebilehed24.ee/en/blog/javascript/javascript-dropdown-menu-examples/">JavaScript dropdown menu examples</a>.</p>



<h2 class="wp-block-heading" id="javascript-fetch-api-examples">30 JavaScript Fetch API Examples</h2>



<p class="wp-block-paragraph">Now let’s look at 30 JavaScript Fetch API examples for real website projects. Each example focuses on a different API request pattern, such as GET, POST, PUT, PATCH, DELETE, JSON rendering, loading states, error handling, search, debounce, pagination, load more, infinite scroll, query parameters, timeout, cancel, retry, authorization headers, FormData upload, multiple requests, sequential requests, and complete dashboard behavior.</p>



<h2 class="wp-block-heading">1. Basic Fetch GET Request</h2>



<p class="wp-block-paragraph"><strong>A basic Fetch GET request</strong> is the first Fetch API pattern every JavaScript developer should understand. It loads data from an API endpoint, checks whether the response was successful, converts the response to JSON, and displays the result in the browser.</p>



<p class="wp-block-paragraph">This example uses <code>async</code>, <code>await</code>, <code>fetch()</code>, <code>response.ok</code>, <code>response.json()</code>, loading text, success state, and error handling. It fetches one post from a public JSON API and renders the result inside a card.</p>



<ul class="wp-block-list">
<li>Basic JavaScript Fetch API GET request</li>
<li>Async/await request structure</li>
<li>Response status checking with <code>response.ok</code></li>
<li>JSON response parsing</li>
<li>Loading, success, and error messages</li>
</ul>



<div class="vb-fetch-01-demo">
  <div class="vb-fetch-01-layout">
    <div class="vb-fetch-01-info">
      <span>Example 01</span>
      <h3>Basic Fetch GET Request</h3>
      <p>Click the button to fetch one JSON record from an API and display it in the result card.</p>
    </div>

    <div class="vb-fetch-01-app">
      <button type="button" data-vb-fetch-01-button>Fetch Post</button>

      <div class="vb-fetch-01-status" data-vb-fetch-01-status>
        Ready. Click the button to start the GET request.
      </div>

      <article class="vb-fetch-01-result" data-vb-fetch-01-result>
        <span>No API data yet</span>
        <h4>Waiting for request</h4>
        <p>The fetched JSON result will appear here.</p>
      </article>
    </div>
  </div>
</div>

<style>
.vb-fetch-01-demo,
.vb-fetch-01-demo * {
  box-sizing: border-box;
}

.vb-fetch-01-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(6, 182, 212, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(37, 99, 235, 0.18), transparent 34%),
    linear-gradient(135deg, #ecfeff 0%, #eff6ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(6, 182, 212, 0.20);
  overflow: hidden;
}

.vb-fetch-01-layout {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
  min-width: 0;
}

.vb-fetch-01-info {
  min-width: 0;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #083344 0%, #0891b2 52%, #1d4ed8 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
  box-shadow: 0 30px 90px rgba(8, 145, 178, 0.22);
}

.vb-fetch-01-info span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #cffafe !important;
  -webkit-text-fill-color: #cffafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-01-info h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-01-info p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-01-app {
  display: grid;
  gap: 16px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-fetch-01-app button {
  min-height: 50px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #06b6d4, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.24);
}

.vb-fetch-01-app button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-01-status {
  min-width: 0;
  padding: 13px 15px;
  border-radius: 16px;
  background: #f0f9ff;
  border: 1px solid #bae6fd;
  color: #075985 !important;
  -webkit-text-fill-color: #075985 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
  overflow-wrap: anywhere;
}

.vb-fetch-01-status.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-01-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-01-result {
  min-width: 0;
  margin: 0;
  padding: 22px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(34, 211, 238, 0.12), transparent 34%),
    linear-gradient(135deg, #f8fafc, #ffffff) !important;
  border: 1px solid #e2e8f0;
}

.vb-fetch-01-result span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-01-result h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(22px, 3vw, 30px) !important;
  line-height: 1.18 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-01-result p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-fetch-01-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-fetch-01-info h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-01-demo");
  if (!demo) return;

  const button = demo.querySelector("[data-vb-fetch-01-button]");
  const status = demo.querySelector("[data-vb-fetch-01-status]");
  const result = demo.querySelector("[data-vb-fetch-01-result]");

  async function fetchPost() {
    button.disabled = true;
    status.className = "vb-fetch-01-status";
    status.textContent = "Loading API data...";

    result.innerHTML =
      "<span>Loading</span>" +
      "<h4>Please wait</h4>" +
      "<p>The GET request is running.</p>";

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts/1");

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const post = await response.json();

      status.className = "vb-fetch-01-status is-success";
      status.textContent = "Success. API data loaded.";

      result.innerHTML =
        "<span>Post ID #" + post.id + "</span>" +
        "<h4>" + post.title + "</h4>" +
        "<p>" + post.body + "</p>";
    } catch (error) {
      status.className = "vb-fetch-01-status is-error";
      status.textContent = "Request failed: " + error.message;

      result.innerHTML =
        "<span>Error</span>" +
        "<h4>Could not load API data</h4>" +
        "<p>Check the endpoint URL or network connection and try again.</p>";
    } finally {
      button.disabled = false;
    }
  }

  button.addEventListener("click", fetchPost);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-01-demo");
  if (!demo) return;

  const button = demo.querySelector("[data-vb-fetch-01-button]");
  const status = demo.querySelector("[data-vb-fetch-01-status]");
  const result = demo.querySelector("[data-vb-fetch-01-result]");

  async function fetchPost() {
    button.disabled = true;
    status.className = "vb-fetch-01-status";
    status.textContent = "Loading API data...";

    result.innerHTML =
      "&lt;span&gt;Loading&lt;/span&gt;" +
      "&lt;h4&gt;Please wait&lt;/h4&gt;" +
      "&lt;p&gt;The GET request is running.&lt;/p&gt;";

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts/1");

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const post = await response.json();

      status.className = "vb-fetch-01-status is-success";
      status.textContent = "Success. API data loaded.";

      result.innerHTML =
        "&lt;span&gt;Post ID #" + post.id + "&lt;/span&gt;" +
        "&lt;h4&gt;" + post.title + "&lt;/h4&gt;" +
        "&lt;p&gt;" + post.body + "&lt;/p&gt;";
    } catch (error) {
      status.className = "vb-fetch-01-status is-error";
      status.textContent = "Request failed: " + error.message;

      result.innerHTML =
        "&lt;span&gt;Error&lt;/span&gt;" +
        "&lt;h4&gt;Could not load API data&lt;/h4&gt;" +
        "&lt;p&gt;Check the endpoint URL or network connection and try again.&lt;/p&gt;";
    } finally {
      button.disabled = false;
    }
  }

  button.addEventListener("click", fetchPost);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-01-demo"&gt;
  &lt;div class="vb-fetch-01-layout"&gt;
    &lt;div class="vb-fetch-01-info"&gt;
      &lt;span&gt;Example 01&lt;/span&gt;
      &lt;h3&gt;Basic Fetch GET Request&lt;/h3&gt;
      &lt;p&gt;Click the button to fetch one JSON record from an API and display it in the result card.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-01-app"&gt;
      &lt;button type="button" data-vb-fetch-01-button&gt;Fetch Post&lt;/button&gt;

      &lt;div class="vb-fetch-01-status" data-vb-fetch-01-status&gt;
        Ready. Click the button to start the GET request.
      &lt;/div&gt;

      &lt;article class="vb-fetch-01-result" data-vb-fetch-01-result&gt;
        &lt;span&gt;No API data yet&lt;/span&gt;
        &lt;h4&gt;Waiting for request&lt;/h4&gt;
        &lt;p&gt;The fetched JSON result will appear here.&lt;/p&gt;
      &lt;/article&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-01-demo,
.vb-fetch-01-demo * {
  box-sizing: border-box;
}

.vb-fetch-01-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(6, 182, 212, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(37, 99, 235, 0.18), transparent 34%),
    linear-gradient(135deg, #ecfeff 0%, #eff6ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(6, 182, 212, 0.20);
  overflow: hidden;
}

.vb-fetch-01-layout {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
  min-width: 0;
}

.vb-fetch-01-info {
  min-width: 0;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #083344 0%, #0891b2 52%, #1d4ed8 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
  box-shadow: 0 30px 90px rgba(8, 145, 178, 0.22);
}

.vb-fetch-01-info span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #cffafe !important;
  -webkit-text-fill-color: #cffafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-01-info h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-01-info p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-01-app {
  display: grid;
  gap: 16px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-fetch-01-app button {
  min-height: 50px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #06b6d4, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.24);
}

.vb-fetch-01-app button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-01-status {
  min-width: 0;
  padding: 13px 15px;
  border-radius: 16px;
  background: #f0f9ff;
  border: 1px solid #bae6fd;
  color: #075985 !important;
  -webkit-text-fill-color: #075985 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
  overflow-wrap: anywhere;
}

.vb-fetch-01-status.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-01-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-01-result {
  min-width: 0;
  margin: 0;
  padding: 22px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(34, 211, 238, 0.12), transparent 34%),
    linear-gradient(135deg, #f8fafc, #ffffff) !important;
  border: 1px solid #e2e8f0;
}

.vb-fetch-01-result span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-01-result h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(22px, 3vw, 30px) !important;
  line-height: 1.18 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-01-result p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-fetch-01-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-fetch-01-info h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}</pre>



<p class="wp-block-paragraph">This basic Fetch GET request example is useful for learning how to request API data, parse JSON, handle request status, show loading feedback, and render a result in the browser.</p>




<h2 class="wp-block-heading">2. Fetch JSON and Render Cards</h2>



<p class="wp-block-paragraph"><strong>Fetching JSON and rendering cards</strong> is a common pattern for blogs, product grids, user directories, dashboards, services, portfolios, and search result pages. The Fetch API loads an array of objects, and JavaScript turns each object into a visible UI card.</p>



<p class="wp-block-paragraph">This example fetches a list of posts, limits the result count, loops through the JSON array with <code>map()</code>, and creates a responsive card grid. It also includes a clear button, loading state, empty state, success message, and error message.</p>



<ul class="wp-block-list">
<li>Fetch JSON array from an API</li>
<li>Render multiple cards from returned data</li>
<li>Use <code>map()</code> to create card markup</li>
<li>Show success, empty, and error states</li>
<li>Build a responsive API-powered card grid</li>
</ul>



<div class="vb-fetch-02-demo">
  <div class="vb-fetch-02-shell">
    <div class="vb-fetch-02-header">
      <span>Example 02</span>
      <h3>Fetch JSON and Render Cards</h3>
      <p>Load a JSON array from an API and render the returned items as responsive cards.</p>
    </div>

    <div class="vb-fetch-02-toolbar">
      <button type="button" data-vb-fetch-02-load>Load Cards</button>
      <button type="button" data-vb-fetch-02-clear>Clear Cards</button>
    </div>

    <div class="vb-fetch-02-message" data-vb-fetch-02-message>
      Click “Load Cards” to fetch JSON data.
    </div>

    <div class="vb-fetch-02-grid" data-vb-fetch-02-grid></div>
  </div>
</div>

<style>
.vb-fetch-02-demo,
.vb-fetch-02-demo * {
  box-sizing: border-box;
}

.vb-fetch-02-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(168, 85, 247, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(14, 165, 233, 0.18), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #f0f9ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.16);
  overflow: hidden;
}

.vb-fetch-02-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-02-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #581c87 0%, #7c3aed 52%, #0284c7 100%) !important;
}

.vb-fetch-02-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #f3e8ff !important;
  -webkit-text-fill-color: #f3e8ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-02-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-02-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-02-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  padding: clamp(20px, 4vw, 28px) clamp(20px, 4vw, 34px) 0;
}

.vb-fetch-02-toolbar button {
  min-height: 48px;
  padding: 0 18px;
  border: 0;
  border-radius: 999px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-fetch-02-toolbar button:first-child {
  background: linear-gradient(135deg, #7c3aed, #0284c7);
  box-shadow: 0 16px 38px rgba(124, 58, 237, 0.22);
}

.vb-fetch-02-toolbar button:last-child {
  background: #0f172a;
}

.vb-fetch-02-toolbar button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-02-message {
  margin: 16px clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 13px 15px;
  border-radius: 16px;
  background: #f5f3ff;
  border: 1px solid #ddd6fe;
  color: #5b21b6 !important;
  -webkit-text-fill-color: #5b21b6 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
  overflow-wrap: anywhere;
}

.vb-fetch-02-message.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-02-message.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-02-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-02-card {
  min-width: 0;
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(124, 58, 237, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.07);
}

.vb-fetch-02-card span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-02-card h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.28 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-02-card p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 980px) {
  .vb-fetch-02-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-fetch-02-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-02-grid {
    grid-template-columns: 1fr;
  }

  .vb-fetch-02-toolbar button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-02-demo");
  if (!demo) return;

  const loadButton = demo.querySelector("[data-vb-fetch-02-load]");
  const clearButton = demo.querySelector("[data-vb-fetch-02-clear]");
  const message = demo.querySelector("[data-vb-fetch-02-message]");
  const grid = demo.querySelector("[data-vb-fetch-02-grid]");

  function setMessage(text, type) {
    message.className = "vb-fetch-02-message";

    if (type === "success") {
      message.classList.add("is-success");
    }

    if (type === "error") {
      message.classList.add("is-error");
    }

    message.textContent = text;
  }

  function renderCards(posts) {
    if (!posts.length) {
      grid.innerHTML = "";
      setMessage("The API returned no results.", "error");
      return;
    }

    grid.innerHTML = posts.map(function (post) {
      return (
        '<article class="vb-fetch-02-card">' +
          '<span>Post #' + post.id + '</span>' +
          '<h4>' + post.title + '</h4>' +
          '<p>' + post.body + '</p>' +
        '</article>'
      );
    }).join("");
  }

  async function loadCards() {
    loadButton.disabled = true;
    grid.innerHTML = "";
    setMessage("Loading JSON array from API...", "");

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts?_limit=6");

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const posts = await response.json();

      renderCards(posts);
      setMessage("Success. " + posts.length + " cards were rendered from API data.", "success");
    } catch (error) {
      grid.innerHTML = "";
      setMessage("Request failed: " + error.message, "error");
    } finally {
      loadButton.disabled = false;
    }
  }

  function clearCards() {
    grid.innerHTML = "";
    setMessage("Cards cleared. Click “Load Cards” to fetch JSON data again.", "");
  }

  loadButton.addEventListener("click", loadCards);
  clearButton.addEventListener("click", clearCards);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-02-demo");
  if (!demo) return;

  const loadButton = demo.querySelector("[data-vb-fetch-02-load]");
  const clearButton = demo.querySelector("[data-vb-fetch-02-clear]");
  const message = demo.querySelector("[data-vb-fetch-02-message]");
  const grid = demo.querySelector("[data-vb-fetch-02-grid]");

  function setMessage(text, type) {
    message.className = "vb-fetch-02-message";

    if (type === "success") {
      message.classList.add("is-success");
    }

    if (type === "error") {
      message.classList.add("is-error");
    }

    message.textContent = text;
  }

  function renderCards(posts) {
    if (!posts.length) {
      grid.innerHTML = "";
      setMessage("The API returned no results.", "error");
      return;
    }

    grid.innerHTML = posts.map(function (post) {
      return (
        '&lt;article class="vb-fetch-02-card"&gt;' +
          '&lt;span&gt;Post #' + post.id + '&lt;/span&gt;' +
          '&lt;h4&gt;' + post.title + '&lt;/h4&gt;' +
          '&lt;p&gt;' + post.body + '&lt;/p&gt;' +
        '&lt;/article&gt;'
      );
    }).join("");
  }

  async function loadCards() {
    loadButton.disabled = true;
    grid.innerHTML = "";
    setMessage("Loading JSON array from API...", "");

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts?_limit=6");

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const posts = await response.json();

      renderCards(posts);
      setMessage("Success. " + posts.length + " cards were rendered from API data.", "success");
    } catch (error) {
      grid.innerHTML = "";
      setMessage("Request failed: " + error.message, "error");
    } finally {
      loadButton.disabled = false;
    }
  }

  function clearCards() {
    grid.innerHTML = "";
    setMessage("Cards cleared. Click “Load Cards” to fetch JSON data again.", "");
  }

  loadButton.addEventListener("click", loadCards);
  clearButton.addEventListener("click", clearCards);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-02-demo"&gt;
  &lt;div class="vb-fetch-02-shell"&gt;
    &lt;div class="vb-fetch-02-header"&gt;
      &lt;span&gt;Example 02&lt;/span&gt;
      &lt;h3&gt;Fetch JSON and Render Cards&lt;/h3&gt;
      &lt;p&gt;Load a JSON array from an API and render the returned items as responsive cards.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-02-toolbar"&gt;
      &lt;button type="button" data-vb-fetch-02-load&gt;Load Cards&lt;/button&gt;
      &lt;button type="button" data-vb-fetch-02-clear&gt;Clear Cards&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-02-message" data-vb-fetch-02-message&gt;
      Click “Load Cards” to fetch JSON data.
    &lt;/div&gt;

    &lt;div class="vb-fetch-02-grid" data-vb-fetch-02-grid&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-02-demo,
.vb-fetch-02-demo * {
  box-sizing: border-box;
}

.vb-fetch-02-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(168, 85, 247, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(14, 165, 233, 0.18), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #f0f9ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.16);
  overflow: hidden;
}

.vb-fetch-02-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-02-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #581c87 0%, #7c3aed 52%, #0284c7 100%) !important;
}

.vb-fetch-02-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #f3e8ff !important;
  -webkit-text-fill-color: #f3e8ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-02-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-02-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-02-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  padding: clamp(20px, 4vw, 28px) clamp(20px, 4vw, 34px) 0;
}

.vb-fetch-02-toolbar button {
  min-height: 48px;
  padding: 0 18px;
  border: 0;
  border-radius: 999px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-fetch-02-toolbar button:first-child {
  background: linear-gradient(135deg, #7c3aed, #0284c7);
  box-shadow: 0 16px 38px rgba(124, 58, 237, 0.22);
}

.vb-fetch-02-toolbar button:last-child {
  background: #0f172a;
}

.vb-fetch-02-toolbar button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-02-message {
  margin: 16px clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 13px 15px;
  border-radius: 16px;
  background: #f5f3ff;
  border: 1px solid #ddd6fe;
  color: #5b21b6 !important;
  -webkit-text-fill-color: #5b21b6 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
  overflow-wrap: anywhere;
}

.vb-fetch-02-message.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-02-message.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-02-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-02-card {
  min-width: 0;
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(124, 58, 237, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.07);
}

.vb-fetch-02-card span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-02-card h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.28 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-02-card p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 980px) {
  .vb-fetch-02-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-fetch-02-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-02-grid {
    grid-template-columns: 1fr;
  }

  .vb-fetch-02-toolbar button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch JSON card rendering example is useful for blog feeds, product cards, service grids, user directories, dashboard records, search results, and API-powered content sections.</p>




<h2 class="wp-block-heading">3. Fetch API with Loading State</h2>



<p class="wp-block-paragraph"><strong>A Fetch API loading state</strong> is important because users need feedback while an API request is running. Without a loading state, the interface can feel broken, frozen, or unclear when the request takes time to finish.</p>



<p class="wp-block-paragraph">This example simulates a slower request by delaying the rendering after the API response. It shows a loading spinner, disables the button during the request, displays success feedback, and catches failed requests with a clear error state.</p>



<ul class="wp-block-list">
<li>Fetch API request with visible loading state</li>
<li>Disabled button while request is running</li>
<li>Spinner animation while waiting</li>
<li>Success and error state handling</li>
<li>Delayed rendering demo for realistic API behavior</li>
</ul>



<div class="vb-fetch-03-demo">
  <div class="vb-fetch-03-card">
    <div class="vb-fetch-03-top">
      <span>Example 03</span>
      <h3>Fetch API with Loading State</h3>
      <p>Show users that the API request is running before the returned data appears.</p>
    </div>

    <div class="vb-fetch-03-app">
      <button type="button" data-vb-fetch-03-load>Load User Profile</button>

      <div class="vb-fetch-03-loader" data-vb-fetch-03-loader hidden>
        <div></div>
        <span>Loading profile from API&#8230;</span>
      </div>

      <div class="vb-fetch-03-profile" data-vb-fetch-03-profile>
        <div class="vb-fetch-03-avatar">API</div>
        <div>
          <span>Waiting</span>
          <h4>No profile loaded</h4>
          <p>Click the button above to fetch a user profile.</p>
        </div>
      </div>

      <div class="vb-fetch-03-message" data-vb-fetch-03-message>
        Ready to run the request.
      </div>
    </div>
  </div>
</div>

<style>
.vb-fetch-03-demo,
.vb-fetch-03-demo * {
  box-sizing: border-box;
}

.vb-fetch-03-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 197, 94, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(6, 182, 212, 0.18), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #ecfeff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.18);
  overflow: hidden;
}

.vb-fetch-03-card {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-03-top {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #064e3b 0%, #059669 52%, #0891b2 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-03-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-03-top h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-03-top p {
  max-width: 760px;
  margin: 0 !important;
  color: #cffafe !important;
  -webkit-text-fill-color: #cffafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-03-app {
  display: grid;
  gap: 16px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-03-app button {
  width: fit-content;
  min-height: 50px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #10b981, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(6, 182, 212, 0.24);
}

.vb-fetch-03-app button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-03-loader {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #ecfeff;
  border: 1px solid #a5f3fc;
}

.vb-fetch-03-loader[hidden] {
  display: none;
}

.vb-fetch-03-loader div {
  width: 22px;
  height: 22px;
  border: 3px solid #bae6fd;
  border-top-color: #0891b2;
  border-radius: 999px;
  animation: vbFetch03Spin 0.8s linear infinite;
}

.vb-fetch-03-loader span {
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 14px;
  line-height: 1.4;
  font-weight: 850;
}

@keyframes vbFetch03Spin {
  to {
    transform: rotate(360deg);
  }
}

.vb-fetch-03-profile {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 16px;
  align-items: center;
  min-width: 0;
  padding: 22px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 12% 12%, rgba(34, 197, 94, 0.12), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid #e2e8f0;
}

.vb-fetch-03-avatar {
  display: flex;
  width: 72px;
  height: 72px;
  align-items: center;
  justify-content: center;
  border-radius: 24px;
  background: linear-gradient(135deg, #10b981, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
  letter-spacing: -0.04em;
  box-shadow: 0 14px 34px rgba(6, 182, 212, 0.24);
}

.vb-fetch-03-profile span {
  display: inline-flex;
  margin-bottom: 7px;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-03-profile h4 {
  margin: 0 0 6px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(22px, 3vw, 32px) !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-03-profile p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-03-message {
  min-width: 0;
  padding: 13px 15px;
  border-radius: 16px;
  background: #f0fdf4;
  border: 1px solid #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
  overflow-wrap: anywhere;
}

.vb-fetch-03-message.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

@media (max-width: 640px) {
  .vb-fetch-03-top h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-03-app button {
    width: 100%;
  }

  .vb-fetch-03-profile {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-03-demo");
  if (!demo) return;

  const button = demo.querySelector("[data-vb-fetch-03-load]");
  const loader = demo.querySelector("[data-vb-fetch-03-loader]");
  const profile = demo.querySelector("[data-vb-fetch-03-profile]");
  const message = demo.querySelector("[data-vb-fetch-03-message]");

  function wait(milliseconds) {
    return new Promise(function (resolve) {
      setTimeout(resolve, milliseconds);
    });
  }

  async function loadProfile() {
    button.disabled = true;
    loader.hidden = false;
    message.className = "vb-fetch-03-message";
    message.textContent = "Request started. Waiting for API response...";

    profile.innerHTML =
      '<div class="vb-fetch-03-avatar">...</div>' +
      '<div>' +
        '<span>Loading</span>' +
        '<h4>Fetching profile</h4>' +
        '<p>The profile will appear after the request finishes.</p>' +
      '</div>';

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/users/1");

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const user = await response.json();

      await wait(900);

      profile.innerHTML =
        '<div class="vb-fetch-03-avatar">' + user.name.slice(0, 2).toUpperCase() + '</div>' +
        '<div>' +
          '<span>' + user.company.name + '</span>' +
          '<h4>' + user.name + '</h4>' +
          '<p>' + user.email + ' · ' + user.address.city + '</p>' +
        '</div>';

      message.textContent = "Success. Profile loaded after visible loading state.";
    } catch (error) {
      message.className = "vb-fetch-03-message is-error";
      message.textContent = "Request failed: " + error.message;

      profile.innerHTML =
        '<div class="vb-fetch-03-avatar">!</div>' +
        '<div>' +
          '<span>Error</span>' +
          '<h4>Profile unavailable</h4>' +
          '<p>The API request failed. Try again later.</p>' +
        '</div>';
    } finally {
      loader.hidden = true;
      button.disabled = false;
    }
  }

  button.addEventListener("click", loadProfile);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-03-demo");
  if (!demo) return;

  const button = demo.querySelector("[data-vb-fetch-03-load]");
  const loader = demo.querySelector("[data-vb-fetch-03-loader]");
  const profile = demo.querySelector("[data-vb-fetch-03-profile]");
  const message = demo.querySelector("[data-vb-fetch-03-message]");

  function wait(milliseconds) {
    return new Promise(function (resolve) {
      setTimeout(resolve, milliseconds);
    });
  }

  async function loadProfile() {
    button.disabled = true;
    loader.hidden = false;
    message.className = "vb-fetch-03-message";
    message.textContent = "Request started. Waiting for API response...";

    profile.innerHTML =
      '&lt;div class="vb-fetch-03-avatar"&gt;...&lt;/div&gt;' +
      '&lt;div&gt;' +
        '&lt;span&gt;Loading&lt;/span&gt;' +
        '&lt;h4&gt;Fetching profile&lt;/h4&gt;' +
        '&lt;p&gt;The profile will appear after the request finishes.&lt;/p&gt;' +
      '&lt;/div&gt;';

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/users/1");

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const user = await response.json();

      await wait(900);

      profile.innerHTML =
        '&lt;div class="vb-fetch-03-avatar"&gt;' + user.name.slice(0, 2).toUpperCase() + '&lt;/div&gt;' +
        '&lt;div&gt;' +
          '&lt;span&gt;' + user.company.name + '&lt;/span&gt;' +
          '&lt;h4&gt;' + user.name + '&lt;/h4&gt;' +
          '&lt;p&gt;' + user.email + ' · ' + user.address.city + '&lt;/p&gt;' +
        '&lt;/div&gt;';

      message.textContent = "Success. Profile loaded after visible loading state.";
    } catch (error) {
      message.className = "vb-fetch-03-message is-error";
      message.textContent = "Request failed: " + error.message;

      profile.innerHTML =
        '&lt;div class="vb-fetch-03-avatar"&gt;!&lt;/div&gt;' +
        '&lt;div&gt;' +
          '&lt;span&gt;Error&lt;/span&gt;' +
          '&lt;h4&gt;Profile unavailable&lt;/h4&gt;' +
          '&lt;p&gt;The API request failed. Try again later.&lt;/p&gt;' +
        '&lt;/div&gt;';
    } finally {
      loader.hidden = true;
      button.disabled = false;
    }
  }

  button.addEventListener("click", loadProfile);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-03-demo"&gt;
  &lt;div class="vb-fetch-03-card"&gt;
    &lt;div class="vb-fetch-03-top"&gt;
      &lt;span&gt;Example 03&lt;/span&gt;
      &lt;h3&gt;Fetch API with Loading State&lt;/h3&gt;
      &lt;p&gt;Show users that the API request is running before the returned data appears.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-03-app"&gt;
      &lt;button type="button" data-vb-fetch-03-load&gt;Load User Profile&lt;/button&gt;

      &lt;div class="vb-fetch-03-loader" data-vb-fetch-03-loader hidden&gt;
        &lt;div&gt;&lt;/div&gt;
        &lt;span&gt;Loading profile from API...&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-fetch-03-profile" data-vb-fetch-03-profile&gt;
        &lt;div class="vb-fetch-03-avatar"&gt;API&lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Waiting&lt;/span&gt;
          &lt;h4&gt;No profile loaded&lt;/h4&gt;
          &lt;p&gt;Click the button above to fetch a user profile.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-fetch-03-message" data-vb-fetch-03-message&gt;
        Ready to run the request.
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-03-demo,
.vb-fetch-03-demo * {
  box-sizing: border-box;
}

.vb-fetch-03-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 197, 94, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(6, 182, 212, 0.18), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #ecfeff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.18);
  overflow: hidden;
}

.vb-fetch-03-card {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-03-top {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #064e3b 0%, #059669 52%, #0891b2 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-03-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-03-top h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-03-top p {
  max-width: 760px;
  margin: 0 !important;
  color: #cffafe !important;
  -webkit-text-fill-color: #cffafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-03-app {
  display: grid;
  gap: 16px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-03-app button {
  width: fit-content;
  min-height: 50px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #10b981, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(6, 182, 212, 0.24);
}

.vb-fetch-03-app button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-03-loader {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #ecfeff;
  border: 1px solid #a5f3fc;
}

.vb-fetch-03-loader[hidden] {
  display: none;
}

.vb-fetch-03-loader div {
  width: 22px;
  height: 22px;
  border: 3px solid #bae6fd;
  border-top-color: #0891b2;
  border-radius: 999px;
  animation: vbFetch03Spin 0.8s linear infinite;
}

.vb-fetch-03-loader span {
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 14px;
  line-height: 1.4;
  font-weight: 850;
}

@keyframes vbFetch03Spin {
  to {
    transform: rotate(360deg);
  }
}

.vb-fetch-03-profile {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 16px;
  align-items: center;
  min-width: 0;
  padding: 22px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 12% 12%, rgba(34, 197, 94, 0.12), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid #e2e8f0;
}

.vb-fetch-03-avatar {
  display: flex;
  width: 72px;
  height: 72px;
  align-items: center;
  justify-content: center;
  border-radius: 24px;
  background: linear-gradient(135deg, #10b981, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
  letter-spacing: -0.04em;
  box-shadow: 0 14px 34px rgba(6, 182, 212, 0.24);
}

.vb-fetch-03-profile span {
  display: inline-flex;
  margin-bottom: 7px;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-03-profile h4 {
  margin: 0 0 6px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(22px, 3vw, 32px) !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-03-profile p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-03-message {
  min-width: 0;
  padding: 13px 15px;
  border-radius: 16px;
  background: #f0fdf4;
  border: 1px solid #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
  overflow-wrap: anywhere;
}

.vb-fetch-03-message.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

@media (max-width: 640px) {
  .vb-fetch-03-top h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-03-app button {
    width: 100%;
  }

  .vb-fetch-03-profile {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API loading state example is useful for dashboards, profile cards, product loading sections, search results, API widgets, admin panels, and any interface where users need clear feedback while data is loading.</p>



<h2 class="wp-block-heading">4. Fetch API Error Handling</h2>



<p class="wp-block-paragraph"><strong>Fetch API error handling</strong> is important because <code>fetch()</code> does not automatically throw an error for HTTP status codes like 404 or 500. You need to check <code>response.ok</code>, throw your own error, and show a useful message in the interface.</p>



<p class="wp-block-paragraph">This example intentionally includes buttons for a successful request and a failed request. It demonstrates <code>try/catch</code>, <code>response.ok</code>, custom error messages, error UI, success UI, and safe fallback rendering.</p>



<ul class="wp-block-list">
<li>Fetch API error handling example</li>
<li>Check failed HTTP responses with <code>response.ok</code></li>
<li>Show friendly error messages</li>
<li>Separate success and error UI states</li>
<li>Useful for real API dashboards and forms</li>
</ul>



<div class="vb-fetch-04-demo">
  <div class="vb-fetch-04-shell">
    <div class="vb-fetch-04-header">
      <span>Example 04</span>
      <h3>Fetch API Error Handling</h3>
      <p>Test successful and failed API requests with clear error messages and safe UI feedback.</p>
    </div>

    <div class="vb-fetch-04-body">
      <div class="vb-fetch-04-actions">
        <button type="button" data-vb-fetch-04-success>Run Successful Request</button>
        <button type="button" data-vb-fetch-04-error>Run Failed Request</button>
      </div>

      <div class="vb-fetch-04-result" data-vb-fetch-04-result>
        <span>Ready</span>
        <h4>No request yet</h4>
        <p>Choose a request type above to test Fetch API error handling.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-fetch-04-demo,
.vb-fetch-04-demo * {
  box-sizing: border-box;
}

.vb-fetch-04-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(239, 68, 68, 0.15), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #fef2f2 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(239, 68, 68, 0.16);
  overflow: hidden;
}

.vb-fetch-04-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-04-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #7f1d1d 0%, #dc2626 48%, #16a34a 100%) !important;
}

.vb-fetch-04-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-04-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-04-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-04-body {
  display: grid;
  gap: 18px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-04-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  min-width: 0;
}

.vb-fetch-04-actions button {
  min-height: 50px;
  padding: 0 18px;
  border: 0;
  border-radius: 999px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-fetch-04-actions button:first-child {
  background: linear-gradient(135deg, #16a34a, #06b6d4);
  box-shadow: 0 16px 38px rgba(22, 163, 74, 0.22);
}

.vb-fetch-04-actions button:last-child {
  background: linear-gradient(135deg, #dc2626, #f97316);
  box-shadow: 0 16px 38px rgba(220, 38, 38, 0.22);
}

.vb-fetch-04-actions button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-04-result {
  min-width: 0;
  padding: 24px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 14% 12%, rgba(100, 116, 139, 0.10), transparent 34%),
    linear-gradient(135deg, #f8fafc, #ffffff) !important;
  border: 1px solid #e2e8f0;
}

.vb-fetch-04-result.is-success {
  background:
    radial-gradient(circle at 14% 12%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4, #ffffff) !important;
  border-color: #bbf7d0;
}

.vb-fetch-04-result.is-error {
  background:
    radial-gradient(circle at 14% 12%, rgba(239, 68, 68, 0.16), transparent 34%),
    linear-gradient(135deg, #fef2f2, #ffffff) !important;
  border-color: #fecaca;
}

.vb-fetch-04-result span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #e2e8f0;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-04-result.is-success span {
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-04-result.is-error span {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-04-result h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(24px, 4vw, 38px) !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-04-result p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 640px) {
  .vb-fetch-04-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-04-actions button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-04-demo");
  if (!demo) return;

  const successButton = demo.querySelector("[data-vb-fetch-04-success]");
  const errorButton = demo.querySelector("[data-vb-fetch-04-error]");
  const result = demo.querySelector("[data-vb-fetch-04-result]");

  function setLoading() {
    successButton.disabled = true;
    errorButton.disabled = true;
    result.className = "vb-fetch-04-result";
    result.innerHTML =
      '<span>Loading</span>' +
      '<h4>Request running</h4>' +
      '<p>The Fetch API request is waiting for a response.</p>';
  }

  function setFinished() {
    successButton.disabled = false;
    errorButton.disabled = false;
  }

  async function runRequest(url) {
    setLoading();

    try {
      const response = await fetch(url);

      if (!response.ok) {
        throw new Error("API returned HTTP status " + response.status);
      }

      const data = await response.json();

      result.className = "vb-fetch-04-result is-success";
      result.innerHTML =
        '<span>Success</span>' +
        '<h4>' + data.title + '</h4>' +
        '<p>The request succeeded and the API returned valid JSON data.</p>';
    } catch (error) {
      result.className = "vb-fetch-04-result is-error";
      result.innerHTML =
        '<span>Error handled</span>' +
        '<h4>Request failed safely</h4>' +
        '<p>' + error.message + '. The UI did not break because the error was caught with try/catch.</p>';
    } finally {
      setFinished();
    }
  }

  successButton.addEventListener("click", function () {
    runRequest("https://jsonplaceholder.typicode.com/posts/1");
  });

  errorButton.addEventListener("click", function () {
    runRequest("https://jsonplaceholder.typicode.com/posts/999999");
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-04-demo");
  if (!demo) return;

  const successButton = demo.querySelector("[data-vb-fetch-04-success]");
  const errorButton = demo.querySelector("[data-vb-fetch-04-error]");
  const result = demo.querySelector("[data-vb-fetch-04-result]");

  function setLoading() {
    successButton.disabled = true;
    errorButton.disabled = true;
    result.className = "vb-fetch-04-result";
    result.innerHTML =
      '&lt;span&gt;Loading&lt;/span&gt;' +
      '&lt;h4&gt;Request running&lt;/h4&gt;' +
      '&lt;p&gt;The Fetch API request is waiting for a response.&lt;/p&gt;';
  }

  function setFinished() {
    successButton.disabled = false;
    errorButton.disabled = false;
  }

  async function runRequest(url) {
    setLoading();

    try {
      const response = await fetch(url);

      if (!response.ok) {
        throw new Error("API returned HTTP status " + response.status);
      }

      const data = await response.json();

      result.className = "vb-fetch-04-result is-success";
      result.innerHTML =
        '&lt;span&gt;Success&lt;/span&gt;' +
        '&lt;h4&gt;' + data.title + '&lt;/h4&gt;' +
        '&lt;p&gt;The request succeeded and the API returned valid JSON data.&lt;/p&gt;';
    } catch (error) {
      result.className = "vb-fetch-04-result is-error";
      result.innerHTML =
        '&lt;span&gt;Error handled&lt;/span&gt;' +
        '&lt;h4&gt;Request failed safely&lt;/h4&gt;' +
        '&lt;p&gt;' + error.message + '. The UI did not break because the error was caught with try/catch.&lt;/p&gt;';
    } finally {
      setFinished();
    }
  }

  successButton.addEventListener("click", function () {
    runRequest("https://jsonplaceholder.typicode.com/posts/1");
  });

  errorButton.addEventListener("click", function () {
    runRequest("https://jsonplaceholder.typicode.com/posts/999999");
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-04-demo"&gt;
  &lt;div class="vb-fetch-04-shell"&gt;
    &lt;div class="vb-fetch-04-header"&gt;
      &lt;span&gt;Example 04&lt;/span&gt;
      &lt;h3&gt;Fetch API Error Handling&lt;/h3&gt;
      &lt;p&gt;Test successful and failed API requests with clear error messages and safe UI feedback.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-04-body"&gt;
      &lt;div class="vb-fetch-04-actions"&gt;
        &lt;button type="button" data-vb-fetch-04-success&gt;Run Successful Request&lt;/button&gt;
        &lt;button type="button" data-vb-fetch-04-error&gt;Run Failed Request&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-fetch-04-result" data-vb-fetch-04-result&gt;
        &lt;span&gt;Ready&lt;/span&gt;
        &lt;h4&gt;No request yet&lt;/h4&gt;
        &lt;p&gt;Choose a request type above to test Fetch API error handling.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-04-demo,
.vb-fetch-04-demo * {
  box-sizing: border-box;
}

.vb-fetch-04-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(239, 68, 68, 0.15), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #fef2f2 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(239, 68, 68, 0.16);
  overflow: hidden;
}

.vb-fetch-04-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-04-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #7f1d1d 0%, #dc2626 48%, #16a34a 100%) !important;
}

.vb-fetch-04-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-04-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-04-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-04-body {
  display: grid;
  gap: 18px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-04-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  min-width: 0;
}

.vb-fetch-04-actions button {
  min-height: 50px;
  padding: 0 18px;
  border: 0;
  border-radius: 999px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-fetch-04-actions button:first-child {
  background: linear-gradient(135deg, #16a34a, #06b6d4);
  box-shadow: 0 16px 38px rgba(22, 163, 74, 0.22);
}

.vb-fetch-04-actions button:last-child {
  background: linear-gradient(135deg, #dc2626, #f97316);
  box-shadow: 0 16px 38px rgba(220, 38, 38, 0.22);
}

.vb-fetch-04-actions button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-04-result {
  min-width: 0;
  padding: 24px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 14% 12%, rgba(100, 116, 139, 0.10), transparent 34%),
    linear-gradient(135deg, #f8fafc, #ffffff) !important;
  border: 1px solid #e2e8f0;
}

.vb-fetch-04-result.is-success {
  background:
    radial-gradient(circle at 14% 12%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4, #ffffff) !important;
  border-color: #bbf7d0;
}

.vb-fetch-04-result.is-error {
  background:
    radial-gradient(circle at 14% 12%, rgba(239, 68, 68, 0.16), transparent 34%),
    linear-gradient(135deg, #fef2f2, #ffffff) !important;
  border-color: #fecaca;
}

.vb-fetch-04-result span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #e2e8f0;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-04-result.is-success span {
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-04-result.is-error span {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-04-result h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(24px, 4vw, 38px) !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-04-result p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 640px) {
  .vb-fetch-04-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-04-actions button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API error handling example is useful for dashboards, admin tools, API widgets, form submissions, search interfaces, and any JavaScript project where failed requests must not break the UI.</p>




<h2 class="wp-block-heading">5. Fetch API POST JSON Request</h2>



<p class="wp-block-paragraph"><strong>A Fetch API POST JSON request</strong> is used when JavaScript needs to send structured data to a server. This is common for contact forms, signup forms, checkout forms, admin settings, support tickets, comments, orders, and dashboard actions.</p>



<p class="wp-block-paragraph">This example sends JSON with <code>method: "POST"</code>, <code>Content-Type: application/json</code>, and <code>JSON.stringify()</code>. It uses a demo API endpoint and displays the created response object returned by the server.</p>



<ul class="wp-block-list">
<li>Fetch API POST request with JSON body</li>
<li>Use <code>method: "POST"</code></li>
<li>Send <code>Content-Type: application/json</code> header</li>
<li>Convert JavaScript object with <code>JSON.stringify()</code></li>
<li>Display returned API response</li>
</ul>



<div class="vb-fetch-05-demo">
  <div class="vb-fetch-05-layout">
    <div class="vb-fetch-05-panel">
      <span>Example 05</span>
      <h3>Fetch API POST JSON Request</h3>
      <p>Send a JavaScript object to an API endpoint as JSON and show the returned response.</p>
    </div>

    <div class="vb-fetch-05-formbox">
      <label>
        Title
        <input type="text" value="New API post" data-vb-fetch-05-title>
      </label>

      <label>
        Message
        <textarea data-vb-fetch-05-body>Created with a Fetch API POST JSON request.</textarea>
      </label>

      <button type="button" data-vb-fetch-05-send>Send POST Request</button>

      <div class="vb-fetch-05-output" data-vb-fetch-05-output>
        <span>Waiting</span>
        <h4>No POST request sent yet</h4>
        <pre>{}</pre>
      </div>
    </div>
  </div>
</div>

<style>
.vb-fetch-05-demo,
.vb-fetch-05-demo * {
  box-sizing: border-box;
}

.vb-fetch-05-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(249, 115, 22, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #faf5ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(249, 115, 22, 0.16);
  overflow: hidden;
}

.vb-fetch-05-layout {
  display: grid;
  grid-template-columns: minmax(0, 0.88fr) minmax(0, 1.12fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
  min-width: 0;
}

.vb-fetch-05-panel {
  min-width: 0;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #7c2d12 0%, #ea580c 52%, #7e22ce 100%) !important;
  box-shadow: 0 30px 90px rgba(249, 115, 22, 0.20);
}

.vb-fetch-05-panel span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-05-panel h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-05-panel p {
  margin: 0 !important;
  color: #f3e8ff !important;
  -webkit-text-fill-color: #f3e8ff !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-05-formbox {
  display: grid;
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-fetch-05-formbox label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-05-formbox input,
.vb-fetch-05-formbox textarea {
  width: 100%;
  min-width: 0;
  border: 1px solid #fed7aa;
  border-radius: 16px;
  background: #fff7ed;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-fetch-05-formbox input {
  min-height: 50px;
  padding: 0 14px;
}

.vb-fetch-05-formbox textarea {
  min-height: 105px;
  padding: 14px;
  resize: vertical;
}

.vb-fetch-05-formbox button {
  min-height: 50px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #ea580c, #7e22ce);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(234, 88, 12, 0.22);
}

.vb-fetch-05-formbox button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-05-output {
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background: #fff7ed;
  border: 1px solid #fed7aa;
}

.vb-fetch-05-output.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-fetch-05-output.is-error {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-fetch-05-output span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #ffedd5;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-05-output h4 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 22px !important;
  line-height: 1.2 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-05-output pre {
  max-width: 100%;
  max-height: 210px;
  overflow: auto;
  margin: 0 !important;
  padding: 14px;
  border-radius: 16px;
  background: #0f172a;
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 13px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-fetch-05-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-fetch-05-panel h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-05-demo");
  if (!demo) return;

  const titleInput = demo.querySelector("[data-vb-fetch-05-title]");
  const bodyInput = demo.querySelector("[data-vb-fetch-05-body]");
  const sendButton = demo.querySelector("[data-vb-fetch-05-send]");
  const output = demo.querySelector("[data-vb-fetch-05-output]");

  async function sendPostRequest() {
    const payload = {
      title: titleInput.value.trim(),
      body: bodyInput.value.trim(),
      userId: 1
    };

    sendButton.disabled = true;
    output.className = "vb-fetch-05-output";
    output.innerHTML =
      '<span>Sending</span>' +
      '<h4>POST request running</h4>' +
      '<pre>' + JSON.stringify(payload, null, 2) + '</pre>';

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts", {
        method: "POST",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify(payload)
      });

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const createdPost = await response.json();

      output.className = "vb-fetch-05-output is-success";
      output.innerHTML =
        '<span>Created</span>' +
        '<h4>JSON was sent successfully</h4>' +
        '<pre>' + JSON.stringify(createdPost, null, 2) + '</pre>';
    } catch (error) {
      output.className = "vb-fetch-05-output is-error";
      output.innerHTML =
        '<span>Error</span>' +
        '<h4>POST request failed</h4>' +
        '<pre>' + error.message + '</pre>';
    } finally {
      sendButton.disabled = false;
    }
  }

  sendButton.addEventListener("click", sendPostRequest);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-05-demo");
  if (!demo) return;

  const titleInput = demo.querySelector("[data-vb-fetch-05-title]");
  const bodyInput = demo.querySelector("[data-vb-fetch-05-body]");
  const sendButton = demo.querySelector("[data-vb-fetch-05-send]");
  const output = demo.querySelector("[data-vb-fetch-05-output]");

  async function sendPostRequest() {
    const payload = {
      title: titleInput.value.trim(),
      body: bodyInput.value.trim(),
      userId: 1
    };

    sendButton.disabled = true;
    output.className = "vb-fetch-05-output";
    output.innerHTML =
      '&lt;span&gt;Sending&lt;/span&gt;' +
      '&lt;h4&gt;POST request running&lt;/h4&gt;' +
      '&lt;pre&gt;' + JSON.stringify(payload, null, 2) + '&lt;/pre&gt;';

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts", {
        method: "POST",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify(payload)
      });

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const createdPost = await response.json();

      output.className = "vb-fetch-05-output is-success";
      output.innerHTML =
        '&lt;span&gt;Created&lt;/span&gt;' +
        '&lt;h4&gt;JSON was sent successfully&lt;/h4&gt;' +
        '&lt;pre&gt;' + JSON.stringify(createdPost, null, 2) + '&lt;/pre&gt;';
    } catch (error) {
      output.className = "vb-fetch-05-output is-error";
      output.innerHTML =
        '&lt;span&gt;Error&lt;/span&gt;' +
        '&lt;h4&gt;POST request failed&lt;/h4&gt;' +
        '&lt;pre&gt;' + error.message + '&lt;/pre&gt;';
    } finally {
      sendButton.disabled = false;
    }
  }

  sendButton.addEventListener("click", sendPostRequest);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-05-demo"&gt;
  &lt;div class="vb-fetch-05-layout"&gt;
    &lt;div class="vb-fetch-05-panel"&gt;
      &lt;span&gt;Example 05&lt;/span&gt;
      &lt;h3&gt;Fetch API POST JSON Request&lt;/h3&gt;
      &lt;p&gt;Send a JavaScript object to an API endpoint as JSON and show the returned response.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-05-formbox"&gt;
      &lt;label&gt;
        Title
        &lt;input type="text" value="New API post" data-vb-fetch-05-title&gt;
      &lt;/label&gt;

      &lt;label&gt;
        Message
        &lt;textarea data-vb-fetch-05-body&gt;Created with a Fetch API POST JSON request.&lt;/textarea&gt;
      &lt;/label&gt;

      &lt;button type="button" data-vb-fetch-05-send&gt;Send POST Request&lt;/button&gt;

      &lt;div class="vb-fetch-05-output" data-vb-fetch-05-output&gt;
        &lt;span&gt;Waiting&lt;/span&gt;
        &lt;h4&gt;No POST request sent yet&lt;/h4&gt;
        &lt;pre&gt;{}&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-05-demo,
.vb-fetch-05-demo * {
  box-sizing: border-box;
}

.vb-fetch-05-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(249, 115, 22, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #faf5ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(249, 115, 22, 0.16);
  overflow: hidden;
}

.vb-fetch-05-layout {
  display: grid;
  grid-template-columns: minmax(0, 0.88fr) minmax(0, 1.12fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
  min-width: 0;
}

.vb-fetch-05-panel {
  min-width: 0;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #7c2d12 0%, #ea580c 52%, #7e22ce 100%) !important;
  box-shadow: 0 30px 90px rgba(249, 115, 22, 0.20);
}

.vb-fetch-05-panel span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-05-panel h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-05-panel p {
  margin: 0 !important;
  color: #f3e8ff !important;
  -webkit-text-fill-color: #f3e8ff !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-05-formbox {
  display: grid;
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-fetch-05-formbox label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-05-formbox input,
.vb-fetch-05-formbox textarea {
  width: 100%;
  min-width: 0;
  border: 1px solid #fed7aa;
  border-radius: 16px;
  background: #fff7ed;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-fetch-05-formbox input {
  min-height: 50px;
  padding: 0 14px;
}

.vb-fetch-05-formbox textarea {
  min-height: 105px;
  padding: 14px;
  resize: vertical;
}

.vb-fetch-05-formbox button {
  min-height: 50px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #ea580c, #7e22ce);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(234, 88, 12, 0.22);
}

.vb-fetch-05-formbox button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-05-output {
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background: #fff7ed;
  border: 1px solid #fed7aa;
}

.vb-fetch-05-output.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-fetch-05-output.is-error {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-fetch-05-output span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #ffedd5;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-05-output h4 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 22px !important;
  line-height: 1.2 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-05-output pre {
  max-width: 100%;
  max-height: 210px;
  overflow: auto;
  margin: 0 !important;
  padding: 14px;
  border-radius: 16px;
  background: #0f172a;
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 13px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-fetch-05-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-fetch-05-panel h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API POST JSON request example is useful for contact forms, signup forms, comment forms, order forms, settings panels, support tickets, admin dashboards, and any JavaScript feature that needs to send JSON data to an API.</p>




<h2 class="wp-block-heading">6. Fetch API Form Submit Example</h2>



<p class="wp-block-paragraph"><strong>A Fetch API form submit example</strong> shows how to submit form data with JavaScript without reloading the page. This pattern is useful for contact forms, newsletter forms, quote request forms, booking forms, support forms, surveys, and lead generation pages.</p>



<p class="wp-block-paragraph">This example prevents the default form submit, collects values with <code>FormData</code>, converts the data into a plain object, sends it as JSON with <code>fetch()</code>, and displays a success or error message after the API responds.</p>



<ul class="wp-block-list">
<li>Submit a form with Fetch API</li>
<li>Use <code>event.preventDefault()</code></li>
<li>Collect fields with <code>FormData</code></li>
<li>Convert form data to JSON</li>
<li>Show success and error feedback without page reload</li>
</ul>



<div class="vb-fetch-06-demo">
  <div class="vb-fetch-06-shell">
    <div class="vb-fetch-06-header">
      <span>Example 06</span>
      <h3>Fetch API Form Submit</h3>
      <p>Submit form data as JSON with Fetch API and show the response without reloading the page.</p>
    </div>

    <form class="vb-fetch-06-form" data-vb-fetch-06-form>
      <div class="vb-fetch-06-grid">
        <label>
          Name
          <input type="text" name="name" value="Alex Johnson" required>
        </label>

        <label>
          Email
          <input type="email" name="email" value="alex@example.com" required>
        </label>
      </div>

      <label>
        Request type
        <select name="requestType">
          <option value="Website project">Website project</option>
          <option value="API integration">API integration</option>
          <option value="Custom dashboard">Custom dashboard</option>
        </select>
      </label>

      <label>
        Message
        <textarea name="message" required>I want to build a website with API-connected forms and dynamic content.</textarea>
      </label>

      <button type="submit" data-vb-fetch-06-submit>Submit Form with Fetch</button>
    </form>

    <div class="vb-fetch-06-response" data-vb-fetch-06-response>
      <span>Ready</span>
      <h4>Form has not been submitted yet</h4>
      <p>The response message will appear here after the Fetch API form submit.</p>
    </div>
  </div>
</div>

<style>
.vb-fetch-06-demo,
.vb-fetch-06-demo * {
  box-sizing: border-box;
}

.vb-fetch-06-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(37, 99, 235, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.16);
  overflow: hidden;
}

.vb-fetch-06-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-06-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #1e3a8a 0%, #2563eb 52%, #16a34a 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-06-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-06-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-06-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-06-form {
  display: grid;
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
  border-bottom: 1px solid rgba(148, 163, 184, 0.18);
}

.vb-fetch-06-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
}

.vb-fetch-06-form label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-06-form input,
.vb-fetch-06-form select,
.vb-fetch-06-form textarea {
  width: 100%;
  min-width: 0;
  border: 1px solid #bfdbfe;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-fetch-06-form input,
.vb-fetch-06-form select {
  min-height: 50px;
  padding: 0 14px;
}

.vb-fetch-06-form textarea {
  min-height: 110px;
  padding: 14px;
  resize: vertical;
}

.vb-fetch-06-form button {
  width: fit-content;
  min-height: 50px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #16a34a);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.24);
}

.vb-fetch-06-form button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-06-response {
  min-width: 0;
  margin: clamp(20px, 4vw, 34px);
  padding: 22px;
  border-radius: 24px;
  background: #eff6ff;
  border: 1px solid #bfdbfe;
}

.vb-fetch-06-response.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-fetch-06-response.is-error {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-fetch-06-response span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-06-response h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(23px, 4vw, 34px) !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-06-response p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 700px) {
  .vb-fetch-06-grid {
    grid-template-columns: 1fr;
  }

  .vb-fetch-06-form button {
    width: 100%;
  }
}

@media (max-width: 640px) {
  .vb-fetch-06-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-06-demo");
  if (!demo) return;

  const form = demo.querySelector("[data-vb-fetch-06-form]");
  const submitButton = demo.querySelector("[data-vb-fetch-06-submit]");
  const responseBox = demo.querySelector("[data-vb-fetch-06-response]");

  form.addEventListener("submit", async function (event) {
    event.preventDefault();

    const formData = new FormData(form);
    const payload = Object.fromEntries(formData.entries());

    submitButton.disabled = true;
    submitButton.textContent = "Submitting...";

    responseBox.className = "vb-fetch-06-response";
    responseBox.innerHTML =
      '<span>Sending</span>' +
      '<h4>Submitting form data</h4>' +
      '<p>The form values are being sent as JSON with Fetch API.</p>';

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts", {
        method: "POST",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify(payload)
      });

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const result = await response.json();

      responseBox.className = "vb-fetch-06-response is-success";
      responseBox.innerHTML =
        '<span>Success</span>' +
        '<h4>Form submitted without reload</h4>' +
        '<p>API returned demo ID #' + result.id + '. Submitted request type: ' + payload.requestType + '.</p>';
    } catch (error) {
      responseBox.className = "vb-fetch-06-response is-error";
      responseBox.innerHTML =
        '<span>Error</span>' +
        '<h4>Form submit failed</h4>' +
        '<p>' + error.message + '</p>';
    } finally {
      submitButton.disabled = false;
      submitButton.textContent = "Submit Form with Fetch";
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-06-demo");
  if (!demo) return;

  const form = demo.querySelector("[data-vb-fetch-06-form]");
  const submitButton = demo.querySelector("[data-vb-fetch-06-submit]");
  const responseBox = demo.querySelector("[data-vb-fetch-06-response]");

  form.addEventListener("submit", async function (event) {
    event.preventDefault();

    const formData = new FormData(form);
    const payload = Object.fromEntries(formData.entries());

    submitButton.disabled = true;
    submitButton.textContent = "Submitting...";

    responseBox.className = "vb-fetch-06-response";
    responseBox.innerHTML =
      '&lt;span&gt;Sending&lt;/span&gt;' +
      '&lt;h4&gt;Submitting form data&lt;/h4&gt;' +
      '&lt;p&gt;The form values are being sent as JSON with Fetch API.&lt;/p&gt;';

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts", {
        method: "POST",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify(payload)
      });

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const result = await response.json();

      responseBox.className = "vb-fetch-06-response is-success";
      responseBox.innerHTML =
        '&lt;span&gt;Success&lt;/span&gt;' +
        '&lt;h4&gt;Form submitted without reload&lt;/h4&gt;' +
        '&lt;p&gt;API returned demo ID #' + result.id + '. Submitted request type: ' + payload.requestType + '.&lt;/p&gt;';
    } catch (error) {
      responseBox.className = "vb-fetch-06-response is-error";
      responseBox.innerHTML =
        '&lt;span&gt;Error&lt;/span&gt;' +
        '&lt;h4&gt;Form submit failed&lt;/h4&gt;' +
        '&lt;p&gt;' + error.message + '&lt;/p&gt;';
    } finally {
      submitButton.disabled = false;
      submitButton.textContent = "Submit Form with Fetch";
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-06-demo"&gt;
  &lt;div class="vb-fetch-06-shell"&gt;
    &lt;div class="vb-fetch-06-header"&gt;
      &lt;span&gt;Example 06&lt;/span&gt;
      &lt;h3&gt;Fetch API Form Submit&lt;/h3&gt;
      &lt;p&gt;Submit form data as JSON with Fetch API and show the response without reloading the page.&lt;/p&gt;
    &lt;/div&gt;

    &lt;form class="vb-fetch-06-form" data-vb-fetch-06-form&gt;
      &lt;div class="vb-fetch-06-grid"&gt;
        &lt;label&gt;
          Name
          &lt;input type="text" name="name" value="Alex Johnson" required&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Email
          &lt;input type="email" name="email" value="alex@example.com" required&gt;
        &lt;/label&gt;
      &lt;/div&gt;

      &lt;label&gt;
        Request type
        &lt;select name="requestType"&gt;
          &lt;option value="Website project"&gt;Website project&lt;/option&gt;
          &lt;option value="API integration"&gt;API integration&lt;/option&gt;
          &lt;option value="Custom dashboard"&gt;Custom dashboard&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;

      &lt;label&gt;
        Message
        &lt;textarea name="message" required&gt;I want to build a website with API-connected forms and dynamic content.&lt;/textarea&gt;
      &lt;/label&gt;

      &lt;button type="submit" data-vb-fetch-06-submit&gt;Submit Form with Fetch&lt;/button&gt;
    &lt;/form&gt;

    &lt;div class="vb-fetch-06-response" data-vb-fetch-06-response&gt;
      &lt;span&gt;Ready&lt;/span&gt;
      &lt;h4&gt;Form has not been submitted yet&lt;/h4&gt;
      &lt;p&gt;The response message will appear here after the Fetch API form submit.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-06-demo,
.vb-fetch-06-demo * {
  box-sizing: border-box;
}

.vb-fetch-06-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(37, 99, 235, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.16);
  overflow: hidden;
}

.vb-fetch-06-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-06-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #1e3a8a 0%, #2563eb 52%, #16a34a 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-06-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-06-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-06-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-06-form {
  display: grid;
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
  border-bottom: 1px solid rgba(148, 163, 184, 0.18);
}

.vb-fetch-06-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
}

.vb-fetch-06-form label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-06-form input,
.vb-fetch-06-form select,
.vb-fetch-06-form textarea {
  width: 100%;
  min-width: 0;
  border: 1px solid #bfdbfe;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-fetch-06-form input,
.vb-fetch-06-form select {
  min-height: 50px;
  padding: 0 14px;
}

.vb-fetch-06-form textarea {
  min-height: 110px;
  padding: 14px;
  resize: vertical;
}

.vb-fetch-06-form button {
  width: fit-content;
  min-height: 50px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #16a34a);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.24);
}

.vb-fetch-06-form button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-06-response {
  min-width: 0;
  margin: clamp(20px, 4vw, 34px);
  padding: 22px;
  border-radius: 24px;
  background: #eff6ff;
  border: 1px solid #bfdbfe;
}

.vb-fetch-06-response.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-fetch-06-response.is-error {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-fetch-06-response span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-06-response h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(23px, 4vw, 34px) !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-06-response p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 700px) {
  .vb-fetch-06-grid {
    grid-template-columns: 1fr;
  }

  .vb-fetch-06-form button {
    width: 100%;
  }
}

@media (max-width: 640px) {
  .vb-fetch-06-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API form submit example is useful for contact forms, lead forms, newsletter forms, booking forms, quote request forms, support forms, surveys, and custom WordPress AJAX-style form interfaces.</p>



<h2 class="wp-block-heading">7. Fetch API PUT Update Request</h2>



<p class="wp-block-paragraph"><strong>A Fetch API PUT update request</strong> is used when JavaScript needs to replace an existing record with a full updated object. This is common in admin dashboards, profile editors, CMS tools, product editors, settings pages, and account management screens.</p>



<p class="wp-block-paragraph">This example sends a complete updated post object to a demo API endpoint with <code>method: "PUT"</code>. It collects field values, sends JSON, checks <code>response.ok</code>, parses the returned response, and updates the UI after the request succeeds.</p>



<ul class="wp-block-list">
<li>Fetch API PUT request example</li>
<li>Update an existing record with JSON</li>
<li>Send full replacement data</li>
<li>Show updated API response</li>
<li>Useful for edit forms and admin dashboards</li>
</ul>



<div class="vb-fetch-07-demo">
  <div class="vb-fetch-07-shell">
    <div class="vb-fetch-07-header">
      <span>Example 07</span>
      <h3>Fetch API PUT Update Request</h3>
      <p>Replace an existing API record with a complete updated JSON object using a PUT request.</p>
    </div>

    <div class="vb-fetch-07-body">
      <div class="vb-fetch-07-form">
        <label>
          Post title
          <input type="text" value="Updated dashboard announcement" data-vb-fetch-07-title>
        </label>

        <label>
          Post body
          <textarea data-vb-fetch-07-body-input>This full record was updated with a JavaScript Fetch API PUT request.</textarea>
        </label>

        <label>
          User ID
          <input type="number" min="1" value="1" data-vb-fetch-07-user>
        </label>

        <button type="button" data-vb-fetch-07-update>Send PUT Update</button>
      </div>

      <div class="vb-fetch-07-result" data-vb-fetch-07-result>
        <span>Waiting</span>
        <h4>No update sent yet</h4>
        <p>The updated API response will appear here after the PUT request.</p>
        <pre>{}</pre>
      </div>
    </div>
  </div>
</div>

<style>
.vb-fetch-07-demo,
.vb-fetch-07-demo * {
  box-sizing: border-box;
}

.vb-fetch-07-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(59, 130, 246, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(99, 102, 241, 0.18), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #eef2ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.18);
  overflow: hidden;
}

.vb-fetch-07-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-07-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #1e3a8a 0%, #2563eb 52%, #4f46e5 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-07-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-07-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-07-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-07-body {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
  gap: 22px;
  padding: clamp(20px, 4vw, 34px);
  min-width: 0;
}

.vb-fetch-07-form {
  display: grid;
  gap: 14px;
  min-width: 0;
  padding: 20px;
  border-radius: 24px;
  background: #eff6ff;
  border: 1px solid #bfdbfe;
}

.vb-fetch-07-form label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-07-form input,
.vb-fetch-07-form textarea {
  width: 100%;
  min-width: 0;
  border: 1px solid #bfdbfe;
  border-radius: 16px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-fetch-07-form input {
  min-height: 50px;
  padding: 0 14px;
}

.vb-fetch-07-form textarea {
  min-height: 120px;
  padding: 14px;
  resize: vertical;
}

.vb-fetch-07-form button {
  min-height: 50px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #4f46e5);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.24);
}

.vb-fetch-07-form button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-07-result {
  min-width: 0;
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 14% 12%, rgba(37, 99, 235, 0.12), transparent 34%),
    linear-gradient(135deg, #f8fafc, #ffffff) !important;
  border: 1px solid #e2e8f0;
}

.vb-fetch-07-result.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-fetch-07-result.is-error {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-fetch-07-result span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-07-result.is-success span {
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-07-result.is-error span {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-07-result h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(23px, 4vw, 34px) !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-07-result p {
  margin: 0 0 14px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-07-result pre {
  max-width: 100%;
  max-height: 230px;
  overflow: auto;
  margin: 0 !important;
  padding: 14px;
  border-radius: 16px;
  background: #0f172a;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 13px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-fetch-07-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-fetch-07-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-07-demo");
  if (!demo) return;

  const titleInput = demo.querySelector("[data-vb-fetch-07-title]");
  const bodyInput = demo.querySelector("[data-vb-fetch-07-body-input]");
  const userInput = demo.querySelector("[data-vb-fetch-07-user]");
  const button = demo.querySelector("[data-vb-fetch-07-update]");
  const resultBox = demo.querySelector("[data-vb-fetch-07-result]");

  async function updateRecord() {
    const payload = {
      id: 1,
      title: titleInput.value.trim(),
      body: bodyInput.value.trim(),
      userId: Number(userInput.value) || 1
    };

    button.disabled = true;
    resultBox.className = "vb-fetch-07-result";
    resultBox.innerHTML =
      '<span>Updating</span>' +
      '<h4>PUT request running</h4>' +
      '<p>Sending the complete replacement object to the API.</p>' +
      '<pre>' + JSON.stringify(payload, null, 2) + '</pre>';

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts/1", {
        method: "PUT",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify(payload)
      });

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const updated = await response.json();

      resultBox.className = "vb-fetch-07-result is-success";
      resultBox.innerHTML =
        '<span>Updated</span>' +
        '<h4>Record replaced successfully</h4>' +
        '<p>The demo API returned the updated object from the PUT request.</p>' +
        '<pre>' + JSON.stringify(updated, null, 2) + '</pre>';
    } catch (error) {
      resultBox.className = "vb-fetch-07-result is-error";
      resultBox.innerHTML =
        '<span>Error</span>' +
        '<h4>PUT request failed</h4>' +
        '<p>' + error.message + '</p>' +
        '<pre>{}</pre>';
    } finally {
      button.disabled = false;
    }
  }

  button.addEventListener("click", updateRecord);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-07-demo");
  if (!demo) return;

  const titleInput = demo.querySelector("[data-vb-fetch-07-title]");
  const bodyInput = demo.querySelector("[data-vb-fetch-07-body-input]");
  const userInput = demo.querySelector("[data-vb-fetch-07-user]");
  const button = demo.querySelector("[data-vb-fetch-07-update]");
  const resultBox = demo.querySelector("[data-vb-fetch-07-result]");

  async function updateRecord() {
    const payload = {
      id: 1,
      title: titleInput.value.trim(),
      body: bodyInput.value.trim(),
      userId: Number(userInput.value) || 1
    };

    button.disabled = true;
    resultBox.className = "vb-fetch-07-result";
    resultBox.innerHTML =
      '&lt;span&gt;Updating&lt;/span&gt;' +
      '&lt;h4&gt;PUT request running&lt;/h4&gt;' +
      '&lt;p&gt;Sending the complete replacement object to the API.&lt;/p&gt;' +
      '&lt;pre&gt;' + JSON.stringify(payload, null, 2) + '&lt;/pre&gt;';

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts/1", {
        method: "PUT",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify(payload)
      });

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const updated = await response.json();

      resultBox.className = "vb-fetch-07-result is-success";
      resultBox.innerHTML =
        '&lt;span&gt;Updated&lt;/span&gt;' +
        '&lt;h4&gt;Record replaced successfully&lt;/h4&gt;' +
        '&lt;p&gt;The demo API returned the updated object from the PUT request.&lt;/p&gt;' +
        '&lt;pre&gt;' + JSON.stringify(updated, null, 2) + '&lt;/pre&gt;';
    } catch (error) {
      resultBox.className = "vb-fetch-07-result is-error";
      resultBox.innerHTML =
        '&lt;span&gt;Error&lt;/span&gt;' +
        '&lt;h4&gt;PUT request failed&lt;/h4&gt;' +
        '&lt;p&gt;' + error.message + '&lt;/p&gt;' +
        '&lt;pre&gt;{}&lt;/pre&gt;';
    } finally {
      button.disabled = false;
    }
  }

  button.addEventListener("click", updateRecord);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-07-demo"&gt;
  &lt;div class="vb-fetch-07-shell"&gt;
    &lt;div class="vb-fetch-07-header"&gt;
      &lt;span&gt;Example 07&lt;/span&gt;
      &lt;h3&gt;Fetch API PUT Update Request&lt;/h3&gt;
      &lt;p&gt;Replace an existing API record with a complete updated JSON object using a PUT request.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-07-body"&gt;
      &lt;div class="vb-fetch-07-form"&gt;
        &lt;label&gt;
          Post title
          &lt;input type="text" value="Updated dashboard announcement" data-vb-fetch-07-title&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Post body
          &lt;textarea data-vb-fetch-07-body-input&gt;This full record was updated with a JavaScript Fetch API PUT request.&lt;/textarea&gt;
        &lt;/label&gt;

        &lt;label&gt;
          User ID
          &lt;input type="number" min="1" value="1" data-vb-fetch-07-user&gt;
        &lt;/label&gt;

        &lt;button type="button" data-vb-fetch-07-update&gt;Send PUT Update&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-fetch-07-result" data-vb-fetch-07-result&gt;
        &lt;span&gt;Waiting&lt;/span&gt;
        &lt;h4&gt;No update sent yet&lt;/h4&gt;
        &lt;p&gt;The updated API response will appear here after the PUT request.&lt;/p&gt;
        &lt;pre&gt;{}&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-07-demo,
.vb-fetch-07-demo * {
  box-sizing: border-box;
}

.vb-fetch-07-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(59, 130, 246, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(99, 102, 241, 0.18), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #eef2ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.18);
  overflow: hidden;
}

.vb-fetch-07-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-07-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #1e3a8a 0%, #2563eb 52%, #4f46e5 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-07-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-07-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-07-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-07-body {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
  gap: 22px;
  padding: clamp(20px, 4vw, 34px);
  min-width: 0;
}

.vb-fetch-07-form {
  display: grid;
  gap: 14px;
  min-width: 0;
  padding: 20px;
  border-radius: 24px;
  background: #eff6ff;
  border: 1px solid #bfdbfe;
}

.vb-fetch-07-form label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-07-form input,
.vb-fetch-07-form textarea {
  width: 100%;
  min-width: 0;
  border: 1px solid #bfdbfe;
  border-radius: 16px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-fetch-07-form input {
  min-height: 50px;
  padding: 0 14px;
}

.vb-fetch-07-form textarea {
  min-height: 120px;
  padding: 14px;
  resize: vertical;
}

.vb-fetch-07-form button {
  min-height: 50px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #4f46e5);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.24);
}

.vb-fetch-07-form button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-07-result {
  min-width: 0;
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 14% 12%, rgba(37, 99, 235, 0.12), transparent 34%),
    linear-gradient(135deg, #f8fafc, #ffffff) !important;
  border: 1px solid #e2e8f0;
}

.vb-fetch-07-result.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-fetch-07-result.is-error {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-fetch-07-result span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-07-result.is-success span {
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-07-result.is-error span {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-07-result h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(23px, 4vw, 34px) !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-07-result p {
  margin: 0 0 14px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-07-result pre {
  max-width: 100%;
  max-height: 230px;
  overflow: auto;
  margin: 0 !important;
  padding: 14px;
  border-radius: 16px;
  background: #0f172a;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 13px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-fetch-07-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-fetch-07-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}</pre>



<p class="wp-block-paragraph">This PUT update example is useful for profile editors, admin dashboards, CMS edit screens, product management tools, settings pages, and any JavaScript interface that replaces an existing API record.</p>




<h2 class="wp-block-heading">8. Fetch API PATCH Partial Update</h2>



<p class="wp-block-paragraph"><strong>A Fetch API PATCH request</strong> updates only part of an existing record instead of replacing the entire object. This is useful for toggling status, changing a title, updating a quantity, saving a preference, marking a task complete, or changing one field in a dashboard.</p>



<p class="wp-block-paragraph">This example updates only the completion status of a todo item. It sends a small JSON payload with <code>method: "PATCH"</code>, renders the returned result, and changes the UI state based on the updated value.</p>



<ul class="wp-block-list">
<li>Fetch API PATCH request example</li>
<li>Partial record update</li>
<li>Status toggle request</li>
<li>Small JSON payload</li>
<li>Useful for dashboards and task apps</li>
</ul>



<div class="vb-fetch-08-demo">
  <div class="vb-fetch-08-card">
    <div class="vb-fetch-08-copy">
      <span>Example 08</span>
      <h3>Fetch API PATCH Partial Update</h3>
      <p>Toggle a task status and send only the changed field to the API with PATCH.</p>
    </div>

    <div class="vb-fetch-08-task" data-vb-fetch-08-task>
      <div class="vb-fetch-08-task-top">
        <span data-vb-fetch-08-badge>Incomplete</span>
        <strong>API task #1</strong>
      </div>

      <p>Complete the JavaScript Fetch API lesson</p>

      <button type="button" data-vb-fetch-08-toggle>Mark as Complete</button>

      <pre data-vb-fetch-08-output>{ "completed": false }</pre>
    </div>
  </div>
</div>

<style>
.vb-fetch-08-demo,
.vb-fetch-08-demo * {
  box-sizing: border-box;
}

.vb-fetch-08-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 197, 94, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(20, 184, 166, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #f0fdfa 54%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.18);
  overflow: hidden;
}

.vb-fetch-08-card {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
  min-width: 0;
}

.vb-fetch-08-copy {
  min-width: 0;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #052e16 0%, #16a34a 54%, #0f766e 100%) !important;
  box-shadow: 0 30px 90px rgba(22, 163, 74, 0.22);
}

.vb-fetch-08-copy span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-08-copy h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-08-copy p {
  margin: 0 !important;
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-08-task {
  display: grid;
  gap: 16px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-fetch-08-task.is-complete {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-fetch-08-task-top {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  justify-content: space-between;
  min-width: 0;
}

.vb-fetch-08-task-top span {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-fetch-08-task.is-complete .vb-fetch-08-task-top span {
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-08-task-top strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-fetch-08-task p {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(24px, 4vw, 40px);
  line-height: 1.08;
  font-weight: 950;
  letter-spacing: -0.05em;
  overflow-wrap: anywhere;
}

.vb-fetch-08-task button {
  min-height: 50px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #16a34a, #0f766e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(22, 163, 74, 0.22);
}

.vb-fetch-08-task button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-08-task pre {
  max-width: 100%;
  max-height: 220px;
  overflow: auto;
  margin: 0 !important;
  padding: 14px;
  border-radius: 16px;
  background: #0f172a;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 13px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-fetch-08-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-fetch-08-copy h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-08-demo");
  if (!demo) return;

  const taskBox = demo.querySelector("[data-vb-fetch-08-task]");
  const badge = demo.querySelector("[data-vb-fetch-08-badge]");
  const button = demo.querySelector("[data-vb-fetch-08-toggle]");
  const output = demo.querySelector("[data-vb-fetch-08-output]");

  let completed = false;

  function renderState(data) {
    completed = Boolean(data.completed);
    taskBox.classList.toggle("is-complete", completed);
    badge.textContent = completed ? "Complete" : "Incomplete";
    button.textContent = completed ? "Mark as Incomplete" : "Mark as Complete";
    output.textContent = JSON.stringify(data, null, 2);
  }

  async function patchTask() {
    const nextStatus = !completed;
    const payload = {
      completed: nextStatus
    };

    button.disabled = true;
    output.textContent = "Sending PATCH request...\n" + JSON.stringify(payload, null, 2);

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/todos/1", {
        method: "PATCH",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify(payload)
      });

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const updatedTask = await response.json();
      renderState(updatedTask);
    } catch (error) {
      output.textContent = "PATCH request failed: " + error.message;
    } finally {
      button.disabled = false;
    }
  }

  button.addEventListener("click", patchTask);
  renderState({ id: 1, title: "Complete the JavaScript Fetch API lesson", completed: completed });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-08-demo");
  if (!demo) return;

  const taskBox = demo.querySelector("[data-vb-fetch-08-task]");
  const badge = demo.querySelector("[data-vb-fetch-08-badge]");
  const button = demo.querySelector("[data-vb-fetch-08-toggle]");
  const output = demo.querySelector("[data-vb-fetch-08-output]");

  let completed = false;

  function renderState(data) {
    completed = Boolean(data.completed);
    taskBox.classList.toggle("is-complete", completed);
    badge.textContent = completed ? "Complete" : "Incomplete";
    button.textContent = completed ? "Mark as Incomplete" : "Mark as Complete";
    output.textContent = JSON.stringify(data, null, 2);
  }

  async function patchTask() {
    const nextStatus = !completed;
    const payload = {
      completed: nextStatus
    };

    button.disabled = true;
    output.textContent = "Sending PATCH request...\n" + JSON.stringify(payload, null, 2);

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/todos/1", {
        method: "PATCH",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify(payload)
      });

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const updatedTask = await response.json();
      renderState(updatedTask);
    } catch (error) {
      output.textContent = "PATCH request failed: " + error.message;
    } finally {
      button.disabled = false;
    }
  }

  button.addEventListener("click", patchTask);
  renderState({ id: 1, title: "Complete the JavaScript Fetch API lesson", completed: completed });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-08-demo"&gt;
  &lt;div class="vb-fetch-08-card"&gt;
    &lt;div class="vb-fetch-08-copy"&gt;
      &lt;span&gt;Example 08&lt;/span&gt;
      &lt;h3&gt;Fetch API PATCH Partial Update&lt;/h3&gt;
      &lt;p&gt;Toggle a task status and send only the changed field to the API with PATCH.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-08-task" data-vb-fetch-08-task&gt;
      &lt;div class="vb-fetch-08-task-top"&gt;
        &lt;span data-vb-fetch-08-badge&gt;Incomplete&lt;/span&gt;
        &lt;strong&gt;API task #1&lt;/strong&gt;
      &lt;/div&gt;

      &lt;p&gt;Complete the JavaScript Fetch API lesson&lt;/p&gt;

      &lt;button type="button" data-vb-fetch-08-toggle&gt;Mark as Complete&lt;/button&gt;

      &lt;pre data-vb-fetch-08-output&gt;{ "completed": false }&lt;/pre&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-08-demo,
.vb-fetch-08-demo * {
  box-sizing: border-box;
}

.vb-fetch-08-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 197, 94, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(20, 184, 166, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #f0fdfa 54%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.18);
  overflow: hidden;
}

.vb-fetch-08-card {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
  min-width: 0;
}

.vb-fetch-08-copy {
  min-width: 0;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #052e16 0%, #16a34a 54%, #0f766e 100%) !important;
  box-shadow: 0 30px 90px rgba(22, 163, 74, 0.22);
}

.vb-fetch-08-copy span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-08-copy h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-08-copy p {
  margin: 0 !important;
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-08-task {
  display: grid;
  gap: 16px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-fetch-08-task.is-complete {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-fetch-08-task-top {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: center;
  justify-content: space-between;
  min-width: 0;
}

.vb-fetch-08-task-top span {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-fetch-08-task.is-complete .vb-fetch-08-task-top span {
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-08-task-top strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-fetch-08-task p {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(24px, 4vw, 40px);
  line-height: 1.08;
  font-weight: 950;
  letter-spacing: -0.05em;
  overflow-wrap: anywhere;
}

.vb-fetch-08-task button {
  min-height: 50px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #16a34a, #0f766e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(22, 163, 74, 0.22);
}

.vb-fetch-08-task button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-08-task pre {
  max-width: 100%;
  max-height: 220px;
  overflow: auto;
  margin: 0 !important;
  padding: 14px;
  border-radius: 16px;
  background: #0f172a;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 13px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-fetch-08-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-fetch-08-copy h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}</pre>



<p class="wp-block-paragraph">This PATCH partial update example is useful for task apps, admin dashboards, status toggles, user settings, ecommerce quantity changes, notification preferences, and any API interface that updates only one field.</p>




<h2 class="wp-block-heading">9. Fetch API DELETE Request</h2>



<p class="wp-block-paragraph"><strong>A Fetch API DELETE request</strong> is used when JavaScript needs to remove an existing resource from an API. This pattern is common in admin dashboards, user management screens, cart items, todo apps, saved lists, comments, messages, and product management tools.</p>



<p class="wp-block-paragraph">This example renders a small list of demo records and lets users delete one item. The JavaScript sends a <code>DELETE</code> request to the API, waits for a successful response, and removes the item from the local UI.</p>



<ul class="wp-block-list">
<li>Fetch API DELETE request example</li>
<li>Remove item from API and UI</li>
<li>Safe confirmation-style interface</li>
<li>Loading state on delete button</li>
<li>Useful for admin panels and list management</li>
</ul>



<div class="vb-fetch-09-demo">
  <div class="vb-fetch-09-shell">
    <div class="vb-fetch-09-header">
      <span>Example 09</span>
      <h3>Fetch API DELETE Request</h3>
      <p>Send a DELETE request and remove the deleted item from the interface after success.</p>
    </div>

    <div class="vb-fetch-09-status" data-vb-fetch-09-status>
      Choose an item to delete. The demo API will confirm the request.
    </div>

    <div class="vb-fetch-09-list" data-vb-fetch-09-list>
      <div class="vb-fetch-09-item" data-id="1">
        <div>
          <strong>API record #1</strong>
          <span>Demo dashboard item</span>
        </div>
        <button type="button">Delete</button>
      </div>

      <div class="vb-fetch-09-item" data-id="2">
        <div>
          <strong>API record #2</strong>
          <span>Demo saved message</span>
        </div>
        <button type="button">Delete</button>
      </div>

      <div class="vb-fetch-09-item" data-id="3">
        <div>
          <strong>API record #3</strong>
          <span>Demo product note</span>
        </div>
        <button type="button">Delete</button>
      </div>
    </div>
  </div>
</div>

<style>
.vb-fetch-09-demo,
.vb-fetch-09-demo * {
  box-sizing: border-box;
}

.vb-fetch-09-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(244, 63, 94, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(15, 23, 42, 0.12), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #f8fafc 54%, #ffffff 100%) !important;
  border: 1px solid rgba(244, 63, 94, 0.16);
  overflow: hidden;
}

.vb-fetch-09-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-09-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #7f1d1d 0%, #e11d48 52%, #0f172a 100%) !important;
}

.vb-fetch-09-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffe4e6 !important;
  -webkit-text-fill-color: #ffe4e6 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-09-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-09-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #e2e8f0 !important;
  -webkit-text-fill-color: #e2e8f0 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-09-status {
  margin: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #fff1f2;
  border: 1px solid #fecdd3;
  color: #9f1239 !important;
  -webkit-text-fill-color: #9f1239 !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-09-status.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-09-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-09-list {
  display: grid;
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-09-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 16px;
  align-items: center;
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 12% 12%, rgba(244, 63, 94, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-fetch-09-item.is-removing {
  opacity: 0.65;
}

.vb-fetch-09-item strong {
  display: block;
  margin-bottom: 4px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-fetch-09-item span {
  display: block;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 700;
  overflow-wrap: anywhere;
}

.vb-fetch-09-item button {
  min-height: 42px;
  padding: 0 16px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #e11d48, #7f1d1d);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-fetch-09-item button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

@media (max-width: 640px) {
  .vb-fetch-09-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-09-item {
    grid-template-columns: 1fr;
  }

  .vb-fetch-09-item button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-09-demo");
  if (!demo) return;

  const list = demo.querySelector("[data-vb-fetch-09-list]");
  const status = demo.querySelector("[data-vb-fetch-09-status]");

  async function deleteItem(item) {
    const id = item.dataset.id;
    const button = item.querySelector("button");

    button.disabled = true;
    button.textContent = "Deleting...";
    item.classList.add("is-removing");
    status.className = "vb-fetch-09-status";
    status.textContent = "Sending DELETE request for item #" + id + "...";

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts/" + id, {
        method: "DELETE"
      });

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      item.remove();
      status.className = "vb-fetch-09-status is-success";
      status.textContent = "Item #" + id + " was deleted successfully and removed from the UI.";

      if (!list.querySelector(".vb-fetch-09-item")) {
        status.textContent = "All demo items were deleted successfully.";
      }
    } catch (error) {
      item.classList.remove("is-removing");
      button.disabled = false;
      button.textContent = "Delete";
      status.className = "vb-fetch-09-status is-error";
      status.textContent = "DELETE request failed: " + error.message;
    }
  }

  list.addEventListener("click", function (event) {
    const button = event.target.closest("button");
    if (!button) return;

    const item = button.closest(".vb-fetch-09-item");
    if (!item) return;

    deleteItem(item);
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-09-demo");
  if (!demo) return;

  const list = demo.querySelector("[data-vb-fetch-09-list]");
  const status = demo.querySelector("[data-vb-fetch-09-status]");

  async function deleteItem(item) {
    const id = item.dataset.id;
    const button = item.querySelector("button");

    button.disabled = true;
    button.textContent = "Deleting...";
    item.classList.add("is-removing");
    status.className = "vb-fetch-09-status";
    status.textContent = "Sending DELETE request for item #" + id + "...";

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts/" + id, {
        method: "DELETE"
      });

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      item.remove();
      status.className = "vb-fetch-09-status is-success";
      status.textContent = "Item #" + id + " was deleted successfully and removed from the UI.";

      if (!list.querySelector(".vb-fetch-09-item")) {
        status.textContent = "All demo items were deleted successfully.";
      }
    } catch (error) {
      item.classList.remove("is-removing");
      button.disabled = false;
      button.textContent = "Delete";
      status.className = "vb-fetch-09-status is-error";
      status.textContent = "DELETE request failed: " + error.message;
    }
  }

  list.addEventListener("click", function (event) {
    const button = event.target.closest("button");
    if (!button) return;

    const item = button.closest(".vb-fetch-09-item");
    if (!item) return;

    deleteItem(item);
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-09-demo"&gt;
  &lt;div class="vb-fetch-09-shell"&gt;
    &lt;div class="vb-fetch-09-header"&gt;
      &lt;span&gt;Example 09&lt;/span&gt;
      &lt;h3&gt;Fetch API DELETE Request&lt;/h3&gt;
      &lt;p&gt;Send a DELETE request and remove the deleted item from the interface after success.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-09-status" data-vb-fetch-09-status&gt;
      Choose an item to delete. The demo API will confirm the request.
    &lt;/div&gt;

    &lt;div class="vb-fetch-09-list" data-vb-fetch-09-list&gt;
      &lt;div class="vb-fetch-09-item" data-id="1"&gt;
        &lt;div&gt;
          &lt;strong&gt;API record #1&lt;/strong&gt;
          &lt;span&gt;Demo dashboard item&lt;/span&gt;
        &lt;/div&gt;
        &lt;button type="button"&gt;Delete&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-fetch-09-item" data-id="2"&gt;
        &lt;div&gt;
          &lt;strong&gt;API record #2&lt;/strong&gt;
          &lt;span&gt;Demo saved message&lt;/span&gt;
        &lt;/div&gt;
        &lt;button type="button"&gt;Delete&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-fetch-09-item" data-id="3"&gt;
        &lt;div&gt;
          &lt;strong&gt;API record #3&lt;/strong&gt;
          &lt;span&gt;Demo product note&lt;/span&gt;
        &lt;/div&gt;
        &lt;button type="button"&gt;Delete&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-09-demo,
.vb-fetch-09-demo * {
  box-sizing: border-box;
}

.vb-fetch-09-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(244, 63, 94, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(15, 23, 42, 0.12), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #f8fafc 54%, #ffffff 100%) !important;
  border: 1px solid rgba(244, 63, 94, 0.16);
  overflow: hidden;
}

.vb-fetch-09-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-09-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #7f1d1d 0%, #e11d48 52%, #0f172a 100%) !important;
}

.vb-fetch-09-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffe4e6 !important;
  -webkit-text-fill-color: #ffe4e6 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-09-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-09-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #e2e8f0 !important;
  -webkit-text-fill-color: #e2e8f0 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-09-status {
  margin: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #fff1f2;
  border: 1px solid #fecdd3;
  color: #9f1239 !important;
  -webkit-text-fill-color: #9f1239 !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-09-status.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-09-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-09-list {
  display: grid;
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-09-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 16px;
  align-items: center;
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 12% 12%, rgba(244, 63, 94, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-fetch-09-item.is-removing {
  opacity: 0.65;
}

.vb-fetch-09-item strong {
  display: block;
  margin-bottom: 4px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-fetch-09-item span {
  display: block;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 700;
  overflow-wrap: anywhere;
}

.vb-fetch-09-item button {
  min-height: 42px;
  padding: 0 16px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #e11d48, #7f1d1d);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-fetch-09-item button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

@media (max-width: 640px) {
  .vb-fetch-09-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-09-item {
    grid-template-columns: 1fr;
  }

  .vb-fetch-09-item button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API DELETE request example is useful for admin dashboards, todo apps, user management tools, comment systems, saved lists, shopping carts, CRM notes, and any interface where JavaScript removes an item after an API request.</p>



<h2 class="wp-block-heading">10. Fetch API Search Request</h2>



<p class="wp-block-paragraph"><strong>A Fetch API search request</strong> is useful when users type a keyword and JavaScript requests matching data from an API. This pattern is common in blog search, product search, user search, documentation search, support center search, and dashboard filters.</p>



<p class="wp-block-paragraph">This example uses a search input, a search button, <code>URLSearchParams</code>, a Fetch API GET request, result filtering, loading feedback, empty state, and error handling. The API is a demo endpoint, but the same pattern works with real search APIs.</p>



<ul class="wp-block-list">
<li>Fetch API search request example</li>
<li>Search input and button</li>
<li>URLSearchParams query building</li>
<li>Loading, empty, success, and error states</li>
<li>Useful for real API search interfaces</li>
</ul>



<div class="vb-fetch-10-demo">
  <div class="vb-fetch-10-shell">
    <div class="vb-fetch-10-header">
      <span>Example 10</span>
      <h3>Fetch API Search Request</h3>
      <p>Search API data with a keyword, build query parameters, and render matching results.</p>
    </div>

    <div class="vb-fetch-10-search">
      <label>
        Search posts
        <input type="search" value="qui" placeholder="Try: qui, sunt, autem" data-vb-fetch-10-input>
      </label>
      <button type="button" data-vb-fetch-10-button>Search API</button>
    </div>

    <div class="vb-fetch-10-status" data-vb-fetch-10-status>
      Enter a keyword and click “Search API”.
    </div>

    <div class="vb-fetch-10-results" data-vb-fetch-10-results></div>
  </div>
</div>

<style>
.vb-fetch-10-demo,
.vb-fetch-10-demo * {
  box-sizing: border-box;
}

.vb-fetch-10-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(14, 165, 233, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  overflow: hidden;
}

.vb-fetch-10-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-10-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #075985 0%, #0284c7 52%, #16a34a 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-10-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-10-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-10-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-10-search {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 14px;
  align-items: end;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
  min-width: 0;
}

.vb-fetch-10-search label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #075985 !important;
  -webkit-text-fill-color: #075985 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-10-search input {
  width: 100%;
  min-width: 0;
  min-height: 52px;
  padding: 0 16px;
  border: 1px solid #bae6fd;
  border-radius: 18px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-fetch-10-search button {
  min-height: 52px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #0284c7, #16a34a);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(14, 165, 233, 0.22);
}

.vb-fetch-10-search button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-10-status {
  margin: 16px clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #f0f9ff;
  border: 1px solid #bae6fd;
  color: #075985 !important;
  -webkit-text-fill-color: #075985 !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-10-status.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-10-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-10-results {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-10-result-card {
  min-width: 0;
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(14, 165, 233, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-fetch-10-result-card span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-10-result-card h4 {
  margin: 0 0 9px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 19px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-10-result-card p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 760px) {
  .vb-fetch-10-search,
  .vb-fetch-10-results {
    grid-template-columns: 1fr;
  }

  .vb-fetch-10-search button {
    width: 100%;
  }
}

@media (max-width: 640px) {
  .vb-fetch-10-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-10-demo");
  if (!demo) return;

  const input = demo.querySelector("[data-vb-fetch-10-input]");
  const button = demo.querySelector("[data-vb-fetch-10-button]");
  const status = demo.querySelector("[data-vb-fetch-10-status]");
  const results = demo.querySelector("[data-vb-fetch-10-results]");

  function setStatus(text, type) {
    status.className = "vb-fetch-10-status";

    if (type === "success") {
      status.classList.add("is-success");
    }

    if (type === "error") {
      status.classList.add("is-error");
    }

    status.textContent = text;
  }

  function renderResults(posts) {
    if (!posts.length) {
      results.innerHTML = "";
      setStatus("No matching posts found. Try another keyword.", "error");
      return;
    }

    results.innerHTML = posts.map(function (post) {
      return (
        '<article class="vb-fetch-10-result-card">' +
          '<span>Post #' + post.id + '</span>' +
          '<h4>' + post.title + '</h4>' +
          '<p>' + post.body + '</p>' +
        '</article>'
      );
    }).join("");

    setStatus("Found " + posts.length + " matching API results.", "success");
  }

  async function searchApi() {
    const keyword = input.value.trim().toLowerCase();

    if (!keyword) {
      results.innerHTML = "";
      setStatus("Please enter a search keyword.", "error");
      return;
    }

    const params = new URLSearchParams({
      _limit: "20"
    });

    button.disabled = true;
    results.innerHTML = "";
    setStatus("Searching API for “" + keyword + "”...", "");

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts?" + params.toString());

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const posts = await response.json();
      const filtered = posts.filter(function (post) {
        return post.title.toLowerCase().includes(keyword) || post.body.toLowerCase().includes(keyword);
      });

      renderResults(filtered.slice(0, 6));
    } catch (error) {
      results.innerHTML = "";
      setStatus("Search request failed: " + error.message, "error");
    } finally {
      button.disabled = false;
    }
  }

  button.addEventListener("click", searchApi);

  input.addEventListener("keydown", function (event) {
    if (event.key === "Enter") {
      searchApi();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-10-demo");
  if (!demo) return;

  const input = demo.querySelector("[data-vb-fetch-10-input]");
  const button = demo.querySelector("[data-vb-fetch-10-button]");
  const status = demo.querySelector("[data-vb-fetch-10-status]");
  const results = demo.querySelector("[data-vb-fetch-10-results]");

  function setStatus(text, type) {
    status.className = "vb-fetch-10-status";

    if (type === "success") {
      status.classList.add("is-success");
    }

    if (type === "error") {
      status.classList.add("is-error");
    }

    status.textContent = text;
  }

  function renderResults(posts) {
    if (!posts.length) {
      results.innerHTML = "";
      setStatus("No matching posts found. Try another keyword.", "error");
      return;
    }

    results.innerHTML = posts.map(function (post) {
      return (
        '&lt;article class="vb-fetch-10-result-card"&gt;' +
          '&lt;span&gt;Post #' + post.id + '&lt;/span&gt;' +
          '&lt;h4&gt;' + post.title + '&lt;/h4&gt;' +
          '&lt;p&gt;' + post.body + '&lt;/p&gt;' +
        '&lt;/article&gt;'
      );
    }).join("");

    setStatus("Found " + posts.length + " matching API results.", "success");
  }

  async function searchApi() {
    const keyword = input.value.trim().toLowerCase();

    if (!keyword) {
      results.innerHTML = "";
      setStatus("Please enter a search keyword.", "error");
      return;
    }

    const params = new URLSearchParams({
      _limit: "20"
    });

    button.disabled = true;
    results.innerHTML = "";
    setStatus("Searching API for “" + keyword + "”...", "");

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts?" + params.toString());

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const posts = await response.json();
      const filtered = posts.filter(function (post) {
        return post.title.toLowerCase().includes(keyword) || post.body.toLowerCase().includes(keyword);
      });

      renderResults(filtered.slice(0, 6));
    } catch (error) {
      results.innerHTML = "";
      setStatus("Search request failed: " + error.message, "error");
    } finally {
      button.disabled = false;
    }
  }

  button.addEventListener("click", searchApi);

  input.addEventListener("keydown", function (event) {
    if (event.key === "Enter") {
      searchApi();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-10-demo"&gt;
  &lt;div class="vb-fetch-10-shell"&gt;
    &lt;div class="vb-fetch-10-header"&gt;
      &lt;span&gt;Example 10&lt;/span&gt;
      &lt;h3&gt;Fetch API Search Request&lt;/h3&gt;
      &lt;p&gt;Search API data with a keyword, build query parameters, and render matching results.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-10-search"&gt;
      &lt;label&gt;
        Search posts
        &lt;input type="search" value="qui" placeholder="Try: qui, sunt, autem" data-vb-fetch-10-input&gt;
      &lt;/label&gt;
      &lt;button type="button" data-vb-fetch-10-button&gt;Search API&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-10-status" data-vb-fetch-10-status&gt;
      Enter a keyword and click “Search API”.
    &lt;/div&gt;

    &lt;div class="vb-fetch-10-results" data-vb-fetch-10-results&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-10-demo,
.vb-fetch-10-demo * {
  box-sizing: border-box;
}

.vb-fetch-10-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(14, 165, 233, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  overflow: hidden;
}

.vb-fetch-10-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-10-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #075985 0%, #0284c7 52%, #16a34a 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-10-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-10-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-10-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-10-search {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 14px;
  align-items: end;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
  min-width: 0;
}

.vb-fetch-10-search label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #075985 !important;
  -webkit-text-fill-color: #075985 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-10-search input {
  width: 100%;
  min-width: 0;
  min-height: 52px;
  padding: 0 16px;
  border: 1px solid #bae6fd;
  border-radius: 18px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-fetch-10-search button {
  min-height: 52px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #0284c7, #16a34a);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(14, 165, 233, 0.22);
}

.vb-fetch-10-search button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-10-status {
  margin: 16px clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #f0f9ff;
  border: 1px solid #bae6fd;
  color: #075985 !important;
  -webkit-text-fill-color: #075985 !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-10-status.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-10-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-10-results {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-10-result-card {
  min-width: 0;
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(14, 165, 233, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-fetch-10-result-card span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-10-result-card h4 {
  margin: 0 0 9px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 19px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-10-result-card p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 760px) {
  .vb-fetch-10-search,
  .vb-fetch-10-results {
    grid-template-columns: 1fr;
  }

  .vb-fetch-10-search button {
    width: 100%;
  }
}

@media (max-width: 640px) {
  .vb-fetch-10-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API search request example is useful for blog search, product search, user directories, documentation search, support center search, dashboard filtering, and API-powered result pages.</p>




<h2 class="wp-block-heading">11. Fetch API Live Search with Debounce</h2>



<p class="wp-block-paragraph"><strong>A Fetch API live search with debounce</strong> prevents too many API requests while the user is typing. Instead of sending a request on every keypress, JavaScript waits until the user stops typing for a short moment.</p>



<p class="wp-block-paragraph">This example uses a debounce function, automatic search, minimum keyword length, loading state, request cancellation with <code>AbortController</code>, and dynamic result rendering. It is a useful pattern for autocomplete search, product search, dashboard search, and API search forms.</p>



<ul class="wp-block-list">
<li>Fetch API live search example</li>
<li>Debounce function to reduce requests</li>
<li>Abort previous request when a new search starts</li>
<li>Minimum query length validation</li>
<li>Dynamic API results while typing</li>
</ul>



<div class="vb-fetch-11-demo">
  <div class="vb-fetch-11-layout">
    <div class="vb-fetch-11-copy">
      <span>Example 11</span>
      <h3>Live Search with Debounce</h3>
      <p>Type a keyword and let JavaScript wait before sending a Fetch API search request.</p>
    </div>

    <div class="vb-fetch-11-app">
      <label>
        Live search posts
        <input type="search" value="" placeholder="Type at least 3 characters..." data-vb-fetch-11-input>
      </label>

      <div class="vb-fetch-11-meta" data-vb-fetch-11-meta>
        Waiting for input.
      </div>

      <div class="vb-fetch-11-results" data-vb-fetch-11-results>
        <div class="vb-fetch-11-empty">Start typing to search API data.</div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-fetch-11-demo,
.vb-fetch-11-demo * {
  box-sizing: border-box;
}

.vb-fetch-11-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(168, 85, 247, 0.17), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(6, 182, 212, 0.17), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #ecfeff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.16);
  overflow: hidden;
}

.vb-fetch-11-layout {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
  min-width: 0;
}

.vb-fetch-11-copy {
  min-width: 0;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #581c87 0%, #9333ea 52%, #0891b2 100%) !important;
  box-shadow: 0 30px 90px rgba(147, 51, 234, 0.20);
}

.vb-fetch-11-copy span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #f3e8ff !important;
  -webkit-text-fill-color: #f3e8ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-11-copy h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-11-copy p {
  margin: 0 !important;
  color: #cffafe !important;
  -webkit-text-fill-color: #cffafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-11-app {
  display: grid;
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-fetch-11-app label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #6b21a8 !important;
  -webkit-text-fill-color: #6b21a8 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-11-app input {
  width: 100%;
  min-width: 0;
  min-height: 54px;
  padding: 0 16px;
  border: 1px solid #e9d5ff;
  border-radius: 18px;
  background: #faf5ff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-fetch-11-meta {
  min-width: 0;
  padding: 13px 15px;
  border-radius: 16px;
  background: #f5f3ff;
  border: 1px solid #ddd6fe;
  color: #5b21b6 !important;
  -webkit-text-fill-color: #5b21b6 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-11-meta.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-11-meta.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-11-results {
  display: grid;
  gap: 10px;
  min-width: 0;
  max-height: 360px;
  overflow: auto;
  padding: 4px;
}

.vb-fetch-11-item,
.vb-fetch-11-empty {
  min-width: 0;
  padding: 16px;
  border-radius: 18px;
  background:
    radial-gradient(circle at 14% 12%, rgba(168, 85, 247, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-fetch-11-item strong {
  display: block;
  margin-bottom: 5px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  line-height: 1.3;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-fetch-11-item span,
.vb-fetch-11-empty {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 700;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-fetch-11-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-fetch-11-copy h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-11-demo");
  if (!demo) return;

  const input = demo.querySelector("[data-vb-fetch-11-input]");
  const meta = demo.querySelector("[data-vb-fetch-11-meta]");
  const results = demo.querySelector("[data-vb-fetch-11-results]");

  let debounceTimer = null;
  let controller = null;

  function setMeta(text, type) {
    meta.className = "vb-fetch-11-meta";

    if (type === "success") {
      meta.classList.add("is-success");
    }

    if (type === "error") {
      meta.classList.add("is-error");
    }

    meta.textContent = text;
  }

  function renderItems(items) {
    if (!items.length) {
      results.innerHTML = '<div class="vb-fetch-11-empty">No results found.</div>';
      setMeta("No matching results.", "error");
      return;
    }

    results.innerHTML = items.map(function (item) {
      return (
        '<div class="vb-fetch-11-item">' +
          '<strong>' + item.title + '</strong>' +
          '<span>Post ID #' + item.id + '</span>' +
        '</div>'
      );
    }).join("");

    setMeta("Showing " + items.length + " debounced API results.", "success");
  }

  async function runLiveSearch(query) {
    if (controller) {
      controller.abort();
    }

    controller = new AbortController();

    setMeta("Searching API for “" + query + "”...", "");
    results.innerHTML = '<div class="vb-fetch-11-empty">Loading results...</div>';

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts?_limit=30", {
        signal: controller.signal
      });

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const posts = await response.json();
      const filtered = posts.filter(function (post) {
        return post.title.toLowerCase().includes(query) || post.body.toLowerCase().includes(query);
      }).slice(0, 7);

      renderItems(filtered);
    } catch (error) {
      if (error.name === "AbortError") {
        return;
      }

      results.innerHTML = '<div class="vb-fetch-11-empty">Request failed.</div>';
      setMeta("Live search failed: " + error.message, "error");
    }
  }

  input.addEventListener("input", function () {
    const query = input.value.trim().toLowerCase();

    clearTimeout(debounceTimer);

    if (query.length < 3) {
      if (controller) {
        controller.abort();
      }

      results.innerHTML = '<div class="vb-fetch-11-empty">Type at least 3 characters to search.</div>';
      setMeta("Waiting for at least 3 characters.", "");
      return;
    }

    setMeta("Typing detected. Waiting 500ms before request...", "");

    debounceTimer = setTimeout(function () {
      runLiveSearch(query);
    }, 500);
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-11-demo");
  if (!demo) return;

  const input = demo.querySelector("[data-vb-fetch-11-input]");
  const meta = demo.querySelector("[data-vb-fetch-11-meta]");
  const results = demo.querySelector("[data-vb-fetch-11-results]");

  let debounceTimer = null;
  let controller = null;

  function setMeta(text, type) {
    meta.className = "vb-fetch-11-meta";

    if (type === "success") {
      meta.classList.add("is-success");
    }

    if (type === "error") {
      meta.classList.add("is-error");
    }

    meta.textContent = text;
  }

  function renderItems(items) {
    if (!items.length) {
      results.innerHTML = '&lt;div class="vb-fetch-11-empty"&gt;No results found.&lt;/div&gt;';
      setMeta("No matching results.", "error");
      return;
    }

    results.innerHTML = items.map(function (item) {
      return (
        '&lt;div class="vb-fetch-11-item"&gt;' +
          '&lt;strong&gt;' + item.title + '&lt;/strong&gt;' +
          '&lt;span&gt;Post ID #' + item.id + '&lt;/span&gt;' +
        '&lt;/div&gt;'
      );
    }).join("");

    setMeta("Showing " + items.length + " debounced API results.", "success");
  }

  async function runLiveSearch(query) {
    if (controller) {
      controller.abort();
    }

    controller = new AbortController();

    setMeta("Searching API for “" + query + "”...", "");
    results.innerHTML = '&lt;div class="vb-fetch-11-empty"&gt;Loading results...&lt;/div&gt;';

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts?_limit=30", {
        signal: controller.signal
      });

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const posts = await response.json();
      const filtered = posts.filter(function (post) {
        return post.title.toLowerCase().includes(query) || post.body.toLowerCase().includes(query);
      }).slice(0, 7);

      renderItems(filtered);
    } catch (error) {
      if (error.name === "AbortError") {
        return;
      }

      results.innerHTML = '&lt;div class="vb-fetch-11-empty"&gt;Request failed.&lt;/div&gt;';
      setMeta("Live search failed: " + error.message, "error");
    }
  }

  input.addEventListener("input", function () {
    const query = input.value.trim().toLowerCase();

    clearTimeout(debounceTimer);

    if (query.length &lt; 3) {
      if (controller) {
        controller.abort();
      }

      results.innerHTML = '&lt;div class="vb-fetch-11-empty"&gt;Type at least 3 characters to search.&lt;/div&gt;';
      setMeta("Waiting for at least 3 characters.", "");
      return;
    }

    setMeta("Typing detected. Waiting 500ms before request...", "");

    debounceTimer = setTimeout(function () {
      runLiveSearch(query);
    }, 500);
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-11-demo"&gt;
  &lt;div class="vb-fetch-11-layout"&gt;
    &lt;div class="vb-fetch-11-copy"&gt;
      &lt;span&gt;Example 11&lt;/span&gt;
      &lt;h3&gt;Live Search with Debounce&lt;/h3&gt;
      &lt;p&gt;Type a keyword and let JavaScript wait before sending a Fetch API search request.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-11-app"&gt;
      &lt;label&gt;
        Live search posts
        &lt;input type="search" value="" placeholder="Type at least 3 characters..." data-vb-fetch-11-input&gt;
      &lt;/label&gt;

      &lt;div class="vb-fetch-11-meta" data-vb-fetch-11-meta&gt;
        Waiting for input.
      &lt;/div&gt;

      &lt;div class="vb-fetch-11-results" data-vb-fetch-11-results&gt;
        &lt;div class="vb-fetch-11-empty"&gt;Start typing to search API data.&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-11-demo,
.vb-fetch-11-demo * {
  box-sizing: border-box;
}

.vb-fetch-11-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(168, 85, 247, 0.17), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(6, 182, 212, 0.17), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #ecfeff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.16);
  overflow: hidden;
}

.vb-fetch-11-layout {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
  min-width: 0;
}

.vb-fetch-11-copy {
  min-width: 0;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #581c87 0%, #9333ea 52%, #0891b2 100%) !important;
  box-shadow: 0 30px 90px rgba(147, 51, 234, 0.20);
}

.vb-fetch-11-copy span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #f3e8ff !important;
  -webkit-text-fill-color: #f3e8ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-11-copy h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-11-copy p {
  margin: 0 !important;
  color: #cffafe !important;
  -webkit-text-fill-color: #cffafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-11-app {
  display: grid;
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-fetch-11-app label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #6b21a8 !important;
  -webkit-text-fill-color: #6b21a8 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-11-app input {
  width: 100%;
  min-width: 0;
  min-height: 54px;
  padding: 0 16px;
  border: 1px solid #e9d5ff;
  border-radius: 18px;
  background: #faf5ff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-fetch-11-meta {
  min-width: 0;
  padding: 13px 15px;
  border-radius: 16px;
  background: #f5f3ff;
  border: 1px solid #ddd6fe;
  color: #5b21b6 !important;
  -webkit-text-fill-color: #5b21b6 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-11-meta.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-11-meta.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-11-results {
  display: grid;
  gap: 10px;
  min-width: 0;
  max-height: 360px;
  overflow: auto;
  padding: 4px;
}

.vb-fetch-11-item,
.vb-fetch-11-empty {
  min-width: 0;
  padding: 16px;
  border-radius: 18px;
  background:
    radial-gradient(circle at 14% 12%, rgba(168, 85, 247, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-fetch-11-item strong {
  display: block;
  margin-bottom: 5px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  line-height: 1.3;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-fetch-11-item span,
.vb-fetch-11-empty {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 700;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-fetch-11-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-fetch-11-copy h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API live search with debounce example is useful for autocomplete interfaces, product search, dashboard search, documentation search, support center search, and API-powered instant search fields.</p>




<h2 class="wp-block-heading">12. Fetch API Pagination Example</h2>



<p class="wp-block-paragraph"><strong>Fetch API pagination</strong> is used when an API returns data in pages instead of loading everything at once. This is important for blogs, products, orders, comments, users, tickets, dashboards, and any large dataset.</p>



<p class="wp-block-paragraph">This example uses page state, previous and next buttons, query parameters, loading state, disabled button logic, and API result rendering. It loads different result pages with <code>_page</code> and <code>_limit</code> query parameters.</p>



<ul class="wp-block-list">
<li>Fetch API pagination example</li>
<li>Previous and next buttons</li>
<li>Page state management</li>
<li>Query parameters with page and limit</li>
<li>Useful for large API result lists</li>
</ul>



<div class="vb-fetch-12-demo">
  <div class="vb-fetch-12-shell">
    <div class="vb-fetch-12-header">
      <span>Example 12</span>
      <h3>Fetch API Pagination</h3>
      <p>Load paginated API results with previous and next buttons using query parameters.</p>
    </div>

    <div class="vb-fetch-12-controls">
      <button type="button" data-vb-fetch-12-prev>Previous</button>
      <div data-vb-fetch-12-page>Page 1</div>
      <button type="button" data-vb-fetch-12-next>Next</button>
    </div>

    <div class="vb-fetch-12-status" data-vb-fetch-12-status>
      Loading first page&#8230;
    </div>

    <div class="vb-fetch-12-list" data-vb-fetch-12-list></div>
  </div>
</div>

<style>
.vb-fetch-12-demo,
.vb-fetch-12-demo * {
  box-sizing: border-box;
}

.vb-fetch-12-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(245, 158, 11, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(37, 99, 235, 0.16), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #eff6ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(245, 158, 11, 0.16);
  overflow: hidden;
}

.vb-fetch-12-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-12-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #78350f 0%, #f59e0b 52%, #2563eb 100%) !important;
}

.vb-fetch-12-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-12-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-12-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-12-controls {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
  min-width: 0;
}

.vb-fetch-12-controls button {
  min-height: 48px;
  padding: 0 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #f59e0b, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(245, 158, 11, 0.20);
}

.vb-fetch-12-controls button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.vb-fetch-12-controls div {
  min-width: 0;
  min-height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 16px;
  border-radius: 999px;
  background: #fffbeb;
  border: 1px solid #fde68a;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-fetch-12-status {
  margin: 16px clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #fffbeb;
  border: 1px solid #fde68a;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-12-status.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-12-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-12-list {
  display: grid;
  gap: 12px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-12-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 14px;
  align-items: start;
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 12% 12%, rgba(245, 158, 11, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-fetch-12-row span {
  display: flex;
  width: 42px;
  height: 42px;
  align-items: center;
  justify-content: center;
  border-radius: 15px;
  background: linear-gradient(135deg, #f59e0b, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-fetch-12-row strong {
  display: block;
  margin-bottom: 5px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 17px;
  line-height: 1.3;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-fetch-12-row p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 640px) {
  .vb-fetch-12-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-12-controls {
    grid-template-columns: 1fr;
  }

  .vb-fetch-12-controls button,
  .vb-fetch-12-controls div {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-12-demo");
  if (!demo) return;

  const prevButton = demo.querySelector("[data-vb-fetch-12-prev]");
  const nextButton = demo.querySelector("[data-vb-fetch-12-next]");
  const pageLabel = demo.querySelector("[data-vb-fetch-12-page]");
  const status = demo.querySelector("[data-vb-fetch-12-status]");
  const list = demo.querySelector("[data-vb-fetch-12-list]");

  let currentPage = 1;
  const limit = 4;
  const maxPage = 5;

  function setStatus(text, type) {
    status.className = "vb-fetch-12-status";

    if (type === "success") {
      status.classList.add("is-success");
    }

    if (type === "error") {
      status.classList.add("is-error");
    }

    status.textContent = text;
  }

  function updateButtons() {
    prevButton.disabled = currentPage <= 1;
    nextButton.disabled = currentPage >= maxPage;
    pageLabel.textContent = "Page " + currentPage + " of " + maxPage;
  }

  function renderPage(posts) {
    list.innerHTML = posts.map(function (post) {
      return (
        '<article class="vb-fetch-12-row">' +
          '<span>' + post.id + '</span>' +
          '<div>' +
            '<strong>' + post.title + '</strong>' +
            '<p>' + post.body + '</p>' +
          '</div>' +
        '</article>'
      );
    }).join("");
  }

  async function loadPage() {
    updateButtons();
    list.innerHTML = "";
    setStatus("Loading page " + currentPage + "...", "");

    const params = new URLSearchParams({
      _page: String(currentPage),
      _limit: String(limit)
    });

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts?" + params.toString());

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const posts = await response.json();

      renderPage(posts);
      setStatus("Loaded " + posts.length + " records for page " + currentPage + ".", "success");
    } catch (error) {
      list.innerHTML = "";
      setStatus("Pagination request failed: " + error.message, "error");
    }

    updateButtons();
  }

  prevButton.addEventListener("click", function () {
    if (currentPage > 1) {
      currentPage -= 1;
      loadPage();
    }
  });

  nextButton.addEventListener("click", function () {
    if (currentPage < maxPage) {
      currentPage += 1;
      loadPage();
    }
  });

  loadPage();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-12-demo");
  if (!demo) return;

  const prevButton = demo.querySelector("[data-vb-fetch-12-prev]");
  const nextButton = demo.querySelector("[data-vb-fetch-12-next]");
  const pageLabel = demo.querySelector("[data-vb-fetch-12-page]");
  const status = demo.querySelector("[data-vb-fetch-12-status]");
  const list = demo.querySelector("[data-vb-fetch-12-list]");

  let currentPage = 1;
  const limit = 4;
  const maxPage = 5;

  function setStatus(text, type) {
    status.className = "vb-fetch-12-status";

    if (type === "success") {
      status.classList.add("is-success");
    }

    if (type === "error") {
      status.classList.add("is-error");
    }

    status.textContent = text;
  }

  function updateButtons() {
    prevButton.disabled = currentPage &lt;= 1;
    nextButton.disabled = currentPage &gt;= maxPage;
    pageLabel.textContent = "Page " + currentPage + " of " + maxPage;
  }

  function renderPage(posts) {
    list.innerHTML = posts.map(function (post) {
      return (
        '&lt;article class="vb-fetch-12-row"&gt;' +
          '&lt;span&gt;' + post.id + '&lt;/span&gt;' +
          '&lt;div&gt;' +
            '&lt;strong&gt;' + post.title + '&lt;/strong&gt;' +
            '&lt;p&gt;' + post.body + '&lt;/p&gt;' +
          '&lt;/div&gt;' +
        '&lt;/article&gt;'
      );
    }).join("");
  }

  async function loadPage() {
    updateButtons();
    list.innerHTML = "";
    setStatus("Loading page " + currentPage + "...", "");

    const params = new URLSearchParams({
      _page: String(currentPage),
      _limit: String(limit)
    });

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts?" + params.toString());

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const posts = await response.json();

      renderPage(posts);
      setStatus("Loaded " + posts.length + " records for page " + currentPage + ".", "success");
    } catch (error) {
      list.innerHTML = "";
      setStatus("Pagination request failed: " + error.message, "error");
    }

    updateButtons();
  }

  prevButton.addEventListener("click", function () {
    if (currentPage &gt; 1) {
      currentPage -= 1;
      loadPage();
    }
  });

  nextButton.addEventListener("click", function () {
    if (currentPage &lt; maxPage) {
      currentPage += 1;
      loadPage();
    }
  });

  loadPage();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-12-demo"&gt;
  &lt;div class="vb-fetch-12-shell"&gt;
    &lt;div class="vb-fetch-12-header"&gt;
      &lt;span&gt;Example 12&lt;/span&gt;
      &lt;h3&gt;Fetch API Pagination&lt;/h3&gt;
      &lt;p&gt;Load paginated API results with previous and next buttons using query parameters.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-12-controls"&gt;
      &lt;button type="button" data-vb-fetch-12-prev&gt;Previous&lt;/button&gt;
      &lt;div data-vb-fetch-12-page&gt;Page 1&lt;/div&gt;
      &lt;button type="button" data-vb-fetch-12-next&gt;Next&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-12-status" data-vb-fetch-12-status&gt;
      Loading first page...
    &lt;/div&gt;

    &lt;div class="vb-fetch-12-list" data-vb-fetch-12-list&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-12-demo,
.vb-fetch-12-demo * {
  box-sizing: border-box;
}

.vb-fetch-12-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(245, 158, 11, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(37, 99, 235, 0.16), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #eff6ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(245, 158, 11, 0.16);
  overflow: hidden;
}

.vb-fetch-12-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-12-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #78350f 0%, #f59e0b 52%, #2563eb 100%) !important;
}

.vb-fetch-12-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-12-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-12-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-12-controls {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 12px;
  align-items: center;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
  min-width: 0;
}

.vb-fetch-12-controls button {
  min-height: 48px;
  padding: 0 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #f59e0b, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(245, 158, 11, 0.20);
}

.vb-fetch-12-controls button:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.vb-fetch-12-controls div {
  min-width: 0;
  min-height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 0 16px;
  border-radius: 999px;
  background: #fffbeb;
  border: 1px solid #fde68a;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-fetch-12-status {
  margin: 16px clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #fffbeb;
  border: 1px solid #fde68a;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-12-status.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-12-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-12-list {
  display: grid;
  gap: 12px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-12-row {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 14px;
  align-items: start;
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 12% 12%, rgba(245, 158, 11, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-fetch-12-row span {
  display: flex;
  width: 42px;
  height: 42px;
  align-items: center;
  justify-content: center;
  border-radius: 15px;
  background: linear-gradient(135deg, #f59e0b, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-fetch-12-row strong {
  display: block;
  margin-bottom: 5px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 17px;
  line-height: 1.3;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-fetch-12-row p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 640px) {
  .vb-fetch-12-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-12-controls {
    grid-template-columns: 1fr;
  }

  .vb-fetch-12-controls button,
  .vb-fetch-12-controls div {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API pagination example is useful for blog lists, product catalogs, order tables, user directories, comment systems, dashboard records, support tickets, and API result pages with many records.</p>



<h2 class="wp-block-heading">13. Fetch API Load More Button</h2>



<p class="wp-block-paragraph"><strong>A Fetch API load more button</strong> is useful when you want to load API results in smaller batches instead of showing everything at once. This pattern is common in blog feeds, product lists, portfolios, comments, dashboards, user lists, and search results.</p>



<p class="wp-block-paragraph">This example keeps track of the current page, requests the next batch with query parameters, appends new results to the existing list, disables the button while loading, and hides the button when there are no more demo pages.</p>



<ul class="wp-block-list">
<li>Fetch API load more button</li>
<li>Append new API results to existing content</li>
<li>Page state and limit state</li>
<li>Loading and end state handling</li>
<li>Useful for feeds and product lists</li>
</ul>



<div class="vb-fetch-13-demo">
  <div class="vb-fetch-13-shell">
    <div class="vb-fetch-13-header">
      <span>Example 13</span>
      <h3>Fetch API Load More Button</h3>
      <p>Load the next batch of API records and append them to the existing list.</p>
    </div>

    <div class="vb-fetch-13-status" data-vb-fetch-13-status>
      Click “Load More” to request the first batch.
    </div>

    <div class="vb-fetch-13-grid" data-vb-fetch-13-grid></div>

    <div class="vb-fetch-13-footer">
      <button type="button" data-vb-fetch-13-load>Load More</button>
    </div>
  </div>
</div>

<style>
.vb-fetch-13-demo,
.vb-fetch-13-demo * {
  box-sizing: border-box;
}

.vb-fetch-13-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 197, 94, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(245, 158, 11, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #fffbeb 54%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.18);
  overflow: hidden;
}

.vb-fetch-13-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-13-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #14532d 0%, #16a34a 52%, #f59e0b 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-13-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-13-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-13-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-13-status {
  margin: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #f0fdf4;
  border: 1px solid #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-13-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-13-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-13-card {
  min-width: 0;
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(34, 197, 94, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-fetch-13-card span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-13-card h4 {
  margin: 0 0 9px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.28 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-13-card p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-13-footer {
  display: flex;
  justify-content: center;
  padding: 0 clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px);
}

.vb-fetch-13-footer button {
  min-height: 52px;
  padding: 0 26px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #16a34a, #f59e0b);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(34, 197, 94, 0.22);
}

.vb-fetch-13-footer button:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

@media (max-width: 980px) {
  .vb-fetch-13-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-fetch-13-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-13-grid {
    grid-template-columns: 1fr;
  }

  .vb-fetch-13-footer button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-13-demo");
  if (!demo) return;

  const status = demo.querySelector("[data-vb-fetch-13-status]");
  const grid = demo.querySelector("[data-vb-fetch-13-grid]");
  const button = demo.querySelector("[data-vb-fetch-13-load]");

  let page = 0;
  const limit = 3;
  const maxPage = 4;

  function renderCards(posts) {
    const markup = posts.map(function (post) {
      return (
        '<article class="vb-fetch-13-card">' +
          '<span>Post #' + post.id + '</span>' +
          '<h4>' + post.title + '</h4>' +
          '<p>' + post.body + '</p>' +
        '</article>'
      );
    }).join("");

    grid.insertAdjacentHTML("beforeend", markup);
  }

  async function loadMore() {
    if (page >= maxPage) return;

    page += 1;
    button.disabled = true;
    button.textContent = "Loading...";
    status.className = "vb-fetch-13-status";
    status.textContent = "Loading batch " + page + " from the API...";

    const params = new URLSearchParams({
      _page: String(page),
      _limit: String(limit)
    });

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts?" + params.toString());

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const posts = await response.json();
      renderCards(posts);

      status.textContent = "Batch " + page + " loaded. Total visible cards: " + grid.children.length + ".";

      if (page >= maxPage) {
        button.textContent = "No More Results";
        button.disabled = true;
      } else {
        button.textContent = "Load More";
        button.disabled = false;
      }
    } catch (error) {
      page -= 1;
      status.className = "vb-fetch-13-status is-error";
      status.textContent = "Load more request failed: " + error.message;
      button.textContent = "Try Again";
      button.disabled = false;
    }
  }

  button.addEventListener("click", loadMore);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-13-demo");
  if (!demo) return;

  const status = demo.querySelector("[data-vb-fetch-13-status]");
  const grid = demo.querySelector("[data-vb-fetch-13-grid]");
  const button = demo.querySelector("[data-vb-fetch-13-load]");

  let page = 0;
  const limit = 3;
  const maxPage = 4;

  function renderCards(posts) {
    const markup = posts.map(function (post) {
      return (
        '&lt;article class="vb-fetch-13-card"&gt;' +
          '&lt;span&gt;Post #' + post.id + '&lt;/span&gt;' +
          '&lt;h4&gt;' + post.title + '&lt;/h4&gt;' +
          '&lt;p&gt;' + post.body + '&lt;/p&gt;' +
        '&lt;/article&gt;'
      );
    }).join("");

    grid.insertAdjacentHTML("beforeend", markup);
  }

  async function loadMore() {
    if (page &gt;= maxPage) return;

    page += 1;
    button.disabled = true;
    button.textContent = "Loading...";
    status.className = "vb-fetch-13-status";
    status.textContent = "Loading batch " + page + " from the API...";

    const params = new URLSearchParams({
      _page: String(page),
      _limit: String(limit)
    });

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts?" + params.toString());

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const posts = await response.json();
      renderCards(posts);

      status.textContent = "Batch " + page + " loaded. Total visible cards: " + grid.children.length + ".";

      if (page &gt;= maxPage) {
        button.textContent = "No More Results";
        button.disabled = true;
      } else {
        button.textContent = "Load More";
        button.disabled = false;
      }
    } catch (error) {
      page -= 1;
      status.className = "vb-fetch-13-status is-error";
      status.textContent = "Load more request failed: " + error.message;
      button.textContent = "Try Again";
      button.disabled = false;
    }
  }

  button.addEventListener("click", loadMore);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-13-demo"&gt;
  &lt;div class="vb-fetch-13-shell"&gt;
    &lt;div class="vb-fetch-13-header"&gt;
      &lt;span&gt;Example 13&lt;/span&gt;
      &lt;h3&gt;Fetch API Load More Button&lt;/h3&gt;
      &lt;p&gt;Load the next batch of API records and append them to the existing list.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-13-status" data-vb-fetch-13-status&gt;
      Click “Load More” to request the first batch.
    &lt;/div&gt;

    &lt;div class="vb-fetch-13-grid" data-vb-fetch-13-grid&gt;&lt;/div&gt;

    &lt;div class="vb-fetch-13-footer"&gt;
      &lt;button type="button" data-vb-fetch-13-load&gt;Load More&lt;/button&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-13-demo,
.vb-fetch-13-demo * {
  box-sizing: border-box;
}

.vb-fetch-13-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 197, 94, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(245, 158, 11, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #fffbeb 54%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.18);
  overflow: hidden;
}

.vb-fetch-13-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-13-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #14532d 0%, #16a34a 52%, #f59e0b 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-13-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-13-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-13-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-13-status {
  margin: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #f0fdf4;
  border: 1px solid #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-13-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-13-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-13-card {
  min-width: 0;
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(34, 197, 94, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-fetch-13-card span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-13-card h4 {
  margin: 0 0 9px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.28 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-13-card p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-13-footer {
  display: flex;
  justify-content: center;
  padding: 0 clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px);
}

.vb-fetch-13-footer button {
  min-height: 52px;
  padding: 0 26px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #16a34a, #f59e0b);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(34, 197, 94, 0.22);
}

.vb-fetch-13-footer button:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

@media (max-width: 980px) {
  .vb-fetch-13-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-fetch-13-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-13-grid {
    grid-template-columns: 1fr;
  }

  .vb-fetch-13-footer button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API load more button example is useful for blog feeds, product lists, portfolio grids, comment sections, user directories, dashboard records, and API-powered result pages.</p>




<h2 class="wp-block-heading">14. Fetch API Infinite Scroll</h2>



<p class="wp-block-paragraph"><strong>Fetch API infinite scroll</strong> loads more data automatically when the user reaches the bottom of a list. This pattern is common in social feeds, product feeds, article lists, image feeds, dashboards, and mobile-first browsing experiences.</p>



<p class="wp-block-paragraph">This example uses <code>IntersectionObserver</code> to watch a sentinel element. When the sentinel becomes visible, JavaScript requests the next API page and appends new items to the feed.</p>



<ul class="wp-block-list">
<li>Fetch API infinite scroll example</li>
<li>IntersectionObserver sentinel</li>
<li>Automatic next page loading</li>
<li>Append API data to feed</li>
<li>Loading and finished states</li>
</ul>



<div class="vb-fetch-14-demo">
  <div class="vb-fetch-14-shell">
    <div class="vb-fetch-14-header">
      <span>Example 14</span>
      <h3>Fetch API Infinite Scroll</h3>
      <p>Automatically load more API data when the scroll sentinel becomes visible.</p>
    </div>

    <div class="vb-fetch-14-feed" data-vb-fetch-14-feed></div>

    <div class="vb-fetch-14-sentinel" data-vb-fetch-14-sentinel>
      Scroll here to load more API items...
    </div>
  </div>
</div>

<style>
.vb-fetch-14-demo,
.vb-fetch-14-demo * {
  box-sizing: border-box;
}

.vb-fetch-14-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(99, 102, 241, 0.17), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(236, 72, 153, 0.14), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #fdf2f8 54%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.16);
  overflow: hidden;
}

.vb-fetch-14-shell {
  max-width: 1120px;
  max-height: 720px;
  margin: 0 auto;
  overflow: auto;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-14-header {
  position: sticky;
  top: 0;
  z-index: 2;
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #312e81 0%, #6366f1 52%, #db2777 100%) !important;
}

.vb-fetch-14-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-14-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 60px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-14-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-14-feed {
  display: grid;
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-14-item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 14px;
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 12% 12%, rgba(99, 102, 241, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-fetch-14-number {
  display: flex;
  width: 46px;
  height: 46px;
  align-items: center;
  justify-content: center;
  border-radius: 16px;
  background: linear-gradient(135deg, #6366f1, #db2777);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-fetch-14-item strong {
  display: block;
  margin-bottom: 6px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 17px;
  line-height: 1.3;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-fetch-14-item p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-14-sentinel {
  margin: 0 clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px);
  min-height: 58px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 18px;
  background: #eef2ff;
  border: 1px dashed #a5b4fc;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 900;
  text-align: center;
}

.vb-fetch-14-sentinel.is-done {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-14-sentinel.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

@media (max-width: 640px) {
  .vb-fetch-14-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-14-item {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-14-demo");
  if (!demo) return;

  const shell = demo.querySelector(".vb-fetch-14-shell");
  const feed = demo.querySelector("[data-vb-fetch-14-feed]");
  const sentinel = demo.querySelector("[data-vb-fetch-14-sentinel]");

  let page = 0;
  const limit = 4;
  const maxPage = 4;
  let loading = false;

  function renderItems(items) {
    const html = items.map(function (item) {
      return (
        '<article class="vb-fetch-14-item">' +
          '<div class="vb-fetch-14-number">' + item.id + '</div>' +
          '<div>' +
            '<strong>' + item.title + '</strong>' +
            '<p>' + item.body + '</p>' +
          '</div>' +
        '</article>'
      );
    }).join("");

    feed.insertAdjacentHTML("beforeend", html);
  }

  async function loadNextPage() {
    if (loading || page >= maxPage) return;

    loading = true;
    page += 1;
    sentinel.className = "vb-fetch-14-sentinel";
    sentinel.textContent = "Loading page " + page + "...";

    const params = new URLSearchParams({
      _page: String(page),
      _limit: String(limit)
    });

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts?" + params.toString());

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const items = await response.json();
      renderItems(items);

      if (page >= maxPage) {
        sentinel.className = "vb-fetch-14-sentinel is-done";
        sentinel.textContent = "All demo pages loaded.";
        observer.disconnect();
      } else {
        sentinel.textContent = "Scroll here to load more API items...";
      }
    } catch (error) {
      page -= 1;
      sentinel.className = "vb-fetch-14-sentinel is-error";
      sentinel.textContent = "Infinite scroll request failed: " + error.message;
    } finally {
      loading = false;
    }
  }

  const observer = new IntersectionObserver(function (entries) {
    if (entries[0].isIntersecting) {
      loadNextPage();
    }
  }, {
    root: shell,
    threshold: 0.6
  });

  observer.observe(sentinel);
  loadNextPage();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-14-demo");
  if (!demo) return;

  const shell = demo.querySelector(".vb-fetch-14-shell");
  const feed = demo.querySelector("[data-vb-fetch-14-feed]");
  const sentinel = demo.querySelector("[data-vb-fetch-14-sentinel]");

  let page = 0;
  const limit = 4;
  const maxPage = 4;
  let loading = false;

  function renderItems(items) {
    const html = items.map(function (item) {
      return (
        '&lt;article class="vb-fetch-14-item"&gt;' +
          '&lt;div class="vb-fetch-14-number"&gt;' + item.id + '&lt;/div&gt;' +
          '&lt;div&gt;' +
            '&lt;strong&gt;' + item.title + '&lt;/strong&gt;' +
            '&lt;p&gt;' + item.body + '&lt;/p&gt;' +
          '&lt;/div&gt;' +
        '&lt;/article&gt;'
      );
    }).join("");

    feed.insertAdjacentHTML("beforeend", html);
  }

  async function loadNextPage() {
    if (loading || page &gt;= maxPage) return;

    loading = true;
    page += 1;
    sentinel.className = "vb-fetch-14-sentinel";
    sentinel.textContent = "Loading page " + page + "...";

    const params = new URLSearchParams({
      _page: String(page),
      _limit: String(limit)
    });

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts?" + params.toString());

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const items = await response.json();
      renderItems(items);

      if (page &gt;= maxPage) {
        sentinel.className = "vb-fetch-14-sentinel is-done";
        sentinel.textContent = "All demo pages loaded.";
        observer.disconnect();
      } else {
        sentinel.textContent = "Scroll here to load more API items...";
      }
    } catch (error) {
      page -= 1;
      sentinel.className = "vb-fetch-14-sentinel is-error";
      sentinel.textContent = "Infinite scroll request failed: " + error.message;
    } finally {
      loading = false;
    }
  }

  const observer = new IntersectionObserver(function (entries) {
    if (entries[0].isIntersecting) {
      loadNextPage();
    }
  }, {
    root: shell,
    threshold: 0.6
  });

  observer.observe(sentinel);
  loadNextPage();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-14-demo"&gt;
  &lt;div class="vb-fetch-14-shell"&gt;
    &lt;div class="vb-fetch-14-header"&gt;
      &lt;span&gt;Example 14&lt;/span&gt;
      &lt;h3&gt;Fetch API Infinite Scroll&lt;/h3&gt;
      &lt;p&gt;Automatically load more API data when the scroll sentinel becomes visible.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-14-feed" data-vb-fetch-14-feed&gt;&lt;/div&gt;

    &lt;div class="vb-fetch-14-sentinel" data-vb-fetch-14-sentinel&gt;
      Scroll here to load more API items...
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-14-demo,
.vb-fetch-14-demo * {
  box-sizing: border-box;
}

.vb-fetch-14-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(99, 102, 241, 0.17), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(236, 72, 153, 0.14), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #fdf2f8 54%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.16);
  overflow: hidden;
}

.vb-fetch-14-shell {
  max-width: 1120px;
  max-height: 720px;
  margin: 0 auto;
  overflow: auto;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-14-header {
  position: sticky;
  top: 0;
  z-index: 2;
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #312e81 0%, #6366f1 52%, #db2777 100%) !important;
}

.vb-fetch-14-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-14-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 60px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-14-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-14-feed {
  display: grid;
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-14-item {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 14px;
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 12% 12%, rgba(99, 102, 241, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-fetch-14-number {
  display: flex;
  width: 46px;
  height: 46px;
  align-items: center;
  justify-content: center;
  border-radius: 16px;
  background: linear-gradient(135deg, #6366f1, #db2777);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-fetch-14-item strong {
  display: block;
  margin-bottom: 6px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 17px;
  line-height: 1.3;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-fetch-14-item p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-14-sentinel {
  margin: 0 clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px);
  min-height: 58px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 18px;
  background: #eef2ff;
  border: 1px dashed #a5b4fc;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 900;
  text-align: center;
}

.vb-fetch-14-sentinel.is-done {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-14-sentinel.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

@media (max-width: 640px) {
  .vb-fetch-14-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-14-item {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API infinite scroll example is useful for social feeds, product feeds, blog lists, dashboard activity feeds, image feeds, mobile browsing interfaces, and API-powered content streams.</p>




<h2 class="wp-block-heading">15. Fetch API Filter Dropdown</h2>



<p class="wp-block-paragraph"><strong>A Fetch API filter dropdown</strong> lets users change the API request based on a selected option. This pattern is useful for product categories, post types, user roles, order status, task status, support tickets, locations, and dashboard filters.</p>



<p class="wp-block-paragraph">This example uses a dropdown to choose a user ID, builds query parameters with <code>URLSearchParams</code>, sends a Fetch API request, and renders only the records that match the selected filter.</p>



<ul class="wp-block-list">
<li>Fetch API filter dropdown example</li>
<li>Dropdown changes API query parameters</li>
<li>Filter by selected value</li>
<li>Loading and error states</li>
<li>Useful for dashboards and product filters</li>
</ul>



<div class="vb-fetch-15-demo">
  <div class="vb-fetch-15-shell">
    <div class="vb-fetch-15-header">
      <span>Example 15</span>
      <h3>Fetch API Filter Dropdown</h3>
      <p>Select a filter option and load matching API records with query parameters.</p>
    </div>

    <div class="vb-fetch-15-filter">
      <label>
        Filter posts by user
        <select data-vb-fetch-15-select>
          <option value="1">User 1</option>
          <option value="2">User 2</option>
          <option value="3">User 3</option>
          <option value="4">User 4</option>
        </select>
      </label>
    </div>

    <div class="vb-fetch-15-status" data-vb-fetch-15-status>
      Loading filtered results...
    </div>

    <div class="vb-fetch-15-grid" data-vb-fetch-15-grid></div>
  </div>
</div>

<style>
.vb-fetch-15-demo,
.vb-fetch-15-demo * {
  box-sizing: border-box;
}

.vb-fetch-15-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(20, 184, 166, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdfa 0%, #eff6ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.16);
  overflow: hidden;
}

.vb-fetch-15-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-15-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #115e59 0%, #14b8a6 52%, #2563eb 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-15-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-15-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-15-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-15-filter {
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
}

.vb-fetch-15-filter label {
  display: grid;
  max-width: 420px;
  gap: 8px;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-15-filter select {
  width: 100%;
  min-height: 52px;
  padding: 0 16px;
  border: 1px solid #99f6e4;
  border-radius: 18px;
  background: #f0fdfa;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 850;
  outline: none;
}

.vb-fetch-15-status {
  margin: 16px clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #f0fdfa;
  border: 1px solid #99f6e4;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-15-status.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-15-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-15-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-15-card {
  min-width: 0;
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(20, 184, 166, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-fetch-15-card span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-15-card h4 {
  margin: 0 0 9px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 19px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-15-card p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 760px) {
  .vb-fetch-15-grid {
    grid-template-columns: 1fr;
  }

  .vb-fetch-15-filter label {
    max-width: 100%;
  }
}

@media (max-width: 640px) {
  .vb-fetch-15-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-15-demo");
  if (!demo) return;

  const select = demo.querySelector("[data-vb-fetch-15-select]");
  const status = demo.querySelector("[data-vb-fetch-15-status]");
  const grid = demo.querySelector("[data-vb-fetch-15-grid]");

  function setStatus(text, type) {
    status.className = "vb-fetch-15-status";

    if (type === "success") {
      status.classList.add("is-success");
    }

    if (type === "error") {
      status.classList.add("is-error");
    }

    status.textContent = text;
  }

  function renderCards(posts) {
    grid.innerHTML = posts.map(function (post) {
      return (
        '<article class="vb-fetch-15-card">' +
          '<span>User #' + post.userId + ' · Post #' + post.id + '</span>' +
          '<h4>' + post.title + '</h4>' +
          '<p>' + post.body + '</p>' +
        '</article>'
      );
    }).join("");
  }

  async function loadFilteredPosts() {
    const userId = select.value;

    grid.innerHTML = "";
    setStatus("Loading posts for user #" + userId + "...", "");

    const params = new URLSearchParams({
      userId: userId,
      _limit: "6"
    });

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts?" + params.toString());

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const posts = await response.json();

      renderCards(posts);
      setStatus("Loaded " + posts.length + " filtered posts for user #" + userId + ".", "success");
    } catch (error) {
      grid.innerHTML = "";
      setStatus("Filter request failed: " + error.message, "error");
    }
  }

  select.addEventListener("change", loadFilteredPosts);
  loadFilteredPosts();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-15-demo");
  if (!demo) return;

  const select = demo.querySelector("[data-vb-fetch-15-select]");
  const status = demo.querySelector("[data-vb-fetch-15-status]");
  const grid = demo.querySelector("[data-vb-fetch-15-grid]");

  function setStatus(text, type) {
    status.className = "vb-fetch-15-status";

    if (type === "success") {
      status.classList.add("is-success");
    }

    if (type === "error") {
      status.classList.add("is-error");
    }

    status.textContent = text;
  }

  function renderCards(posts) {
    grid.innerHTML = posts.map(function (post) {
      return (
        '&lt;article class="vb-fetch-15-card"&gt;' +
          '&lt;span&gt;User #' + post.userId + ' · Post #' + post.id + '&lt;/span&gt;' +
          '&lt;h4&gt;' + post.title + '&lt;/h4&gt;' +
          '&lt;p&gt;' + post.body + '&lt;/p&gt;' +
        '&lt;/article&gt;'
      );
    }).join("");
  }

  async function loadFilteredPosts() {
    const userId = select.value;

    grid.innerHTML = "";
    setStatus("Loading posts for user #" + userId + "...", "");

    const params = new URLSearchParams({
      userId: userId,
      _limit: "6"
    });

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts?" + params.toString());

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const posts = await response.json();

      renderCards(posts);
      setStatus("Loaded " + posts.length + " filtered posts for user #" + userId + ".", "success");
    } catch (error) {
      grid.innerHTML = "";
      setStatus("Filter request failed: " + error.message, "error");
    }
  }

  select.addEventListener("change", loadFilteredPosts);
  loadFilteredPosts();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-15-demo"&gt;
  &lt;div class="vb-fetch-15-shell"&gt;
    &lt;div class="vb-fetch-15-header"&gt;
      &lt;span&gt;Example 15&lt;/span&gt;
      &lt;h3&gt;Fetch API Filter Dropdown&lt;/h3&gt;
      &lt;p&gt;Select a filter option and load matching API records with query parameters.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-15-filter"&gt;
      &lt;label&gt;
        Filter posts by user
        &lt;select data-vb-fetch-15-select&gt;
          &lt;option value="1"&gt;User 1&lt;/option&gt;
          &lt;option value="2"&gt;User 2&lt;/option&gt;
          &lt;option value="3"&gt;User 3&lt;/option&gt;
          &lt;option value="4"&gt;User 4&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-15-status" data-vb-fetch-15-status&gt;
      Loading filtered results...
    &lt;/div&gt;

    &lt;div class="vb-fetch-15-grid" data-vb-fetch-15-grid&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-15-demo,
.vb-fetch-15-demo * {
  box-sizing: border-box;
}

.vb-fetch-15-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(20, 184, 166, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdfa 0%, #eff6ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.16);
  overflow: hidden;
}

.vb-fetch-15-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-15-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #115e59 0%, #14b8a6 52%, #2563eb 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-15-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-15-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-15-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-15-filter {
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
}

.vb-fetch-15-filter label {
  display: grid;
  max-width: 420px;
  gap: 8px;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-15-filter select {
  width: 100%;
  min-height: 52px;
  padding: 0 16px;
  border: 1px solid #99f6e4;
  border-radius: 18px;
  background: #f0fdfa;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 850;
  outline: none;
}

.vb-fetch-15-status {
  margin: 16px clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #f0fdfa;
  border: 1px solid #99f6e4;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-15-status.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-15-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-15-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-15-card {
  min-width: 0;
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(20, 184, 166, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-fetch-15-card span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-15-card h4 {
  margin: 0 0 9px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 19px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-15-card p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 760px) {
  .vb-fetch-15-grid {
    grid-template-columns: 1fr;
  }

  .vb-fetch-15-filter label {
    max-width: 100%;
  }
}

@media (max-width: 640px) {
  .vb-fetch-15-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API filter dropdown example is useful for product categories, user roles, order statuses, support tickets, dashboard records, task filters, location filters, and API-powered admin screens.</p>



<h2 class="wp-block-heading">16. Fetch API with Query Parameters</h2>



<p class="wp-block-paragraph"><strong>Fetch API query parameters</strong> are used when you need to send options through the URL, such as search keywords, page numbers, result limits, categories, sorting values, filters, or user IDs. The cleanest way to build these URLs in JavaScript is with <code>URLSearchParams</code>.</p>



<p class="wp-block-paragraph">This example lets users choose a user ID and result limit. JavaScript builds the API URL with <code>URLSearchParams</code>, sends the Fetch API request, shows the final generated URL, and renders the matching records.</p>



<ul class="wp-block-list">
<li>Fetch API query parameters example</li>
<li>Build URL parameters with <code>URLSearchParams</code></li>
<li>Filter by user ID and limit</li>
<li>Show generated API URL</li>
<li>Useful for search, filters, sorting, and pagination</li>
</ul>



<div class="vb-fetch-16-demo">
  <div class="vb-fetch-16-shell">
    <div class="vb-fetch-16-header">
      <span>Example 16</span>
      <h3>Fetch API with Query Parameters</h3>
      <p>Build a dynamic API URL with URLSearchParams and load filtered results.</p>
    </div>

    <div class="vb-fetch-16-controls">
      <label>
        User ID
        <select data-vb-fetch-16-user>
          <option value="1">User 1</option>
          <option value="2">User 2</option>
          <option value="3">User 3</option>
          <option value="4">User 4</option>
        </select>
      </label>

      <label>
        Result limit
        <select data-vb-fetch-16-limit>
          <option value="3">3 results</option>
          <option value="5" selected>5 results</option>
          <option value="8">8 results</option>
        </select>
      </label>

      <button type="button" data-vb-fetch-16-load>Load Results</button>
    </div>

    <div class="vb-fetch-16-url" data-vb-fetch-16-url>
      Generated URL will appear here.
    </div>

    <div class="vb-fetch-16-status" data-vb-fetch-16-status>
      Choose parameters and load API data.
    </div>

    <div class="vb-fetch-16-grid" data-vb-fetch-16-grid></div>
  </div>
</div>

<style>
.vb-fetch-16-demo,
.vb-fetch-16-demo * {
  box-sizing: border-box;
}

.vb-fetch-16-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(37, 99, 235, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(14, 165, 233, 0.17), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfeff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.16);
  overflow: hidden;
}

.vb-fetch-16-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-16-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #1e3a8a 0%, #2563eb 52%, #0891b2 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-16-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-16-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-16-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #cffafe !important;
  -webkit-text-fill-color: #cffafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-16-controls {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr)) auto;
  gap: 14px;
  align-items: end;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
  min-width: 0;
}

.vb-fetch-16-controls label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-16-controls select {
  width: 100%;
  min-width: 0;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid #bfdbfe;
  border-radius: 18px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 850;
  outline: none;
}

.vb-fetch-16-controls button {
  min-height: 52px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #0891b2);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.24);
}

.vb-fetch-16-controls button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-16-url,
.vb-fetch-16-status {
  margin: 16px clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-16-url {
  background: #0f172a;
  border: 1px solid #1e293b;
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}

.vb-fetch-16-status {
  background: #eff6ff;
  border: 1px solid #bfdbfe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
}

.vb-fetch-16-status.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-16-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-16-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-16-card {
  min-width: 0;
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(37, 99, 235, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-fetch-16-card span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-16-card h4 {
  margin: 0 0 9px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 19px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-16-card p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 820px) {
  .vb-fetch-16-controls,
  .vb-fetch-16-grid {
    grid-template-columns: 1fr;
  }

  .vb-fetch-16-controls button {
    width: 100%;
  }
}

@media (max-width: 640px) {
  .vb-fetch-16-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-16-demo");
  if (!demo) return;

  const userSelect = demo.querySelector("[data-vb-fetch-16-user]");
  const limitSelect = demo.querySelector("[data-vb-fetch-16-limit]");
  const button = demo.querySelector("[data-vb-fetch-16-load]");
  const urlBox = demo.querySelector("[data-vb-fetch-16-url]");
  const status = demo.querySelector("[data-vb-fetch-16-status]");
  const grid = demo.querySelector("[data-vb-fetch-16-grid]");

  function setStatus(text, type) {
    status.className = "vb-fetch-16-status";

    if (type === "success") {
      status.classList.add("is-success");
    }

    if (type === "error") {
      status.classList.add("is-error");
    }

    status.textContent = text;
  }

  function renderPosts(posts) {
    grid.innerHTML = posts.map(function (post) {
      return (
        '<article class="vb-fetch-16-card">' +
          '<span>User #' + post.userId + ' · ID #' + post.id + '</span>' +
          '<h4>' + post.title + '</h4>' +
          '<p>' + post.body + '</p>' +
        '</article>'
      );
    }).join("");
  }

  async function loadWithParams() {
    const params = new URLSearchParams({
      userId: userSelect.value,
      _limit: limitSelect.value
    });

    const url = "https://jsonplaceholder.typicode.com/posts?" + params.toString();

    button.disabled = true;
    urlBox.textContent = url;
    grid.innerHTML = "";
    setStatus("Loading API data with query parameters...", "");

    try {
      const response = await fetch(url);

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const posts = await response.json();

      renderPosts(posts);
      setStatus("Loaded " + posts.length + " records using URLSearchParams.", "success");
    } catch (error) {
      setStatus("Query parameter request failed: " + error.message, "error");
    } finally {
      button.disabled = false;
    }
  }

  button.addEventListener("click", loadWithParams);
  loadWithParams();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-16-demo");
  if (!demo) return;

  const userSelect = demo.querySelector("[data-vb-fetch-16-user]");
  const limitSelect = demo.querySelector("[data-vb-fetch-16-limit]");
  const button = demo.querySelector("[data-vb-fetch-16-load]");
  const urlBox = demo.querySelector("[data-vb-fetch-16-url]");
  const status = demo.querySelector("[data-vb-fetch-16-status]");
  const grid = demo.querySelector("[data-vb-fetch-16-grid]");

  function setStatus(text, type) {
    status.className = "vb-fetch-16-status";

    if (type === "success") {
      status.classList.add("is-success");
    }

    if (type === "error") {
      status.classList.add("is-error");
    }

    status.textContent = text;
  }

  function renderPosts(posts) {
    grid.innerHTML = posts.map(function (post) {
      return (
        '&lt;article class="vb-fetch-16-card"&gt;' +
          '&lt;span&gt;User #' + post.userId + ' · ID #' + post.id + '&lt;/span&gt;' +
          '&lt;h4&gt;' + post.title + '&lt;/h4&gt;' +
          '&lt;p&gt;' + post.body + '&lt;/p&gt;' +
        '&lt;/article&gt;'
      );
    }).join("");
  }

  async function loadWithParams() {
    const params = new URLSearchParams({
      userId: userSelect.value,
      _limit: limitSelect.value
    });

    const url = "https://jsonplaceholder.typicode.com/posts?" + params.toString();

    button.disabled = true;
    urlBox.textContent = url;
    grid.innerHTML = "";
    setStatus("Loading API data with query parameters...", "");

    try {
      const response = await fetch(url);

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const posts = await response.json();

      renderPosts(posts);
      setStatus("Loaded " + posts.length + " records using URLSearchParams.", "success");
    } catch (error) {
      setStatus("Query parameter request failed: " + error.message, "error");
    } finally {
      button.disabled = false;
    }
  }

  button.addEventListener("click", loadWithParams);
  loadWithParams();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-16-demo"&gt;
  &lt;div class="vb-fetch-16-shell"&gt;
    &lt;div class="vb-fetch-16-header"&gt;
      &lt;span&gt;Example 16&lt;/span&gt;
      &lt;h3&gt;Fetch API with Query Parameters&lt;/h3&gt;
      &lt;p&gt;Build a dynamic API URL with URLSearchParams and load filtered results.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-16-controls"&gt;
      &lt;label&gt;
        User ID
        &lt;select data-vb-fetch-16-user&gt;
          &lt;option value="1"&gt;User 1&lt;/option&gt;
          &lt;option value="2"&gt;User 2&lt;/option&gt;
          &lt;option value="3"&gt;User 3&lt;/option&gt;
          &lt;option value="4"&gt;User 4&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;

      &lt;label&gt;
        Result limit
        &lt;select data-vb-fetch-16-limit&gt;
          &lt;option value="3"&gt;3 results&lt;/option&gt;
          &lt;option value="5" selected&gt;5 results&lt;/option&gt;
          &lt;option value="8"&gt;8 results&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;

      &lt;button type="button" data-vb-fetch-16-load&gt;Load Results&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-16-url" data-vb-fetch-16-url&gt;
      Generated URL will appear here.
    &lt;/div&gt;

    &lt;div class="vb-fetch-16-status" data-vb-fetch-16-status&gt;
      Choose parameters and load API data.
    &lt;/div&gt;

    &lt;div class="vb-fetch-16-grid" data-vb-fetch-16-grid&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-16-demo,
.vb-fetch-16-demo * {
  box-sizing: border-box;
}

.vb-fetch-16-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(37, 99, 235, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(14, 165, 233, 0.17), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfeff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.16);
  overflow: hidden;
}

.vb-fetch-16-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-16-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #1e3a8a 0%, #2563eb 52%, #0891b2 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-16-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-16-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-16-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #cffafe !important;
  -webkit-text-fill-color: #cffafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-16-controls {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr)) auto;
  gap: 14px;
  align-items: end;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
  min-width: 0;
}

.vb-fetch-16-controls label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-16-controls select {
  width: 100%;
  min-width: 0;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid #bfdbfe;
  border-radius: 18px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 850;
  outline: none;
}

.vb-fetch-16-controls button {
  min-height: 52px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #0891b2);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.24);
}

.vb-fetch-16-controls button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-16-url,
.vb-fetch-16-status {
  margin: 16px clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-16-url {
  background: #0f172a;
  border: 1px solid #1e293b;
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
}

.vb-fetch-16-status {
  background: #eff6ff;
  border: 1px solid #bfdbfe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
}

.vb-fetch-16-status.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-16-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-16-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-16-card {
  min-width: 0;
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(37, 99, 235, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-fetch-16-card span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-16-card h4 {
  margin: 0 0 9px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 19px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-16-card p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 820px) {
  .vb-fetch-16-controls,
  .vb-fetch-16-grid {
    grid-template-columns: 1fr;
  }

  .vb-fetch-16-controls button {
    width: 100%;
  }
}

@media (max-width: 640px) {
  .vb-fetch-16-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API query parameters example is useful for search pages, product filters, blog archives, dashboards, user directories, order filters, category pages, and paginated API result interfaces.</p>




<h2 class="wp-block-heading">17. Fetch API Weather Card Example</h2>



<p class="wp-block-paragraph"><strong>A Fetch API weather card</strong> shows how API data can be transformed into a user-friendly widget. Many real weather APIs require API keys, so this demo uses a local mock weather API function with the same async Fetch API-style flow.</p>



<p class="wp-block-paragraph">This example focuses on request-like behavior: selecting a city, showing loading state, waiting for async data, handling invalid city values, rendering weather details, and updating the card UI based on the returned response object.</p>



<ul class="wp-block-list">
<li>Fetch-style weather card example</li>
<li>Async API-style data loading</li>
<li>City selection and dynamic UI</li>
<li>Loading, success, and error states</li>
<li>Useful for API widget layouts</li>
</ul>



<div class="vb-fetch-17-demo">
  <div class="vb-fetch-17-shell">
    <div class="vb-fetch-17-header">
      <span>Example 17</span>
      <h3>Fetch API Weather Card</h3>
      <p>Load weather-style API data and render a polished weather dashboard card.</p>
    </div>

    <div class="vb-fetch-17-body">
      <div class="vb-fetch-17-controls">
        <label>
          Choose city
          <select data-vb-fetch-17-city>
            <option value="Tallinn">Tallinn</option>
            <option value="London">London</option>
            <option value="New York">New York</option>
            <option value="Tokyo">Tokyo</option>
          </select>
        </label>

        <button type="button" data-vb-fetch-17-load>Load Weather</button>
      </div>

      <div class="vb-fetch-17-card" data-vb-fetch-17-card>
        <span>Weather API</span>
        <h4>Ready to load</h4>
        <p>Select a city and load weather data.</p>
        <div class="vb-fetch-17-stats">
          <div><strong>--°</strong><small>Temperature</small></div>
          <div><strong>--%</strong><small>Humidity</small></div>
          <div><strong>-- km/h</strong><small>Wind</small></div>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-fetch-17-demo,
.vb-fetch-17-demo * {
  box-sizing: border-box;
}

.vb-fetch-17-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(14, 165, 233, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(234, 179, 8, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #fefce8 54%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.16);
  overflow: hidden;
}

.vb-fetch-17-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-17-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #075985 0%, #0284c7 52%, #eab308 100%) !important;
}

.vb-fetch-17-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-17-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-17-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #fef9c3 !important;
  -webkit-text-fill-color: #fef9c3 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-17-body {
  display: grid;
  grid-template-columns: minmax(260px, 0.8fr) minmax(0, 1.2fr);
  gap: 22px;
  padding: clamp(20px, 4vw, 34px);
  min-width: 0;
}

.vb-fetch-17-controls {
  display: grid;
  align-content: start;
  gap: 14px;
  min-width: 0;
  padding: 20px;
  border-radius: 24px;
  background: #f0f9ff;
  border: 1px solid #bae6fd;
}

.vb-fetch-17-controls label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-17-controls select {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid #bae6fd;
  border-radius: 18px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 850;
  outline: none;
}

.vb-fetch-17-controls button {
  min-height: 52px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #0284c7, #eab308);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(14, 165, 233, 0.22);
}

.vb-fetch-17-controls button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-17-card {
  min-width: 0;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 28px;
  background:
    radial-gradient(circle at 16% 14%, rgba(255,255,255,0.28), transparent 34%),
    linear-gradient(135deg, #0284c7 0%, #06b6d4 50%, #facc15 100%) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 24px 70px rgba(14, 165, 233, 0.22);
}

.vb-fetch-17-card.is-error {
  background: linear-gradient(135deg, #991b1b, #ef4444) !important;
}

.vb-fetch-17-card span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.18);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.vb-fetch-17-card h4 {
  margin: 0 0 10px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
  overflow-wrap: anywhere;
}

.vb-fetch-17-card p {
  margin: 0 0 22px !important;
  color: #f8fafc !important;
  -webkit-text-fill-color: #f8fafc !important;
  font-size: 16px;
  line-height: 1.6;
  font-weight: 750;
  overflow-wrap: anywhere;
}

.vb-fetch-17-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-fetch-17-stats div {
  min-width: 0;
  padding: 16px;
  border-radius: 20px;
  background: rgba(255,255,255,0.18);
  border: 1px solid rgba(255,255,255,0.20);
  backdrop-filter: blur(10px);
}

.vb-fetch-17-stats strong {
  display: block;
  margin-bottom: 5px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 26px;
  line-height: 1;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-fetch-17-stats small {
  display: block;
  color: #f8fafc !important;
  -webkit-text-fill-color: #f8fafc !important;
  font-size: 12px;
  line-height: 1.3;
  font-weight: 800;
}

@media (max-width: 840px) {
  .vb-fetch-17-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-fetch-17-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-17-stats {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-17-demo");
  if (!demo) return;

  const citySelect = demo.querySelector("[data-vb-fetch-17-city]");
  const button = demo.querySelector("[data-vb-fetch-17-load]");
  const card = demo.querySelector("[data-vb-fetch-17-card]");

  const weatherData = {
    Tallinn: { temp: 18, humidity: 61, wind: 14, condition: "Cloudy with light wind" },
    London: { temp: 16, humidity: 72, wind: 18, condition: "Light rain expected" },
    "New York": { temp: 24, humidity: 58, wind: 11, condition: "Bright and partly sunny" },
    Tokyo: { temp: 28, humidity: 66, wind: 9, condition: "Warm evening weather" }
  };

  function fakeWeatherFetch(city) {
    return new Promise(function (resolve, reject) {
      setTimeout(function () {
        if (!weatherData[city]) {
          reject(new Error("City not found"));
          return;
        }

        resolve({
          ok: true,
          json: function () {
            return Promise.resolve({
              city: city,
              current: weatherData[city]
            });
          }
        });
      }, 850);
    });
  }

  function renderWeather(data) {
    const weather = data.current;

    card.className = "vb-fetch-17-card";
    card.innerHTML =
      '<span>Weather API</span>' +
      '<h4>' + data.city + '</h4>' +
      '<p>' + weather.condition + '</p>' +
      '<div class="vb-fetch-17-stats">' +
        '<div><strong>' + weather.temp + '°C</strong><small>Temperature</small></div>' +
        '<div><strong>' + weather.humidity + '%</strong><small>Humidity</small></div>' +
        '<div><strong>' + weather.wind + ' km/h</strong><small>Wind</small></div>' +
      '</div>';
  }

  async function loadWeather() {
    const city = citySelect.value;

    button.disabled = true;
    button.textContent = "Loading...";

    card.className = "vb-fetch-17-card";
    card.innerHTML =
      '<span>Loading</span>' +
      '<h4>' + city + '</h4>' +
      '<p>Requesting weather-style API data...</p>' +
      '<div class="vb-fetch-17-stats">' +
        '<div><strong>--°</strong><small>Temperature</small></div>' +
        '<div><strong>--%</strong><small>Humidity</small></div>' +
        '<div><strong>-- km/h</strong><small>Wind</small></div>' +
      '</div>';

    try {
      const response = await fakeWeatherFetch(city);

      if (!response.ok) {
        throw new Error("Weather API request failed");
      }

      const data = await response.json();
      renderWeather(data);
    } catch (error) {
      card.className = "vb-fetch-17-card is-error";
      card.innerHTML =
        '<span>Error</span>' +
        '<h4>Weather unavailable</h4>' +
        '<p>' + error.message + '</p>' +
        '<div class="vb-fetch-17-stats">' +
          '<div><strong>--</strong><small>No data</small></div>' +
          '<div><strong>--</strong><small>No data</small></div>' +
          '<div><strong>--</strong><small>No data</small></div>' +
        '</div>';
    } finally {
      button.disabled = false;
      button.textContent = "Load Weather";
    }
  }

  button.addEventListener("click", loadWeather);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-17-demo");
  if (!demo) return;

  const citySelect = demo.querySelector("[data-vb-fetch-17-city]");
  const button = demo.querySelector("[data-vb-fetch-17-load]");
  const card = demo.querySelector("[data-vb-fetch-17-card]");

  const weatherData = {
    Tallinn: { temp: 18, humidity: 61, wind: 14, condition: "Cloudy with light wind" },
    London: { temp: 16, humidity: 72, wind: 18, condition: "Light rain expected" },
    "New York": { temp: 24, humidity: 58, wind: 11, condition: "Bright and partly sunny" },
    Tokyo: { temp: 28, humidity: 66, wind: 9, condition: "Warm evening weather" }
  };

  function fakeWeatherFetch(city) {
    return new Promise(function (resolve, reject) {
      setTimeout(function () {
        if (!weatherData[city]) {
          reject(new Error("City not found"));
          return;
        }

        resolve({
          ok: true,
          json: function () {
            return Promise.resolve({
              city: city,
              current: weatherData[city]
            });
          }
        });
      }, 850);
    });
  }

  function renderWeather(data) {
    const weather = data.current;

    card.className = "vb-fetch-17-card";
    card.innerHTML =
      '&lt;span&gt;Weather API&lt;/span&gt;' +
      '&lt;h4&gt;' + data.city + '&lt;/h4&gt;' +
      '&lt;p&gt;' + weather.condition + '&lt;/p&gt;' +
      '&lt;div class="vb-fetch-17-stats"&gt;' +
        '&lt;div&gt;&lt;strong&gt;' + weather.temp + '°C&lt;/strong&gt;&lt;small&gt;Temperature&lt;/small&gt;&lt;/div&gt;' +
        '&lt;div&gt;&lt;strong&gt;' + weather.humidity + '%&lt;/strong&gt;&lt;small&gt;Humidity&lt;/small&gt;&lt;/div&gt;' +
        '&lt;div&gt;&lt;strong&gt;' + weather.wind + ' km/h&lt;/strong&gt;&lt;small&gt;Wind&lt;/small&gt;&lt;/div&gt;' +
      '&lt;/div&gt;';
  }

  async function loadWeather() {
    const city = citySelect.value;

    button.disabled = true;
    button.textContent = "Loading...";

    card.className = "vb-fetch-17-card";
    card.innerHTML =
      '&lt;span&gt;Loading&lt;/span&gt;' +
      '&lt;h4&gt;' + city + '&lt;/h4&gt;' +
      '&lt;p&gt;Requesting weather-style API data...&lt;/p&gt;' +
      '&lt;div class="vb-fetch-17-stats"&gt;' +
        '&lt;div&gt;&lt;strong&gt;--°&lt;/strong&gt;&lt;small&gt;Temperature&lt;/small&gt;&lt;/div&gt;' +
        '&lt;div&gt;&lt;strong&gt;--%&lt;/strong&gt;&lt;small&gt;Humidity&lt;/small&gt;&lt;/div&gt;' +
        '&lt;div&gt;&lt;strong&gt;-- km/h&lt;/strong&gt;&lt;small&gt;Wind&lt;/small&gt;&lt;/div&gt;' +
      '&lt;/div&gt;';

    try {
      const response = await fakeWeatherFetch(city);

      if (!response.ok) {
        throw new Error("Weather API request failed");
      }

      const data = await response.json();
      renderWeather(data);
    } catch (error) {
      card.className = "vb-fetch-17-card is-error";
      card.innerHTML =
        '&lt;span&gt;Error&lt;/span&gt;' +
        '&lt;h4&gt;Weather unavailable&lt;/h4&gt;' +
        '&lt;p&gt;' + error.message + '&lt;/p&gt;' +
        '&lt;div class="vb-fetch-17-stats"&gt;' +
          '&lt;div&gt;&lt;strong&gt;--&lt;/strong&gt;&lt;small&gt;No data&lt;/small&gt;&lt;/div&gt;' +
          '&lt;div&gt;&lt;strong&gt;--&lt;/strong&gt;&lt;small&gt;No data&lt;/small&gt;&lt;/div&gt;' +
          '&lt;div&gt;&lt;strong&gt;--&lt;/strong&gt;&lt;small&gt;No data&lt;/small&gt;&lt;/div&gt;' +
        '&lt;/div&gt;';
    } finally {
      button.disabled = false;
      button.textContent = "Load Weather";
    }
  }

  button.addEventListener("click", loadWeather);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-17-demo"&gt;
  &lt;div class="vb-fetch-17-shell"&gt;
    &lt;div class="vb-fetch-17-header"&gt;
      &lt;span&gt;Example 17&lt;/span&gt;
      &lt;h3&gt;Fetch API Weather Card&lt;/h3&gt;
      &lt;p&gt;Load weather-style API data and render a polished weather dashboard card.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-17-body"&gt;
      &lt;div class="vb-fetch-17-controls"&gt;
        &lt;label&gt;
          Choose city
          &lt;select data-vb-fetch-17-city&gt;
            &lt;option value="Tallinn"&gt;Tallinn&lt;/option&gt;
            &lt;option value="London"&gt;London&lt;/option&gt;
            &lt;option value="New York"&gt;New York&lt;/option&gt;
            &lt;option value="Tokyo"&gt;Tokyo&lt;/option&gt;
          &lt;/select&gt;
        &lt;/label&gt;

        &lt;button type="button" data-vb-fetch-17-load&gt;Load Weather&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-fetch-17-card" data-vb-fetch-17-card&gt;
        &lt;span&gt;Weather API&lt;/span&gt;
        &lt;h4&gt;Ready to load&lt;/h4&gt;
        &lt;p&gt;Select a city and load weather data.&lt;/p&gt;
        &lt;div class="vb-fetch-17-stats"&gt;
          &lt;div&gt;&lt;strong&gt;--°&lt;/strong&gt;&lt;small&gt;Temperature&lt;/small&gt;&lt;/div&gt;
          &lt;div&gt;&lt;strong&gt;--%&lt;/strong&gt;&lt;small&gt;Humidity&lt;/small&gt;&lt;/div&gt;
          &lt;div&gt;&lt;strong&gt;-- km/h&lt;/strong&gt;&lt;small&gt;Wind&lt;/small&gt;&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-17-demo,
.vb-fetch-17-demo * {
  box-sizing: border-box;
}

.vb-fetch-17-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(14, 165, 233, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(234, 179, 8, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #fefce8 54%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.16);
  overflow: hidden;
}

.vb-fetch-17-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-17-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #075985 0%, #0284c7 52%, #eab308 100%) !important;
}

.vb-fetch-17-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-17-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-17-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #fef9c3 !important;
  -webkit-text-fill-color: #fef9c3 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-17-body {
  display: grid;
  grid-template-columns: minmax(260px, 0.8fr) minmax(0, 1.2fr);
  gap: 22px;
  padding: clamp(20px, 4vw, 34px);
  min-width: 0;
}

.vb-fetch-17-controls {
  display: grid;
  align-content: start;
  gap: 14px;
  min-width: 0;
  padding: 20px;
  border-radius: 24px;
  background: #f0f9ff;
  border: 1px solid #bae6fd;
}

.vb-fetch-17-controls label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-17-controls select {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid #bae6fd;
  border-radius: 18px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 850;
  outline: none;
}

.vb-fetch-17-controls button {
  min-height: 52px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #0284c7, #eab308);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(14, 165, 233, 0.22);
}

.vb-fetch-17-controls button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-17-card {
  min-width: 0;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 28px;
  background:
    radial-gradient(circle at 16% 14%, rgba(255,255,255,0.28), transparent 34%),
    linear-gradient(135deg, #0284c7 0%, #06b6d4 50%, #facc15 100%) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 24px 70px rgba(14, 165, 233, 0.22);
}

.vb-fetch-17-card.is-error {
  background: linear-gradient(135deg, #991b1b, #ef4444) !important;
}

.vb-fetch-17-card span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.18);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.09em;
  text-transform: uppercase;
}

.vb-fetch-17-card h4 {
  margin: 0 0 10px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
  overflow-wrap: anywhere;
}

.vb-fetch-17-card p {
  margin: 0 0 22px !important;
  color: #f8fafc !important;
  -webkit-text-fill-color: #f8fafc !important;
  font-size: 16px;
  line-height: 1.6;
  font-weight: 750;
  overflow-wrap: anywhere;
}

.vb-fetch-17-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-fetch-17-stats div {
  min-width: 0;
  padding: 16px;
  border-radius: 20px;
  background: rgba(255,255,255,0.18);
  border: 1px solid rgba(255,255,255,0.20);
  backdrop-filter: blur(10px);
}

.vb-fetch-17-stats strong {
  display: block;
  margin-bottom: 5px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 26px;
  line-height: 1;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-fetch-17-stats small {
  display: block;
  color: #f8fafc !important;
  -webkit-text-fill-color: #f8fafc !important;
  font-size: 12px;
  line-height: 1.3;
  font-weight: 800;
}

@media (max-width: 840px) {
  .vb-fetch-17-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-fetch-17-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-17-stats {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This weather card example is useful for API widgets, dashboard cards, weather-style layouts, location widgets, async UI states, and frontend components that need to transform API data into a clean visual card.</p>




<h2 class="wp-block-heading">18. Fetch API Product List Example</h2>



<p class="wp-block-paragraph"><strong>A Fetch API product list</strong> is a practical pattern for ecommerce interfaces, product catalogs, price lists, dashboards, inventory tools, and API-powered landing pages. JavaScript loads product data, renders product cards, and shows useful product details in the UI.</p>



<p class="wp-block-paragraph">This example uses a local mock product API with the same async structure as a real Fetch API request. It includes loading state, product cards, category labels, price formatting with <code>Intl.NumberFormat</code>, and a refresh button.</p>



<ul class="wp-block-list">
<li>Fetch-style product list example</li>
<li>Async product data loading</li>
<li>Render ecommerce product cards</li>
<li>Format prices with <code>Intl.NumberFormat</code></li>
<li>Useful for ecommerce and dashboard UI</li>
</ul>



<div class="vb-fetch-18-demo">
  <div class="vb-fetch-18-shell">
    <div class="vb-fetch-18-header">
      <span>Example 18</span>
      <h3>Fetch API Product List</h3>
      <p>Load product-style API data and render ecommerce cards with formatted prices.</p>
    </div>

    <div class="vb-fetch-18-toolbar">
      <button type="button" data-vb-fetch-18-load>Load Products</button>
      <div data-vb-fetch-18-status>Ready to load product data.</div>
    </div>

    <div class="vb-fetch-18-grid" data-vb-fetch-18-grid></div>
  </div>
</div>

<style>
.vb-fetch-18-demo,
.vb-fetch-18-demo * {
  box-sizing: border-box;
}

.vb-fetch-18-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(236, 72, 153, 0.15), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(236, 72, 153, 0.14);
  overflow: hidden;
}

.vb-fetch-18-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-18-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #831843 0%, #db2777 52%, #16a34a 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-18-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-18-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-18-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-18-toolbar {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 14px;
  align-items: center;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
}

.vb-fetch-18-toolbar button {
  min-height: 52px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #db2777, #16a34a);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(219, 39, 119, 0.20);
}

.vb-fetch-18-toolbar button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-18-toolbar div {
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #fdf2f8;
  border: 1px solid #fbcfe8;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-18-toolbar div.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-18-toolbar div.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-18-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-18-product {
  min-width: 0;
  overflow: hidden;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 44px rgba(15, 23, 42, 0.08);
}

.vb-fetch-18-image {
  min-height: 150px;
  background:
    radial-gradient(circle at 30% 25%, rgba(255,255,255,0.38), transparent 34%),
    linear-gradient(135deg, #db2777, #16a34a) !important;
}

.vb-fetch-18-product-body {
  padding: 18px;
}

.vb-fetch-18-product-body span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-18-product-body h4 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px !important;
  line-height: 1.2 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-18-product-body p {
  margin: 0 0 14px !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-18-price {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.vb-fetch-18-price strong {
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 24px;
  line-height: 1;
  font-weight: 950;
}

.vb-fetch-18-price small {
  color: #16a34a !important;
  -webkit-text-fill-color: #16a34a !important;
  font-size: 12px;
  font-weight: 950;
}

@media (max-width: 980px) {
  .vb-fetch-18-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 720px) {
  .vb-fetch-18-toolbar {
    grid-template-columns: 1fr;
  }

  .vb-fetch-18-toolbar button {
    width: 100%;
  }

  .vb-fetch-18-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-fetch-18-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-18-demo");
  if (!demo) return;

  const button = demo.querySelector("[data-vb-fetch-18-load]");
  const status = demo.querySelector("[data-vb-fetch-18-status]");
  const grid = demo.querySelector("[data-vb-fetch-18-grid]");

  const formatter = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "USD"
  });

  const products = [
    { name: "API Dashboard Kit", category: "SaaS", price: 79, stock: 12, description: "Reusable dashboard UI for API data." },
    { name: "Product Feed Template", category: "Ecommerce", price: 49, stock: 22, description: "Card layout for dynamic product lists." },
    { name: "Search API Module", category: "Tools", price: 39, stock: 8, description: "Frontend search block for API projects." },
    { name: "Admin Panel Starter", category: "Admin", price: 99, stock: 5, description: "Clean admin interface with API states." },
    { name: "Landing API Widget", category: "Marketing", price: 29, stock: 31, description: "Small API-powered widget for landing pages." },
    { name: "Inventory Grid UI", category: "Business", price: 59, stock: 16, description: "Product grid for internal inventory tools." }
  ];

  function fakeProductFetch() {
    return new Promise(function (resolve) {
      setTimeout(function () {
        resolve({
          ok: true,
          json: function () {
            return Promise.resolve(products);
          }
        });
      }, 750);
    });
  }

  function setStatus(text, type) {
    status.className = "";

    if (type === "success") {
      status.classList.add("is-success");
    }

    if (type === "error") {
      status.classList.add("is-error");
    }

    status.textContent = text;
  }

  function renderProducts(items) {
    grid.innerHTML = items.map(function (product, index) {
      return (
        '<article class="vb-fetch-18-product">' +
          '<div class="vb-fetch-18-image"></div>' +
          '<div class="vb-fetch-18-product-body">' +
            '<span>' + product.category + '</span>' +
            '<h4>' + product.name + '</h4>' +
            '<p>' + product.description + '</p>' +
            '<div class="vb-fetch-18-price">' +
              '<strong>' + formatter.format(product.price) + '</strong>' +
              '<small>' + product.stock + ' in stock</small>' +
            '</div>' +
          '</div>' +
        '</article>'
      );
    }).join("");
  }

  async function loadProducts() {
    button.disabled = true;
    button.textContent = "Loading...";
    grid.innerHTML = "";
    setStatus("Loading product API data...", "");

    try {
      const response = await fakeProductFetch();

      if (!response.ok) {
        throw new Error("Product API request failed");
      }

      const data = await response.json();

      renderProducts(data);
      setStatus("Loaded " + data.length + " product cards from async API-style data.", "success");
    } catch (error) {
      grid.innerHTML = "";
      setStatus("Product list failed: " + error.message, "error");
    } finally {
      button.disabled = false;
      button.textContent = "Load Products";
    }
  }

  button.addEventListener("click", loadProducts);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-18-demo");
  if (!demo) return;

  const button = demo.querySelector("[data-vb-fetch-18-load]");
  const status = demo.querySelector("[data-vb-fetch-18-status]");
  const grid = demo.querySelector("[data-vb-fetch-18-grid]");

  const formatter = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "USD"
  });

  const products = [
    { name: "API Dashboard Kit", category: "SaaS", price: 79, stock: 12, description: "Reusable dashboard UI for API data." },
    { name: "Product Feed Template", category: "Ecommerce", price: 49, stock: 22, description: "Card layout for dynamic product lists." },
    { name: "Search API Module", category: "Tools", price: 39, stock: 8, description: "Frontend search block for API projects." },
    { name: "Admin Panel Starter", category: "Admin", price: 99, stock: 5, description: "Clean admin interface with API states." },
    { name: "Landing API Widget", category: "Marketing", price: 29, stock: 31, description: "Small API-powered widget for landing pages." },
    { name: "Inventory Grid UI", category: "Business", price: 59, stock: 16, description: "Product grid for internal inventory tools." }
  ];

  function fakeProductFetch() {
    return new Promise(function (resolve) {
      setTimeout(function () {
        resolve({
          ok: true,
          json: function () {
            return Promise.resolve(products);
          }
        });
      }, 750);
    });
  }

  function setStatus(text, type) {
    status.className = "";

    if (type === "success") {
      status.classList.add("is-success");
    }

    if (type === "error") {
      status.classList.add("is-error");
    }

    status.textContent = text;
  }

  function renderProducts(items) {
    grid.innerHTML = items.map(function (product, index) {
      return (
        '&lt;article class="vb-fetch-18-product"&gt;' +
          '&lt;div class="vb-fetch-18-image"&gt;&lt;/div&gt;' +
          '&lt;div class="vb-fetch-18-product-body"&gt;' +
            '&lt;span&gt;' + product.category + '&lt;/span&gt;' +
            '&lt;h4&gt;' + product.name + '&lt;/h4&gt;' +
            '&lt;p&gt;' + product.description + '&lt;/p&gt;' +
            '&lt;div class="vb-fetch-18-price"&gt;' +
              '&lt;strong&gt;' + formatter.format(product.price) + '&lt;/strong&gt;' +
              '&lt;small&gt;' + product.stock + ' in stock&lt;/small&gt;' +
            '&lt;/div&gt;' +
          '&lt;/div&gt;' +
        '&lt;/article&gt;'
      );
    }).join("");
  }

  async function loadProducts() {
    button.disabled = true;
    button.textContent = "Loading...";
    grid.innerHTML = "";
    setStatus("Loading product API data...", "");

    try {
      const response = await fakeProductFetch();

      if (!response.ok) {
        throw new Error("Product API request failed");
      }

      const data = await response.json();

      renderProducts(data);
      setStatus("Loaded " + data.length + " product cards from async API-style data.", "success");
    } catch (error) {
      grid.innerHTML = "";
      setStatus("Product list failed: " + error.message, "error");
    } finally {
      button.disabled = false;
      button.textContent = "Load Products";
    }
  }

  button.addEventListener("click", loadProducts);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-18-demo"&gt;
  &lt;div class="vb-fetch-18-shell"&gt;
    &lt;div class="vb-fetch-18-header"&gt;
      &lt;span&gt;Example 18&lt;/span&gt;
      &lt;h3&gt;Fetch API Product List&lt;/h3&gt;
      &lt;p&gt;Load product-style API data and render ecommerce cards with formatted prices.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-18-toolbar"&gt;
      &lt;button type="button" data-vb-fetch-18-load&gt;Load Products&lt;/button&gt;
      &lt;div data-vb-fetch-18-status&gt;Ready to load product data.&lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-18-grid" data-vb-fetch-18-grid&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-18-demo,
.vb-fetch-18-demo * {
  box-sizing: border-box;
}

.vb-fetch-18-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(236, 72, 153, 0.15), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(236, 72, 153, 0.14);
  overflow: hidden;
}

.vb-fetch-18-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-18-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #831843 0%, #db2777 52%, #16a34a 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-18-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-18-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-18-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-18-toolbar {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 14px;
  align-items: center;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
}

.vb-fetch-18-toolbar button {
  min-height: 52px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #db2777, #16a34a);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(219, 39, 119, 0.20);
}

.vb-fetch-18-toolbar button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-18-toolbar div {
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #fdf2f8;
  border: 1px solid #fbcfe8;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-18-toolbar div.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-18-toolbar div.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-18-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-18-product {
  min-width: 0;
  overflow: hidden;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 44px rgba(15, 23, 42, 0.08);
}

.vb-fetch-18-image {
  min-height: 150px;
  background:
    radial-gradient(circle at 30% 25%, rgba(255,255,255,0.38), transparent 34%),
    linear-gradient(135deg, #db2777, #16a34a) !important;
}

.vb-fetch-18-product-body {
  padding: 18px;
}

.vb-fetch-18-product-body span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-18-product-body h4 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px !important;
  line-height: 1.2 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-18-product-body p {
  margin: 0 0 14px !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-18-price {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.vb-fetch-18-price strong {
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 24px;
  line-height: 1;
  font-weight: 950;
}

.vb-fetch-18-price small {
  color: #16a34a !important;
  -webkit-text-fill-color: #16a34a !important;
  font-size: 12px;
  font-weight: 950;
}

@media (max-width: 980px) {
  .vb-fetch-18-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 720px) {
  .vb-fetch-18-toolbar {
    grid-template-columns: 1fr;
  }

  .vb-fetch-18-toolbar button {
    width: 100%;
  }

  .vb-fetch-18-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-fetch-18-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API product list example is useful for ecommerce product grids, price lists, inventory dashboards, landing page products, SaaS plan lists, catalog interfaces, and API-powered shop sections.</p>



<h2 class="wp-block-heading">19. Fetch API User Profile Dashboard</h2>



<p class="wp-block-paragraph"><strong>A Fetch API user profile dashboard</strong> is useful when a website or app needs to load account data, profile details, company information, address data, and contact fields from an API. This pattern is common in SaaS dashboards, admin panels, CRM tools, user portals, and account pages.</p>



<p class="wp-block-paragraph">This example loads a user profile from a public JSON API, extracts nested object data, renders a dashboard card, and displays company, email, phone, website, and address information in a clean layout.</p>



<ul class="wp-block-list">
<li>Fetch API user profile request</li>
<li>Render nested API object data</li>
<li>Dashboard-style profile layout</li>
<li>Loading, success, and error states</li>
<li>Useful for account pages and admin panels</li>
</ul>



<div class="vb-fetch-19-demo">
  <div class="vb-fetch-19-shell">
    <div class="vb-fetch-19-header">
      <span>Example 19</span>
      <h3>Fetch API User Profile Dashboard</h3>
      <p>Load a user profile from an API and render nested contact, company, and address data.</p>
    </div>

    <div class="vb-fetch-19-controls">
      <label>
        Choose user
        <select data-vb-fetch-19-user>
          <option value="1">User 1</option>
          <option value="2">User 2</option>
          <option value="3">User 3</option>
          <option value="4">User 4</option>
        </select>
      </label>

      <button type="button" data-vb-fetch-19-load>Load Profile</button>
    </div>

    <div class="vb-fetch-19-status" data-vb-fetch-19-status>
      Choose a user and load profile data.
    </div>

    <div class="vb-fetch-19-profile" data-vb-fetch-19-profile>
      <div class="vb-fetch-19-avatar">API</div>
      <div class="vb-fetch-19-main">
        <span>No profile loaded</span>
        <h4>Waiting for API request</h4>
        <p>The user profile dashboard will appear here.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-fetch-19-demo,
.vb-fetch-19-demo * {
  box-sizing: border-box;
}

.vb-fetch-19-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(79, 70, 229, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #f0f9ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(79, 70, 229, 0.16);
  overflow: hidden;
}

.vb-fetch-19-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-19-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #312e81 0%, #4f46e5 52%, #0284c7 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-19-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-19-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-19-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-19-controls {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 14px;
  align-items: end;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
  min-width: 0;
}

.vb-fetch-19-controls label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-19-controls select {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid #c7d2fe;
  border-radius: 18px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 850;
  outline: none;
}

.vb-fetch-19-controls button {
  min-height: 52px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #4f46e5, #0284c7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(79, 70, 229, 0.22);
}

.vb-fetch-19-controls button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-19-status {
  margin: 16px clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #eef2ff;
  border: 1px solid #c7d2fe;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-19-status.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-19-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-19-profile {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 20px;
  min-width: 0;
  margin: clamp(20px, 4vw, 34px);
  padding: clamp(20px, 4vw, 32px);
  border-radius: 28px;
  background:
    radial-gradient(circle at 14% 12%, rgba(79, 70, 229, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.08);
}

.vb-fetch-19-avatar {
  display: flex;
  width: 86px;
  height: 86px;
  align-items: center;
  justify-content: center;
  border-radius: 28px;
  background: linear-gradient(135deg, #4f46e5, #0284c7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  font-weight: 950;
  letter-spacing: -0.05em;
  box-shadow: 0 18px 42px rgba(79, 70, 229, 0.22);
}

.vb-fetch-19-main {
  min-width: 0;
}

.vb-fetch-19-main > span {
  display: inline-flex;
  margin-bottom: 9px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #e0e7ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-19-main h4 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(28px, 5vw, 48px) !important;
  line-height: 1.02 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
  overflow-wrap: anywhere;
}

.vb-fetch-19-main p {
  margin: 0 0 18px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-19-info-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-fetch-19-info-grid div {
  min-width: 0;
  padding: 14px;
  border-radius: 18px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-fetch-19-info-grid strong {
  display: block;
  margin-bottom: 4px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-fetch-19-info-grid small {
  display: block;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.45;
  font-weight: 700;
  overflow-wrap: anywhere;
}

@media (max-width: 760px) {
  .vb-fetch-19-controls,
  .vb-fetch-19-profile,
  .vb-fetch-19-info-grid {
    grid-template-columns: 1fr;
  }

  .vb-fetch-19-controls button {
    width: 100%;
  }
}

@media (max-width: 640px) {
  .vb-fetch-19-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-19-avatar {
    width: 72px;
    height: 72px;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-19-demo");
  if (!demo) return;

  const userSelect = demo.querySelector("[data-vb-fetch-19-user]");
  const button = demo.querySelector("[data-vb-fetch-19-load]");
  const status = demo.querySelector("[data-vb-fetch-19-status]");
  const profile = demo.querySelector("[data-vb-fetch-19-profile]");

  function setStatus(text, type) {
    status.className = "vb-fetch-19-status";

    if (type === "success") {
      status.classList.add("is-success");
    }

    if (type === "error") {
      status.classList.add("is-error");
    }

    status.textContent = text;
  }

  function getInitials(name) {
    return name.split(" ").map(function (part) {
      return part.charAt(0);
    }).join("").slice(0, 2).toUpperCase();
  }

  function renderProfile(user) {
    profile.innerHTML =
      '<div class="vb-fetch-19-avatar">' + getInitials(user.name) + '</div>' +
      '<div class="vb-fetch-19-main">' +
        '<span>' + user.company.name + '</span>' +
        '<h4>' + user.name + '</h4>' +
        '<p>' + user.company.catchPhrase + '</p>' +
        '<div class="vb-fetch-19-info-grid">' +
          '<div><strong>Email</strong><small>' + user.email + '</small></div>' +
          '<div><strong>Phone</strong><small>' + user.phone + '</small></div>' +
          '<div><strong>Website</strong><small>' + user.website + '</small></div>' +
          '<div><strong>Address</strong><small>' + user.address.street + ', ' + user.address.city + '</small></div>' +
        '</div>' +
      '</div>';
  }

  async function loadProfile() {
    const userId = userSelect.value;

    button.disabled = true;
    setStatus("Loading user profile #" + userId + "...", "");

    profile.innerHTML =
      '<div class="vb-fetch-19-avatar">...</div>' +
      '<div class="vb-fetch-19-main">' +
        '<span>Loading</span>' +
        '<h4>Fetching profile</h4>' +
        '<p>Waiting for API response...</p>' +
      '</div>';

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/users/" + userId);

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const user = await response.json();

      renderProfile(user);
      setStatus("User profile #" + userId + " loaded successfully.", "success");
    } catch (error) {
      setStatus("Profile request failed: " + error.message, "error");
      profile.innerHTML =
        '<div class="vb-fetch-19-avatar">!</div>' +
        '<div class="vb-fetch-19-main">' +
          '<span>Error</span>' +
          '<h4>Profile unavailable</h4>' +
          '<p>The API request failed. Try again later.</p>' +
        '</div>';
    } finally {
      button.disabled = false;
    }
  }

  button.addEventListener("click", loadProfile);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-19-demo");
  if (!demo) return;

  const userSelect = demo.querySelector("[data-vb-fetch-19-user]");
  const button = demo.querySelector("[data-vb-fetch-19-load]");
  const status = demo.querySelector("[data-vb-fetch-19-status]");
  const profile = demo.querySelector("[data-vb-fetch-19-profile]");

  function setStatus(text, type) {
    status.className = "vb-fetch-19-status";

    if (type === "success") {
      status.classList.add("is-success");
    }

    if (type === "error") {
      status.classList.add("is-error");
    }

    status.textContent = text;
  }

  function getInitials(name) {
    return name.split(" ").map(function (part) {
      return part.charAt(0);
    }).join("").slice(0, 2).toUpperCase();
  }

  function renderProfile(user) {
    profile.innerHTML =
      '&lt;div class="vb-fetch-19-avatar"&gt;' + getInitials(user.name) + '&lt;/div&gt;' +
      '&lt;div class="vb-fetch-19-main"&gt;' +
        '&lt;span&gt;' + user.company.name + '&lt;/span&gt;' +
        '&lt;h4&gt;' + user.name + '&lt;/h4&gt;' +
        '&lt;p&gt;' + user.company.catchPhrase + '&lt;/p&gt;' +
        '&lt;div class="vb-fetch-19-info-grid"&gt;' +
          '&lt;div&gt;&lt;strong&gt;Email&lt;/strong&gt;&lt;small&gt;' + user.email + '&lt;/small&gt;&lt;/div&gt;' +
          '&lt;div&gt;&lt;strong&gt;Phone&lt;/strong&gt;&lt;small&gt;' + user.phone + '&lt;/small&gt;&lt;/div&gt;' +
          '&lt;div&gt;&lt;strong&gt;Website&lt;/strong&gt;&lt;small&gt;' + user.website + '&lt;/small&gt;&lt;/div&gt;' +
          '&lt;div&gt;&lt;strong&gt;Address&lt;/strong&gt;&lt;small&gt;' + user.address.street + ', ' + user.address.city + '&lt;/small&gt;&lt;/div&gt;' +
        '&lt;/div&gt;' +
      '&lt;/div&gt;';
  }

  async function loadProfile() {
    const userId = userSelect.value;

    button.disabled = true;
    setStatus("Loading user profile #" + userId + "...", "");

    profile.innerHTML =
      '&lt;div class="vb-fetch-19-avatar"&gt;...&lt;/div&gt;' +
      '&lt;div class="vb-fetch-19-main"&gt;' +
        '&lt;span&gt;Loading&lt;/span&gt;' +
        '&lt;h4&gt;Fetching profile&lt;/h4&gt;' +
        '&lt;p&gt;Waiting for API response...&lt;/p&gt;' +
      '&lt;/div&gt;';

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/users/" + userId);

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const user = await response.json();

      renderProfile(user);
      setStatus("User profile #" + userId + " loaded successfully.", "success");
    } catch (error) {
      setStatus("Profile request failed: " + error.message, "error");
      profile.innerHTML =
        '&lt;div class="vb-fetch-19-avatar"&gt;!&lt;/div&gt;' +
        '&lt;div class="vb-fetch-19-main"&gt;' +
          '&lt;span&gt;Error&lt;/span&gt;' +
          '&lt;h4&gt;Profile unavailable&lt;/h4&gt;' +
          '&lt;p&gt;The API request failed. Try again later.&lt;/p&gt;' +
        '&lt;/div&gt;';
    } finally {
      button.disabled = false;
    }
  }

  button.addEventListener("click", loadProfile);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-19-demo"&gt;
  &lt;div class="vb-fetch-19-shell"&gt;
    &lt;div class="vb-fetch-19-header"&gt;
      &lt;span&gt;Example 19&lt;/span&gt;
      &lt;h3&gt;Fetch API User Profile Dashboard&lt;/h3&gt;
      &lt;p&gt;Load a user profile from an API and render nested contact, company, and address data.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-19-controls"&gt;
      &lt;label&gt;
        Choose user
        &lt;select data-vb-fetch-19-user&gt;
          &lt;option value="1"&gt;User 1&lt;/option&gt;
          &lt;option value="2"&gt;User 2&lt;/option&gt;
          &lt;option value="3"&gt;User 3&lt;/option&gt;
          &lt;option value="4"&gt;User 4&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;

      &lt;button type="button" data-vb-fetch-19-load&gt;Load Profile&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-19-status" data-vb-fetch-19-status&gt;
      Choose a user and load profile data.
    &lt;/div&gt;

    &lt;div class="vb-fetch-19-profile" data-vb-fetch-19-profile&gt;
      &lt;div class="vb-fetch-19-avatar"&gt;API&lt;/div&gt;
      &lt;div class="vb-fetch-19-main"&gt;
        &lt;span&gt;No profile loaded&lt;/span&gt;
        &lt;h4&gt;Waiting for API request&lt;/h4&gt;
        &lt;p&gt;The user profile dashboard will appear here.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-19-demo,
.vb-fetch-19-demo * {
  box-sizing: border-box;
}

.vb-fetch-19-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(79, 70, 229, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #f0f9ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(79, 70, 229, 0.16);
  overflow: hidden;
}

.vb-fetch-19-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-19-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #312e81 0%, #4f46e5 52%, #0284c7 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-19-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-19-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-19-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-19-controls {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 14px;
  align-items: end;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
  min-width: 0;
}

.vb-fetch-19-controls label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-19-controls select {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid #c7d2fe;
  border-radius: 18px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 850;
  outline: none;
}

.vb-fetch-19-controls button {
  min-height: 52px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #4f46e5, #0284c7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(79, 70, 229, 0.22);
}

.vb-fetch-19-controls button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-19-status {
  margin: 16px clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #eef2ff;
  border: 1px solid #c7d2fe;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-19-status.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-19-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-19-profile {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 20px;
  min-width: 0;
  margin: clamp(20px, 4vw, 34px);
  padding: clamp(20px, 4vw, 32px);
  border-radius: 28px;
  background:
    radial-gradient(circle at 14% 12%, rgba(79, 70, 229, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.08);
}

.vb-fetch-19-avatar {
  display: flex;
  width: 86px;
  height: 86px;
  align-items: center;
  justify-content: center;
  border-radius: 28px;
  background: linear-gradient(135deg, #4f46e5, #0284c7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  font-weight: 950;
  letter-spacing: -0.05em;
  box-shadow: 0 18px 42px rgba(79, 70, 229, 0.22);
}

.vb-fetch-19-main {
  min-width: 0;
}

.vb-fetch-19-main &gt; span {
  display: inline-flex;
  margin-bottom: 9px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #e0e7ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-19-main h4 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(28px, 5vw, 48px) !important;
  line-height: 1.02 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
  overflow-wrap: anywhere;
}

.vb-fetch-19-main p {
  margin: 0 0 18px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-19-info-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-fetch-19-info-grid div {
  min-width: 0;
  padding: 14px;
  border-radius: 18px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-fetch-19-info-grid strong {
  display: block;
  margin-bottom: 4px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-fetch-19-info-grid small {
  display: block;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.45;
  font-weight: 700;
  overflow-wrap: anywhere;
}

@media (max-width: 760px) {
  .vb-fetch-19-controls,
  .vb-fetch-19-profile,
  .vb-fetch-19-info-grid {
    grid-template-columns: 1fr;
  }

  .vb-fetch-19-controls button {
    width: 100%;
  }
}

@media (max-width: 640px) {
  .vb-fetch-19-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-19-avatar {
    width: 72px;
    height: 72px;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API user profile dashboard example is useful for SaaS dashboards, CRM tools, profile pages, account areas, admin panels, client portals, and interfaces that display nested API user data.</p>




<h2 class="wp-block-heading">20. Fetch API Comments Loader</h2>



<p class="wp-block-paragraph"><strong>A Fetch API comments loader</strong> is useful when a page needs to load related comments, reviews, replies, notes, or messages after the main content is already visible. This keeps the page lighter and loads secondary data only when needed.</p>



<p class="wp-block-paragraph">This example loads comments for a selected post ID, uses query parameters, renders email and message data, and includes loading, empty, success, and error states.</p>



<ul class="wp-block-list">
<li>Fetch API comments loader</li>
<li>Load related comments by post ID</li>
<li>Render comments after button click</li>
<li>Use query parameters for filtering</li>
<li>Useful for comments, reviews, and message feeds</li>
</ul>



<div class="vb-fetch-20-demo">
  <div class="vb-fetch-20-shell">
    <div class="vb-fetch-20-header">
      <span>Example 20</span>
      <h3>Fetch API Comments Loader</h3>
      <p>Load related comments from an API and render them in a clean discussion layout.</p>
    </div>

    <div class="vb-fetch-20-controls">
      <label>
        Post ID
        <select data-vb-fetch-20-post>
          <option value="1">Post 1</option>
          <option value="2">Post 2</option>
          <option value="3">Post 3</option>
        </select>
      </label>

      <button type="button" data-vb-fetch-20-load>Load Comments</button>
    </div>

    <div class="vb-fetch-20-status" data-vb-fetch-20-status>
      Select a post and load related comments.
    </div>

    <div class="vb-fetch-20-list" data-vb-fetch-20-list></div>
  </div>
</div>

<style>
.vb-fetch-20-demo,
.vb-fetch-20-demo * {
  box-sizing: border-box;
}

.vb-fetch-20-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(249, 115, 22, 0.15), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(168, 85, 247, 0.15), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #faf5ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(249, 115, 22, 0.16);
  overflow: hidden;
}

.vb-fetch-20-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-20-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #7c2d12 0%, #f97316 52%, #7e22ce 100%) !important;
}

.vb-fetch-20-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-20-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-20-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #f3e8ff !important;
  -webkit-text-fill-color: #f3e8ff !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-20-controls {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 14px;
  align-items: end;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
  min-width: 0;
}

.vb-fetch-20-controls label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-20-controls select {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid #fed7aa;
  border-radius: 18px;
  background: #fff7ed;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 850;
  outline: none;
}

.vb-fetch-20-controls button {
  min-height: 52px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #f97316, #7e22ce);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(249, 115, 22, 0.22);
}

.vb-fetch-20-controls button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-20-status {
  margin: 16px clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #fff7ed;
  border: 1px solid #fed7aa;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-20-status.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-20-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-20-list {
  display: grid;
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-20-comment {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 14px;
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 12% 12%, rgba(249, 115, 22, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-fetch-20-avatar {
  display: flex;
  width: 48px;
  height: 48px;
  align-items: center;
  justify-content: center;
  border-radius: 16px;
  background: linear-gradient(135deg, #f97316, #7e22ce);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  text-transform: uppercase;
}

.vb-fetch-20-comment strong {
  display: block;
  margin-bottom: 4px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  line-height: 1.3;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-fetch-20-comment small {
  display: block;
  margin-bottom: 8px;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 13px;
  line-height: 1.4;
  font-weight: 800;
  overflow-wrap: anywhere;
}

.vb-fetch-20-comment p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 720px) {
  .vb-fetch-20-controls,
  .vb-fetch-20-comment {
    grid-template-columns: 1fr;
  }

  .vb-fetch-20-controls button {
    width: 100%;
  }
}

@media (max-width: 640px) {
  .vb-fetch-20-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-20-demo");
  if (!demo) return;

  const postSelect = demo.querySelector("[data-vb-fetch-20-post]");
  const button = demo.querySelector("[data-vb-fetch-20-load]");
  const status = demo.querySelector("[data-vb-fetch-20-status]");
  const list = demo.querySelector("[data-vb-fetch-20-list]");

  function setStatus(text, type) {
    status.className = "vb-fetch-20-status";

    if (type === "success") {
      status.classList.add("is-success");
    }

    if (type === "error") {
      status.classList.add("is-error");
    }

    status.textContent = text;
  }

  function initials(email) {
    return email.slice(0, 2).toUpperCase();
  }

  function renderComments(comments) {
    if (!comments.length) {
      list.innerHTML = "";
      setStatus("No comments found for this post.", "error");
      return;
    }

    list.innerHTML = comments.map(function (comment) {
      return (
        '<article class="vb-fetch-20-comment">' +
          '<div class="vb-fetch-20-avatar">' + initials(comment.email) + '</div>' +
          '<div>' +
            '<strong>' + comment.name + '</strong>' +
            '<small>' + comment.email + '</small>' +
            '<p>' + comment.body + '</p>' +
          '</div>' +
        '</article>'
      );
    }).join("");
  }

  async function loadComments() {
    const postId = postSelect.value;
    const params = new URLSearchParams({
      postId: postId
    });

    button.disabled = true;
    list.innerHTML = "";
    setStatus("Loading comments for post #" + postId + "...", "");

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/comments?" + params.toString());

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const comments = await response.json();

      renderComments(comments.slice(0, 5));
      setStatus("Loaded " + Math.min(comments.length, 5) + " comments for post #" + postId + ".", "success");
    } catch (error) {
      list.innerHTML = "";
      setStatus("Comments request failed: " + error.message, "error");
    } finally {
      button.disabled = false;
    }
  }

  button.addEventListener("click", loadComments);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-20-demo");
  if (!demo) return;

  const postSelect = demo.querySelector("[data-vb-fetch-20-post]");
  const button = demo.querySelector("[data-vb-fetch-20-load]");
  const status = demo.querySelector("[data-vb-fetch-20-status]");
  const list = demo.querySelector("[data-vb-fetch-20-list]");

  function setStatus(text, type) {
    status.className = "vb-fetch-20-status";

    if (type === "success") {
      status.classList.add("is-success");
    }

    if (type === "error") {
      status.classList.add("is-error");
    }

    status.textContent = text;
  }

  function initials(email) {
    return email.slice(0, 2).toUpperCase();
  }

  function renderComments(comments) {
    if (!comments.length) {
      list.innerHTML = "";
      setStatus("No comments found for this post.", "error");
      return;
    }

    list.innerHTML = comments.map(function (comment) {
      return (
        '&lt;article class="vb-fetch-20-comment"&gt;' +
          '&lt;div class="vb-fetch-20-avatar"&gt;' + initials(comment.email) + '&lt;/div&gt;' +
          '&lt;div&gt;' +
            '&lt;strong&gt;' + comment.name + '&lt;/strong&gt;' +
            '&lt;small&gt;' + comment.email + '&lt;/small&gt;' +
            '&lt;p&gt;' + comment.body + '&lt;/p&gt;' +
          '&lt;/div&gt;' +
        '&lt;/article&gt;'
      );
    }).join("");
  }

  async function loadComments() {
    const postId = postSelect.value;
    const params = new URLSearchParams({
      postId: postId
    });

    button.disabled = true;
    list.innerHTML = "";
    setStatus("Loading comments for post #" + postId + "...", "");

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/comments?" + params.toString());

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const comments = await response.json();

      renderComments(comments.slice(0, 5));
      setStatus("Loaded " + Math.min(comments.length, 5) + " comments for post #" + postId + ".", "success");
    } catch (error) {
      list.innerHTML = "";
      setStatus("Comments request failed: " + error.message, "error");
    } finally {
      button.disabled = false;
    }
  }

  button.addEventListener("click", loadComments);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-20-demo"&gt;
  &lt;div class="vb-fetch-20-shell"&gt;
    &lt;div class="vb-fetch-20-header"&gt;
      &lt;span&gt;Example 20&lt;/span&gt;
      &lt;h3&gt;Fetch API Comments Loader&lt;/h3&gt;
      &lt;p&gt;Load related comments from an API and render them in a clean discussion layout.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-20-controls"&gt;
      &lt;label&gt;
        Post ID
        &lt;select data-vb-fetch-20-post&gt;
          &lt;option value="1"&gt;Post 1&lt;/option&gt;
          &lt;option value="2"&gt;Post 2&lt;/option&gt;
          &lt;option value="3"&gt;Post 3&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;

      &lt;button type="button" data-vb-fetch-20-load&gt;Load Comments&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-20-status" data-vb-fetch-20-status&gt;
      Select a post and load related comments.
    &lt;/div&gt;

    &lt;div class="vb-fetch-20-list" data-vb-fetch-20-list&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-20-demo,
.vb-fetch-20-demo * {
  box-sizing: border-box;
}

.vb-fetch-20-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(249, 115, 22, 0.15), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(168, 85, 247, 0.15), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #faf5ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(249, 115, 22, 0.16);
  overflow: hidden;
}

.vb-fetch-20-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-20-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #7c2d12 0%, #f97316 52%, #7e22ce 100%) !important;
}

.vb-fetch-20-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-20-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-20-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #f3e8ff !important;
  -webkit-text-fill-color: #f3e8ff !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-20-controls {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 14px;
  align-items: end;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
  min-width: 0;
}

.vb-fetch-20-controls label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-20-controls select {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid #fed7aa;
  border-radius: 18px;
  background: #fff7ed;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 850;
  outline: none;
}

.vb-fetch-20-controls button {
  min-height: 52px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #f97316, #7e22ce);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(249, 115, 22, 0.22);
}

.vb-fetch-20-controls button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-20-status {
  margin: 16px clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #fff7ed;
  border: 1px solid #fed7aa;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-20-status.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-20-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-20-list {
  display: grid;
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-20-comment {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  gap: 14px;
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 12% 12%, rgba(249, 115, 22, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-fetch-20-avatar {
  display: flex;
  width: 48px;
  height: 48px;
  align-items: center;
  justify-content: center;
  border-radius: 16px;
  background: linear-gradient(135deg, #f97316, #7e22ce);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  text-transform: uppercase;
}

.vb-fetch-20-comment strong {
  display: block;
  margin-bottom: 4px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  line-height: 1.3;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-fetch-20-comment small {
  display: block;
  margin-bottom: 8px;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 13px;
  line-height: 1.4;
  font-weight: 800;
  overflow-wrap: anywhere;
}

.vb-fetch-20-comment p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 720px) {
  .vb-fetch-20-controls,
  .vb-fetch-20-comment {
    grid-template-columns: 1fr;
  }

  .vb-fetch-20-controls button {
    width: 100%;
  }
}

@media (max-width: 640px) {
  .vb-fetch-20-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API comments loader example is useful for comment sections, review lists, support replies, message feeds, notes panels, discussion blocks, and any page that loads related API data after the main content.</p>




<h2 class="wp-block-heading">21. Fetch API Retry Failed Request</h2>



<p class="wp-block-paragraph"><strong>A Fetch API retry pattern</strong> lets users try again when an API request fails. This is useful for unstable networks, temporary server errors, rate limits, loading widgets, checkout actions, admin dashboards, and API-powered forms.</p>



<p class="wp-block-paragraph">This example intentionally alternates between a failed request and a successful request so the retry workflow is easy to test. It shows an error card, retry count, disabled button states, and successful recovery after retry.</p>



<ul class="wp-block-list">
<li>Fetch API retry request example</li>
<li>Failed request state</li>
<li>Retry button workflow</li>
<li>Attempt counter</li>
<li>Useful for resilient API interfaces</li>
</ul>



<div class="vb-fetch-21-demo">
  <div class="vb-fetch-21-shell">
    <div class="vb-fetch-21-header">
      <span>Example 21</span>
      <h3>Fetch API Retry Failed Request</h3>
      <p>Show a failed API request state and let users retry until the request succeeds.</p>
    </div>

    <div class="vb-fetch-21-card" data-vb-fetch-21-card>
      <span>Ready</span>
      <h4>No request started</h4>
      <p>Click the button to test the retry workflow.</p>
      <div class="vb-fetch-21-actions">
        <button type="button" data-vb-fetch-21-run>Run Request</button>
      </div>
    </div>
  </div>
</div>

<style>
.vb-fetch-21-demo,
.vb-fetch-21-demo * {
  box-sizing: border-box;
}

.vb-fetch-21-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(239, 68, 68, 0.15), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #fef2f2 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(239, 68, 68, 0.16);
  overflow: hidden;
}

.vb-fetch-21-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-21-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #7f1d1d 0%, #ef4444 48%, #16a34a 100%) !important;
}

.vb-fetch-21-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-21-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-21-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-21-card {
  min-width: 0;
  margin: clamp(20px, 4vw, 34px);
  padding: clamp(22px, 4vw, 34px);
  border-radius: 28px;
  background:
    radial-gradient(circle at 14% 12%, rgba(148, 163, 184, 0.12), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.08);
}

.vb-fetch-21-card.is-loading {
  background: #fffbeb;
  border-color: #fde68a;
}

.vb-fetch-21-card.is-error {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-fetch-21-card.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-fetch-21-card span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 8px 11px;
  border-radius: 999px;
  background: #e2e8f0;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-21-card.is-loading span {
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
}

.vb-fetch-21-card.is-error span {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-21-card.is-success span {
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-21-card h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(30px, 5vw, 52px) !important;
  line-height: 1.02 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
  overflow-wrap: anywhere;
}

.vb-fetch-21-card p {
  max-width: 760px;
  margin: 0 0 20px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.65;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-21-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.vb-fetch-21-actions button {
  min-height: 50px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #ef4444, #16a34a);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(239, 68, 68, 0.20);
}

.vb-fetch-21-actions button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-21-json {
  max-width: 100%;
  max-height: 220px;
  overflow: auto;
  margin: 14px 0 0 !important;
  padding: 14px;
  border-radius: 16px;
  background: #0f172a;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 13px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 640px) {
  .vb-fetch-21-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-21-actions button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-21-demo");
  if (!demo) return;

  const card = demo.querySelector("[data-vb-fetch-21-card]");
  let attempts = 0;

  function fakeUnstableFetch() {
    attempts += 1;

    return new Promise(function (resolve, reject) {
      setTimeout(function () {
        if (attempts % 2 === 1) {
          reject(new Error("Temporary API error on attempt #" + attempts));
          return;
        }

        resolve({
          ok: true,
          json: function () {
            return Promise.resolve({
              id: 1,
              title: "Recovered API response",
              attempt: attempts,
              status: "success"
            });
          }
        });
      }, 800);
    });
  }

  function renderState(type, title, message, buttonText, data) {
    card.className = "vb-fetch-21-card";

    if (type) {
      card.classList.add(type);
    }

    card.innerHTML =
      '<span>' + (type ? type.replace("is-", "") : "Ready") + '</span>' +
      '<h4>' + title + '</h4>' +
      '<p>' + message + '</p>' +
      '<div class="vb-fetch-21-actions">' +
        '<button type="button" data-vb-fetch-21-run>' + buttonText + '</button>' +
      '</div>' +
      (data ? '<pre class="vb-fetch-21-json">' + JSON.stringify(data, null, 2) + '</pre>' : '');

    card.querySelector("[data-vb-fetch-21-run]").addEventListener("click", runRequest);
  }

  async function runRequest() {
    renderState("is-loading", "Request running", "Trying API request attempt #" + (attempts + 1) + "...", "Please wait");

    const activeButton = card.querySelector("[data-vb-fetch-21-run]");
    activeButton.disabled = true;

    try {
      const response = await fakeUnstableFetch();

      if (!response.ok) {
        throw new Error("HTTP request failed");
      }

      const data = await response.json();

      renderState(
        "is-success",
        "Request recovered",
        "The retry workflow succeeded on attempt #" + data.attempt + ".",
        "Run Again",
        data
      );
    } catch (error) {
      renderState(
        "is-error",
        "Request failed",
        error.message + ". Click retry to run the request again.",
        "Retry Request"
      );
    }
  }

  card.querySelector("[data-vb-fetch-21-run]").addEventListener("click", runRequest);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-21-demo");
  if (!demo) return;

  const card = demo.querySelector("[data-vb-fetch-21-card]");
  let attempts = 0;

  function fakeUnstableFetch() {
    attempts += 1;

    return new Promise(function (resolve, reject) {
      setTimeout(function () {
        if (attempts % 2 === 1) {
          reject(new Error("Temporary API error on attempt #" + attempts));
          return;
        }

        resolve({
          ok: true,
          json: function () {
            return Promise.resolve({
              id: 1,
              title: "Recovered API response",
              attempt: attempts,
              status: "success"
            });
          }
        });
      }, 800);
    });
  }

  function renderState(type, title, message, buttonText, data) {
    card.className = "vb-fetch-21-card";

    if (type) {
      card.classList.add(type);
    }

    card.innerHTML =
      '&lt;span&gt;' + (type ? type.replace("is-", "") : "Ready") + '&lt;/span&gt;' +
      '&lt;h4&gt;' + title + '&lt;/h4&gt;' +
      '&lt;p&gt;' + message + '&lt;/p&gt;' +
      '&lt;div class="vb-fetch-21-actions"&gt;' +
        '&lt;button type="button" data-vb-fetch-21-run&gt;' + buttonText + '&lt;/button&gt;' +
      '&lt;/div&gt;' +
      (data ? '&lt;pre class="vb-fetch-21-json"&gt;' + JSON.stringify(data, null, 2) + '&lt;/pre&gt;' : '');

    card.querySelector("[data-vb-fetch-21-run]").addEventListener("click", runRequest);
  }

  async function runRequest() {
    renderState("is-loading", "Request running", "Trying API request attempt #" + (attempts + 1) + "...", "Please wait");

    const activeButton = card.querySelector("[data-vb-fetch-21-run]");
    activeButton.disabled = true;

    try {
      const response = await fakeUnstableFetch();

      if (!response.ok) {
        throw new Error("HTTP request failed");
      }

      const data = await response.json();

      renderState(
        "is-success",
        "Request recovered",
        "The retry workflow succeeded on attempt #" + data.attempt + ".",
        "Run Again",
        data
      );
    } catch (error) {
      renderState(
        "is-error",
        "Request failed",
        error.message + ". Click retry to run the request again.",
        "Retry Request"
      );
    }
  }

  card.querySelector("[data-vb-fetch-21-run]").addEventListener("click", runRequest);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-21-demo"&gt;
  &lt;div class="vb-fetch-21-shell"&gt;
    &lt;div class="vb-fetch-21-header"&gt;
      &lt;span&gt;Example 21&lt;/span&gt;
      &lt;h3&gt;Fetch API Retry Failed Request&lt;/h3&gt;
      &lt;p&gt;Show a failed API request state and let users retry until the request succeeds.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-21-card" data-vb-fetch-21-card&gt;
      &lt;span&gt;Ready&lt;/span&gt;
      &lt;h4&gt;No request started&lt;/h4&gt;
      &lt;p&gt;Click the button to test the retry workflow.&lt;/p&gt;
      &lt;div class="vb-fetch-21-actions"&gt;
        &lt;button type="button" data-vb-fetch-21-run&gt;Run Request&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-21-demo,
.vb-fetch-21-demo * {
  box-sizing: border-box;
}

.vb-fetch-21-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(239, 68, 68, 0.15), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #fef2f2 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(239, 68, 68, 0.16);
  overflow: hidden;
}

.vb-fetch-21-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-21-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #7f1d1d 0%, #ef4444 48%, #16a34a 100%) !important;
}

.vb-fetch-21-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-21-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-21-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-21-card {
  min-width: 0;
  margin: clamp(20px, 4vw, 34px);
  padding: clamp(22px, 4vw, 34px);
  border-radius: 28px;
  background:
    radial-gradient(circle at 14% 12%, rgba(148, 163, 184, 0.12), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.08);
}

.vb-fetch-21-card.is-loading {
  background: #fffbeb;
  border-color: #fde68a;
}

.vb-fetch-21-card.is-error {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-fetch-21-card.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-fetch-21-card span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 8px 11px;
  border-radius: 999px;
  background: #e2e8f0;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-21-card.is-loading span {
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
}

.vb-fetch-21-card.is-error span {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-21-card.is-success span {
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-21-card h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(30px, 5vw, 52px) !important;
  line-height: 1.02 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
  overflow-wrap: anywhere;
}

.vb-fetch-21-card p {
  max-width: 760px;
  margin: 0 0 20px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.65;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-21-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

.vb-fetch-21-actions button {
  min-height: 50px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #ef4444, #16a34a);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(239, 68, 68, 0.20);
}

.vb-fetch-21-actions button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-21-json {
  max-width: 100%;
  max-height: 220px;
  overflow: auto;
  margin: 14px 0 0 !important;
  padding: 14px;
  border-radius: 16px;
  background: #0f172a;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 13px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 640px) {
  .vb-fetch-21-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-21-actions button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API retry failed request example is useful for resilient dashboards, checkout actions, form submissions, widgets, API cards, admin tools, and any JavaScript interface that needs a safe retry workflow after a request fails.</p>



<h2 class="wp-block-heading">22. Fetch API Timeout with AbortController</h2>



<p class="wp-block-paragraph"><strong>A Fetch API timeout</strong> is useful when a request takes too long and the interface should not wait forever. JavaScript can use <code>AbortController</code> together with <code>setTimeout()</code> to cancel slow requests and show a clear timeout message.</p>



<p class="wp-block-paragraph">This example simulates a slow API request, starts a timeout timer, cancels the request if it takes too long, and gives users a controlled error state instead of a frozen loading screen.</p>



<ul class="wp-block-list">
<li>Fetch API timeout example</li>
<li>AbortController request cancellation</li>
<li>Cancel slow API requests</li>
<li>Loading, success, and timeout states</li>
<li>Useful for dashboards, widgets, and forms</li>
</ul>



<div class="vb-fetch-22-demo">
  <div class="vb-fetch-22-shell">
    <div class="vb-fetch-22-header">
      <span>Example 22</span>
      <h3>Fetch API Timeout with AbortController</h3>
      <p>Cancel a slow API request after a timeout and show a safe UI error state.</p>
    </div>

    <div class="vb-fetch-22-panel" data-vb-fetch-22-panel>
      <span>Ready</span>
      <h4>No request running</h4>
      <p>Run a fast request or a slow request to test timeout handling with AbortController.</p>

      <div class="vb-fetch-22-actions">
        <button type="button" data-vb-fetch-22-fast>Run Fast Request</button>
        <button type="button" data-vb-fetch-22-slow>Run Slow Timeout</button>
      </div>

      <pre data-vb-fetch-22-output>{}</pre>
    </div>
  </div>
</div>

<style>
.vb-fetch-22-demo,
.vb-fetch-22-demo * {
  box-sizing: border-box;
}

.vb-fetch-22-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(37, 99, 235, 0.17), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(239, 68, 68, 0.15), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #fef2f2 54%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.16);
  overflow: hidden;
}

.vb-fetch-22-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-22-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #1e3a8a 0%, #2563eb 48%, #dc2626 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-22-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-22-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-22-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-22-panel {
  min-width: 0;
  margin: clamp(20px, 4vw, 34px);
  padding: clamp(22px, 4vw, 34px);
  border-radius: 28px;
  background:
    radial-gradient(circle at 14% 12%, rgba(37, 99, 235, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.08);
}

.vb-fetch-22-panel.is-loading {
  background: #fffbeb;
  border-color: #fde68a;
}

.vb-fetch-22-panel.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-fetch-22-panel.is-error {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-fetch-22-panel span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 8px 11px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-22-panel.is-loading span {
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
}

.vb-fetch-22-panel.is-success span {
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-22-panel.is-error span {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-22-panel h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(30px, 5vw, 52px) !important;
  line-height: 1.02 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
  overflow-wrap: anywhere;
}

.vb-fetch-22-panel p {
  max-width: 780px;
  margin: 0 0 20px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.65;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-22-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 16px;
}

.vb-fetch-22-actions button {
  min-height: 50px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
}

.vb-fetch-22-actions button:first-child {
  background: linear-gradient(135deg, #2563eb, #16a34a);
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.20);
}

.vb-fetch-22-actions button:last-child {
  background: linear-gradient(135deg, #dc2626, #f97316);
  box-shadow: 0 16px 38px rgba(220, 38, 38, 0.20);
}

.vb-fetch-22-actions button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-22-panel pre {
  max-width: 100%;
  max-height: 230px;
  overflow: auto;
  margin: 0 !important;
  padding: 14px;
  border-radius: 16px;
  background: #0f172a;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 13px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 640px) {
  .vb-fetch-22-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-22-actions button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-22-demo");
  if (!demo) return;

  const panel = demo.querySelector("[data-vb-fetch-22-panel]");
  const output = demo.querySelector("[data-vb-fetch-22-output]");
  const fastButton = demo.querySelector("[data-vb-fetch-22-fast]");
  const slowButton = demo.querySelector("[data-vb-fetch-22-slow]");

  function fakeFetchWithAbort(delay, signal) {
    return new Promise(function (resolve, reject) {
      const timer = setTimeout(function () {
        resolve({
          ok: true,
          json: function () {
            return Promise.resolve({
              id: 22,
              delay: delay,
              message: "Request completed before timeout."
            });
          }
        });
      }, delay);

      signal.addEventListener("abort", function () {
        clearTimeout(timer);
        reject(new DOMException("Request timeout reached", "AbortError"));
      });
    });
  }

  function setPanel(type, label, title, message, data) {
    panel.className = "vb-fetch-22-panel";

    if (type) {
      panel.classList.add(type);
    }

    panel.querySelector("span").textContent = label;
    panel.querySelector("h4").textContent = title;
    panel.querySelector("p").textContent = message;
    output.textContent = JSON.stringify(data || {}, null, 2);
  }

  function setButtons(disabled) {
    fastButton.disabled = disabled;
    slowButton.disabled = disabled;
  }

  async function runRequest(delay) {
    const controller = new AbortController();
    const timeoutMs = 1200;

    setButtons(true);
    setPanel("is-loading", "Loading", "Request running", "Timeout is set to " + timeoutMs + "ms.", {
      delay: delay,
      timeout: timeoutMs
    });

    const timeoutId = setTimeout(function () {
      controller.abort();
    }, timeoutMs);

    try {
      const response = await fakeFetchWithAbort(delay, controller.signal);

      if (!response.ok) {
        throw new Error("HTTP request failed");
      }

      const data = await response.json();

      clearTimeout(timeoutId);
      setPanel("is-success", "Success", "Request completed", "The API-style request completed before timeout.", data);
    } catch (error) {
      clearTimeout(timeoutId);

      if (error.name === "AbortError") {
        setPanel("is-error", "Timeout", "Request cancelled", "The request took too long and was aborted safely.", {
          error: error.message,
          timeout: timeoutMs
        });
      } else {
        setPanel("is-error", "Error", "Request failed", error.message, {
          error: error.message
        });
      }
    } finally {
      setButtons(false);
    }
  }

  fastButton.addEventListener("click", function () {
    runRequest(600);
  });

  slowButton.addEventListener("click", function () {
    runRequest(2200);
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-22-demo");
  if (!demo) return;

  const panel = demo.querySelector("[data-vb-fetch-22-panel]");
  const output = demo.querySelector("[data-vb-fetch-22-output]");
  const fastButton = demo.querySelector("[data-vb-fetch-22-fast]");
  const slowButton = demo.querySelector("[data-vb-fetch-22-slow]");

  function fakeFetchWithAbort(delay, signal) {
    return new Promise(function (resolve, reject) {
      const timer = setTimeout(function () {
        resolve({
          ok: true,
          json: function () {
            return Promise.resolve({
              id: 22,
              delay: delay,
              message: "Request completed before timeout."
            });
          }
        });
      }, delay);

      signal.addEventListener("abort", function () {
        clearTimeout(timer);
        reject(new DOMException("Request timeout reached", "AbortError"));
      });
    });
  }

  function setPanel(type, label, title, message, data) {
    panel.className = "vb-fetch-22-panel";

    if (type) {
      panel.classList.add(type);
    }

    panel.querySelector("span").textContent = label;
    panel.querySelector("h4").textContent = title;
    panel.querySelector("p").textContent = message;
    output.textContent = JSON.stringify(data || {}, null, 2);
  }

  function setButtons(disabled) {
    fastButton.disabled = disabled;
    slowButton.disabled = disabled;
  }

  async function runRequest(delay) {
    const controller = new AbortController();
    const timeoutMs = 1200;

    setButtons(true);
    setPanel("is-loading", "Loading", "Request running", "Timeout is set to " + timeoutMs + "ms.", {
      delay: delay,
      timeout: timeoutMs
    });

    const timeoutId = setTimeout(function () {
      controller.abort();
    }, timeoutMs);

    try {
      const response = await fakeFetchWithAbort(delay, controller.signal);

      if (!response.ok) {
        throw new Error("HTTP request failed");
      }

      const data = await response.json();

      clearTimeout(timeoutId);
      setPanel("is-success", "Success", "Request completed", "The API-style request completed before timeout.", data);
    } catch (error) {
      clearTimeout(timeoutId);

      if (error.name === "AbortError") {
        setPanel("is-error", "Timeout", "Request cancelled", "The request took too long and was aborted safely.", {
          error: error.message,
          timeout: timeoutMs
        });
      } else {
        setPanel("is-error", "Error", "Request failed", error.message, {
          error: error.message
        });
      }
    } finally {
      setButtons(false);
    }
  }

  fastButton.addEventListener("click", function () {
    runRequest(600);
  });

  slowButton.addEventListener("click", function () {
    runRequest(2200);
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-22-demo"&gt;
  &lt;div class="vb-fetch-22-shell"&gt;
    &lt;div class="vb-fetch-22-header"&gt;
      &lt;span&gt;Example 22&lt;/span&gt;
      &lt;h3&gt;Fetch API Timeout with AbortController&lt;/h3&gt;
      &lt;p&gt;Cancel a slow API request after a timeout and show a safe UI error state.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-22-panel" data-vb-fetch-22-panel&gt;
      &lt;span&gt;Ready&lt;/span&gt;
      &lt;h4&gt;No request running&lt;/h4&gt;
      &lt;p&gt;Run a fast request or a slow request to test timeout handling with AbortController.&lt;/p&gt;

      &lt;div class="vb-fetch-22-actions"&gt;
        &lt;button type="button" data-vb-fetch-22-fast&gt;Run Fast Request&lt;/button&gt;
        &lt;button type="button" data-vb-fetch-22-slow&gt;Run Slow Timeout&lt;/button&gt;
      &lt;/div&gt;

      &lt;pre data-vb-fetch-22-output&gt;{}&lt;/pre&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-22-demo,
.vb-fetch-22-demo * {
  box-sizing: border-box;
}

.vb-fetch-22-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(37, 99, 235, 0.17), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(239, 68, 68, 0.15), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #fef2f2 54%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.16);
  overflow: hidden;
}

.vb-fetch-22-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-22-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #1e3a8a 0%, #2563eb 48%, #dc2626 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-22-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-22-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-22-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-22-panel {
  min-width: 0;
  margin: clamp(20px, 4vw, 34px);
  padding: clamp(22px, 4vw, 34px);
  border-radius: 28px;
  background:
    radial-gradient(circle at 14% 12%, rgba(37, 99, 235, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.08);
}

.vb-fetch-22-panel.is-loading {
  background: #fffbeb;
  border-color: #fde68a;
}

.vb-fetch-22-panel.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-fetch-22-panel.is-error {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-fetch-22-panel span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 8px 11px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-22-panel.is-loading span {
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
}

.vb-fetch-22-panel.is-success span {
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-22-panel.is-error span {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-22-panel h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(30px, 5vw, 52px) !important;
  line-height: 1.02 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
  overflow-wrap: anywhere;
}

.vb-fetch-22-panel p {
  max-width: 780px;
  margin: 0 0 20px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.65;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-22-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 16px;
}

.vb-fetch-22-actions button {
  min-height: 50px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
}

.vb-fetch-22-actions button:first-child {
  background: linear-gradient(135deg, #2563eb, #16a34a);
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.20);
}

.vb-fetch-22-actions button:last-child {
  background: linear-gradient(135deg, #dc2626, #f97316);
  box-shadow: 0 16px 38px rgba(220, 38, 38, 0.20);
}

.vb-fetch-22-actions button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-22-panel pre {
  max-width: 100%;
  max-height: 230px;
  overflow: auto;
  margin: 0 !important;
  padding: 14px;
  border-radius: 16px;
  background: #0f172a;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 13px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 640px) {
  .vb-fetch-22-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-22-actions button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API timeout example is useful for slow API widgets, admin dashboards, checkout steps, forms, search interfaces, external integrations, and any JavaScript request that needs safe cancellation.</p>




<h2 class="wp-block-heading">23. Fetch API Multiple Requests with Promise.all</h2>



<p class="wp-block-paragraph"><strong>Fetch API multiple requests</strong> are useful when a page needs several pieces of data at the same time. Instead of waiting for one request and then starting the next, JavaScript can run them in parallel with <code>Promise.all()</code>.</p>



<p class="wp-block-paragraph">This example loads a user profile, posts, and todos at the same time. When all requests finish, it renders a combined dashboard summary from multiple API endpoints.</p>



<ul class="wp-block-list">
<li>Fetch API multiple requests example</li>
<li>Run requests in parallel with <code>Promise.all()</code></li>
<li>Combine user, posts, and todo data</li>
<li>Dashboard summary rendering</li>
<li>Useful for admin panels and SaaS dashboards</li>
</ul>



<div class="vb-fetch-23-demo">
  <div class="vb-fetch-23-shell">
    <div class="vb-fetch-23-header">
      <span>Example 23</span>
      <h3>Multiple Fetch Requests with Promise.all</h3>
      <p>Load several API endpoints in parallel and combine the results into one dashboard.</p>
    </div>

    <div class="vb-fetch-23-controls">
      <label>
        Dashboard user
        <select data-vb-fetch-23-user>
          <option value="1">User 1</option>
          <option value="2">User 2</option>
          <option value="3">User 3</option>
        </select>
      </label>

      <button type="button" data-vb-fetch-23-load>Load Dashboard</button>
    </div>

    <div class="vb-fetch-23-status" data-vb-fetch-23-status>
      Load multiple endpoints to build the dashboard.
    </div>

    <div class="vb-fetch-23-summary" data-vb-fetch-23-summary>
      <div>
        <span>User</span>
        <strong>--</strong>
      </div>
      <div>
        <span>Posts</span>
        <strong>--</strong>
      </div>
      <div>
        <span>Todos</span>
        <strong>--</strong>
      </div>
    </div>

    <div class="vb-fetch-23-output" data-vb-fetch-23-output></div>
  </div>
</div>

<style>
.vb-fetch-23-demo,
.vb-fetch-23-demo * {
  box-sizing: border-box;
}

.vb-fetch-23-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(124, 58, 237, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #f5f3ff 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(124, 58, 237, 0.16);
  overflow: hidden;
}

.vb-fetch-23-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-23-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #4c1d95 0%, #7c3aed 52%, #16a34a 100%) !important;
}

.vb-fetch-23-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ede9fe !important;
  -webkit-text-fill-color: #ede9fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-23-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-23-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-23-controls {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 14px;
  align-items: end;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
  min-width: 0;
}

.vb-fetch-23-controls label {
  display: grid;
  gap: 8px;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-23-controls select {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid #ddd6fe;
  border-radius: 18px;
  background: #faf5ff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 850;
  outline: none;
}

.vb-fetch-23-controls button {
  min-height: 52px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #7c3aed, #16a34a);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(124, 58, 237, 0.22);
}

.vb-fetch-23-controls button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-23-status {
  margin: 16px clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #f5f3ff;
  border: 1px solid #ddd6fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-23-status.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-23-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-23-summary {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
}

.vb-fetch-23-summary div {
  min-width: 0;
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(124, 58, 237, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-fetch-23-summary span {
  display: block;
  margin-bottom: 8px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-fetch-23-summary strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(28px, 4vw, 44px);
  line-height: 1;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-fetch-23-output {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-23-card {
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-fetch-23-card span {
  display: inline-flex;
  margin-bottom: 9px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-23-card h4 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-23-card p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 800px) {
  .vb-fetch-23-controls,
  .vb-fetch-23-summary,
  .vb-fetch-23-output {
    grid-template-columns: 1fr;
  }

  .vb-fetch-23-controls button {
    width: 100%;
  }
}

@media (max-width: 640px) {
  .vb-fetch-23-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.045em;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-23-demo");
  if (!demo) return;

  const userSelect = demo.querySelector("[data-vb-fetch-23-user]");
  const button = demo.querySelector("[data-vb-fetch-23-load]");
  const status = demo.querySelector("[data-vb-fetch-23-status]");
  const summary = demo.querySelector("[data-vb-fetch-23-summary]");
  const output = demo.querySelector("[data-vb-fetch-23-output]");

  function setStatus(text, type) {
    status.className = "vb-fetch-23-status";

    if (type === "success") {
      status.classList.add("is-success");
    }

    if (type === "error") {
      status.classList.add("is-error");
    }

    status.textContent = text;
  }

  function renderDashboard(user, posts, todos) {
    const completedTodos = todos.filter(function (todo) {
      return todo.completed;
    }).length;

    summary.innerHTML =
      '<div><span>User</span><strong>' + user.name + '</strong></div>' +
      '<div><span>Posts</span><strong>' + posts.length + '</strong></div>' +
      '<div><span>Done Todos</span><strong>' + completedTodos + '/' + todos.length + '</strong></div>';

    output.innerHTML =
      '<article class="vb-fetch-23-card">' +
        '<span>Profile endpoint</span>' +
        '<h4>' + user.company.name + '</h4>' +
        '<p>' + user.email + ' · ' + user.website + '</p>' +
      '</article>' +
      posts.slice(0, 3).map(function (post) {
        return (
          '<article class="vb-fetch-23-card">' +
            '<span>Post #' + post.id + '</span>' +
            '<h4>' + post.title + '</h4>' +
            '<p>' + post.body + '</p>' +
          '</article>'
        );
      }).join("");
  }

  async function loadDashboard() {
    const userId = userSelect.value;

    button.disabled = true;
    output.innerHTML = "";
    setStatus("Loading user, posts, and todos in parallel...", "");

    try {
      const urls = [
        "https://jsonplaceholder.typicode.com/users/" + userId,
        "https://jsonplaceholder.typicode.com/posts?userId=" + userId,
        "https://jsonplaceholder.typicode.com/todos?userId=" + userId
      ];

      const responses = await Promise.all(urls.map(function (url) {
        return fetch(url);
      }));

      responses.forEach(function (response) {
        if (!response.ok) {
          throw new Error("One request failed with HTTP status " + response.status);
        }
      });

      const data = await Promise.all(responses.map(function (response) {
        return response.json();
      }));

      renderDashboard(data[0], data[1], data[2]);
      setStatus("All 3 API requests finished successfully with Promise.all().", "success");
    } catch (error) {
      setStatus("Multiple request workflow failed: " + error.message, "error");
    } finally {
      button.disabled = false;
    }
  }

  button.addEventListener("click", loadDashboard);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-23-demo");
  if (!demo) return;

  const userSelect = demo.querySelector("[data-vb-fetch-23-user]");
  const button = demo.querySelector("[data-vb-fetch-23-load]");
  const status = demo.querySelector("[data-vb-fetch-23-status]");
  const summary = demo.querySelector("[data-vb-fetch-23-summary]");
  const output = demo.querySelector("[data-vb-fetch-23-output]");

  function setStatus(text, type) {
    status.className = "vb-fetch-23-status";

    if (type === "success") {
      status.classList.add("is-success");
    }

    if (type === "error") {
      status.classList.add("is-error");
    }

    status.textContent = text;
  }

  function renderDashboard(user, posts, todos) {
    const completedTodos = todos.filter(function (todo) {
      return todo.completed;
    }).length;

    summary.innerHTML =
      '&lt;div&gt;&lt;span&gt;User&lt;/span&gt;&lt;strong&gt;' + user.name + '&lt;/strong&gt;&lt;/div&gt;' +
      '&lt;div&gt;&lt;span&gt;Posts&lt;/span&gt;&lt;strong&gt;' + posts.length + '&lt;/strong&gt;&lt;/div&gt;' +
      '&lt;div&gt;&lt;span&gt;Done Todos&lt;/span&gt;&lt;strong&gt;' + completedTodos + '/' + todos.length + '&lt;/strong&gt;&lt;/div&gt;';

    output.innerHTML =
      '&lt;article class="vb-fetch-23-card"&gt;' +
        '&lt;span&gt;Profile endpoint&lt;/span&gt;' +
        '&lt;h4&gt;' + user.company.name + '&lt;/h4&gt;' +
        '&lt;p&gt;' + user.email + ' · ' + user.website + '&lt;/p&gt;' +
      '&lt;/article&gt;' +
      posts.slice(0, 3).map(function (post) {
        return (
          '&lt;article class="vb-fetch-23-card"&gt;' +
            '&lt;span&gt;Post #' + post.id + '&lt;/span&gt;' +
            '&lt;h4&gt;' + post.title + '&lt;/h4&gt;' +
            '&lt;p&gt;' + post.body + '&lt;/p&gt;' +
          '&lt;/article&gt;'
        );
      }).join("");
  }

  async function loadDashboard() {
    const userId = userSelect.value;

    button.disabled = true;
    output.innerHTML = "";
    setStatus("Loading user, posts, and todos in parallel...", "");

    try {
      const urls = [
        "https://jsonplaceholder.typicode.com/users/" + userId,
        "https://jsonplaceholder.typicode.com/posts?userId=" + userId,
        "https://jsonplaceholder.typicode.com/todos?userId=" + userId
      ];

      const responses = await Promise.all(urls.map(function (url) {
        return fetch(url);
      }));

      responses.forEach(function (response) {
        if (!response.ok) {
          throw new Error("One request failed with HTTP status " + response.status);
        }
      });

      const data = await Promise.all(responses.map(function (response) {
        return response.json();
      }));

      renderDashboard(data[0], data[1], data[2]);
      setStatus("All 3 API requests finished successfully with Promise.all().", "success");
    } catch (error) {
      setStatus("Multiple request workflow failed: " + error.message, "error");
    } finally {
      button.disabled = false;
    }
  }

  button.addEventListener("click", loadDashboard);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-23-demo"&gt;
  &lt;div class="vb-fetch-23-shell"&gt;
    &lt;div class="vb-fetch-23-header"&gt;
      &lt;span&gt;Example 23&lt;/span&gt;
      &lt;h3&gt;Multiple Fetch Requests with Promise.all&lt;/h3&gt;
      &lt;p&gt;Load several API endpoints in parallel and combine the results into one dashboard.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-23-controls"&gt;
      &lt;label&gt;
        Dashboard user
        &lt;select data-vb-fetch-23-user&gt;
          &lt;option value="1"&gt;User 1&lt;/option&gt;
          &lt;option value="2"&gt;User 2&lt;/option&gt;
          &lt;option value="3"&gt;User 3&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;

      &lt;button type="button" data-vb-fetch-23-load&gt;Load Dashboard&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-23-status" data-vb-fetch-23-status&gt;
      Load multiple endpoints to build the dashboard.
    &lt;/div&gt;

    &lt;div class="vb-fetch-23-summary" data-vb-fetch-23-summary&gt;
      &lt;div&gt;
        &lt;span&gt;User&lt;/span&gt;
        &lt;strong&gt;--&lt;/strong&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;span&gt;Posts&lt;/span&gt;
        &lt;strong&gt;--&lt;/strong&gt;
      &lt;/div&gt;
      &lt;div&gt;
        &lt;span&gt;Todos&lt;/span&gt;
        &lt;strong&gt;--&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-23-output" data-vb-fetch-23-output&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-23-demo,
.vb-fetch-23-demo * {
  box-sizing: border-box;
}

.vb-fetch-23-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(124, 58, 237, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #f5f3ff 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(124, 58, 237, 0.16);
  overflow: hidden;
}

.vb-fetch-23-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-23-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #4c1d95 0%, #7c3aed 52%, #16a34a 100%) !important;
}

.vb-fetch-23-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ede9fe !important;
  -webkit-text-fill-color: #ede9fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-23-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-23-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-23-controls {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 14px;
  align-items: end;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
  min-width: 0;
}

.vb-fetch-23-controls label {
  display: grid;
  gap: 8px;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-23-controls select {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid #ddd6fe;
  border-radius: 18px;
  background: #faf5ff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 850;
  outline: none;
}

.vb-fetch-23-controls button {
  min-height: 52px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #7c3aed, #16a34a);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(124, 58, 237, 0.22);
}

.vb-fetch-23-controls button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-23-status {
  margin: 16px clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #f5f3ff;
  border: 1px solid #ddd6fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-23-status.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-23-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-23-summary {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
}

.vb-fetch-23-summary div {
  min-width: 0;
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(124, 58, 237, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-fetch-23-summary span {
  display: block;
  margin-bottom: 8px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-fetch-23-summary strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(28px, 4vw, 44px);
  line-height: 1;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-fetch-23-output {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-23-card {
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-fetch-23-card span {
  display: inline-flex;
  margin-bottom: 9px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-23-card h4 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-23-card p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 800px) {
  .vb-fetch-23-controls,
  .vb-fetch-23-summary,
  .vb-fetch-23-output {
    grid-template-columns: 1fr;
  }

  .vb-fetch-23-controls button {
    width: 100%;
  }
}

@media (max-width: 640px) {
  .vb-fetch-23-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.045em;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API multiple requests example is useful for dashboards, SaaS home screens, analytics panels, account pages, CRM overviews, admin tools, and any interface that needs several API resources at once.</p>




<h2 class="wp-block-heading">24. Fetch API Dependent Requests</h2>



<p class="wp-block-paragraph"><strong>Fetch API dependent requests</strong> are used when one API request depends on data from another request. For example, JavaScript may first load a user, then use that user ID to load posts, orders, invoices, comments, or related records.</p>



<p class="wp-block-paragraph">This example first loads a user profile, then automatically loads that user’s posts. The second request depends on the result of the first request, which makes this a useful pattern for real connected data workflows.</p>



<ul class="wp-block-list">
<li>Fetch API dependent requests example</li>
<li>First load user data</li>
<li>Then load related posts</li>
<li>Sequential async/await workflow</li>
<li>Useful for connected API data</li>
</ul>



<div class="vb-fetch-24-demo">
  <div class="vb-fetch-24-shell">
    <div class="vb-fetch-24-header">
      <span>Example 24</span>
      <h3>Fetch API Dependent Requests</h3>
      <p>Load one API resource first, then use its data to request related records.</p>
    </div>

    <div class="vb-fetch-24-controls">
      <label>
        Start with user ID
        <select data-vb-fetch-24-user>
          <option value="1">User 1</option>
          <option value="2">User 2</option>
          <option value="3">User 3</option>
        </select>
      </label>

      <button type="button" data-vb-fetch-24-load>Load User + Posts</button>
    </div>

    <div class="vb-fetch-24-flow" data-vb-fetch-24-flow>
      <div class="vb-fetch-24-step">
        <span>Step 1</span>
        <strong>Waiting for user request</strong>
        <p>The first request loads user data.</p>
      </div>
      <div class="vb-fetch-24-step">
        <span>Step 2</span>
        <strong>Waiting for posts request</strong>
        <p>The second request uses the user ID.</p>
      </div>
    </div>

    <div class="vb-fetch-24-results" data-vb-fetch-24-results></div>
  </div>
</div>

<style>
.vb-fetch-24-demo,
.vb-fetch-24-demo * {
  box-sizing: border-box;
}

.vb-fetch-24-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(20, 184, 166, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(245, 158, 11, 0.15), transparent 34%),
    linear-gradient(135deg, #f0fdfa 0%, #fffbeb 54%, #ffffff 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.16);
  overflow: hidden;
}

.vb-fetch-24-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-24-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #115e59 0%, #14b8a6 52%, #f59e0b 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-24-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-24-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-24-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-24-controls {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 14px;
  align-items: end;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
  min-width: 0;
}

.vb-fetch-24-controls label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-24-controls select {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid #99f6e4;
  border-radius: 18px;
  background: #f0fdfa;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 850;
  outline: none;
}

.vb-fetch-24-controls button {
  min-height: 52px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #14b8a6, #f59e0b);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(20, 184, 166, 0.22);
}

.vb-fetch-24-controls button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-24-flow {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
}

.vb-fetch-24-step {
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-fetch-24-step.is-loading {
  background: #fffbeb;
  border-color: #fde68a;
}

.vb-fetch-24-step.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-fetch-24-step.is-error {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-fetch-24-step span {
  display: inline-flex;
  margin-bottom: 9px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-24-step strong {
  display: block;
  margin-bottom: 7px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-fetch-24-step p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-24-results {
  display: grid;
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-24-user-card,
.vb-fetch-24-post-card {
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(20, 184, 166, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-fetch-24-user-card span,
.vb-fetch-24-post-card span {
  display: inline-flex;
  margin-bottom: 9px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-24-user-card h4,
.vb-fetch-24-post-card h4 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px !important;
  line-height: 1.22 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-24-user-card p,
.vb-fetch-24-post-card p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 800px) {
  .vb-fetch-24-controls,
  .vb-fetch-24-flow {
    grid-template-columns: 1fr;
  }

  .vb-fetch-24-controls button {
    width: 100%;
  }
}

@media (max-width: 640px) {
  .vb-fetch-24-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-24-demo");
  if (!demo) return;

  const userSelect = demo.querySelector("[data-vb-fetch-24-user]");
  const button = demo.querySelector("[data-vb-fetch-24-load]");
  const flow = demo.querySelector("[data-vb-fetch-24-flow]");
  const results = demo.querySelector("[data-vb-fetch-24-results]");

  function renderStep(index, state, title, message) {
    const step = flow.children[index];

    step.className = "vb-fetch-24-step";

    if (state) {
      step.classList.add(state);
    }

    step.querySelector("strong").textContent = title;
    step.querySelector("p").textContent = message;
  }

  function renderResults(user, posts) {
    results.innerHTML =
      '<article class="vb-fetch-24-user-card">' +
        '<span>First request result</span>' +
        '<h4>' + user.name + '</h4>' +
        '<p>' + user.email + ' · ' + user.company.name + '</p>' +
      '</article>' +
      posts.slice(0, 4).map(function (post) {
        return (
          '<article class="vb-fetch-24-post-card">' +
            '<span>Related post #' + post.id + '</span>' +
            '<h4>' + post.title + '</h4>' +
            '<p>' + post.body + '</p>' +
          '</article>'
        );
      }).join("");
  }

  async function loadDependentData() {
    const userId = userSelect.value;

    button.disabled = true;
    results.innerHTML = "";
    renderStep(0, "is-loading", "Loading user", "Requesting user #" + userId + " first.");
    renderStep(1, "", "Waiting for user data", "Posts request starts after user data is loaded.");

    try {
      const userResponse = await fetch("https://jsonplaceholder.typicode.com/users/" + userId);

      if (!userResponse.ok) {
        throw new Error("User request failed with HTTP status " + userResponse.status);
      }

      const user = await userResponse.json();

      renderStep(0, "is-success", "User loaded", "User ID " + user.id + " was loaded successfully.");
      renderStep(1, "is-loading", "Loading related posts", "Using user ID " + user.id + " for the second request.");

      const postsResponse = await fetch("https://jsonplaceholder.typicode.com/posts?userId=" + user.id);

      if (!postsResponse.ok) {
        throw new Error("Posts request failed with HTTP status " + postsResponse.status);
      }

      const posts = await postsResponse.json();

      renderStep(1, "is-success", "Related posts loaded", "Loaded " + posts.length + " posts for user ID " + user.id + ".");
      renderResults(user, posts);
    } catch (error) {
      renderStep(0, "is-error", "Workflow failed", error.message);
      renderStep(1, "is-error", "Stopped", "The second request did not run or did not complete.");
      results.innerHTML = "";
    } finally {
      button.disabled = false;
    }
  }

  button.addEventListener("click", loadDependentData);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-24-demo");
  if (!demo) return;

  const userSelect = demo.querySelector("[data-vb-fetch-24-user]");
  const button = demo.querySelector("[data-vb-fetch-24-load]");
  const flow = demo.querySelector("[data-vb-fetch-24-flow]");
  const results = demo.querySelector("[data-vb-fetch-24-results]");

  function renderStep(index, state, title, message) {
    const step = flow.children[index];

    step.className = "vb-fetch-24-step";

    if (state) {
      step.classList.add(state);
    }

    step.querySelector("strong").textContent = title;
    step.querySelector("p").textContent = message;
  }

  function renderResults(user, posts) {
    results.innerHTML =
      '&lt;article class="vb-fetch-24-user-card"&gt;' +
        '&lt;span&gt;First request result&lt;/span&gt;' +
        '&lt;h4&gt;' + user.name + '&lt;/h4&gt;' +
        '&lt;p&gt;' + user.email + ' · ' + user.company.name + '&lt;/p&gt;' +
      '&lt;/article&gt;' +
      posts.slice(0, 4).map(function (post) {
        return (
          '&lt;article class="vb-fetch-24-post-card"&gt;' +
            '&lt;span&gt;Related post #' + post.id + '&lt;/span&gt;' +
            '&lt;h4&gt;' + post.title + '&lt;/h4&gt;' +
            '&lt;p&gt;' + post.body + '&lt;/p&gt;' +
          '&lt;/article&gt;'
        );
      }).join("");
  }

  async function loadDependentData() {
    const userId = userSelect.value;

    button.disabled = true;
    results.innerHTML = "";
    renderStep(0, "is-loading", "Loading user", "Requesting user #" + userId + " first.");
    renderStep(1, "", "Waiting for user data", "Posts request starts after user data is loaded.");

    try {
      const userResponse = await fetch("https://jsonplaceholder.typicode.com/users/" + userId);

      if (!userResponse.ok) {
        throw new Error("User request failed with HTTP status " + userResponse.status);
      }

      const user = await userResponse.json();

      renderStep(0, "is-success", "User loaded", "User ID " + user.id + " was loaded successfully.");
      renderStep(1, "is-loading", "Loading related posts", "Using user ID " + user.id + " for the second request.");

      const postsResponse = await fetch("https://jsonplaceholder.typicode.com/posts?userId=" + user.id);

      if (!postsResponse.ok) {
        throw new Error("Posts request failed with HTTP status " + postsResponse.status);
      }

      const posts = await postsResponse.json();

      renderStep(1, "is-success", "Related posts loaded", "Loaded " + posts.length + " posts for user ID " + user.id + ".");
      renderResults(user, posts);
    } catch (error) {
      renderStep(0, "is-error", "Workflow failed", error.message);
      renderStep(1, "is-error", "Stopped", "The second request did not run or did not complete.");
      results.innerHTML = "";
    } finally {
      button.disabled = false;
    }
  }

  button.addEventListener("click", loadDependentData);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-24-demo"&gt;
  &lt;div class="vb-fetch-24-shell"&gt;
    &lt;div class="vb-fetch-24-header"&gt;
      &lt;span&gt;Example 24&lt;/span&gt;
      &lt;h3&gt;Fetch API Dependent Requests&lt;/h3&gt;
      &lt;p&gt;Load one API resource first, then use its data to request related records.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-24-controls"&gt;
      &lt;label&gt;
        Start with user ID
        &lt;select data-vb-fetch-24-user&gt;
          &lt;option value="1"&gt;User 1&lt;/option&gt;
          &lt;option value="2"&gt;User 2&lt;/option&gt;
          &lt;option value="3"&gt;User 3&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;

      &lt;button type="button" data-vb-fetch-24-load&gt;Load User + Posts&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-24-flow" data-vb-fetch-24-flow&gt;
      &lt;div class="vb-fetch-24-step"&gt;
        &lt;span&gt;Step 1&lt;/span&gt;
        &lt;strong&gt;Waiting for user request&lt;/strong&gt;
        &lt;p&gt;The first request loads user data.&lt;/p&gt;
      &lt;/div&gt;
      &lt;div class="vb-fetch-24-step"&gt;
        &lt;span&gt;Step 2&lt;/span&gt;
        &lt;strong&gt;Waiting for posts request&lt;/strong&gt;
        &lt;p&gt;The second request uses the user ID.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-24-results" data-vb-fetch-24-results&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-24-demo,
.vb-fetch-24-demo * {
  box-sizing: border-box;
}

.vb-fetch-24-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(20, 184, 166, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(245, 158, 11, 0.15), transparent 34%),
    linear-gradient(135deg, #f0fdfa 0%, #fffbeb 54%, #ffffff 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.16);
  overflow: hidden;
}

.vb-fetch-24-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-24-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #115e59 0%, #14b8a6 52%, #f59e0b 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-24-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-24-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-24-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-24-controls {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 14px;
  align-items: end;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
  min-width: 0;
}

.vb-fetch-24-controls label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-24-controls select {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid #99f6e4;
  border-radius: 18px;
  background: #f0fdfa;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 850;
  outline: none;
}

.vb-fetch-24-controls button {
  min-height: 52px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #14b8a6, #f59e0b);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(20, 184, 166, 0.22);
}

.vb-fetch-24-controls button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-24-flow {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
}

.vb-fetch-24-step {
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-fetch-24-step.is-loading {
  background: #fffbeb;
  border-color: #fde68a;
}

.vb-fetch-24-step.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-fetch-24-step.is-error {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-fetch-24-step span {
  display: inline-flex;
  margin-bottom: 9px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-24-step strong {
  display: block;
  margin-bottom: 7px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-fetch-24-step p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-24-results {
  display: grid;
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-24-user-card,
.vb-fetch-24-post-card {
  min-width: 0;
  padding: 18px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(20, 184, 166, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-fetch-24-user-card span,
.vb-fetch-24-post-card span {
  display: inline-flex;
  margin-bottom: 9px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-24-user-card h4,
.vb-fetch-24-post-card h4 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px !important;
  line-height: 1.22 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-24-user-card p,
.vb-fetch-24-post-card p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 800px) {
  .vb-fetch-24-controls,
  .vb-fetch-24-flow {
    grid-template-columns: 1fr;
  }

  .vb-fetch-24-controls button {
    width: 100%;
  }
}

@media (max-width: 640px) {
  .vb-fetch-24-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API dependent requests example is useful for user portals, ecommerce account pages, CRM records, order details, invoice lists, project dashboards, and any JavaScript workflow where one API request depends on another.</p>



<h2 class="wp-block-heading">25. Fetch API Form Submission with Validation</h2>



<p class="wp-block-paragraph"><strong>A Fetch API form submission</strong> is one of the most common JavaScript API use cases. It lets a form validate user input, send JSON data to an API, show loading feedback, handle errors, and display a success message without reloading the page.</p>



<p class="wp-block-paragraph">This example validates a contact-style form, prevents empty fields, sends the data as a JSON POST request, disables the button while loading, and renders the API response after the request succeeds.</p>



<ul class="wp-block-list">
<li>Fetch API form submission example</li>
<li>Client-side form validation</li>
<li>POST JSON body to API</li>
<li>Loading, success, and error states</li>
<li>Useful for contact forms, quote forms, and signup forms</li>
</ul>



<div class="vb-fetch-25-demo">
  <div class="vb-fetch-25-shell">
    <div class="vb-fetch-25-header">
      <span>Example 25</span>
      <h3>Fetch API Form Submission with Validation</h3>
      <p>Validate form fields, submit JSON with Fetch API, and show a clean success response.</p>
    </div>

    <div class="vb-fetch-25-body">
      <form class="vb-fetch-25-form" data-vb-fetch-25-form>
        <label>
          Full name
          <input type="text" data-vb-fetch-25-name placeholder="Jane Developer">
          <small data-vb-fetch-25-error="name"></small>
        </label>

        <label>
          Email address
          <input type="email" data-vb-fetch-25-email placeholder="jane@example.com">
          <small data-vb-fetch-25-error="email"></small>
        </label>

        <label>
          Message
          <textarea data-vb-fetch-25-message placeholder="Tell us what you need..."></textarea>
          <small data-vb-fetch-25-error="message"></small>
        </label>

        <button type="submit" data-vb-fetch-25-submit>Submit with Fetch</button>
      </form>

      <div class="vb-fetch-25-response" data-vb-fetch-25-response>
        <span>Waiting</span>
        <h4>No form submitted yet</h4>
        <p>Fill the form and send a JSON POST request.</p>
        <pre>{}</pre>
      </div>
    </div>
  </div>
</div>

<style>
.vb-fetch-25-demo,
.vb-fetch-25-demo * {
  box-sizing: border-box;
}

.vb-fetch-25-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(59, 130, 246, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #faf5ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.16);
  overflow: hidden;
}

.vb-fetch-25-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-25-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #1e3a8a 0%, #2563eb 50%, #9333ea 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-25-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-25-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-25-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #f3e8ff !important;
  -webkit-text-fill-color: #f3e8ff !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-25-body {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
  gap: 22px;
  padding: clamp(20px, 4vw, 34px);
  min-width: 0;
}

.vb-fetch-25-form {
  display: grid;
  gap: 14px;
  min-width: 0;
  padding: 20px;
  border-radius: 24px;
  background: #eff6ff;
  border: 1px solid #bfdbfe;
}

.vb-fetch-25-form label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-25-form input,
.vb-fetch-25-form textarea {
  width: 100%;
  min-width: 0;
  border: 1px solid #bfdbfe;
  border-radius: 16px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-fetch-25-form input {
  min-height: 50px;
  padding: 0 14px;
}

.vb-fetch-25-form textarea {
  min-height: 130px;
  padding: 14px;
  resize: vertical;
}

.vb-fetch-25-form small {
  min-height: 17px;
  color: #dc2626 !important;
  -webkit-text-fill-color: #dc2626 !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 850;
}

.vb-fetch-25-form button {
  min-height: 52px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #9333ea);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.24);
}

.vb-fetch-25-form button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-25-response {
  min-width: 0;
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 14% 12%, rgba(147, 51, 234, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-fetch-25-response.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-fetch-25-response.is-error {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-fetch-25-response span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #e0e7ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-25-response.is-success span {
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-25-response.is-error span {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-25-response h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(26px, 4vw, 42px) !important;
  line-height: 1.05 !important;
  font-weight: 950 !important;
  letter-spacing: -0.05em;
  overflow-wrap: anywhere;
}

.vb-fetch-25-response p {
  margin: 0 0 14px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-25-response pre {
  max-width: 100%;
  max-height: 240px;
  overflow: auto;
  margin: 0 !important;
  padding: 14px;
  border-radius: 16px;
  background: #0f172a;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 13px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-fetch-25-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-fetch-25-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.045em;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-25-demo");
  if (!demo) return;

  const form = demo.querySelector("[data-vb-fetch-25-form]");
  const nameInput = demo.querySelector("[data-vb-fetch-25-name]");
  const emailInput = demo.querySelector("[data-vb-fetch-25-email]");
  const messageInput = demo.querySelector("[data-vb-fetch-25-message]");
  const submitButton = demo.querySelector("[data-vb-fetch-25-submit]");
  const responseBox = demo.querySelector("[data-vb-fetch-25-response]");

  function setError(field, message) {
    const error = demo.querySelector('[data-vb-fetch-25-error="' + field + '"]');
    if (error) {
      error.textContent = message;
    }
  }

  function clearErrors() {
    setError("name", "");
    setError("email", "");
    setError("message", "");
  }

  function validateForm(payload) {
    let valid = true;
    clearErrors();

    if (payload.name.length < 2) {
      setError("name", "Name must be at least 2 characters.");
      valid = false;
    }

    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(payload.email)) {
      setError("email", "Enter a valid email address.");
      valid = false;
    }

    if (payload.message.length < 10) {
      setError("message", "Message must be at least 10 characters.");
      valid = false;
    }

    return valid;
  }

  function renderResponse(type, title, message, data) {
    responseBox.className = "vb-fetch-25-response";

    if (type) {
      responseBox.classList.add(type);
    }

    responseBox.innerHTML =
      '<span>' + (type === "is-success" ? "Success" : type === "is-error" ? "Error" : "Status") + '</span>' +
      '<h4>' + title + '</h4>' +
      '<p>' + message + '</p>' +
      '<pre>' + JSON.stringify(data || {}, null, 2) + '</pre>';
  }

  form.addEventListener("submit", async function (event) {
    event.preventDefault();

    const payload = {
      title: nameInput.value.trim(),
      body: messageInput.value.trim(),
      email: emailInput.value.trim(),
      userId: 1
    };

    const validationPayload = {
      name: payload.title,
      email: payload.email,
      message: payload.body
    };

    if (!validateForm(validationPayload)) {
      renderResponse("is-error", "Validation failed", "Fix the form errors before sending the Fetch API request.", validationPayload);
      return;
    }

    submitButton.disabled = true;
    submitButton.textContent = "Submitting...";
    renderResponse("", "Sending request", "Posting JSON form data to the API...", payload);

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts", {
        method: "POST",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify(payload)
      });

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const data = await response.json();

      renderResponse("is-success", "Form submitted", "The API returned a successful JSON response.", data);
      form.reset();
      clearErrors();
    } catch (error) {
      renderResponse("is-error", "Submission failed", error.message, payload);
    } finally {
      submitButton.disabled = false;
      submitButton.textContent = "Submit with Fetch";
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-25-demo");
  if (!demo) return;

  const form = demo.querySelector("[data-vb-fetch-25-form]");
  const nameInput = demo.querySelector("[data-vb-fetch-25-name]");
  const emailInput = demo.querySelector("[data-vb-fetch-25-email]");
  const messageInput = demo.querySelector("[data-vb-fetch-25-message]");
  const submitButton = demo.querySelector("[data-vb-fetch-25-submit]");
  const responseBox = demo.querySelector("[data-vb-fetch-25-response]");

  function setError(field, message) {
    const error = demo.querySelector('[data-vb-fetch-25-error="' + field + '"]');
    if (error) {
      error.textContent = message;
    }
  }

  function clearErrors() {
    setError("name", "");
    setError("email", "");
    setError("message", "");
  }

  function validateForm(payload) {
    let valid = true;
    clearErrors();

    if (payload.name.length &lt; 2) {
      setError("name", "Name must be at least 2 characters.");
      valid = false;
    }

    if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(payload.email)) {
      setError("email", "Enter a valid email address.");
      valid = false;
    }

    if (payload.message.length &lt; 10) {
      setError("message", "Message must be at least 10 characters.");
      valid = false;
    }

    return valid;
  }

  function renderResponse(type, title, message, data) {
    responseBox.className = "vb-fetch-25-response";

    if (type) {
      responseBox.classList.add(type);
    }

    responseBox.innerHTML =
      '&lt;span&gt;' + (type === "is-success" ? "Success" : type === "is-error" ? "Error" : "Status") + '&lt;/span&gt;' +
      '&lt;h4&gt;' + title + '&lt;/h4&gt;' +
      '&lt;p&gt;' + message + '&lt;/p&gt;' +
      '&lt;pre&gt;' + JSON.stringify(data || {}, null, 2) + '&lt;/pre&gt;';
  }

  form.addEventListener("submit", async function (event) {
    event.preventDefault();

    const payload = {
      title: nameInput.value.trim(),
      body: messageInput.value.trim(),
      email: emailInput.value.trim(),
      userId: 1
    };

    const validationPayload = {
      name: payload.title,
      email: payload.email,
      message: payload.body
    };

    if (!validateForm(validationPayload)) {
      renderResponse("is-error", "Validation failed", "Fix the form errors before sending the Fetch API request.", validationPayload);
      return;
    }

    submitButton.disabled = true;
    submitButton.textContent = "Submitting...";
    renderResponse("", "Sending request", "Posting JSON form data to the API...", payload);

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts", {
        method: "POST",
        headers: {
          "Content-Type": "application/json"
        },
        body: JSON.stringify(payload)
      });

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const data = await response.json();

      renderResponse("is-success", "Form submitted", "The API returned a successful JSON response.", data);
      form.reset();
      clearErrors();
    } catch (error) {
      renderResponse("is-error", "Submission failed", error.message, payload);
    } finally {
      submitButton.disabled = false;
      submitButton.textContent = "Submit with Fetch";
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-25-demo"&gt;
  &lt;div class="vb-fetch-25-shell"&gt;
    &lt;div class="vb-fetch-25-header"&gt;
      &lt;span&gt;Example 25&lt;/span&gt;
      &lt;h3&gt;Fetch API Form Submission with Validation&lt;/h3&gt;
      &lt;p&gt;Validate form fields, submit JSON with Fetch API, and show a clean success response.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-25-body"&gt;
      &lt;form class="vb-fetch-25-form" data-vb-fetch-25-form&gt;
        &lt;label&gt;
          Full name
          &lt;input type="text" data-vb-fetch-25-name placeholder="Jane Developer"&gt;
          &lt;small data-vb-fetch-25-error="name"&gt;&lt;/small&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Email address
          &lt;input type="email" data-vb-fetch-25-email placeholder="jane@example.com"&gt;
          &lt;small data-vb-fetch-25-error="email"&gt;&lt;/small&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Message
          &lt;textarea data-vb-fetch-25-message placeholder="Tell us what you need..."&gt;&lt;/textarea&gt;
          &lt;small data-vb-fetch-25-error="message"&gt;&lt;/small&gt;
        &lt;/label&gt;

        &lt;button type="submit" data-vb-fetch-25-submit&gt;Submit with Fetch&lt;/button&gt;
      &lt;/form&gt;

      &lt;div class="vb-fetch-25-response" data-vb-fetch-25-response&gt;
        &lt;span&gt;Waiting&lt;/span&gt;
        &lt;h4&gt;No form submitted yet&lt;/h4&gt;
        &lt;p&gt;Fill the form and send a JSON POST request.&lt;/p&gt;
        &lt;pre&gt;{}&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-25-demo,
.vb-fetch-25-demo * {
  box-sizing: border-box;
}

.vb-fetch-25-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(59, 130, 246, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #faf5ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.16);
  overflow: hidden;
}

.vb-fetch-25-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-25-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #1e3a8a 0%, #2563eb 50%, #9333ea 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-25-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-25-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-25-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #f3e8ff !important;
  -webkit-text-fill-color: #f3e8ff !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-25-body {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
  gap: 22px;
  padding: clamp(20px, 4vw, 34px);
  min-width: 0;
}

.vb-fetch-25-form {
  display: grid;
  gap: 14px;
  min-width: 0;
  padding: 20px;
  border-radius: 24px;
  background: #eff6ff;
  border: 1px solid #bfdbfe;
}

.vb-fetch-25-form label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-25-form input,
.vb-fetch-25-form textarea {
  width: 100%;
  min-width: 0;
  border: 1px solid #bfdbfe;
  border-radius: 16px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-fetch-25-form input {
  min-height: 50px;
  padding: 0 14px;
}

.vb-fetch-25-form textarea {
  min-height: 130px;
  padding: 14px;
  resize: vertical;
}

.vb-fetch-25-form small {
  min-height: 17px;
  color: #dc2626 !important;
  -webkit-text-fill-color: #dc2626 !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 850;
}

.vb-fetch-25-form button {
  min-height: 52px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #9333ea);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.24);
}

.vb-fetch-25-form button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-25-response {
  min-width: 0;
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 14% 12%, rgba(147, 51, 234, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-fetch-25-response.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-fetch-25-response.is-error {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-fetch-25-response span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #e0e7ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-25-response.is-success span {
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-25-response.is-error span {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-25-response h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(26px, 4vw, 42px) !important;
  line-height: 1.05 !important;
  font-weight: 950 !important;
  letter-spacing: -0.05em;
  overflow-wrap: anywhere;
}

.vb-fetch-25-response p {
  margin: 0 0 14px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-25-response pre {
  max-width: 100%;
  max-height: 240px;
  overflow: auto;
  margin: 0 !important;
  padding: 14px;
  border-radius: 16px;
  background: #0f172a;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 13px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-fetch-25-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-fetch-25-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.045em;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API form submission example is useful for contact forms, quote request forms, signup forms, lead forms, support forms, feedback forms, and any JavaScript form that sends JSON data to an API.</p>




<h2 class="wp-block-heading">26. Fetch API File Upload Progress UI</h2>



<p class="wp-block-paragraph"><strong>A file upload UI</strong> is a common API feature for dashboards, profile pages, document portals, support tickets, admin panels, and SaaS tools. Native <code>fetch()</code> does not provide upload progress events in all browsers the same way <code>XMLHttpRequest</code> does, so this demo uses a Fetch-style async upload simulation to show the complete UI workflow safely without sending files to a real server.</p>



<p class="wp-block-paragraph">This example validates the selected file, shows file name and size, animates a progress bar, handles success and error states, and keeps the demo safe because it does not upload anything to your server.</p>



<ul class="wp-block-list">
<li>Fetch-style file upload UI example</li>
<li>File selection and validation</li>
<li>Progress bar interface</li>
<li>Success and error states</li>
<li>Useful for upload forms and dashboard tools</li>
</ul>



<div class="vb-fetch-26-demo">
  <div class="vb-fetch-26-shell">
    <div class="vb-fetch-26-header">
      <span>Example 26</span>
      <h3>Fetch API File Upload Progress UI</h3>
      <p>Select a file, validate it, and simulate a safe API upload progress workflow.</p>
    </div>

    <div class="vb-fetch-26-body">
      <div class="vb-fetch-26-uploader">
        <label class="vb-fetch-26-drop">
          <input type="file" data-vb-fetch-26-file>
          <strong>Choose a file</strong>
          <span>Max 2 MB. Demo does not upload to a server.</span>
        </label>

        <button type="button" data-vb-fetch-26-upload>Start Upload</button>
      </div>

      <div class="vb-fetch-26-status" data-vb-fetch-26-status>
        <span>Waiting</span>
        <h4>No file selected</h4>
        <p>Choose a file to prepare the upload UI.</p>

        <div class="vb-fetch-26-progress">
          <div data-vb-fetch-26-bar></div>
        </div>

        <pre data-vb-fetch-26-output>{}</pre>
      </div>
    </div>
  </div>
</div>

<style>
.vb-fetch-26-demo,
.vb-fetch-26-demo * {
  box-sizing: border-box;
}

.vb-fetch-26-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(20, 184, 166, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdfa 0%, #eff6ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.16);
  overflow: hidden;
}

.vb-fetch-26-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-26-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #115e59 0%, #14b8a6 52%, #2563eb 100%) !important;
}

.vb-fetch-26-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-26-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-26-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-26-body {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: 22px;
  padding: clamp(20px, 4vw, 34px);
  min-width: 0;
}

.vb-fetch-26-uploader {
  display: grid;
  align-content: start;
  gap: 14px;
  min-width: 0;
  padding: 20px;
  border-radius: 24px;
  background: #f0fdfa;
  border: 1px solid #99f6e4;
}

.vb-fetch-26-drop {
  display: grid;
  place-items: center;
  min-height: 220px;
  gap: 10px;
  padding: 24px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 18% 16%, rgba(20, 184, 166, 0.12), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 2px dashed #5eead4;
  text-align: center;
  cursor: pointer;
}

.vb-fetch-26-drop input {
  width: 1px;
  height: 1px;
  opacity: 0;
  position: absolute;
  pointer-events: none;
}

.vb-fetch-26-drop strong {
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 24px;
  line-height: 1.1;
  font-weight: 950;
}

.vb-fetch-26-drop span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 750;
}

.vb-fetch-26-uploader button {
  min-height: 52px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #14b8a6, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(20, 184, 166, 0.22);
}

.vb-fetch-26-uploader button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-26-status {
  min-width: 0;
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 14% 12%, rgba(37, 99, 235, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-fetch-26-status.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-fetch-26-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-fetch-26-status span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-26-status.is-success span {
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-26-status.is-error span {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-26-status h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(28px, 5vw, 48px) !important;
  line-height: 1.02 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
  overflow-wrap: anywhere;
}

.vb-fetch-26-status p {
  margin: 0 0 16px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-26-progress {
  width: 100%;
  height: 16px;
  overflow: hidden;
  margin: 0 0 16px;
  border-radius: 999px;
  background: #e2e8f0;
}

.vb-fetch-26-progress div {
  width: 0%;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(135deg, #14b8a6, #2563eb);
  transition: width 0.25s ease;
}

.vb-fetch-26-status pre {
  max-width: 100%;
  max-height: 220px;
  overflow: auto;
  margin: 0 !important;
  padding: 14px;
  border-radius: 16px;
  background: #0f172a;
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 13px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 860px) {
  .vb-fetch-26-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-fetch-26-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.045em;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-26-demo");
  if (!demo) return;

  const fileInput = demo.querySelector("[data-vb-fetch-26-file]");
  const uploadButton = demo.querySelector("[data-vb-fetch-26-upload]");
  const statusBox = demo.querySelector("[data-vb-fetch-26-status]");
  const progressBar = demo.querySelector("[data-vb-fetch-26-bar]");
  const output = demo.querySelector("[data-vb-fetch-26-output]");

  let selectedFile = null;
  let uploading = false;

  function formatSize(bytes) {
    if (bytes < 1024) return bytes + " B";
    if (bytes < 1024 * 1024) return Math.round(bytes / 1024) + " KB";
    return (bytes / 1024 / 1024).toFixed(2) + " MB";
  }

  function setStatus(type, label, title, message, data, progress) {
    statusBox.className = "vb-fetch-26-status";

    if (type) {
      statusBox.classList.add(type);
    }

    statusBox.querySelector("span").textContent = label;
    statusBox.querySelector("h4").textContent = title;
    statusBox.querySelector("p").textContent = message;
    output.textContent = JSON.stringify(data || {}, null, 2);
    progressBar.style.width = (progress || 0) + "%";
  }

  function validateFile(file) {
    if (!file) {
      return "Choose a file first.";
    }

    if (file.size > 2 * 1024 * 1024) {
      return "File is too large. Maximum size is 2 MB.";
    }

    return "";
  }

  fileInput.addEventListener("change", function () {
    selectedFile = fileInput.files[0] || null;
    const error = validateFile(selectedFile);

    if (error) {
      setStatus("is-error", "Invalid", "File not accepted", error, {}, 0);
      return;
    }

    setStatus(
      "",
      "Selected",
      selectedFile.name,
      "Ready to simulate upload. File size: " + formatSize(selectedFile.size) + ".",
      {
        name: selectedFile.name,
        type: selectedFile.type || "unknown",
        size: formatSize(selectedFile.size)
      },
      0
    );
  });

  uploadButton.addEventListener("click", function () {
    if (uploading) return;

    const error = validateFile(selectedFile);

    if (error) {
      setStatus("is-error", "Error", "Upload blocked", error, {}, 0);
      return;
    }

    uploading = true;
    uploadButton.disabled = true;
    uploadButton.textContent = "Uploading...";

    let progress = 0;

    setStatus(
      "",
      "Uploading",
      selectedFile.name,
      "Simulating Fetch-style file upload progress...",
      {
        name: selectedFile.name,
        size: formatSize(selectedFile.size),
        note: "Demo only. No file is sent to a server."
      },
      progress
    );

    const timer = setInterval(function () {
      progress += Math.floor(Math.random() * 16) + 8;

      if (progress >= 100) {
        progress = 100;
        clearInterval(timer);

        setStatus(
          "is-success",
          "Complete",
          "Upload UI completed",
          "The file upload workflow finished successfully in the demo UI.",
          {
            file: selectedFile.name,
            uploaded: true,
            progress: "100%",
            server: "No real server upload in this safe demo"
          },
          progress
        );

        uploading = false;
        uploadButton.disabled = false;
        uploadButton.textContent = "Start Upload";
        return;
      }

      setStatus(
        "",
        "Uploading",
        selectedFile.name,
        "Upload progress: " + progress + "%",
        {
          file: selectedFile.name,
          progress: progress + "%"
        },
        progress
      );
    }, 280);
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-26-demo");
  if (!demo) return;

  const fileInput = demo.querySelector("[data-vb-fetch-26-file]");
  const uploadButton = demo.querySelector("[data-vb-fetch-26-upload]");
  const statusBox = demo.querySelector("[data-vb-fetch-26-status]");
  const progressBar = demo.querySelector("[data-vb-fetch-26-bar]");
  const output = demo.querySelector("[data-vb-fetch-26-output]");

  let selectedFile = null;
  let uploading = false;

  function formatSize(bytes) {
    if (bytes &lt; 1024) return bytes + " B";
    if (bytes &lt; 1024 * 1024) return Math.round(bytes / 1024) + " KB";
    return (bytes / 1024 / 1024).toFixed(2) + " MB";
  }

  function setStatus(type, label, title, message, data, progress) {
    statusBox.className = "vb-fetch-26-status";

    if (type) {
      statusBox.classList.add(type);
    }

    statusBox.querySelector("span").textContent = label;
    statusBox.querySelector("h4").textContent = title;
    statusBox.querySelector("p").textContent = message;
    output.textContent = JSON.stringify(data || {}, null, 2);
    progressBar.style.width = (progress || 0) + "%";
  }

  function validateFile(file) {
    if (!file) {
      return "Choose a file first.";
    }

    if (file.size &gt; 2 * 1024 * 1024) {
      return "File is too large. Maximum size is 2 MB.";
    }

    return "";
  }

  fileInput.addEventListener("change", function () {
    selectedFile = fileInput.files[0] || null;
    const error = validateFile(selectedFile);

    if (error) {
      setStatus("is-error", "Invalid", "File not accepted", error, {}, 0);
      return;
    }

    setStatus(
      "",
      "Selected",
      selectedFile.name,
      "Ready to simulate upload. File size: " + formatSize(selectedFile.size) + ".",
      {
        name: selectedFile.name,
        type: selectedFile.type || "unknown",
        size: formatSize(selectedFile.size)
      },
      0
    );
  });

  uploadButton.addEventListener("click", function () {
    if (uploading) return;

    const error = validateFile(selectedFile);

    if (error) {
      setStatus("is-error", "Error", "Upload blocked", error, {}, 0);
      return;
    }

    uploading = true;
    uploadButton.disabled = true;
    uploadButton.textContent = "Uploading...";

    let progress = 0;

    setStatus(
      "",
      "Uploading",
      selectedFile.name,
      "Simulating Fetch-style file upload progress...",
      {
        name: selectedFile.name,
        size: formatSize(selectedFile.size),
        note: "Demo only. No file is sent to a server."
      },
      progress
    );

    const timer = setInterval(function () {
      progress += Math.floor(Math.random() * 16) + 8;

      if (progress &gt;= 100) {
        progress = 100;
        clearInterval(timer);

        setStatus(
          "is-success",
          "Complete",
          "Upload UI completed",
          "The file upload workflow finished successfully in the demo UI.",
          {
            file: selectedFile.name,
            uploaded: true,
            progress: "100%",
            server: "No real server upload in this safe demo"
          },
          progress
        );

        uploading = false;
        uploadButton.disabled = false;
        uploadButton.textContent = "Start Upload";
        return;
      }

      setStatus(
        "",
        "Uploading",
        selectedFile.name,
        "Upload progress: " + progress + "%",
        {
          file: selectedFile.name,
          progress: progress + "%"
        },
        progress
      );
    }, 280);
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-26-demo"&gt;
  &lt;div class="vb-fetch-26-shell"&gt;
    &lt;div class="vb-fetch-26-header"&gt;
      &lt;span&gt;Example 26&lt;/span&gt;
      &lt;h3&gt;Fetch API File Upload Progress UI&lt;/h3&gt;
      &lt;p&gt;Select a file, validate it, and simulate a safe API upload progress workflow.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-26-body"&gt;
      &lt;div class="vb-fetch-26-uploader"&gt;
        &lt;label class="vb-fetch-26-drop"&gt;
          &lt;input type="file" data-vb-fetch-26-file&gt;
          &lt;strong&gt;Choose a file&lt;/strong&gt;
          &lt;span&gt;Max 2 MB. Demo does not upload to a server.&lt;/span&gt;
        &lt;/label&gt;

        &lt;button type="button" data-vb-fetch-26-upload&gt;Start Upload&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-fetch-26-status" data-vb-fetch-26-status&gt;
        &lt;span&gt;Waiting&lt;/span&gt;
        &lt;h4&gt;No file selected&lt;/h4&gt;
        &lt;p&gt;Choose a file to prepare the upload UI.&lt;/p&gt;

        &lt;div class="vb-fetch-26-progress"&gt;
          &lt;div data-vb-fetch-26-bar&gt;&lt;/div&gt;
        &lt;/div&gt;

        &lt;pre data-vb-fetch-26-output&gt;{}&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-26-demo,
.vb-fetch-26-demo * {
  box-sizing: border-box;
}

.vb-fetch-26-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(20, 184, 166, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdfa 0%, #eff6ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.16);
  overflow: hidden;
}

.vb-fetch-26-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-26-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #115e59 0%, #14b8a6 52%, #2563eb 100%) !important;
}

.vb-fetch-26-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-26-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-26-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-26-body {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: 22px;
  padding: clamp(20px, 4vw, 34px);
  min-width: 0;
}

.vb-fetch-26-uploader {
  display: grid;
  align-content: start;
  gap: 14px;
  min-width: 0;
  padding: 20px;
  border-radius: 24px;
  background: #f0fdfa;
  border: 1px solid #99f6e4;
}

.vb-fetch-26-drop {
  display: grid;
  place-items: center;
  min-height: 220px;
  gap: 10px;
  padding: 24px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 18% 16%, rgba(20, 184, 166, 0.12), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 2px dashed #5eead4;
  text-align: center;
  cursor: pointer;
}

.vb-fetch-26-drop input {
  width: 1px;
  height: 1px;
  opacity: 0;
  position: absolute;
  pointer-events: none;
}

.vb-fetch-26-drop strong {
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 24px;
  line-height: 1.1;
  font-weight: 950;
}

.vb-fetch-26-drop span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 750;
}

.vb-fetch-26-uploader button {
  min-height: 52px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #14b8a6, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(20, 184, 166, 0.22);
}

.vb-fetch-26-uploader button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-26-status {
  min-width: 0;
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 14% 12%, rgba(37, 99, 235, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-fetch-26-status.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-fetch-26-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-fetch-26-status span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-26-status.is-success span {
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-26-status.is-error span {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-26-status h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(28px, 5vw, 48px) !important;
  line-height: 1.02 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
  overflow-wrap: anywhere;
}

.vb-fetch-26-status p {
  margin: 0 0 16px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-26-progress {
  width: 100%;
  height: 16px;
  overflow: hidden;
  margin: 0 0 16px;
  border-radius: 999px;
  background: #e2e8f0;
}

.vb-fetch-26-progress div {
  width: 0%;
  height: 100%;
  border-radius: 999px;
  background: linear-gradient(135deg, #14b8a6, #2563eb);
  transition: width 0.25s ease;
}

.vb-fetch-26-status pre {
  max-width: 100%;
  max-height: 220px;
  overflow: auto;
  margin: 0 !important;
  padding: 14px;
  border-radius: 16px;
  background: #0f172a;
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 13px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 860px) {
  .vb-fetch-26-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-fetch-26-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.045em;
  }
}</pre>



<p class="wp-block-paragraph">This file upload progress UI example is useful for upload forms, profile image uploaders, document portals, support ticket attachments, admin dashboards, client portals, and SaaS file management interfaces.</p>




<h2 class="wp-block-heading">27. Fetch API Cache with LocalStorage</h2>



<p class="wp-block-paragraph"><strong>Fetch API caching with localStorage</strong> helps reduce repeated API requests and makes small interfaces feel faster. JavaScript can save API data locally, reuse it for a limited time, and refresh it when the cache expires or when the user clicks a refresh button.</p>



<p class="wp-block-paragraph">This example loads posts from an API, stores the response in <code>localStorage</code> with a timestamp, shows whether data came from cache or network, and lets users clear or refresh the cache manually.</p>



<ul class="wp-block-list">
<li>Fetch API cache with localStorage</li>
<li>Save API response locally</li>
<li>Cache expiry timestamp</li>
<li>Manual refresh and clear cache actions</li>
<li>Useful for widgets, dashboards, and repeated API data</li>
</ul>



<div class="vb-fetch-27-demo">
  <div class="vb-fetch-27-shell">
    <div class="vb-fetch-27-header">
      <span>Example 27</span>
      <h3>Fetch API Cache with LocalStorage</h3>
      <p>Cache API results locally, reuse fresh data, and refresh the cache when needed.</p>
    </div>

    <div class="vb-fetch-27-toolbar">
      <button type="button" data-vb-fetch-27-load>Load Cached Data</button>
      <button type="button" data-vb-fetch-27-refresh>Force Refresh</button>
      <button type="button" data-vb-fetch-27-clear>Clear Cache</button>
    </div>

    <div class="vb-fetch-27-status" data-vb-fetch-27-status>
      Cache is ready. Click load to check localStorage first.
    </div>

    <div class="vb-fetch-27-grid" data-vb-fetch-27-grid></div>
  </div>
</div>

<style>
.vb-fetch-27-demo,
.vb-fetch-27-demo * {
  box-sizing: border-box;
}

.vb-fetch-27-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 197, 94, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #f0f9ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.16);
  overflow: hidden;
}

.vb-fetch-27-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-27-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #14532d 0%, #16a34a 52%, #0284c7 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-27-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-27-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-27-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-27-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
}

.vb-fetch-27-toolbar button {
  min-height: 50px;
  padding: 0 18px;
  border: 0;
  border-radius: 999px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-fetch-27-toolbar button:nth-child(1) {
  background: linear-gradient(135deg, #16a34a, #0284c7);
  box-shadow: 0 16px 38px rgba(34, 197, 94, 0.20);
}

.vb-fetch-27-toolbar button:nth-child(2) {
  background: linear-gradient(135deg, #2563eb, #7c3aed);
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.20);
}

.vb-fetch-27-toolbar button:nth-child(3) {
  background: linear-gradient(135deg, #dc2626, #f97316);
  box-shadow: 0 16px 38px rgba(220, 38, 38, 0.18);
}

.vb-fetch-27-toolbar button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-27-status {
  margin: 16px clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #f0fdf4;
  border: 1px solid #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-27-status.is-network {
  background: #eff6ff;
  border-color: #bfdbfe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
}

.vb-fetch-27-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-27-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-27-card {
  min-width: 0;
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(34, 197, 94, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-fetch-27-card span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-27-card h4 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-27-card p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 980px) {
  .vb-fetch-27-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 700px) {
  .vb-fetch-27-grid {
    grid-template-columns: 1fr;
  }

  .vb-fetch-27-toolbar button {
    width: 100%;
  }
}

@media (max-width: 640px) {
  .vb-fetch-27-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.045em;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-27-demo");
  if (!demo) return;

  const loadButton = demo.querySelector("[data-vb-fetch-27-load]");
  const refreshButton = demo.querySelector("[data-vb-fetch-27-refresh]");
  const clearButton = demo.querySelector("[data-vb-fetch-27-clear]");
  const status = demo.querySelector("[data-vb-fetch-27-status]");
  const grid = demo.querySelector("[data-vb-fetch-27-grid]");

  const cacheKey = "vb_fetch_27_posts_cache";
  const cacheTimeKey = "vb_fetch_27_posts_cache_time";
  const maxAge = 60 * 1000;

  function setStatus(text, type) {
    status.className = "vb-fetch-27-status";

    if (type) {
      status.classList.add(type);
    }

    status.textContent = text;
  }

  function setButtons(disabled) {
    loadButton.disabled = disabled;
    refreshButton.disabled = disabled;
    clearButton.disabled = disabled;
  }

  function renderPosts(posts) {
    grid.innerHTML = posts.slice(0, 6).map(function (post) {
      return (
        '<article class="vb-fetch-27-card">' +
          '<span>Post #' + post.id + '</span>' +
          '<h4>' + post.title + '</h4>' +
          '<p>' + post.body + '</p>' +
        '</article>'
      );
    }).join("");
  }

  function getCachedPosts() {
    const cached = localStorage.getItem(cacheKey);
    const cachedTime = Number(localStorage.getItem(cacheTimeKey) || 0);
    const fresh = cached && Date.now() - cachedTime < maxAge;

    if (!fresh) {
      return null;
    }

    return {
      posts: JSON.parse(cached),
      age: Math.round((Date.now() - cachedTime) / 1000)
    };
  }

  async function fetchPostsFromNetwork() {
    const response = await fetch("https://jsonplaceholder.typicode.com/posts?_limit=6");

    if (!response.ok) {
      throw new Error("HTTP status " + response.status);
    }

    const posts = await response.json();

    localStorage.setItem(cacheKey, JSON.stringify(posts));
    localStorage.setItem(cacheTimeKey, String(Date.now()));

    return posts;
  }

  async function loadPosts(forceRefresh) {
    setButtons(true);
    grid.innerHTML = "";

    try {
      if (!forceRefresh) {
        const cached = getCachedPosts();

        if (cached) {
          renderPosts(cached.posts);
          setStatus("Loaded from localStorage cache. Cache age: " + cached.age + " seconds.", "");
          setButtons(false);
          return;
        }
      }

      setStatus("Fetching fresh data from network and updating cache...", "is-network");
      const posts = await fetchPostsFromNetwork();
      renderPosts(posts);
      setStatus("Loaded fresh API data and saved it to localStorage cache.", "is-network");
    } catch (error) {
      setStatus("Cache workflow failed: " + error.message, "is-error");
    } finally {
      setButtons(false);
    }
  }

  loadButton.addEventListener("click", function () {
    loadPosts(false);
  });

  refreshButton.addEventListener("click", function () {
    loadPosts(true);
  });

  clearButton.addEventListener("click", function () {
    localStorage.removeItem(cacheKey);
    localStorage.removeItem(cacheTimeKey);
    grid.innerHTML = "";
    setStatus("Cache cleared. Next load will fetch fresh API data.", "is-network");
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-27-demo");
  if (!demo) return;

  const loadButton = demo.querySelector("[data-vb-fetch-27-load]");
  const refreshButton = demo.querySelector("[data-vb-fetch-27-refresh]");
  const clearButton = demo.querySelector("[data-vb-fetch-27-clear]");
  const status = demo.querySelector("[data-vb-fetch-27-status]");
  const grid = demo.querySelector("[data-vb-fetch-27-grid]");

  const cacheKey = "vb_fetch_27_posts_cache";
  const cacheTimeKey = "vb_fetch_27_posts_cache_time";
  const maxAge = 60 * 1000;

  function setStatus(text, type) {
    status.className = "vb-fetch-27-status";

    if (type) {
      status.classList.add(type);
    }

    status.textContent = text;
  }

  function setButtons(disabled) {
    loadButton.disabled = disabled;
    refreshButton.disabled = disabled;
    clearButton.disabled = disabled;
  }

  function renderPosts(posts) {
    grid.innerHTML = posts.slice(0, 6).map(function (post) {
      return (
        '&lt;article class="vb-fetch-27-card"&gt;' +
          '&lt;span&gt;Post #' + post.id + '&lt;/span&gt;' +
          '&lt;h4&gt;' + post.title + '&lt;/h4&gt;' +
          '&lt;p&gt;' + post.body + '&lt;/p&gt;' +
        '&lt;/article&gt;'
      );
    }).join("");
  }

  function getCachedPosts() {
    const cached = localStorage.getItem(cacheKey);
    const cachedTime = Number(localStorage.getItem(cacheTimeKey) || 0);
    const fresh = cached && Date.now() - cachedTime &lt; maxAge;

    if (!fresh) {
      return null;
    }

    return {
      posts: JSON.parse(cached),
      age: Math.round((Date.now() - cachedTime) / 1000)
    };
  }

  async function fetchPostsFromNetwork() {
    const response = await fetch("https://jsonplaceholder.typicode.com/posts?_limit=6");

    if (!response.ok) {
      throw new Error("HTTP status " + response.status);
    }

    const posts = await response.json();

    localStorage.setItem(cacheKey, JSON.stringify(posts));
    localStorage.setItem(cacheTimeKey, String(Date.now()));

    return posts;
  }

  async function loadPosts(forceRefresh) {
    setButtons(true);
    grid.innerHTML = "";

    try {
      if (!forceRefresh) {
        const cached = getCachedPosts();

        if (cached) {
          renderPosts(cached.posts);
          setStatus("Loaded from localStorage cache. Cache age: " + cached.age + " seconds.", "");
          setButtons(false);
          return;
        }
      }

      setStatus("Fetching fresh data from network and updating cache...", "is-network");
      const posts = await fetchPostsFromNetwork();
      renderPosts(posts);
      setStatus("Loaded fresh API data and saved it to localStorage cache.", "is-network");
    } catch (error) {
      setStatus("Cache workflow failed: " + error.message, "is-error");
    } finally {
      setButtons(false);
    }
  }

  loadButton.addEventListener("click", function () {
    loadPosts(false);
  });

  refreshButton.addEventListener("click", function () {
    loadPosts(true);
  });

  clearButton.addEventListener("click", function () {
    localStorage.removeItem(cacheKey);
    localStorage.removeItem(cacheTimeKey);
    grid.innerHTML = "";
    setStatus("Cache cleared. Next load will fetch fresh API data.", "is-network");
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-27-demo"&gt;
  &lt;div class="vb-fetch-27-shell"&gt;
    &lt;div class="vb-fetch-27-header"&gt;
      &lt;span&gt;Example 27&lt;/span&gt;
      &lt;h3&gt;Fetch API Cache with LocalStorage&lt;/h3&gt;
      &lt;p&gt;Cache API results locally, reuse fresh data, and refresh the cache when needed.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-27-toolbar"&gt;
      &lt;button type="button" data-vb-fetch-27-load&gt;Load Cached Data&lt;/button&gt;
      &lt;button type="button" data-vb-fetch-27-refresh&gt;Force Refresh&lt;/button&gt;
      &lt;button type="button" data-vb-fetch-27-clear&gt;Clear Cache&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-27-status" data-vb-fetch-27-status&gt;
      Cache is ready. Click load to check localStorage first.
    &lt;/div&gt;

    &lt;div class="vb-fetch-27-grid" data-vb-fetch-27-grid&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-27-demo,
.vb-fetch-27-demo * {
  box-sizing: border-box;
}

.vb-fetch-27-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 197, 94, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #f0f9ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.16);
  overflow: hidden;
}

.vb-fetch-27-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-27-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #14532d 0%, #16a34a 52%, #0284c7 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-27-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-27-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-27-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-27-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
}

.vb-fetch-27-toolbar button {
  min-height: 50px;
  padding: 0 18px;
  border: 0;
  border-radius: 999px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-fetch-27-toolbar button:nth-child(1) {
  background: linear-gradient(135deg, #16a34a, #0284c7);
  box-shadow: 0 16px 38px rgba(34, 197, 94, 0.20);
}

.vb-fetch-27-toolbar button:nth-child(2) {
  background: linear-gradient(135deg, #2563eb, #7c3aed);
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.20);
}

.vb-fetch-27-toolbar button:nth-child(3) {
  background: linear-gradient(135deg, #dc2626, #f97316);
  box-shadow: 0 16px 38px rgba(220, 38, 38, 0.18);
}

.vb-fetch-27-toolbar button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-27-status {
  margin: 16px clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #f0fdf4;
  border: 1px solid #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-27-status.is-network {
  background: #eff6ff;
  border-color: #bfdbfe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
}

.vb-fetch-27-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-27-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-27-card {
  min-width: 0;
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(34, 197, 94, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-fetch-27-card span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-27-card h4 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-27-card p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
  overflow-wrap: anywhere;
}

@media (max-width: 980px) {
  .vb-fetch-27-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 700px) {
  .vb-fetch-27-grid {
    grid-template-columns: 1fr;
  }

  .vb-fetch-27-toolbar button {
    width: 100%;
  }
}

@media (max-width: 640px) {
  .vb-fetch-27-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.045em;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API localStorage cache example is useful for dashboards, small widgets, repeated API data, blog previews, product previews, user panels, settings pages, and frontend apps where cached API data improves speed.</p>



<h2 class="wp-block-heading">28. Fetch API JSON Error Handling</h2>



<p class="wp-block-paragraph"><strong>Fetch API JSON error handling</strong> is important because a request can fail in more than one way. The server can return an HTTP error, the response can contain invalid JSON, the network can fail, or the API can return a custom error object.</p>



<p class="wp-block-paragraph">This example lets users test success, HTTP error, invalid JSON, and API error states. It uses <code>try...catch</code>, checks <code>response.ok</code>, safely parses JSON, and shows a readable UI message for each failure type.</p>



<ul class="wp-block-list">
<li>Fetch API error handling example</li>
<li>Handle HTTP errors</li>
<li>Handle invalid JSON safely</li>
<li>Handle API error objects</li>
<li>Useful for production-ready API interfaces</li>
</ul>



<div class="vb-fetch-28-demo">
  <div class="vb-fetch-28-shell">
    <div class="vb-fetch-28-header">
      <span>Example 28</span>
      <h3>Fetch API JSON Error Handling</h3>
      <p>Test different API response states and show clean user-friendly error messages.</p>
    </div>

    <div class="vb-fetch-28-buttons">
      <button type="button" data-vb-fetch-28-mode="success">Success JSON</button>
      <button type="button" data-vb-fetch-28-mode="http">HTTP Error</button>
      <button type="button" data-vb-fetch-28-mode="invalid">Invalid JSON</button>
      <button type="button" data-vb-fetch-28-mode="api">API Error Object</button>
    </div>

    <div class="vb-fetch-28-result" data-vb-fetch-28-result>
      <span>Waiting</span>
      <h4>No request tested yet</h4>
      <p>Choose a response type to test Fetch API error handling.</p>
      <pre>{}</pre>
    </div>
  </div>
</div>

<style>
.vb-fetch-28-demo,
.vb-fetch-28-demo * {
  box-sizing: border-box;
}

.vb-fetch-28-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(239, 68, 68, 0.14), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #fef2f2 0%, #eff6ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(239, 68, 68, 0.15);
  overflow: hidden;
}

.vb-fetch-28-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-28-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #7f1d1d 0%, #ef4444 48%, #2563eb 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-28-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-28-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-28-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-28-buttons {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
}

.vb-fetch-28-buttons button {
  min-height: 50px;
  padding: 0 14px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #ef4444, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(239, 68, 68, 0.18);
}

.vb-fetch-28-buttons button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-28-result {
  min-width: 0;
  margin: clamp(20px, 4vw, 34px);
  padding: clamp(20px, 4vw, 32px);
  border-radius: 28px;
  background:
    radial-gradient(circle at 14% 12%, rgba(59, 130, 246, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.08);
}

.vb-fetch-28-result.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-fetch-28-result.is-error {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-fetch-28-result span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 8px 11px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-28-result.is-success span {
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-28-result.is-error span {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-28-result h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(30px, 5vw, 52px) !important;
  line-height: 1.02 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
  overflow-wrap: anywhere;
}

.vb-fetch-28-result p {
  max-width: 780px;
  margin: 0 0 16px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.65;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-28-result pre {
  max-width: 100%;
  max-height: 260px;
  overflow: auto;
  margin: 0 !important;
  padding: 14px;
  border-radius: 16px;
  background: #0f172a;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 13px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-fetch-28-buttons {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-fetch-28-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-28-buttons {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-28-demo");
  if (!demo) return;

  const buttons = demo.querySelectorAll("[data-vb-fetch-28-mode]");
  const result = demo.querySelector("[data-vb-fetch-28-result]");

  function fakeResponse(mode) {
    return new Promise(function (resolve) {
      setTimeout(function () {
        if (mode === "success") {
          resolve({
            ok: true,
            status: 200,
            text: function () {
              return Promise.resolve(JSON.stringify({
                id: 28,
                status: "success",
                message: "Valid JSON response parsed successfully."
              }));
            }
          });
          return;
        }

        if (mode === "http") {
          resolve({
            ok: false,
            status: 500,
            text: function () {
              return Promise.resolve(JSON.stringify({
                error: "Internal server error",
                code: "SERVER_ERROR"
              }));
            }
          });
          return;
        }

        if (mode === "invalid") {
          resolve({
            ok: true,
            status: 200,
            text: function () {
              return Promise.resolve("{ invalid json response");
            }
          });
          return;
        }

        resolve({
          ok: true,
          status: 200,
          text: function () {
            return Promise.resolve(JSON.stringify({
              success: false,
              error: "API rejected the request",
              field: "email"
            }));
          }
        });
      }, 700);
    });
  }

  async function safeJson(response) {
    const text = await response.text();

    try {
      return {
        data: JSON.parse(text),
        raw: text
      };
    } catch (error) {
      throw new Error("Invalid JSON response: " + error.message);
    }
  }

  function render(type, label, title, message, data) {
    result.className = "vb-fetch-28-result";

    if (type) {
      result.classList.add(type);
    }

    result.innerHTML =
      '<span>' + label + '</span>' +
      '<h4>' + title + '</h4>' +
      '<p>' + message + '</p>' +
      '<pre>' + JSON.stringify(data || {}, null, 2) + '</pre>';
  }

  async function runMode(mode) {
    buttons.forEach(function (button) {
      button.disabled = true;
    });

    render("", "Loading", "Checking response", "Testing the " + mode + " response mode...", {
      mode: mode
    });

    try {
      const response = await fakeResponse(mode);
      const parsed = await safeJson(response);

      if (!response.ok) {
        throw new Error("HTTP " + response.status + ": " + (parsed.data.error || "Request failed"));
      }

      if (parsed.data.success === false) {
        throw new Error(parsed.data.error || "API returned a custom error object");
      }

      render("is-success", "Success", "JSON handled correctly", "The response was parsed and accepted.", parsed.data);
    } catch (error) {
      render("is-error", "Error", "Request handled safely", error.message, {
        mode: mode,
        error: error.message
      });
    } finally {
      buttons.forEach(function (button) {
        button.disabled = false;
      });
    }
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      runMode(button.dataset.vbFetch28Mode);
    });
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-28-demo");
  if (!demo) return;

  const buttons = demo.querySelectorAll("[data-vb-fetch-28-mode]");
  const result = demo.querySelector("[data-vb-fetch-28-result]");

  function fakeResponse(mode) {
    return new Promise(function (resolve) {
      setTimeout(function () {
        if (mode === "success") {
          resolve({
            ok: true,
            status: 200,
            text: function () {
              return Promise.resolve(JSON.stringify({
                id: 28,
                status: "success",
                message: "Valid JSON response parsed successfully."
              }));
            }
          });
          return;
        }

        if (mode === "http") {
          resolve({
            ok: false,
            status: 500,
            text: function () {
              return Promise.resolve(JSON.stringify({
                error: "Internal server error",
                code: "SERVER_ERROR"
              }));
            }
          });
          return;
        }

        if (mode === "invalid") {
          resolve({
            ok: true,
            status: 200,
            text: function () {
              return Promise.resolve("{ invalid json response");
            }
          });
          return;
        }

        resolve({
          ok: true,
          status: 200,
          text: function () {
            return Promise.resolve(JSON.stringify({
              success: false,
              error: "API rejected the request",
              field: "email"
            }));
          }
        });
      }, 700);
    });
  }

  async function safeJson(response) {
    const text = await response.text();

    try {
      return {
        data: JSON.parse(text),
        raw: text
      };
    } catch (error) {
      throw new Error("Invalid JSON response: " + error.message);
    }
  }

  function render(type, label, title, message, data) {
    result.className = "vb-fetch-28-result";

    if (type) {
      result.classList.add(type);
    }

    result.innerHTML =
      '&lt;span&gt;' + label + '&lt;/span&gt;' +
      '&lt;h4&gt;' + title + '&lt;/h4&gt;' +
      '&lt;p&gt;' + message + '&lt;/p&gt;' +
      '&lt;pre&gt;' + JSON.stringify(data || {}, null, 2) + '&lt;/pre&gt;';
  }

  async function runMode(mode) {
    buttons.forEach(function (button) {
      button.disabled = true;
    });

    render("", "Loading", "Checking response", "Testing the " + mode + " response mode...", {
      mode: mode
    });

    try {
      const response = await fakeResponse(mode);
      const parsed = await safeJson(response);

      if (!response.ok) {
        throw new Error("HTTP " + response.status + ": " + (parsed.data.error || "Request failed"));
      }

      if (parsed.data.success === false) {
        throw new Error(parsed.data.error || "API returned a custom error object");
      }

      render("is-success", "Success", "JSON handled correctly", "The response was parsed and accepted.", parsed.data);
    } catch (error) {
      render("is-error", "Error", "Request handled safely", error.message, {
        mode: mode,
        error: error.message
      });
    } finally {
      buttons.forEach(function (button) {
        button.disabled = false;
      });
    }
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      runMode(button.dataset.vbFetch28Mode);
    });
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-28-demo"&gt;
  &lt;div class="vb-fetch-28-shell"&gt;
    &lt;div class="vb-fetch-28-header"&gt;
      &lt;span&gt;Example 28&lt;/span&gt;
      &lt;h3&gt;Fetch API JSON Error Handling&lt;/h3&gt;
      &lt;p&gt;Test different API response states and show clean user-friendly error messages.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-28-buttons"&gt;
      &lt;button type="button" data-vb-fetch-28-mode="success"&gt;Success JSON&lt;/button&gt;
      &lt;button type="button" data-vb-fetch-28-mode="http"&gt;HTTP Error&lt;/button&gt;
      &lt;button type="button" data-vb-fetch-28-mode="invalid"&gt;Invalid JSON&lt;/button&gt;
      &lt;button type="button" data-vb-fetch-28-mode="api"&gt;API Error Object&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-28-result" data-vb-fetch-28-result&gt;
      &lt;span&gt;Waiting&lt;/span&gt;
      &lt;h4&gt;No request tested yet&lt;/h4&gt;
      &lt;p&gt;Choose a response type to test Fetch API error handling.&lt;/p&gt;
      &lt;pre&gt;{}&lt;/pre&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-28-demo,
.vb-fetch-28-demo * {
  box-sizing: border-box;
}

.vb-fetch-28-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(239, 68, 68, 0.14), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #fef2f2 0%, #eff6ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(239, 68, 68, 0.15);
  overflow: hidden;
}

.vb-fetch-28-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-28-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #7f1d1d 0%, #ef4444 48%, #2563eb 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-28-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-28-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-28-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-28-buttons {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
}

.vb-fetch-28-buttons button {
  min-height: 50px;
  padding: 0 14px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #ef4444, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(239, 68, 68, 0.18);
}

.vb-fetch-28-buttons button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-28-result {
  min-width: 0;
  margin: clamp(20px, 4vw, 34px);
  padding: clamp(20px, 4vw, 32px);
  border-radius: 28px;
  background:
    radial-gradient(circle at 14% 12%, rgba(59, 130, 246, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.08);
}

.vb-fetch-28-result.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-fetch-28-result.is-error {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-fetch-28-result span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 8px 11px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-28-result.is-success span {
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-28-result.is-error span {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-28-result h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(30px, 5vw, 52px) !important;
  line-height: 1.02 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
  overflow-wrap: anywhere;
}

.vb-fetch-28-result p {
  max-width: 780px;
  margin: 0 0 16px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.65;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-28-result pre {
  max-width: 100%;
  max-height: 260px;
  overflow: auto;
  margin: 0 !important;
  padding: 14px;
  border-radius: 16px;
  background: #0f172a;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 13px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-fetch-28-buttons {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-fetch-28-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.045em;
  }

  .vb-fetch-28-buttons {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API JSON error handling example is useful for production API forms, dashboards, widgets, checkout actions, admin panels, integrations, and any JavaScript interface that needs reliable error messages.</p>




<h2 class="wp-block-heading">29. Fetch API Authentication Header Example</h2>



<p class="wp-block-paragraph"><strong>Fetch API authentication headers</strong> are used when JavaScript needs to send a token, API key, session value, or authorization string with a request. In real projects, secrets should be stored securely on the backend, but frontend demos can still show how headers are attached to a request.</p>



<p class="wp-block-paragraph">This example builds a safe demo request with an authorization header, shows the generated header preview, masks the token in the UI, and sends a public API request. The token is fake and only used to demonstrate the structure.</p>



<ul class="wp-block-list">
<li>Fetch API authentication header example</li>
<li>Authorization Bearer token structure</li>
<li>Custom request headers</li>
<li>Masked token preview</li>
<li>Useful for protected API workflows</li>
</ul>



<div class="vb-fetch-29-demo">
  <div class="vb-fetch-29-shell">
    <div class="vb-fetch-29-header">
      <span>Example 29</span>
      <h3>Fetch API Authentication Header</h3>
      <p>Send a request with a demo authorization header and display a safe masked token preview.</p>
    </div>

    <div class="vb-fetch-29-body">
      <div class="vb-fetch-29-form">
        <label>
          Demo bearer token
          <input type="text" value="demo_token_123456789" data-vb-fetch-29-token>
        </label>

        <label>
          Custom client name
          <input type="text" value="website-demo-client" data-vb-fetch-29-client>
        </label>

        <button type="button" data-vb-fetch-29-send>Send Auth Request</button>
      </div>

      <div class="vb-fetch-29-result" data-vb-fetch-29-result>
        <span>Waiting</span>
        <h4>No auth request sent</h4>
        <p>Enter a demo token and send a request with custom headers.</p>
        <pre>{}</pre>
      </div>
    </div>
  </div>
</div>

<style>
.vb-fetch-29-demo,
.vb-fetch-29-demo * {
  box-sizing: border-box;
}

.vb-fetch-29-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(15, 23, 42, 0.12), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(99, 102, 241, 0.17), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #eef2ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(15, 23, 42, 0.10);
  overflow: hidden;
}

.vb-fetch-29-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-29-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.12), transparent 34%),
    linear-gradient(135deg, #020617 0%, #334155 45%, #4f46e5 100%) !important;
}

.vb-fetch-29-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e2e8f0 !important;
  -webkit-text-fill-color: #e2e8f0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-29-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-29-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-29-body {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 22px;
  padding: clamp(20px, 4vw, 34px);
  min-width: 0;
}

.vb-fetch-29-form {
  display: grid;
  align-content: start;
  gap: 14px;
  min-width: 0;
  padding: 20px;
  border-radius: 24px;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
}

.vb-fetch-29-form label {
  display: grid;
  gap: 8px;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-29-form input {
  width: 100%;
  min-width: 0;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid #cbd5e1;
  border-radius: 18px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 800;
  outline: none;
}

.vb-fetch-29-form button {
  min-height: 52px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #334155, #4f46e5);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(51, 65, 85, 0.22);
}

.vb-fetch-29-form button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-29-result {
  min-width: 0;
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 14% 12%, rgba(79, 70, 229, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-fetch-29-result.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-fetch-29-result.is-error {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-fetch-29-result span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #e0e7ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-29-result.is-success span {
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-29-result.is-error span {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-29-result h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(26px, 4vw, 44px) !important;
  line-height: 1.05 !important;
  font-weight: 950 !important;
  letter-spacing: -0.05em;
  overflow-wrap: anywhere;
}

.vb-fetch-29-result p {
  margin: 0 0 14px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-29-result pre {
  max-width: 100%;
  max-height: 260px;
  overflow: auto;
  margin: 0 !important;
  padding: 14px;
  border-radius: 16px;
  background: #0f172a;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 13px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 860px) {
  .vb-fetch-29-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-fetch-29-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.045em;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-29-demo");
  if (!demo) return;

  const tokenInput = demo.querySelector("[data-vb-fetch-29-token]");
  const clientInput = demo.querySelector("[data-vb-fetch-29-client]");
  const button = demo.querySelector("[data-vb-fetch-29-send]");
  const result = demo.querySelector("[data-vb-fetch-29-result]");

  function maskToken(token) {
    if (token.length <= 8) {
      return "********";
    }

    return token.slice(0, 4) + "..." + token.slice(-4);
  }

  function render(type, label, title, message, data) {
    result.className = "vb-fetch-29-result";

    if (type) {
      result.classList.add(type);
    }

    result.innerHTML =
      '<span>' + label + '</span>' +
      '<h4>' + title + '</h4>' +
      '<p>' + message + '</p>' +
      '<pre>' + JSON.stringify(data || {}, null, 2) + '</pre>';
  }

  async function sendAuthRequest() {
    const token = tokenInput.value.trim();
    const client = clientInput.value.trim();

    if (!token || !client) {
      render("is-error", "Error", "Missing header data", "Enter both a demo token and client name.", {});
      return;
    }

    const headersPreview = {
      Authorization: "Bearer " + maskToken(token),
      "X-Client-Name": client,
      "Content-Type": "application/json"
    };

    button.disabled = true;

    render("", "Loading", "Sending header request", "The request includes Authorization and custom client headers.", headersPreview);

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts/1", {
        method: "GET",
        headers: {
          Authorization: "Bearer " + token,
          "X-Client-Name": client,
          "Content-Type": "application/json"
        }
      });

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const data = await response.json();

      render("is-success", "Success", "Auth-style request sent", "The demo request completed. Token is masked in the UI preview.", {
        sentHeaders: headersPreview,
        apiResponse: data
      });
    } catch (error) {
      render("is-error", "Error", "Request failed", error.message, {
        sentHeaders: headersPreview
      });
    } finally {
      button.disabled = false;
    }
  }

  button.addEventListener("click", sendAuthRequest);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-29-demo");
  if (!demo) return;

  const tokenInput = demo.querySelector("[data-vb-fetch-29-token]");
  const clientInput = demo.querySelector("[data-vb-fetch-29-client]");
  const button = demo.querySelector("[data-vb-fetch-29-send]");
  const result = demo.querySelector("[data-vb-fetch-29-result]");

  function maskToken(token) {
    if (token.length &lt;= 8) {
      return "********";
    }

    return token.slice(0, 4) + "..." + token.slice(-4);
  }

  function render(type, label, title, message, data) {
    result.className = "vb-fetch-29-result";

    if (type) {
      result.classList.add(type);
    }

    result.innerHTML =
      '&lt;span&gt;' + label + '&lt;/span&gt;' +
      '&lt;h4&gt;' + title + '&lt;/h4&gt;' +
      '&lt;p&gt;' + message + '&lt;/p&gt;' +
      '&lt;pre&gt;' + JSON.stringify(data || {}, null, 2) + '&lt;/pre&gt;';
  }

  async function sendAuthRequest() {
    const token = tokenInput.value.trim();
    const client = clientInput.value.trim();

    if (!token || !client) {
      render("is-error", "Error", "Missing header data", "Enter both a demo token and client name.", {});
      return;
    }

    const headersPreview = {
      Authorization: "Bearer " + maskToken(token),
      "X-Client-Name": client,
      "Content-Type": "application/json"
    };

    button.disabled = true;

    render("", "Loading", "Sending header request", "The request includes Authorization and custom client headers.", headersPreview);

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts/1", {
        method: "GET",
        headers: {
          Authorization: "Bearer " + token,
          "X-Client-Name": client,
          "Content-Type": "application/json"
        }
      });

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      const data = await response.json();

      render("is-success", "Success", "Auth-style request sent", "The demo request completed. Token is masked in the UI preview.", {
        sentHeaders: headersPreview,
        apiResponse: data
      });
    } catch (error) {
      render("is-error", "Error", "Request failed", error.message, {
        sentHeaders: headersPreview
      });
    } finally {
      button.disabled = false;
    }
  }

  button.addEventListener("click", sendAuthRequest);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-29-demo"&gt;
  &lt;div class="vb-fetch-29-shell"&gt;
    &lt;div class="vb-fetch-29-header"&gt;
      &lt;span&gt;Example 29&lt;/span&gt;
      &lt;h3&gt;Fetch API Authentication Header&lt;/h3&gt;
      &lt;p&gt;Send a request with a demo authorization header and display a safe masked token preview.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-29-body"&gt;
      &lt;div class="vb-fetch-29-form"&gt;
        &lt;label&gt;
          Demo bearer token
          &lt;input type="text" value="demo_token_123456789" data-vb-fetch-29-token&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Custom client name
          &lt;input type="text" value="website-demo-client" data-vb-fetch-29-client&gt;
        &lt;/label&gt;

        &lt;button type="button" data-vb-fetch-29-send&gt;Send Auth Request&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-fetch-29-result" data-vb-fetch-29-result&gt;
        &lt;span&gt;Waiting&lt;/span&gt;
        &lt;h4&gt;No auth request sent&lt;/h4&gt;
        &lt;p&gt;Enter a demo token and send a request with custom headers.&lt;/p&gt;
        &lt;pre&gt;{}&lt;/pre&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-29-demo,
.vb-fetch-29-demo * {
  box-sizing: border-box;
}

.vb-fetch-29-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(15, 23, 42, 0.12), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(99, 102, 241, 0.17), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #eef2ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(15, 23, 42, 0.10);
  overflow: hidden;
}

.vb-fetch-29-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-29-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.12), transparent 34%),
    linear-gradient(135deg, #020617 0%, #334155 45%, #4f46e5 100%) !important;
}

.vb-fetch-29-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e2e8f0 !important;
  -webkit-text-fill-color: #e2e8f0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-29-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-29-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-29-body {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 22px;
  padding: clamp(20px, 4vw, 34px);
  min-width: 0;
}

.vb-fetch-29-form {
  display: grid;
  align-content: start;
  gap: 14px;
  min-width: 0;
  padding: 20px;
  border-radius: 24px;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
}

.vb-fetch-29-form label {
  display: grid;
  gap: 8px;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-29-form input {
  width: 100%;
  min-width: 0;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid #cbd5e1;
  border-radius: 18px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 800;
  outline: none;
}

.vb-fetch-29-form button {
  min-height: 52px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #334155, #4f46e5);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(51, 65, 85, 0.22);
}

.vb-fetch-29-form button:disabled {
  opacity: 0.65;
  cursor: not-allowed;
}

.vb-fetch-29-result {
  min-width: 0;
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 14% 12%, rgba(79, 70, 229, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-fetch-29-result.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-fetch-29-result.is-error {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-fetch-29-result span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #e0e7ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-29-result.is-success span {
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-29-result.is-error span {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-29-result h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(26px, 4vw, 44px) !important;
  line-height: 1.05 !important;
  font-weight: 950 !important;
  letter-spacing: -0.05em;
  overflow-wrap: anywhere;
}

.vb-fetch-29-result p {
  margin: 0 0 14px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-29-result pre {
  max-width: 100%;
  max-height: 260px;
  overflow: auto;
  margin: 0 !important;
  padding: 14px;
  border-radius: 16px;
  background: #0f172a;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 13px;
  line-height: 1.55;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 860px) {
  .vb-fetch-29-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-fetch-29-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.045em;
  }
}</pre>



<p class="wp-block-paragraph">This Fetch API authentication header example is useful for protected endpoints, SaaS dashboards, backend integrations, API clients, admin tools, user portals, and any JavaScript request that needs custom headers.</p>




<h2 class="wp-block-heading">30. Complete Responsive Fetch API Dashboard Section</h2>



<p class="wp-block-paragraph"><strong>A complete responsive Fetch API dashboard</strong> combines several common API patterns into one practical section: loading data, search, filtering, refresh, status cards, error handling, and responsive result rendering.</p>



<p class="wp-block-paragraph">This final example loads API data, stores it in local state, lets users search and filter the visible cards, refresh the API data, and shows a full responsive dashboard layout that can be adapted for real admin panels and SaaS interfaces.</p>



<ul class="wp-block-list">
<li>Complete Fetch API dashboard section</li>
<li>Load, refresh, search, and filter data</li>
<li>Local state after API request</li>
<li>Status cards and responsive result grid</li>
<li>Useful for real dashboards and admin panels</li>
</ul>



<div class="vb-fetch-30-demo">
  <div class="vb-fetch-30-shell">
    <div class="vb-fetch-30-hero">
      <div>
        <span>Example 30</span>
        <h3>Complete Responsive Fetch API Dashboard</h3>
        <p>Load API data, search it, filter it, refresh it, and render a complete dashboard section.</p>
      </div>

      <button type="button" data-vb-fetch-30-refresh>Refresh API Data</button>
    </div>

    <div class="vb-fetch-30-stats" data-vb-fetch-30-stats>
      <div><span>Total posts</span><strong>--</strong></div>
      <div><span>Visible cards</span><strong>--</strong></div>
      <div><span>Active user</span><strong>All</strong></div>
    </div>

    <div class="vb-fetch-30-controls">
      <label>
        Search dashboard data
        <input type="search" placeholder="Search titles or content..." data-vb-fetch-30-search>
      </label>

      <label>
        Filter by user
        <select data-vb-fetch-30-user>
          <option value="all">All users</option>
          <option value="1">User 1</option>
          <option value="2">User 2</option>
          <option value="3">User 3</option>
        </select>
      </label>
    </div>

    <div class="vb-fetch-30-status" data-vb-fetch-30-status>
      Dashboard is ready. Loading API data...
    </div>

    <div class="vb-fetch-30-grid" data-vb-fetch-30-grid></div>
  </div>
</div>

<style>
.vb-fetch-30-demo,
.vb-fetch-30-demo * {
  box-sizing: border-box;
}

.vb-fetch-30-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(99, 102, 241, 0.17), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.16);
  overflow: hidden;
}

.vb-fetch-30-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-30-hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 20px;
  align-items: end;
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #312e81 0%, #6366f1 50%, #16a34a 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-30-hero span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-30-hero h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-30-hero p {
  max-width: 780px;
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-30-hero button {
  min-height: 52px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(15, 23, 42, 0.18);
}

.vb-fetch-30-hero button:disabled {
  opacity: 0.7;
  cursor: not-allowed;
}

.vb-fetch-30-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
}

.vb-fetch-30-stats div {
  min-width: 0;
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(99, 102, 241, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-fetch-30-stats span {
  display: block;
  margin-bottom: 8px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-fetch-30-stats strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(28px, 4vw, 44px);
  line-height: 1;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-fetch-30-controls {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(220px, 0.8fr);
  gap: 14px;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
  min-width: 0;
}

.vb-fetch-30-controls label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-30-controls input,
.vb-fetch-30-controls select {
  width: 100%;
  min-width: 0;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid #c7d2fe;
  border-radius: 18px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 800;
  outline: none;
}

.vb-fetch-30-status {
  margin: 16px clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #eef2ff;
  border: 1px solid #c7d2fe;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-30-status.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-30-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-30-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-30-card {
  min-width: 0;
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(99, 102, 241, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-fetch-30-card span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #e0e7ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-30-card h4 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-30-card p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-30-empty {
  grid-column: 1 / -1;
  padding: 22px;
  border-radius: 22px;
  background: #fef2f2;
  border: 1px solid #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 15px;
  line-height: 1.55;
  font-weight: 850;
  text-align: center;
}

@media (max-width: 980px) {
  .vb-fetch-30-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-fetch-30-hero {
    grid-template-columns: 1fr;
  }

  .vb-fetch-30-hero button {
    width: 100%;
  }
}

@media (max-width: 760px) {
  .vb-fetch-30-stats,
  .vb-fetch-30-controls,
  .vb-fetch-30-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-fetch-30-hero h3 {
    font-size: 36px !important;
    letter-spacing: -0.045em;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-fetch-30-demo");
  if (!demo) return;

  const refreshButton = demo.querySelector("[data-vb-fetch-30-refresh]");
  const searchInput = demo.querySelector("[data-vb-fetch-30-search]");
  const userSelect = demo.querySelector("[data-vb-fetch-30-user]");
  const status = demo.querySelector("[data-vb-fetch-30-status]");
  const stats = demo.querySelector("[data-vb-fetch-30-stats]");
  const grid = demo.querySelector("[data-vb-fetch-30-grid]");

  let posts = [];

  function setStatus(text, type) {
    status.className = "vb-fetch-30-status";

    if (type) {
      status.classList.add(type);
    }

    status.textContent = text;
  }

  function updateStats(visiblePosts) {
    const activeUser = userSelect.value === "all" ? "All" : "User " + userSelect.value;

    stats.innerHTML =
      '<div><span>Total posts</span><strong>' + posts.length + '</strong></div>' +
      '<div><span>Visible cards</span><strong>' + visiblePosts.length + '</strong></div>' +
      '<div><span>Active user</span><strong>' + activeUser + '</strong></div>';
  }

  function renderCards(visiblePosts) {
    if (!visiblePosts.length) {
      grid.innerHTML = '<div class="vb-fetch-30-empty">No matching dashboard records found. Try another search or filter.</div>';
      return;
    }

    grid.innerHTML = visiblePosts.slice(0, 9).map(function (post) {
      return (
        '<article class="vb-fetch-30-card">' +
          '<span>User #' + post.userId + ' · Post #' + post.id + '</span>' +
          '<h4>' + post.title + '</h4>' +
          '<p>' + post.body + '</p>' +
        '</article>'
      );
    }).join("");
  }

  function applyFilters() {
    const query = searchInput.value.trim().toLowerCase();
    const user = userSelect.value;

    const visiblePosts = posts.filter(function (post) {
      const matchesUser = user === "all" || String(post.userId) === user;
      const matchesSearch = !query || post.title.toLowerCase().includes(query) || post.body.toLowerCase().includes(query);

      return matchesUser && matchesSearch;
    });

    updateStats(visiblePosts);
    renderCards(visiblePosts);

    if (posts.length) {
      setStatus("Showing " + Math.min(visiblePosts.length, 9) + " of " + visiblePosts.length + " matching records.", "is-success");
    }
  }

  async function loadDashboardData() {
    refreshButton.disabled = true;
    grid.innerHTML = "";
    setStatus("Loading dashboard API data...", "");

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts?_limit=30");

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      posts = await response.json();

      applyFilters();
      setStatus("Dashboard loaded " + posts.length + " API records successfully.", "is-success");
    } catch (error) {
      posts = [];
      updateStats([]);
      grid.innerHTML = "";
      setStatus("Dashboard request failed: " + error.message, "is-error");
    } finally {
      refreshButton.disabled = false;
    }
  }

  refreshButton.addEventListener("click", loadDashboardData);
  searchInput.addEventListener("input", applyFilters);
  userSelect.addEventListener("change", applyFilters);

  loadDashboardData();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-fetch-30-demo");
  if (!demo) return;

  const refreshButton = demo.querySelector("[data-vb-fetch-30-refresh]");
  const searchInput = demo.querySelector("[data-vb-fetch-30-search]");
  const userSelect = demo.querySelector("[data-vb-fetch-30-user]");
  const status = demo.querySelector("[data-vb-fetch-30-status]");
  const stats = demo.querySelector("[data-vb-fetch-30-stats]");
  const grid = demo.querySelector("[data-vb-fetch-30-grid]");

  let posts = [];

  function setStatus(text, type) {
    status.className = "vb-fetch-30-status";

    if (type) {
      status.classList.add(type);
    }

    status.textContent = text;
  }

  function updateStats(visiblePosts) {
    const activeUser = userSelect.value === "all" ? "All" : "User " + userSelect.value;

    stats.innerHTML =
      '&lt;div&gt;&lt;span&gt;Total posts&lt;/span&gt;&lt;strong&gt;' + posts.length + '&lt;/strong&gt;&lt;/div&gt;' +
      '&lt;div&gt;&lt;span&gt;Visible cards&lt;/span&gt;&lt;strong&gt;' + visiblePosts.length + '&lt;/strong&gt;&lt;/div&gt;' +
      '&lt;div&gt;&lt;span&gt;Active user&lt;/span&gt;&lt;strong&gt;' + activeUser + '&lt;/strong&gt;&lt;/div&gt;';
  }

  function renderCards(visiblePosts) {
    if (!visiblePosts.length) {
      grid.innerHTML = '&lt;div class="vb-fetch-30-empty"&gt;No matching dashboard records found. Try another search or filter.&lt;/div&gt;';
      return;
    }

    grid.innerHTML = visiblePosts.slice(0, 9).map(function (post) {
      return (
        '&lt;article class="vb-fetch-30-card"&gt;' +
          '&lt;span&gt;User #' + post.userId + ' · Post #' + post.id + '&lt;/span&gt;' +
          '&lt;h4&gt;' + post.title + '&lt;/h4&gt;' +
          '&lt;p&gt;' + post.body + '&lt;/p&gt;' +
        '&lt;/article&gt;'
      );
    }).join("");
  }

  function applyFilters() {
    const query = searchInput.value.trim().toLowerCase();
    const user = userSelect.value;

    const visiblePosts = posts.filter(function (post) {
      const matchesUser = user === "all" || String(post.userId) === user;
      const matchesSearch = !query || post.title.toLowerCase().includes(query) || post.body.toLowerCase().includes(query);

      return matchesUser && matchesSearch;
    });

    updateStats(visiblePosts);
    renderCards(visiblePosts);

    if (posts.length) {
      setStatus("Showing " + Math.min(visiblePosts.length, 9) + " of " + visiblePosts.length + " matching records.", "is-success");
    }
  }

  async function loadDashboardData() {
    refreshButton.disabled = true;
    grid.innerHTML = "";
    setStatus("Loading dashboard API data...", "");

    try {
      const response = await fetch("https://jsonplaceholder.typicode.com/posts?_limit=30");

      if (!response.ok) {
        throw new Error("HTTP status " + response.status);
      }

      posts = await response.json();

      applyFilters();
      setStatus("Dashboard loaded " + posts.length + " API records successfully.", "is-success");
    } catch (error) {
      posts = [];
      updateStats([]);
      grid.innerHTML = "";
      setStatus("Dashboard request failed: " + error.message, "is-error");
    } finally {
      refreshButton.disabled = false;
    }
  }

  refreshButton.addEventListener("click", loadDashboardData);
  searchInput.addEventListener("input", applyFilters);
  userSelect.addEventListener("change", applyFilters);

  loadDashboardData();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-fetch-30-demo"&gt;
  &lt;div class="vb-fetch-30-shell"&gt;
    &lt;div class="vb-fetch-30-hero"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 30&lt;/span&gt;
        &lt;h3&gt;Complete Responsive Fetch API Dashboard&lt;/h3&gt;
        &lt;p&gt;Load API data, search it, filter it, refresh it, and render a complete dashboard section.&lt;/p&gt;
      &lt;/div&gt;

      &lt;button type="button" data-vb-fetch-30-refresh&gt;Refresh API Data&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-30-stats" data-vb-fetch-30-stats&gt;
      &lt;div&gt;&lt;span&gt;Total posts&lt;/span&gt;&lt;strong&gt;--&lt;/strong&gt;&lt;/div&gt;
      &lt;div&gt;&lt;span&gt;Visible cards&lt;/span&gt;&lt;strong&gt;--&lt;/strong&gt;&lt;/div&gt;
      &lt;div&gt;&lt;span&gt;Active user&lt;/span&gt;&lt;strong&gt;All&lt;/strong&gt;&lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-30-controls"&gt;
      &lt;label&gt;
        Search dashboard data
        &lt;input type="search" placeholder="Search titles or content..." data-vb-fetch-30-search&gt;
      &lt;/label&gt;

      &lt;label&gt;
        Filter by user
        &lt;select data-vb-fetch-30-user&gt;
          &lt;option value="all"&gt;All users&lt;/option&gt;
          &lt;option value="1"&gt;User 1&lt;/option&gt;
          &lt;option value="2"&gt;User 2&lt;/option&gt;
          &lt;option value="3"&gt;User 3&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;
    &lt;/div&gt;

    &lt;div class="vb-fetch-30-status" data-vb-fetch-30-status&gt;
      Dashboard is ready. Loading API data...
    &lt;/div&gt;

    &lt;div class="vb-fetch-30-grid" data-vb-fetch-30-grid&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-fetch-30-demo,
.vb-fetch-30-demo * {
  box-sizing: border-box;
}

.vb-fetch-30-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(99, 102, 241, 0.17), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.16);
  overflow: hidden;
}

.vb-fetch-30-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-fetch-30-hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 20px;
  align-items: end;
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #312e81 0%, #6366f1 50%, #16a34a 100%) !important;
  background-size: 24px 24px, 24px 24px, auto !important;
}

.vb-fetch-30-hero span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-fetch-30-hero h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-fetch-30-hero p {
  max-width: 780px;
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-fetch-30-hero button {
  min-height: 52px;
  padding: 0 20px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 15px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(15, 23, 42, 0.18);
}

.vb-fetch-30-hero button:disabled {
  opacity: 0.7;
  cursor: not-allowed;
}

.vb-fetch-30-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
}

.vb-fetch-30-stats div {
  min-width: 0;
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(99, 102, 241, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-fetch-30-stats span {
  display: block;
  margin-bottom: 8px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-fetch-30-stats strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(28px, 4vw, 44px);
  line-height: 1;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-fetch-30-controls {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(220px, 0.8fr);
  gap: 14px;
  padding: clamp(20px, 4vw, 34px) clamp(20px, 4vw, 34px) 0;
  min-width: 0;
}

.vb-fetch-30-controls label {
  display: grid;
  gap: 8px;
  min-width: 0;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-fetch-30-controls input,
.vb-fetch-30-controls select {
  width: 100%;
  min-width: 0;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid #c7d2fe;
  border-radius: 18px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 800;
  outline: none;
}

.vb-fetch-30-status {
  margin: 16px clamp(20px, 4vw, 34px) 0;
  min-width: 0;
  padding: 14px 16px;
  border-radius: 18px;
  background: #eef2ff;
  border: 1px solid #c7d2fe;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-fetch-30-status.is-success {
  background: #f0fdf4;
  border-color: #bbf7d0;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-fetch-30-status.is-error {
  background: #fef2f2;
  border-color: #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-fetch-30-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
  padding: clamp(20px, 4vw, 34px);
}

.vb-fetch-30-card {
  min-width: 0;
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(99, 102, 241, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-fetch-30-card span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #e0e7ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-fetch-30-card h4 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.25 !important;
  font-weight: 950 !important;
  overflow-wrap: anywhere;
}

.vb-fetch-30-card p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-fetch-30-empty {
  grid-column: 1 / -1;
  padding: 22px;
  border-radius: 22px;
  background: #fef2f2;
  border: 1px solid #fecaca;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 15px;
  line-height: 1.55;
  font-weight: 850;
  text-align: center;
}

@media (max-width: 980px) {
  .vb-fetch-30-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-fetch-30-hero {
    grid-template-columns: 1fr;
  }

  .vb-fetch-30-hero button {
    width: 100%;
  }
}

@media (max-width: 760px) {
  .vb-fetch-30-stats,
  .vb-fetch-30-controls,
  .vb-fetch-30-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-fetch-30-hero h3 {
    font-size: 36px !important;
    letter-spacing: -0.045em;
  }
}</pre>



<p class="wp-block-paragraph">This complete responsive Fetch API dashboard section is useful for admin panels, SaaS dashboards, API data tools, user portals, content dashboards, CRM overviews, and production-style frontend interfaces that combine loading, filtering, searching, and rendering API data.</p>



<div class="vb24-fetch-bottom-ad-wrap">
  <a class="vb24-entityschema-ad-wide" href="https://veebilehed24.ee/en/shop/entityschema-pro/" target="_blank" rel="sponsored noopener">
    <div class="vb24-entityschema-ad-wide-media">
      <img decoding="async" src="https://veebilehed24.ee/wp-content/uploads/2026/03/entityschema-cover-600x400.webp" width="600" height="400" alt="EntitySchema Pro WordPress structured data and entity SEO plugin" loading="lazy">
    </div>

    <div class="vb24-entityschema-ad-wide-content">
      <span class="vb24-entityschema-ad-wide-badge">WordPress SEO Plugin</span>
      <h2>EntitySchema Pro</h2>
      <p>Build a real entity-based structured data system for WordPress, modern SEO, Google visibility, and AI-readable websites.</p>

      <div class="vb24-entityschema-ad-wide-price">
        <span class="vb24-entityschema-ad-wide-old">89€</span>
        <strong>29€</strong>
        <span class="vb24-entityschema-ad-wide-save">Save 60€</span>
      </div>

      <span class="vb24-entityschema-ad-wide-button">View Plugin</span>
    </div>
  </a>
</div>

<style>
.vb24-fetch-bottom-ad-wrap,
.vb24-fetch-bottom-ad-wrap * {
  box-sizing: border-box;
}

.vb24-fetch-bottom-ad-wrap {
  margin: 44px 0 46px;
}

.vb24-entityschema-ad-wide {
  display: grid;
  grid-template-columns: minmax(240px, 0.9fr) minmax(0, 1.1fr);
  gap: clamp(18px, 4vw, 34px);
  align-items: center;
  padding: clamp(18px, 4vw, 30px);
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 12%, rgba(34, 211, 238, 0.26), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(168, 85, 247, 0.24), transparent 36%),
    linear-gradient(135deg, #111827 0%, #312e81 50%, #701a75 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  overflow: hidden;
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.28);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-entityschema-ad-wide:hover {
  transform: translateY(-3px);
  filter: saturate(1.08);
  box-shadow: 0 34px 96px rgba(15, 23, 42, 0.36);
}

.vb24-entityschema-ad-wide-media {
  overflow: hidden;
  border-radius: 24px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.18);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.10);
}

.vb24-entityschema-ad-wide-media img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 24px;
}

.vb24-entityschema-ad-wide-content {
  min-width: 0;
}

.vb24-entityschema-ad-wide-badge {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.62);
  border: 1px solid rgba(255,255,255,0.20);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb24-entityschema-ad-wide-content h2 {
  margin: 0 0 12px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 58px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb24-entityschema-ad-wide-content p {
  max-width: 660px;
  margin: 0 0 18px !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb24-entityschema-ad-wide-price {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin: 0 0 18px;
}

.vb24-entityschema-ad-wide-old {
  color: rgba(255,255,255,0.60) !important;
  -webkit-text-fill-color: rgba(255,255,255,0.60) !important;
  font-size: 19px;
  font-weight: 850;
  text-decoration: line-through;
  text-decoration-thickness: 2px;
  text-decoration-color: rgba(248, 113, 113, 0.95);
}

.vb24-entityschema-ad-wide-price strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 48px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb24-entityschema-ad-wide-save {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.18);
  border: 1px solid rgba(74, 222, 128, 0.34);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb24-entityschema-ad-wide-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 46px;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22d3ee, #2563eb 55%, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  text-decoration: none !important;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.30);
}

@media (max-width: 800px) {
  .vb24-entityschema-ad-wide {
    grid-template-columns: 1fr;
    border-radius: 26px;
  }
}

@media (max-width: 640px) {
  .vb24-entityschema-ad-wide {
    padding: 16px;
  }

  .vb24-entityschema-ad-wide-content h2 {
    font-size: 34px !important;
  }

  .vb24-entityschema-ad-wide-button {
    width: 100%;
  }
}
</style>



<h2 class="wp-block-heading" id="javascript-fetch-api-best-practices">JavaScript Fetch API Best Practices</h2>



<p class="wp-block-paragraph">Good Fetch API code is not only about making a request. A real website needs reliable loading states, safe error handling, readable response parsing, clear UI feedback, and request logic that does not break when the API returns an unexpected result. These best practices help you build Fetch API features that work better in production websites, WordPress integrations, SaaS dashboards, ecommerce tools, and custom admin panels.</p>



<div class="vb24-fetch-best-grid">
  <div class="vb24-fetch-best-card">
    <span>01</span>
    <h3>Always check response.ok</h3>
    <p>Fetch does not automatically throw an error for HTTP status codes like 404 or 500. Check <code>response.ok</code> before parsing and rendering data.</p>
  </div>

  <div class="vb24-fetch-best-card">
    <span>02</span>
    <h3>Use clear loading states</h3>
    <p>Disable buttons, show progress text, and let users know that data is being requested. This prevents duplicate clicks and confusing UI states.</p>
  </div>

  <div class="vb24-fetch-best-card">
    <span>03</span>
    <h3>Keep request logic scoped</h3>
    <p>Use unique class names, data attributes, and local variables so multiple Fetch API demos or widgets can run on the same page without conflicts.</p>
  </div>

  <div class="vb24-fetch-best-card">
    <span>04</span>
    <h3>Protect private tokens</h3>
    <p>Never expose real private API keys inside frontend JavaScript. Use a backend endpoint, proxy route, or server-side integration for sensitive credentials.</p>
  </div>
</div>

<style>
.vb24-fetch-best-grid,
.vb24-fetch-best-grid * {
  box-sizing: border-box;
}

.vb24-fetch-best-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 32px;
}

.vb24-fetch-best-card {
  min-width: 0;
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 18% 12%, rgba(6, 182, 212, 0.12), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.08);
}

.vb24-fetch-best-card span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 12px;
  font-weight: 950;
}

.vb24-fetch-best-card h3 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.25 !important;
  font-weight: 900 !important;
}

.vb24-fetch-best-card p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb24-fetch-best-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-fetch-best-grid {
    grid-template-columns: 1fr;
  }
}
</style>



<p class="wp-block-paragraph">When you build a real Fetch API feature, think about the full user journey. What happens before the request starts? What should the user see while waiting? What happens if the request fails? What should happen if the response is empty? What should happen if the user clicks twice, changes a filter, or leaves the page? A strong Fetch API implementation handles these details instead of only showing the happy path.</p>



<ul class="wp-block-list">
  <li><strong>Use <code>async/await</code></strong> when the code has several steps and needs to stay readable.</li>
  <li><strong>Use <code>try/catch</code></strong> around request logic so network errors and JSON parsing errors do not break the page.</li>
  <li><strong>Use <code>URLSearchParams</code></strong> for query parameters instead of manually joining strings.</li>
  <li><strong>Use <code>AbortController</code></strong> when a request should be cancelled, timed out, or replaced by a newer request.</li>
  <li><strong>Keep API rendering safe</strong> by checking if fields exist before inserting them into the interface.</li>
  <li><strong>Use loading, empty, success, and error states</strong> for every important request.</li>
  <li><strong>Avoid duplicate submissions</strong> by disabling buttons while a POST, PUT, PATCH, or DELETE request is running.</li>
  <li><strong>Cache carefully</strong> when the same API data is loaded often, but always provide a refresh option.</li>
  <li><strong>Do not trust frontend validation alone</strong> because backend validation is still required for security.</li>
  <li><strong>Test slow networks and failed responses</strong> before publishing a real API feature.</li>
</ul>



<h2 class="wp-block-heading" id="fetch-api-error-handling-tips">Fetch API Error Handling Tips</h2>



<p class="wp-block-paragraph">Error handling is one of the most important parts of a good Fetch API example. Many beginners expect <code>fetch()</code> to automatically fail when an API returns a 404, 500, or validation error, but Fetch only rejects on network-level failures. That means you must check the response status yourself and decide what message to show to the user.</p>



<p class="wp-block-paragraph">A professional Fetch API feature should handle at least four types of problems: network errors, HTTP status errors, invalid JSON responses, and API-level error objects. It should also explain the issue in plain language so users are not left looking at a broken form, empty dashboard, or frozen loading screen.</p>



<div class="vb24-fetch-error-box">
  <h3>Simple production-style Fetch API error pattern</h3>
  <pre>async function getApiData(url) {
  try {
    const response = await fetch(url);

    if (!response.ok) {
      throw new Error("Request failed with status " + response.status);
    }

    const data = await response.json();

    return {
      success: true,
      data: data
    };
  } catch (error) {
    return {
      success: false,
      message: error.message
    };
  }
}</pre>
</div>

<style>
.vb24-fetch-error-box,
.vb24-fetch-error-box * {
  box-sizing: border-box;
}

.vb24-fetch-error-box {
  margin: 24px 0 32px;
  padding: clamp(20px, 4vw, 28px);
  border-radius: 26px;
  background:
    radial-gradient(circle at 14% 12%, rgba(239, 68, 68, 0.14), transparent 34%),
    linear-gradient(135deg, #111827 0%, #7f1d1d 50%, #1e3a8a 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 22px 62px rgba(15, 23, 42, 0.20);
}

.vb24-fetch-error-box h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px !important;
  line-height: 1.2 !important;
  font-weight: 900 !important;
}

.vb24-fetch-error-box pre {
  max-width: 100%;
  max-height: 360px;
  overflow: auto;
  margin: 0 !important;
  padding: 16px;
  border-radius: 18px;
  background: rgba(15, 23, 42, 0.82);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 14px;
  line-height: 1.65;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
</style>



<p class="wp-block-paragraph">For user-facing interfaces, avoid showing raw technical errors only. A developer console can contain detailed logs, but the page itself should show a clean message such as “Could not load products. Please try again.” or “Your message could not be sent. Check the form and try again.” This makes the interface feel stable even when the API fails.</p>



<h2 class="wp-block-heading" id="common-fetch-api-mistakes">Common Fetch API Mistakes</h2>



<p class="wp-block-paragraph">Most Fetch API bugs happen because the code only handles the perfect response. Real APIs can be slow, unavailable, empty, protected, rate-limited, or formatted differently than expected. Avoiding the following mistakes will make your JavaScript API examples and production code much stronger.</p>



<ul class="wp-block-list">
  <li><strong>Not checking <code>response.ok</code></strong> before using <code>response.json()</code>.</li>
  <li><strong>Forgetting loading states</strong>, which makes users click the same button multiple times.</li>
  <li><strong>Rendering API data without fallbacks</strong>, which can break the layout when a field is missing.</li>
  <li><strong>Exposing private API keys</strong> directly in frontend JavaScript.</li>
  <li><strong>Using the wrong HTTP method</strong>, such as using GET for a form submission that should be POST.</li>
  <li><strong>Forgetting headers</strong> such as <code>Content-Type: application/json</code> when sending JSON data.</li>
  <li><strong>Not handling empty arrays</strong>, which can leave the results area blank.</li>
  <li><strong>Not cancelling outdated requests</strong> in fast search interfaces or filter dashboards.</li>
  <li><strong>Assuming every response is valid JSON</strong>, even though APIs sometimes return HTML error pages or malformed output.</li>
  <li><strong>Mixing too much logic in one function</strong>, which makes request handling, rendering, validation, and state management difficult to maintain.</li>
</ul>



<p class="wp-block-paragraph">A good rule is simple: every Fetch API feature should answer what happens when the request succeeds, fails, returns no data, takes too long, or gets triggered again before the first request is finished.</p>



<h2 class="wp-block-heading" id="javascript-fetch-api-faq">JavaScript Fetch API FAQ</h2>



<div class="vb24-fetch-faq" data-vb24-fetch-faq>
  <div class="vb24-fetch-faq-item">
    <button type="button" aria-expanded="false">
      <span>What is the JavaScript Fetch API used for?</span>
    </button>
    <div class="vb24-fetch-faq-panel">
      <p>The JavaScript Fetch API is used to make HTTP requests from the browser. It can load JSON data, submit forms, send POST requests, update records, delete items, request search results, connect to backend endpoints, and power dynamic dashboards or API-connected website features.</p>
    </div>
  </div>

  <div class="vb24-fetch-faq-item">
    <button type="button" aria-expanded="false">
      <span>Is Fetch API better than XMLHttpRequest?</span>
    </button>
    <div class="vb24-fetch-faq-panel">
      <p>Fetch API is usually easier to read and more modern than XMLHttpRequest, especially when used with promises and async/await. XMLHttpRequest can still be useful for upload progress events, but Fetch API is the standard choice for many modern JSON and API request workflows.</p>
    </div>
  </div>

  <div class="vb24-fetch-faq-item">
    <button type="button" aria-expanded="false">
      <span>Does Fetch API throw errors for 404 or 500 responses?</span>
    </button>
    <div class="vb24-fetch-faq-panel">
      <p>No. Fetch API only rejects automatically for network-level failures. For HTTP errors like 404 or 500, you should check <code>response.ok</code> or <code>response.status</code> and throw your own error when needed.</p>
    </div>
  </div>

  <div class="vb24-fetch-faq-item">
    <button type="button" aria-expanded="false">
      <span>Can Fetch API send form data?</span>
    </button>
    <div class="vb24-fetch-faq-panel">
      <p>Yes. Fetch API can send JSON data, regular form data, and FormData objects. For JSON requests, use <code>JSON.stringify()</code> and the <code>Content-Type: application/json</code> header. For file uploads or multipart forms, use <code>FormData</code>.</p>
    </div>
  </div>

  <div class="vb24-fetch-faq-item">
    <button type="button" aria-expanded="false">
      <span>Can I use Fetch API in WordPress?</span>
    </button>
    <div class="vb24-fetch-faq-panel">
      <p>Yes. Fetch API works well with WordPress REST API endpoints, custom plugin endpoints, admin AJAX routes, form handlers, product data, search features, dashboards, and frontend tools. For protected requests, use nonces and backend validation.</p>
    </div>
  </div>

  <div class="vb24-fetch-faq-item">
    <button type="button" aria-expanded="false">
      <span>Should API keys be stored in frontend JavaScript?</span>
    </button>
    <div class="vb24-fetch-faq-panel">
      <p>No. Real private API keys should not be stored in frontend JavaScript because visitors can inspect the code. Use a backend endpoint, server-side proxy, WordPress plugin setting, or secure server environment variable instead.</p>
    </div>
  </div>
</div>

<style>
.vb24-fetch-faq,
.vb24-fetch-faq * {
  box-sizing: border-box;
}

.vb24-fetch-faq {
  display: grid;
  gap: 12px;
  margin: 24px 0 34px;
}

.vb24-fetch-faq-item {
  overflow: hidden;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 12px 34px rgba(15, 23, 42, 0.06);
}

.vb24-fetch-faq-item button {
  position: relative;
  width: 100%;
  min-height: 62px;
  padding: 18px 58px 18px 20px;
  border: 0;
  background:
    radial-gradient(circle at 10% 10%, rgba(6, 182, 212, 0.10), transparent 32%),
    linear-gradient(135deg, #f8fafc, #ffffff) !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  text-align: left;
  cursor: pointer;
}

.vb24-fetch-faq-item button span {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 17px;
  line-height: 1.35;
  font-weight: 900;
}

.vb24-fetch-faq-item button::after {
  content: "+";
  position: absolute;
  top: 50%;
  right: 20px;
  display: flex;
  width: 30px;
  height: 30px;
  align-items: center;
  justify-content: center;
  transform: translateY(-50%);
  border-radius: 999px;
  background: linear-gradient(135deg, #22c55e, #06b6d4, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  line-height: 1;
  font-weight: 900;
}

.vb24-fetch-faq-item.is-open button::after {
  content: "–";
}

.vb24-fetch-faq-panel {
  display: none;
  padding: 0 20px 20px;
  background: #ffffff;
}

.vb24-fetch-faq-item.is-open .vb24-fetch-faq-panel {
  display: block;
}

.vb24-fetch-faq-panel p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.75;
}

@media (max-width: 640px) {
  .vb24-fetch-faq-item button {
    padding: 16px 54px 16px 16px;
  }

  .vb24-fetch-faq-item button span {
    font-size: 16px;
  }
}
</style>

<script>
(function () {
  const faq = document.querySelector("[data-vb24-fetch-faq]");
  if (!faq) return;

  const items = faq.querySelectorAll(".vb24-fetch-faq-item");

  items.forEach(function (item) {
    const button = item.querySelector("button");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(function (otherItem) {
        otherItem.classList.remove("is-open");
        otherItem.querySelector("button").setAttribute("aria-expanded", "false");
      });

      if (!isOpen) {
        item.classList.add("is-open");
        button.setAttribute("aria-expanded", "true");
      }
    });
  });
})();
</script>



<h2 class="wp-block-heading" id="javascript-fetch-api-conclusion">Conclusion</h2>



<p class="wp-block-paragraph">The JavaScript Fetch API is one of the most useful skills for building modern interactive websites. Once you understand GET requests, POST requests, JSON handling, form submissions, headers, error states, query parameters, request cancellation, caching, retry logic, and dashboard rendering, you can connect almost any frontend interface to real backend data.</p>



<p class="wp-block-paragraph">The examples in this guide are designed to be practical and reusable. You can adapt them for WordPress plugins, custom forms, ecommerce product feeds, quote request systems, SaaS dashboards, admin panels, search interfaces, user portals, API widgets, and real business websites. The most important part is not only making the request, but handling the entire request lifecycle in a way that feels stable for the user.</p>



<p class="wp-block-paragraph">For best results, start with a simple GET request, then add loading states, error handling, validation, filtering, caching, and safe rendering step by step. This approach keeps your JavaScript easier to debug and makes your Fetch API features more reliable in real projects.</p>



<h2 class="wp-block-heading" id="related-javascript-guides">Related JavaScript Guides</h2>



<div class="vb24-fetch-related">
  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-calculator-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Calculator Examples</strong>
    <p>Price, loan, BMI, discount, form and business calculator examples.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-form-validation-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Form Validation Examples</strong>
    <p>Validate contact forms, signup forms, checkout forms and input fields.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-search-filter-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Search Filter Examples</strong>
    <p>Build live search, filter panels, product filters and searchable UI sections.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-dropdown-menu-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Dropdown Menu Examples</strong>
    <p>Custom select menus, navigation dropdowns and interactive menu components.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-countdown-timer-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Countdown Timer Examples</strong>
    <p>Sale timers, event timers, launch timers and responsive countdown UI.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-forms/">
    <span>CSS</span>
    <strong>30 Modern CSS Forms</strong>
    <p>Use these layouts together with Fetch API form submission examples.</p>
  </a>
</div>

<style>
.vb24-fetch-related,
.vb24-fetch-related * {
  box-sizing: border-box;
}

.vb24-fetch-related {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 40px;
}

.vb24-fetch-related a {
  display: block;
  min-width: 0;
  padding: 20px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(6, 182, 212, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.08);
  text-decoration: none !important;
  transition: transform 0.22s ease, box-shadow 0.22s ease, border-color 0.22s ease;
}

.vb24-fetch-related a:hover {
  transform: translateY(-3px);
  border-color: rgba(6, 182, 212, 0.48);
  box-shadow: 0 22px 54px rgba(15, 23, 42, 0.12);
}

.vb24-fetch-related span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb24-fetch-related strong {
  display: block;
  margin-bottom: 8px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  line-height: 1.3;
  font-weight: 950;
}

.vb24-fetch-related p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb24-fetch-related {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-fetch-related {
    grid-template-columns: 1fr;
  }
}
</style>
]]></content:encoded>
					
					<wfw:commentRss>https://veebilehed24.ee/en/blog/javascript/javascript-fetch-api-examples/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>30 JavaScript Accordion Examples – FAQ, Toggle &#038; Content Expand UI Examples</title>
		<link>https://veebilehed24.ee/en/blog/javascript/javascript-accordion-examples/</link>
					<comments>https://veebilehed24.ee/en/blog/javascript/javascript-accordion-examples/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Sat, 13 Jun 2026 08:52:28 +0000</pubDate>
				<category><![CDATA[Javascript]]></category>
		<guid isPermaLink="false">https://veebilehed24.ee/?p=1623</guid>

					<description><![CDATA[JavaScript accordions are one of the most useful interactive UI components for modern websites, FAQ sections, product pages, dashboards, documentation pages, pricing pages, support centers, mobile layouts, and content-heavy landing pages. They help you hide long content behind clickable headers, reduce page clutter, and let users open only the information they need. In this guide, [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">JavaScript accordions are one of the most useful interactive UI components for modern websites, FAQ sections, product pages, dashboards, documentation pages, pricing pages, support centers, mobile layouts, and content-heavy landing pages. They help you hide long content behind clickable headers, reduce page clutter, and let users open only the information they need.</p>



<p class="wp-block-paragraph">In this guide, you will find 30 JavaScript accordion examples for real website projects, including FAQ accordions, product details accordions, mobile filter accordions, documentation toggles, pricing FAQ sections, dashboard settings panels, nested accordions, animated content expanders, one-open-at-a-time accordions, multi-open accordions, accessible accordion patterns, and responsive UI components you can customize for your own work.</p>



<p class="wp-block-paragraph">This post focuses on JavaScript accordion behavior, click handling, open and close logic, active states, smooth content expansion, keyboard-friendly interaction, responsive accordion design, and reusable vanilla JavaScript patterns. For related UI components, you can also explore our <a href="https://veebilehed24.ee/en/blog/javascript/javascript-search-filter-examples/">JavaScript search filter examples</a>, <a href="https://veebilehed24.ee/en/blog/javascript/javascript-dropdown-menu-examples/">JavaScript dropdown menu examples</a>, <a href="https://veebilehed24.ee/en/blog/javascript/javascript-slider-examples/">JavaScript slider examples</a>, and <a href="https://veebilehed24.ee/en/blog/javascript/javascript-modal-examples/">JavaScript modal examples</a>.</p>



<div class="vb24-js-accordion-jump-box">
  <a class="vb24-js-accordion-jump-button" href="#javascript-accordion-examples">View All 30 JavaScript Accordion Examples</a>
</div>

<style>
.vb24-js-accordion-jump-box {
  margin: 28px 0 36px;
}

.vb24-js-accordion-jump-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 14px 22px;
  border-radius: 999px;
  background: linear-gradient(135deg, #8b5cf6, #06b6d4 52%, #10b981);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 850;
  line-height: 1.2;
  text-decoration: none !important;
  box-shadow: 0 16px 38px rgba(139, 92, 246, 0.28);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-js-accordion-jump-button::after {
  content: "↓";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.18);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  line-height: 1;
}

.vb24-js-accordion-jump-button:hover {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transform: translateY(-2px);
  filter: saturate(1.08);
  box-shadow: 0 20px 46px rgba(139, 92, 246, 0.36);
}

@media (max-width: 640px) {
  .vb24-js-accordion-jump-button {
    width: 100%;
    padding: 14px 16px;
    font-size: 14px;
  }
}
</style>



<div class="toc-affiliate-wrap vb24-js-accordion-toc-wrap">

  <div class="toc-left vb24-js-accordion-toc-left">

    <div class="vb24-js-accordion-toc-kicker">On this page</div>

    <h2>Table of Contents</h2>

    <ul class="vl24-toc vb24-js-accordion-toc">
      <li><a href="#what-is-a-javascript-accordion">What Is a JavaScript Accordion?</a></li>
      <li><a href="#why-javascript-accordions-matter">Why JavaScript Accordions Matter</a></li>
      <li><a href="#javascript-accordion-vs-css-accordion">JavaScript Accordion vs CSS Accordion</a></li>
      <li><a href="#what-should-a-good-javascript-accordion-include">What Should a Good JavaScript Accordion Include?</a></li>
      <li><a class="vb24-featured-toc-link" href="#javascript-accordion-examples">30 JavaScript Accordion Examples</a></li>
      <li><a href="#javascript-accordion-best-practices">JavaScript Accordion Best Practices</a></li>
      <li><a href="#responsive-accordion-design-tips">Responsive Accordion Design Tips</a></li>
      <li><a href="#common-javascript-accordion-mistakes">Common JavaScript Accordion Mistakes</a></li>
      <li><a href="#javascript-accordion-faq">JavaScript Accordion FAQ</a></li>
      <li><a href="#javascript-accordion-conclusion">Conclusion</a></li>
      <li><a href="#related-javascript-and-css-guides">Related JavaScript and CSS Guides</a></li>
    </ul>

  </div>

  <div class="toc-right vb24-js-accordion-toc-right">

    <a class="vb24-entityschema-ad-card" href="https://veebilehed24.ee/en/shop/entityschema-pro/" target="_blank" rel="sponsored noopener">
      <span class="vb24-entityschema-ad-badge">WordPress SEO Plugin</span>

      <div class="vb24-entityschema-ad-image">
        <img decoding="async" src="https://veebilehed24.ee/wp-content/uploads/2026/03/entityschema-cover-600x400.webp" width="300" height="200" alt="EntitySchema Pro WordPress structured data and entity SEO plugin" loading="lazy">
      </div>

      <div class="vb24-entityschema-ad-content">
        <h3>EntitySchema Pro</h3>
        <p>Build a real entity-based structured data system for WordPress, modern SEO, and AI-readable websites.</p>

        <div class="vb24-entityschema-ad-price">
          <div class="vb24-entityschema-ad-price-left">
            <span class="vb24-entityschema-ad-price-label">Sale price</span>
            <span class="vb24-entityschema-ad-old-price">89€</span>
          </div>

          <strong class="vb24-entityschema-ad-sale-price">29€</strong>

          <span class="vb24-entityschema-ad-save">Save 60€</span>
        </div>

        <span class="vb24-entityschema-ad-button">View Plugin</span>
      </div>
    </a>

  </div>

</div>

<style>
.vb24-js-accordion-toc-wrap {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 26px;
  align-items: stretch;
  margin: 34px 0 44px;
}

.vb24-js-accordion-toc-left,
.vb24-js-accordion-toc-right {
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 28px;
  background: linear-gradient(135deg, #111827 0%, #312e81 100%);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.18);
}

.vb24-js-accordion-toc-left {
  padding: 28px 30px 30px;
}

.vb24-js-accordion-toc-kicker {
  margin-bottom: 10px;
  color: #c4b5fd !important;
  -webkit-text-fill-color: #c4b5fd !important;
  font-size: 13px;
  font-weight: 850;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb24-js-accordion-toc-left h2 {
  margin: 0 0 22px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px !important;
  line-height: 1.15 !important;
  font-weight: 850 !important;
}

.vb24-js-accordion-toc {
  display: grid !important;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px !important;
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb24-js-accordion-toc li {
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb24-js-accordion-toc li::before {
  display: none !important;
  content: none !important;
}

.vb24-js-accordion-toc a {
  display: flex;
  align-items: center;
  min-height: 54px;
  padding: 13px 15px;
  border: 1px solid rgba(148, 163, 184, 0.18);
  border-radius: 15px;
  background: rgba(255, 255, 255, 0.065);
  color: #f3f4f6 !important;
  -webkit-text-fill-color: #f3f4f6 !important;
  font-size: 15px;
  font-weight: 750;
  line-height: 1.35;
  text-decoration: none !important;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.05);
  transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease;
}

.vb24-js-accordion-toc a:hover {
  transform: translateY(-2px);
  border-color: rgba(139, 92, 246, 0.68);
  background: rgba(139, 92, 246, 0.16);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb24-js-accordion-toc .vb24-featured-toc-link {
  border-color: rgba(139, 92, 246, 0.78);
  background: linear-gradient(135deg, rgba(139, 92, 246, 0.34), rgba(6, 182, 212, 0.26), rgba(16, 185, 129, 0.24));
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb24-js-accordion-toc-right {
  display: flex;
  align-items: stretch;
  justify-content: center;
  padding: 16px;
  overflow: hidden;
}

.vb24-entityschema-ad-card,
.vb24-entityschema-ad-card * {
  box-sizing: border-box;
}

.vb24-entityschema-ad-card {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  min-height: 100%;
  padding: 12px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(34, 211, 238, 0.28), transparent 34%),
    radial-gradient(circle at 86% 14%, rgba(236, 72, 153, 0.24), transparent 36%),
    linear-gradient(135deg, #111827 0%, #312e81 52%, #701a75 100%) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  overflow: hidden;
  box-shadow: 0 20px 56px rgba(2, 6, 23, 0.32);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-entityschema-ad-card:hover {
  transform: translateY(-3px);
  filter: saturate(1.08);
  box-shadow: 0 26px 70px rgba(2, 6, 23, 0.42);
}

.vb24-entityschema-ad-badge {
  position: absolute;
  z-index: 3;
  top: 18px;
  left: 18px;
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.70);
  border: 1px solid rgba(255,255,255,0.22);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb24-entityschema-ad-image {
  overflow: hidden;
  border-radius: 17px;
  border: 1px solid rgba(255,255,255,0.16);
  background: rgba(255,255,255,0.08);
}

.vb24-entityschema-ad-image img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 17px;
}

.vb24-entityschema-ad-content {
  padding: 15px 8px 4px;
}

.vb24-entityschema-ad-content h3 {
  margin: 0 0 8px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 23px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb24-entityschema-ad-content p {
  margin: 0 0 14px !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 13px;
  line-height: 1.5;
  font-weight: 650;
}

.vb24-entityschema-ad-price {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin: 0 0 12px;
  padding: 11px 12px;
  border-radius: 16px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.16);
}

.vb24-entityschema-ad-price-left {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.vb24-entityschema-ad-price-label {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 11px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb24-entityschema-ad-old-price {
  color: rgba(255,255,255,0.62) !important;
  -webkit-text-fill-color: rgba(255,255,255,0.62) !important;
  font-size: 15px;
  line-height: 1;
  font-weight: 850;
  text-decoration: line-through;
  text-decoration-thickness: 2px;
  text-decoration-color: rgba(248, 113, 113, 0.95);
}

.vb24-entityschema-ad-sale-price {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 31px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb24-entityschema-ad-save {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 28px;
  padding: 6px 9px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.18);
  border: 1px solid rgba(74, 222, 128, 0.34);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 11px;
  font-weight: 950;
  white-space: nowrap;
}

.vb24-entityschema-ad-button {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 43px;
  padding: 12px 14px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22d3ee, #2563eb 55%, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
  box-shadow: 0 14px 34px rgba(37, 99, 235, 0.30);
}

@media (max-width: 900px) {
  .vb24-js-accordion-toc-wrap {
    grid-template-columns: 1fr;
  }

  .vb24-js-accordion-toc-right {
    justify-content: flex-start;
    max-width: 360px;
  }
}

@media (max-width: 640px) {
  .vb24-js-accordion-toc-left {
    padding: 22px 18px;
    border-radius: 22px;
  }

  .vb24-js-accordion-toc-left h2 {
    font-size: 26px !important;
  }

  .vb24-js-accordion-toc {
    grid-template-columns: 1fr;
  }

  .vb24-js-accordion-toc a {
    min-height: 48px;
    font-size: 14px;
  }

  .vb24-js-accordion-toc-right {
    max-width: 100%;
    border-radius: 22px;
  }
}
</style>



<h2 class="wp-block-heading" id="what-is-a-javascript-accordion">What Is a JavaScript Accordion?</h2>



<p class="wp-block-paragraph">A JavaScript accordion is an interactive content component where users click a header, question, label, or button to reveal hidden content below it. When the same header is clicked again, the content can close. Accordions are commonly used for FAQ sections, product information, support answers, mobile filters, pricing questions, documentation topics, settings panels, and compact landing page sections.</p>



<p class="wp-block-paragraph">The main purpose of an accordion is to organize information without making the page feel too long. Instead of showing every answer, paragraph, specification, or setting at once, an accordion keeps the layout clean and lets visitors expand only the content they want to read.</p>



<p class="wp-block-paragraph">A JavaScript accordion can be very simple or highly advanced. A basic version may toggle one answer open and closed. A more advanced version may include smooth height animation, one-open-at-a-time behavior, nested panels, icons that rotate, keyboard support, dynamic content, search filtering, active states, URL hash support, or accessible ARIA attributes.</p>



<h2 class="wp-block-heading" id="why-javascript-accordions-matter">Why JavaScript Accordions Matter</h2>



<p class="wp-block-paragraph">JavaScript accordions matter because many modern pages need to show a lot of information without overwhelming the visitor. A long FAQ section, product specification table, pricing explanation, help center, mobile filter panel, or onboarding checklist can quickly become hard to scan if everything is open at once.</p>



<ul class="wp-block-list">
  <li><strong>They reduce visual clutter</strong> by hiding secondary content until the user needs it.</li>
  <li><strong>They improve FAQ sections</strong> by making questions easier to scan and answers easier to open.</li>
  <li><strong>They help ecommerce pages</strong> by organizing product details, shipping info, sizing, materials, warranty text, and reviews.</li>
  <li><strong>They support mobile layouts</strong> by turning long sections, filters, menus, and settings into compact expandable panels.</li>
  <li><strong>They improve documentation UX</strong> by grouping related topics, steps, examples, and explanations into readable blocks.</li>
</ul>



<p class="wp-block-paragraph">Accordions are especially useful when users do not need every piece of content at the same time. Someone reading a pricing page may only care about billing questions. Someone viewing a product page may only want size details. Someone using a dashboard may only need one settings group. A well-built JavaScript accordion makes that interaction faster and cleaner.</p>



<h2 class="wp-block-heading" id="javascript-accordion-vs-css-accordion">JavaScript Accordion vs CSS Accordion</h2>



<p class="wp-block-paragraph">A CSS accordion can work well for simple show-and-hide content, especially when using checkbox, radio, details, summary, or hover-based patterns. However, JavaScript gives you more control over behavior, state, animation, accessibility, and logic.</p>



<p class="wp-block-paragraph">With JavaScript, you can decide whether multiple panels can stay open, whether opening one panel should close the others, whether the first item should be open by default, how icons should animate, how keyboard interaction should work, and how the accordion should respond to dynamic content changes.</p>



<ul class="wp-block-list">
  <li><strong>Use a CSS accordion</strong> when the component is very simple and does not need advanced logic.</li>
  <li><strong>Use a JavaScript accordion</strong> when you need custom open and close behavior, animation control, ARIA updates, or dynamic state.</li>
  <li><strong>Use one-open-at-a-time logic</strong> for FAQ sections, pricing questions, and compact information groups.</li>
  <li><strong>Use multi-open logic</strong> when users may need to compare several answers, settings, or product details.</li>
  <li><strong>Use nested accordions carefully</strong> when documentation, menus, filters, or help centers need multiple content levels.</li>
</ul>



<p class="wp-block-paragraph">This guide focuses on JavaScript accordion examples, so every demo will include visible JavaScript, HTML, and CSS code. The examples are designed to be copy-paste friendly, easy to customize, and different in layout, style, structure, and interaction pattern.</p>



<h2 class="wp-block-heading" id="what-should-a-good-javascript-accordion-include">What Should a Good JavaScript Accordion Include?</h2>



<p class="wp-block-paragraph">A good JavaScript accordion should feel obvious, fast, and stable. Users should understand which parts are clickable, which panel is open, and what happened after they clicked. The content should open smoothly, the active state should be visible, and the layout should remain usable on desktop, tablet, and mobile.</p>



<div class="vb24-js-accordion-checklist">
  <div class="vb24-js-accordion-check-item">
    <h3>Clear clickable headers</h3>
    <p>Accordion buttons should look interactive, with strong labels, icons, arrows, or plus signs that show users they can expand the content.</p>
  </div>

  <div class="vb24-js-accordion-check-item">
    <h3>Visible active state</h3>
    <p>The open accordion item should look different from closed items, so users know which section they are currently reading.</p>
  </div>

  <div class="vb24-js-accordion-check-item">
    <h3>Smooth open and close behavior</h3>
    <p>JavaScript can control height, classes, icons, and state so the accordion feels polished instead of abrupt or broken.</p>
  </div>

  <div class="vb24-js-accordion-check-item">
    <h3>Responsive mobile layout</h3>
    <p>Accordions should be easy to tap on small screens, with readable text, enough spacing, and no cramped controls.</p>
  </div>
</div>

<style>
.vb24-js-accordion-checklist {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 30px;
}

.vb24-js-accordion-check-item {
  padding: 20px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 22px;
  background:
    radial-gradient(circle at 18% 10%, rgba(139, 92, 246, 0.08), transparent 32%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb24-js-accordion-check-item h3 {
  margin: 0 0 10px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 850;
}

.vb24-js-accordion-check-item p {
  margin: 0;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb24-js-accordion-checklist {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-js-accordion-checklist {
    grid-template-columns: 1fr;
  }

  .vb24-js-accordion-check-item {
    padding: 18px;
    border-radius: 20px;
  }
}
</style>



<p class="wp-block-paragraph">Before building an accordion, decide how the component should behave. Should one item open at a time, or should users be able to open multiple items? Should the first panel be open by default? Should the accordion use a plus icon, chevron, number, badge, or progress indicator? Should it work as a FAQ block, product information section, mobile menu, dashboard panel, or documentation layout?</p>



<ul class="wp-block-list">
  <li><strong>Use button elements</strong> for accordion triggers so the clickable areas are more accessible and predictable.</li>
  <li><strong>Add active classes</strong> to open items so CSS can style the selected state clearly.</li>
  <li><strong>Update icons</strong> when panels open and close, such as plus to minus or chevron rotation.</li>
  <li><strong>Use smooth animation carefully</strong> so content expands nicely without layout jumps.</li>
  <li><strong>Keep panel content readable</strong> with enough spacing, line height, and contrast.</li>
  <li><strong>Support keyboard users</strong> with real buttons, focus states, and logical tab order.</li>
  <li><strong>Avoid hiding important content</strong> if users must see it immediately to complete a task.</li>
  <li><strong>Test long answers</strong> because real FAQ, product, and documentation content is often longer than demo text.</li>
  <li><strong>Make touch targets large enough</strong> for mobile users who tap accordion headers with a thumb.</li>
  <li><strong>Keep JavaScript scoped</strong> so multiple accordions can work on the same page without conflicts.</li>
</ul>



<p class="wp-block-paragraph">You can combine JavaScript accordions with many other interface patterns. FAQ accordions work well with <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-forms/">modern CSS forms</a> on support pages, product accordions can be placed inside <a href="https://veebilehed24.ee/en/blog/css-effects/25-modern-css-cards-for-websites-html-css-examples/">modern CSS cards</a>, mobile filter accordions can pair with <a href="https://veebilehed24.ee/en/blog/javascript/javascript-search-filter-examples/">JavaScript search filters</a>, and documentation accordions can be combined with layouts from our <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-layouts/">modern CSS layouts</a> guide.</p>



<h2 class="wp-block-heading" id="javascript-accordion-examples">30 JavaScript Accordion Examples</h2>



<p class="wp-block-paragraph">Now let’s look at 30 JavaScript accordion examples for real website projects. Each example uses a different layout, visual style, open and close behavior, content structure, animation style, icon pattern, FAQ format, product details section, dashboard panel, mobile filter layout, nested structure, or responsive accordion approach, so you can build professional expandable UI components with visible JavaScript, HTML, and CSS code.</p>



<h2 class="wp-block-heading">1. Modern FAQ Accordion</h2>



<p class="wp-block-paragraph"><strong>A modern FAQ accordion</strong> is one of the most common JavaScript accordion patterns for websites, SaaS pages, service pages, ecommerce stores, and landing pages. It keeps questions visible while hiding longer answers until the user clicks.</p>



<p class="wp-block-paragraph">This example uses a clean FAQ card layout with smooth open and close behavior, plus and minus icons, active item styling, and one-open-at-a-time JavaScript logic.</p>



<ul class="wp-block-list">
<li>One-open-at-a-time accordion behavior</li>
<li>Smooth FAQ answer expansion</li>
<li>Plus and minus icon update</li>
<li>Active state styling</li>
<li>Responsive FAQ layout</li>
</ul>



<div class="vb-accordion-one-demo">
  <div class="vb-accordion-one-shell" data-vb-accordion-one>
    <div class="vb-accordion-one-intro">
      <span>Example 01</span>
      <h3>Modern FAQ Accordion</h3>
      <p>Click a question to open the answer. Opening one FAQ item automatically closes the others.</p>
    </div>

    <div class="vb-accordion-one-list">
      <div class="vb-accordion-one-item is-open">
        <button class="vb-accordion-one-trigger" type="button" aria-expanded="true">
          <span>What is a JavaScript accordion?</span>
          <strong>−</strong>
        </button>
        <div class="vb-accordion-one-panel">
          <div class="vb-accordion-one-content">
            <p>A JavaScript accordion is an interactive UI component that shows or hides content when a user clicks a heading, question, or button.</p>
          </div>
        </div>
      </div>

      <div class="vb-accordion-one-item">
        <button class="vb-accordion-one-trigger" type="button" aria-expanded="false">
          <span>Where should I use accordions?</span>
          <strong>+</strong>
        </button>
        <div class="vb-accordion-one-panel">
          <div class="vb-accordion-one-content">
            <p>Accordions work well for FAQ sections, product details, pricing questions, documentation pages, mobile filters, and dashboard settings panels.</p>
          </div>
        </div>
      </div>

      <div class="vb-accordion-one-item">
        <button class="vb-accordion-one-trigger" type="button" aria-expanded="false">
          <span>Can multiple accordion items stay open?</span>
          <strong>+</strong>
        </button>
        <div class="vb-accordion-one-panel">
          <div class="vb-accordion-one-content">
            <p>Yes. JavaScript can be written for one-open-at-a-time accordions or multi-open accordions depending on the user experience you want.</p>
          </div>
        </div>
      </div>

      <div class="vb-accordion-one-item">
        <button class="vb-accordion-one-trigger" type="button" aria-expanded="false">
          <span>Is this accordion responsive?</span>
          <strong>+</strong>
        </button>
        <div class="vb-accordion-one-panel">
          <div class="vb-accordion-one-content">
            <p>Yes. The layout, spacing, font sizes, and clickable buttons are designed to stay readable and easy to tap on smaller screens.</p>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-accordion-one-demo,
.vb-accordion-one-demo * {
  box-sizing: border-box;
}

.vb-accordion-one-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 18%, rgba(139, 92, 246, 0.24), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(6, 182, 212, 0.20), transparent 36%),
    linear-gradient(135deg, #f5f3ff 0%, #ecfeff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(196, 181, 253, 0.50);
  box-shadow: 0 24px 70px rgba(76, 29, 149, 0.12);
}

.vb-accordion-one-shell {
  max-width: 980px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-accordion-one-intro {
  max-width: 720px;
  margin-bottom: 26px;
}

.vb-accordion-one-intro > span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-accordion-one-intro h3 {
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 64px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-accordion-one-intro p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-one-list {
  display: grid;
  gap: 14px;
}

.vb-accordion-one-item {
  overflow: hidden;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.26);
  transition: background 0.22s ease, border-color 0.22s ease, box-shadow 0.22s ease;
}

.vb-accordion-one-item.is-open {
  background:
    radial-gradient(circle at 12% 12%, rgba(139, 92, 246, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border-color: rgba(139, 92, 246, 0.42);
  box-shadow: 0 18px 46px rgba(76, 29, 149, 0.10);
}

.vb-accordion-one-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  width: 100%;
  min-height: 72px;
  padding: 20px 22px;
  border: 0;
  background: transparent;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  text-align: left;
  cursor: pointer;
}

.vb-accordion-one-trigger span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.3;
  font-weight: 900;
  letter-spacing: -0.025em;
}

.vb-accordion-one-trigger strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 24px;
  line-height: 1;
  font-weight: 900;
}

.vb-accordion-one-item.is-open .vb-accordion-one-trigger strong {
  background: linear-gradient(135deg, #8b5cf6, #06b6d4) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-one-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-one-content {
  padding: 0 22px 22px;
}

.vb-accordion-one-content p {
  margin: 0 !important;
  padding-top: 2px;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 640px) {
  .vb-accordion-one-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-accordion-one-shell {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-accordion-one-intro h3 {
    font-size: 38px !important;
  }

  .vb-accordion-one-trigger {
    min-height: 64px;
    padding: 18px;
  }

  .vb-accordion-one-trigger span {
    font-size: 16px;
  }

  .vb-accordion-one-content {
    padding: 0 18px 18px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-one]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-one-item"));

  function closeItem(item) {
    const trigger = item.querySelector(".vb-accordion-one-trigger");
    const panel = item.querySelector(".vb-accordion-one-panel");
    const icon = trigger.querySelector("strong");

    item.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
    icon.textContent = "+";
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const trigger = item.querySelector(".vb-accordion-one-trigger");
    const panel = item.querySelector(".vb-accordion-one-panel");
    const icon = trigger.querySelector("strong");

    item.classList.add("is-open");
    trigger.setAttribute("aria-expanded", "true");
    icon.textContent = "−";
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const trigger = item.querySelector(".vb-accordion-one-trigger");

    trigger.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const firstOpen = accordion.querySelector(".vb-accordion-one-item.is-open");
  if (firstOpen) {
    openItem(firstOpen);
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-one]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-one-item"));

  function closeItem(item) {
    const trigger = item.querySelector(".vb-accordion-one-trigger");
    const panel = item.querySelector(".vb-accordion-one-panel");
    const icon = trigger.querySelector("strong");

    item.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
    icon.textContent = "+";
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const trigger = item.querySelector(".vb-accordion-one-trigger");
    const panel = item.querySelector(".vb-accordion-one-panel");
    const icon = trigger.querySelector("strong");

    item.classList.add("is-open");
    trigger.setAttribute("aria-expanded", "true");
    icon.textContent = "−";
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const trigger = item.querySelector(".vb-accordion-one-trigger");

    trigger.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const firstOpen = accordion.querySelector(".vb-accordion-one-item.is-open");
  if (firstOpen) {
    openItem(firstOpen);
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-one-demo"&gt;
  &lt;div class="vb-accordion-one-shell" data-vb-accordion-one&gt;
    &lt;div class="vb-accordion-one-intro"&gt;
      &lt;span&gt;Example 01&lt;/span&gt;
      &lt;h3&gt;Modern FAQ Accordion&lt;/h3&gt;
      &lt;p&gt;Click a question to open the answer. Opening one FAQ item automatically closes the others.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-one-list"&gt;
      &lt;div class="vb-accordion-one-item is-open"&gt;
        &lt;button class="vb-accordion-one-trigger" type="button" aria-expanded="true"&gt;
          &lt;span&gt;What is a JavaScript accordion?&lt;/span&gt;
          &lt;strong&gt;−&lt;/strong&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-one-panel"&gt;
          &lt;div class="vb-accordion-one-content"&gt;
            &lt;p&gt;A JavaScript accordion is an interactive UI component that shows or hides content when a user clicks a heading, question, or button.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-one-item"&gt;
        &lt;button class="vb-accordion-one-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Where should I use accordions?&lt;/span&gt;
          &lt;strong&gt;+&lt;/strong&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-one-panel"&gt;
          &lt;div class="vb-accordion-one-content"&gt;
            &lt;p&gt;Accordions work well for FAQ sections, product details, pricing questions, documentation pages, mobile filters, and dashboard settings panels.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-one-item"&gt;
        &lt;button class="vb-accordion-one-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Can multiple accordion items stay open?&lt;/span&gt;
          &lt;strong&gt;+&lt;/strong&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-one-panel"&gt;
          &lt;div class="vb-accordion-one-content"&gt;
            &lt;p&gt;Yes. JavaScript can be written for one-open-at-a-time accordions or multi-open accordions depending on the user experience you want.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-one-item"&gt;
        &lt;button class="vb-accordion-one-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Is this accordion responsive?&lt;/span&gt;
          &lt;strong&gt;+&lt;/strong&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-one-panel"&gt;
          &lt;div class="vb-accordion-one-content"&gt;
            &lt;p&gt;Yes. The layout, spacing, font sizes, and clickable buttons are designed to stay readable and easy to tap on smaller screens.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-one-demo,
.vb-accordion-one-demo * {
  box-sizing: border-box;
}

.vb-accordion-one-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 18%, rgba(139, 92, 246, 0.24), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(6, 182, 212, 0.20), transparent 36%),
    linear-gradient(135deg, #f5f3ff 0%, #ecfeff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(196, 181, 253, 0.50);
  box-shadow: 0 24px 70px rgba(76, 29, 149, 0.12);
}

.vb-accordion-one-shell {
  max-width: 980px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-accordion-one-intro {
  max-width: 720px;
  margin-bottom: 26px;
}

.vb-accordion-one-intro &gt; span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-accordion-one-intro h3 {
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 64px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-accordion-one-intro p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-one-list {
  display: grid;
  gap: 14px;
}

.vb-accordion-one-item {
  overflow: hidden;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.26);
  transition: background 0.22s ease, border-color 0.22s ease, box-shadow 0.22s ease;
}

.vb-accordion-one-item.is-open {
  background:
    radial-gradient(circle at 12% 12%, rgba(139, 92, 246, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border-color: rgba(139, 92, 246, 0.42);
  box-shadow: 0 18px 46px rgba(76, 29, 149, 0.10);
}

.vb-accordion-one-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  width: 100%;
  min-height: 72px;
  padding: 20px 22px;
  border: 0;
  background: transparent;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  text-align: left;
  cursor: pointer;
}

.vb-accordion-one-trigger span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.3;
  font-weight: 900;
  letter-spacing: -0.025em;
}

.vb-accordion-one-trigger strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 24px;
  line-height: 1;
  font-weight: 900;
}

.vb-accordion-one-item.is-open .vb-accordion-one-trigger strong {
  background: linear-gradient(135deg, #8b5cf6, #06b6d4) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-one-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-one-content {
  padding: 0 22px 22px;
}

.vb-accordion-one-content p {
  margin: 0 !important;
  padding-top: 2px;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 640px) {
  .vb-accordion-one-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-accordion-one-shell {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-accordion-one-intro h3 {
    font-size: 38px !important;
  }

  .vb-accordion-one-trigger {
    min-height: 64px;
    padding: 18px;
  }

  .vb-accordion-one-trigger span {
    font-size: 16px;
  }

  .vb-accordion-one-content {
    padding: 0 18px 18px;
  }
}</pre>



<p class="wp-block-paragraph">This modern FAQ accordion is a strong base pattern for support sections, pricing pages, homepage FAQ blocks, service pages, and landing pages where visitors need quick answers without scrolling through long visible text.</p>



<h2 class="wp-block-heading">2. Product Details Accordion</h2>



<p class="wp-block-paragraph"><strong>A product details accordion</strong> helps ecommerce pages organize important information such as specifications, shipping, materials, care instructions, warranty details, and return policy content. It keeps product pages cleaner while still making detailed information available.</p>



<p class="wp-block-paragraph">This example uses a split ecommerce layout with a product preview card on the left and a vertical accordion on the right. The JavaScript allows multiple sections to stay open, which is useful when shoppers want to compare details before buying.</p>



<ul class="wp-block-list">
<li>Multi-open accordion behavior</li>
<li>Product page information layout</li>
<li>Animated chevron rotation</li>
<li>Specification and shipping panels</li>
<li>Professional ecommerce-style design</li>
</ul>



<div class="vb-accordion-two-demo">
  <div class="vb-accordion-two-product" data-vb-accordion-two>
    <div class="vb-accordion-two-preview">
      <span>Example 02</span>
      <div class="vb-accordion-two-product-art">
        <div class="vb-accordion-two-card-shape"></div>
      </div>
      <h3>Product Details Accordion</h3>
      <p>Use expandable panels to organize product specifications, delivery details, materials, and warranty text.</p>
      <div class="vb-accordion-two-price">
        <strong>€149</strong>
        <small>In stock</small>
      </div>
    </div>

    <div class="vb-accordion-two-info">
      <div class="vb-accordion-two-item is-open">
        <button class="vb-accordion-two-trigger" type="button" aria-expanded="true">
          <span>Product specifications</span>
          <strong>⌄</strong>
        </button>
        <div class="vb-accordion-two-panel">
          <div class="vb-accordion-two-content">
            <ul>
              <li>Material: powder-coated aluminum frame</li>
              <li>Finish: matte graphite surface</li>
              <li>Size: 120 × 60 × 74 cm</li>
              <li>Best for: modern home office setups</li>
            </ul>
          </div>
        </div>
      </div>

      <div class="vb-accordion-two-item">
        <button class="vb-accordion-two-trigger" type="button" aria-expanded="false">
          <span>Shipping and delivery</span>
          <strong>⌄</strong>
        </button>
        <div class="vb-accordion-two-panel">
          <div class="vb-accordion-two-content">
            <p>Standard delivery usually takes 3–6 business days. Large items may arrive in separate packages depending on warehouse availability.</p>
          </div>
        </div>
      </div>

      <div class="vb-accordion-two-item">
        <button class="vb-accordion-two-trigger" type="button" aria-expanded="false">
          <span>Care instructions</span>
          <strong>⌄</strong>
        </button>
        <div class="vb-accordion-two-panel">
          <div class="vb-accordion-two-content">
            <p>Clean the surface with a soft cloth and mild soap. Avoid abrasive cleaners, harsh chemicals, and rough scrubbing tools.</p>
          </div>
        </div>
      </div>

      <div class="vb-accordion-two-item">
        <button class="vb-accordion-two-trigger" type="button" aria-expanded="false">
          <span>Warranty and returns</span>
          <strong>⌄</strong>
        </button>
        <div class="vb-accordion-two-panel">
          <div class="vb-accordion-two-content">
            <p>The product includes a 2-year limited warranty. Returns are accepted within 30 days if the item is unused and returned in original packaging.</p>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-accordion-two-demo,
.vb-accordion-two-demo * {
  box-sizing: border-box;
}

.vb-accordion-two-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 16%, rgba(251, 146, 60, 0.24), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(244, 63, 94, 0.20), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #fff1f2 52%, #ffffff 100%) !important;
  border: 1px solid rgba(253, 186, 116, 0.48);
  box-shadow: 0 24px 70px rgba(124, 45, 18, 0.12);
}

.vb-accordion-two-product {
  display: grid;
  grid-template-columns: minmax(280px, 0.88fr) minmax(0, 1.12fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
  padding: 18px;
  border-radius: 30px;
  background: #111827;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.24);
}

.vb-accordion-two-preview {
  padding: 26px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 18% 16%, rgba(251, 146, 60, 0.28), transparent 34%),
    linear-gradient(135deg, #7c2d12, #be123c) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-two-preview > span {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-accordion-two-product-art {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 260px;
  margin-bottom: 22px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 36% 28%, rgba(255, 255, 255, 0.28), transparent 32%),
    linear-gradient(135deg, rgba(255,255,255,0.14), rgba(255,255,255,0.06)) !important;
  border: 1px solid rgba(255,255,255,0.15);
  overflow: hidden;
}

.vb-accordion-two-card-shape {
  width: 190px;
  height: 150px;
  border-radius: 32px;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.92), rgba(255,237,213,0.76)) !important;
  box-shadow:
    0 28px 60px rgba(0,0,0,0.28),
    inset 0 1px 0 rgba(255,255,255,0.76);
  transform: rotate(-7deg);
  position: relative;
}

.vb-accordion-two-card-shape::before {
  content: "";
  position: absolute;
  left: 28px;
  right: 28px;
  top: 34px;
  height: 12px;
  border-radius: 999px;
  background: rgba(190, 18, 60, 0.32);
  box-shadow: 0 32px 0 rgba(190, 18, 60, 0.22), 0 64px 0 rgba(190, 18, 60, 0.16);
}

.vb-accordion-two-preview h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 4vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-accordion-two-preview p {
  margin: 0 0 22px !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-accordion-two-price {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 16px;
  border-radius: 20px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-accordion-two-price strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-two-price small {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.18);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-accordion-two-info {
  display: grid;
  align-content: start;
  gap: 14px;
  padding: 10px;
}

.vb-accordion-two-item {
  overflow: hidden;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 18px 50px rgba(2, 6, 23, 0.18);
}

.vb-accordion-two-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  width: 100%;
  min-height: 72px;
  padding: 20px 22px;
  border: 0;
  background: #ffffff;
  text-align: left;
  cursor: pointer;
}

.vb-accordion-two-trigger span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
  letter-spacing: -0.03em;
}

.vb-accordion-two-trigger strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 38px;
  height: 38px;
  border-radius: 14px;
  background: #fff7ed;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 24px;
  font-weight: 950;
  transform: rotate(0deg);
  transition: transform 0.22s ease, background 0.22s ease, color 0.22s ease;
}

.vb-accordion-two-item.is-open .vb-accordion-two-trigger strong {
  transform: rotate(180deg);
  background: linear-gradient(135deg, #fb923c, #be123c) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-two-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-two-content {
  padding: 0 22px 22px;
}

.vb-accordion-two-content p,
.vb-accordion-two-content li {
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-two-content p {
  margin: 0 !important;
}

.vb-accordion-two-content ul {
  display: grid;
  gap: 8px;
  margin: 0 !important;
  padding-left: 20px !important;
}

@media (max-width: 900px) {
  .vb-accordion-two-product {
    grid-template-columns: 1fr;
  }

  .vb-accordion-two-product-art {
    min-height: 220px;
  }
}

@media (max-width: 640px) {
  .vb-accordion-two-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-accordion-two-product {
    padding: 12px;
    border-radius: 24px;
  }

  .vb-accordion-two-preview {
    padding: 22px;
    border-radius: 20px;
  }

  .vb-accordion-two-preview h3 {
    font-size: 38px !important;
  }

  .vb-accordion-two-trigger {
    min-height: 64px;
    padding: 18px;
  }

  .vb-accordion-two-trigger span {
    font-size: 16px;
  }

  .vb-accordion-two-content {
    padding: 0 18px 18px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-two]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-two-item"));

  function setPanelHeight(item) {
    const panel = item.querySelector(".vb-accordion-two-panel");

    if (item.classList.contains("is-open")) {
      panel.style.maxHeight = panel.scrollHeight + "px";
    } else {
      panel.style.maxHeight = "0px";
    }
  }

  items.forEach(function (item) {
    const trigger = item.querySelector(".vb-accordion-two-trigger");

    trigger.addEventListener("click", function () {
      const isOpen = item.classList.toggle("is-open");
      trigger.setAttribute("aria-expanded", isOpen ? "true" : "false");
      setPanelHeight(item);
    });

    setPanelHeight(item);
  });

  window.addEventListener("resize", function () {
    items.forEach(setPanelHeight);
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-two]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-two-item"));

  function setPanelHeight(item) {
    const panel = item.querySelector(".vb-accordion-two-panel");

    if (item.classList.contains("is-open")) {
      panel.style.maxHeight = panel.scrollHeight + "px";
    } else {
      panel.style.maxHeight = "0px";
    }
  }

  items.forEach(function (item) {
    const trigger = item.querySelector(".vb-accordion-two-trigger");

    trigger.addEventListener("click", function () {
      const isOpen = item.classList.toggle("is-open");
      trigger.setAttribute("aria-expanded", isOpen ? "true" : "false");
      setPanelHeight(item);
    });

    setPanelHeight(item);
  });

  window.addEventListener("resize", function () {
    items.forEach(setPanelHeight);
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-two-demo"&gt;
  &lt;div class="vb-accordion-two-product" data-vb-accordion-two&gt;
    &lt;div class="vb-accordion-two-preview"&gt;
      &lt;span&gt;Example 02&lt;/span&gt;
      &lt;div class="vb-accordion-two-product-art"&gt;
        &lt;div class="vb-accordion-two-card-shape"&gt;&lt;/div&gt;
      &lt;/div&gt;
      &lt;h3&gt;Product Details Accordion&lt;/h3&gt;
      &lt;p&gt;Use expandable panels to organize product specifications, delivery details, materials, and warranty text.&lt;/p&gt;
      &lt;div class="vb-accordion-two-price"&gt;
        &lt;strong&gt;€149&lt;/strong&gt;
        &lt;small&gt;In stock&lt;/small&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-two-info"&gt;
      &lt;div class="vb-accordion-two-item is-open"&gt;
        &lt;button class="vb-accordion-two-trigger" type="button" aria-expanded="true"&gt;
          &lt;span&gt;Product specifications&lt;/span&gt;
          &lt;strong&gt;⌄&lt;/strong&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-two-panel"&gt;
          &lt;div class="vb-accordion-two-content"&gt;
            &lt;ul&gt;
              &lt;li&gt;Material: powder-coated aluminum frame&lt;/li&gt;
              &lt;li&gt;Finish: matte graphite surface&lt;/li&gt;
              &lt;li&gt;Size: 120 × 60 × 74 cm&lt;/li&gt;
              &lt;li&gt;Best for: modern home office setups&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-two-item"&gt;
        &lt;button class="vb-accordion-two-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Shipping and delivery&lt;/span&gt;
          &lt;strong&gt;⌄&lt;/strong&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-two-panel"&gt;
          &lt;div class="vb-accordion-two-content"&gt;
            &lt;p&gt;Standard delivery usually takes 3–6 business days. Large items may arrive in separate packages depending on warehouse availability.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-two-item"&gt;
        &lt;button class="vb-accordion-two-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Care instructions&lt;/span&gt;
          &lt;strong&gt;⌄&lt;/strong&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-two-panel"&gt;
          &lt;div class="vb-accordion-two-content"&gt;
            &lt;p&gt;Clean the surface with a soft cloth and mild soap. Avoid abrasive cleaners, harsh chemicals, and rough scrubbing tools.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-two-item"&gt;
        &lt;button class="vb-accordion-two-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Warranty and returns&lt;/span&gt;
          &lt;strong&gt;⌄&lt;/strong&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-two-panel"&gt;
          &lt;div class="vb-accordion-two-content"&gt;
            &lt;p&gt;The product includes a 2-year limited warranty. Returns are accepted within 30 days if the item is unused and returned in original packaging.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-two-demo,
.vb-accordion-two-demo * {
  box-sizing: border-box;
}

.vb-accordion-two-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 16%, rgba(251, 146, 60, 0.24), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(244, 63, 94, 0.20), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #fff1f2 52%, #ffffff 100%) !important;
  border: 1px solid rgba(253, 186, 116, 0.48);
  box-shadow: 0 24px 70px rgba(124, 45, 18, 0.12);
}

.vb-accordion-two-product {
  display: grid;
  grid-template-columns: minmax(280px, 0.88fr) minmax(0, 1.12fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
  padding: 18px;
  border-radius: 30px;
  background: #111827;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.24);
}

.vb-accordion-two-preview {
  padding: 26px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 18% 16%, rgba(251, 146, 60, 0.28), transparent 34%),
    linear-gradient(135deg, #7c2d12, #be123c) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-two-preview &gt; span {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-accordion-two-product-art {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 260px;
  margin-bottom: 22px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 36% 28%, rgba(255, 255, 255, 0.28), transparent 32%),
    linear-gradient(135deg, rgba(255,255,255,0.14), rgba(255,255,255,0.06)) !important;
  border: 1px solid rgba(255,255,255,0.15);
  overflow: hidden;
}

.vb-accordion-two-card-shape {
  width: 190px;
  height: 150px;
  border-radius: 32px;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.92), rgba(255,237,213,0.76)) !important;
  box-shadow:
    0 28px 60px rgba(0,0,0,0.28),
    inset 0 1px 0 rgba(255,255,255,0.76);
  transform: rotate(-7deg);
  position: relative;
}

.vb-accordion-two-card-shape::before {
  content: "";
  position: absolute;
  left: 28px;
  right: 28px;
  top: 34px;
  height: 12px;
  border-radius: 999px;
  background: rgba(190, 18, 60, 0.32);
  box-shadow: 0 32px 0 rgba(190, 18, 60, 0.22), 0 64px 0 rgba(190, 18, 60, 0.16);
}

.vb-accordion-two-preview h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 4vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-accordion-two-preview p {
  margin: 0 0 22px !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-accordion-two-price {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 16px;
  border-radius: 20px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-accordion-two-price strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-two-price small {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.18);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-accordion-two-info {
  display: grid;
  align-content: start;
  gap: 14px;
  padding: 10px;
}

.vb-accordion-two-item {
  overflow: hidden;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 18px 50px rgba(2, 6, 23, 0.18);
}

.vb-accordion-two-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  width: 100%;
  min-height: 72px;
  padding: 20px 22px;
  border: 0;
  background: #ffffff;
  text-align: left;
  cursor: pointer;
}

.vb-accordion-two-trigger span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
  letter-spacing: -0.03em;
}

.vb-accordion-two-trigger strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 38px;
  height: 38px;
  border-radius: 14px;
  background: #fff7ed;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 24px;
  font-weight: 950;
  transform: rotate(0deg);
  transition: transform 0.22s ease, background 0.22s ease, color 0.22s ease;
}

.vb-accordion-two-item.is-open .vb-accordion-two-trigger strong {
  transform: rotate(180deg);
  background: linear-gradient(135deg, #fb923c, #be123c) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-two-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-two-content {
  padding: 0 22px 22px;
}

.vb-accordion-two-content p,
.vb-accordion-two-content li {
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-two-content p {
  margin: 0 !important;
}

.vb-accordion-two-content ul {
  display: grid;
  gap: 8px;
  margin: 0 !important;
  padding-left: 20px !important;
}

@media (max-width: 900px) {
  .vb-accordion-two-product {
    grid-template-columns: 1fr;
  }

  .vb-accordion-two-product-art {
    min-height: 220px;
  }
}

@media (max-width: 640px) {
  .vb-accordion-two-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-accordion-two-product {
    padding: 12px;
    border-radius: 24px;
  }

  .vb-accordion-two-preview {
    padding: 22px;
    border-radius: 20px;
  }

  .vb-accordion-two-preview h3 {
    font-size: 38px !important;
  }

  .vb-accordion-two-trigger {
    min-height: 64px;
    padding: 18px;
  }

  .vb-accordion-two-trigger span {
    font-size: 16px;
  }

  .vb-accordion-two-content {
    padding: 0 18px 18px;
  }
}</pre>



<p class="wp-block-paragraph">This product details accordion is useful for ecommerce product pages, catalog landing pages, service packages, digital products, course pages, and any page where users need structured details without a long block of visible text.</p>



<h2 class="wp-block-heading">3. Dark Glassmorphism Accordion</h2>



<p class="wp-block-paragraph"><strong>A dark glassmorphism accordion</strong> is a strong choice for SaaS landing pages, AI tools, crypto dashboards, premium product pages, and futuristic website sections. It uses translucent panels, blurred backgrounds, glowing borders, and smooth JavaScript toggle behavior.</p>



<p class="wp-block-paragraph">This example uses a dark gradient background, glass-style accordion rows, numbered labels, glowing active states, and one-open-at-a-time behavior. The design is intentionally different from the previous examples, with softer pill-shaped panels and neon visual details.</p>



<ul class="wp-block-list">
<li>Dark glassmorphism accordion UI</li>
<li>One-open-at-a-time JavaScript behavior</li>
<li>Numbered accordion rows</li>
<li>Glowing active border effect</li>
<li>Responsive premium-style layout</li>
</ul>



<div class="vb-accordion-three-demo">
  <div class="vb-accordion-three-orb vb-accordion-three-orb-a"></div>
  <div class="vb-accordion-three-orb vb-accordion-three-orb-b"></div>

  <div class="vb-accordion-three-shell" data-vb-accordion-three>
    <div class="vb-accordion-three-top">
      <span>Example 03</span>
      <h3>Dark Glassmorphism Accordion</h3>
      <p>Use a glowing glass accordion layout for futuristic FAQ, SaaS, AI tool, or dashboard sections.</p>
    </div>

    <div class="vb-accordion-three-stack">
      <section class="vb-accordion-three-item is-open">
        <button class="vb-accordion-three-trigger" type="button" aria-expanded="true">
          <span class="vb-accordion-three-number">01</span>
          <span class="vb-accordion-three-title">Can I use this accordion on a SaaS landing page?</span>
          <span class="vb-accordion-three-icon"></span>
        </button>
        <div class="vb-accordion-three-panel">
          <div class="vb-accordion-three-content">
            <p>Yes. This layout works well for product FAQs, feature explanations, onboarding questions, pricing details, and premium landing page sections.</p>
          </div>
        </div>
      </section>

      <section class="vb-accordion-three-item">
        <button class="vb-accordion-three-trigger" type="button" aria-expanded="false">
          <span class="vb-accordion-three-number">02</span>
          <span class="vb-accordion-three-title">What makes glassmorphism different?</span>
          <span class="vb-accordion-three-icon"></span>
        </button>
        <div class="vb-accordion-three-panel">
          <div class="vb-accordion-three-content">
            <p>Glassmorphism uses translucent backgrounds, subtle borders, blurred layers, and soft glowing effects to create depth without heavy visual blocks.</p>
          </div>
        </div>
      </section>

      <section class="vb-accordion-three-item">
        <button class="vb-accordion-three-trigger" type="button" aria-expanded="false">
          <span class="vb-accordion-three-number">03</span>
          <span class="vb-accordion-three-title">Does this design support long content?</span>
          <span class="vb-accordion-three-icon"></span>
        </button>
        <div class="vb-accordion-three-panel">
          <div class="vb-accordion-three-content">
            <p>The JavaScript calculates the panel height dynamically, so longer answers, feature lists, short paragraphs, or documentation notes can open smoothly.</p>
          </div>
        </div>
      </section>

      <section class="vb-accordion-three-item">
        <button class="vb-accordion-three-trigger" type="button" aria-expanded="false">
          <span class="vb-accordion-three-number">04</span>
          <span class="vb-accordion-three-title">Can I change the colors?</span>
          <span class="vb-accordion-three-icon"></span>
        </button>
        <div class="vb-accordion-three-panel">
          <div class="vb-accordion-three-content">
            <p>Yes. You can adjust the background gradients, glowing borders, text colors, and orb effects to match your brand or website theme.</p>
          </div>
        </div>
      </section>
    </div>
  </div>
</div>

<style>
.vb-accordion-three-demo,
.vb-accordion-three-demo * {
  box-sizing: border-box;
}

.vb-accordion-three-demo {
  position: relative;
  isolation: isolate;
  margin: 28px 0;
  padding: 46px;
  border-radius: 18px 58px 18px 58px;
  background:
    radial-gradient(circle at 20% 20%, rgba(34, 211, 238, 0.18), transparent 34%),
    radial-gradient(circle at 80% 14%, rgba(168, 85, 247, 0.20), transparent 34%),
    linear-gradient(135deg, #020617 0%, #111827 48%, #312e81 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  overflow: hidden;
  box-shadow: 0 30px 90px rgba(2, 6, 23, 0.38);
}

.vb-accordion-three-orb {
  position: absolute;
  z-index: -1;
  border-radius: 999px;
  filter: blur(4px);
  opacity: 0.72;
}

.vb-accordion-three-orb-a {
  width: 180px;
  height: 180px;
  left: -52px;
  top: -48px;
  background: rgba(34, 211, 238, 0.22);
}

.vb-accordion-three-orb-b {
  width: 240px;
  height: 240px;
  right: -80px;
  bottom: -90px;
  background: rgba(168, 85, 247, 0.24);
}

.vb-accordion-three-shell {
  max-width: 1040px;
  margin: 0 auto;
}

.vb-accordion-three-top {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(260px, 0.7fr);
  gap: 24px;
  align-items: end;
  margin-bottom: 28px;
}

.vb-accordion-three-top > span {
  grid-column: 1 / -1;
  justify-self: start;
  display: inline-flex;
  padding: 8px 13px;
  border-radius: 0 999px 999px 999px;
  background: rgba(34, 211, 238, 0.12);
  border: 1px solid rgba(34, 211, 238, 0.28);
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.vb-accordion-three-top h3 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-three-top p {
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-three-stack {
  display: grid;
  gap: 12px;
}

.vb-accordion-three-item {
  overflow: hidden;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.075);
  border: 1px solid rgba(255, 255, 255, 0.13);
  backdrop-filter: blur(18px);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
  transition: border-color 0.24s ease, background 0.24s ease, border-radius 0.24s ease, box-shadow 0.24s ease;
}

.vb-accordion-three-item.is-open {
  border-radius: 28px;
  background: rgba(255, 255, 255, 0.105);
  border-color: rgba(34, 211, 238, 0.44);
  box-shadow:
    0 24px 70px rgba(34, 211, 238, 0.10),
    inset 0 1px 0 rgba(255,255,255,0.12);
}

.vb-accordion-three-trigger {
  display: grid;
  grid-template-columns: 54px minmax(0, 1fr) 42px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 72px;
  padding: 12px 16px 12px 12px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-three-number {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 54px;
  height: 54px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.82);
  border: 1px solid rgba(255,255,255,0.12);
  color: #67e8f9 !important;
  -webkit-text-fill-color: #67e8f9 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-accordion-three-title {
  color: #f8fafc !important;
  -webkit-text-fill-color: #f8fafc !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 900;
  letter-spacing: -0.03em;
}

.vb-accordion-three-icon {
  position: relative;
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-accordion-three-icon::before,
.vb-accordion-three-icon::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 16px;
  height: 2px;
  border-radius: 999px;
  background: #ffffff;
  transform: translate(-50%, -50%);
  transition: transform 0.22s ease, opacity 0.22s ease;
}

.vb-accordion-three-icon::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-three-item.is-open .vb-accordion-three-icon {
  background: linear-gradient(135deg, #22d3ee, #8b5cf6) !important;
}

.vb-accordion-three-item.is-open .vb-accordion-three-icon::after {
  opacity: 0;
  transform: translate(-50%, -50%) rotate(0deg);
}

.vb-accordion-three-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-three-content {
  padding: 0 24px 24px 82px;
}

.vb-accordion-three-content p {
  max-width: 720px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 760px) {
  .vb-accordion-three-demo {
    padding: 22px;
    border-radius: 18px 34px 18px 34px;
  }

  .vb-accordion-three-top {
    grid-template-columns: 1fr;
  }

  .vb-accordion-three-top h3 {
    font-size: 38px !important;
  }

  .vb-accordion-three-trigger {
    grid-template-columns: 44px minmax(0, 1fr) 36px;
    gap: 12px;
  }

  .vb-accordion-three-number {
    width: 44px;
    height: 44px;
  }

  .vb-accordion-three-title {
    font-size: 15px;
  }

  .vb-accordion-three-icon {
    width: 36px;
    height: 36px;
  }

  .vb-accordion-three-content {
    padding: 0 18px 20px 68px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-three]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-three-item"));

  function closeItem(item) {
    const trigger = item.querySelector(".vb-accordion-three-trigger");
    const panel = item.querySelector(".vb-accordion-three-panel");

    item.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const trigger = item.querySelector(".vb-accordion-three-trigger");
    const panel = item.querySelector(".vb-accordion-three-panel");

    item.classList.add("is-open");
    trigger.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const trigger = item.querySelector(".vb-accordion-three-trigger");

    trigger.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const openDefault = accordion.querySelector(".vb-accordion-three-item.is-open");
  if (openDefault) {
    openItem(openDefault);
  }

  window.addEventListener("resize", function () {
    const openItemElement = accordion.querySelector(".vb-accordion-three-item.is-open");
    if (openItemElement) {
      openItem(openItemElement);
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-three]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-three-item"));

  function closeItem(item) {
    const trigger = item.querySelector(".vb-accordion-three-trigger");
    const panel = item.querySelector(".vb-accordion-three-panel");

    item.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const trigger = item.querySelector(".vb-accordion-three-trigger");
    const panel = item.querySelector(".vb-accordion-three-panel");

    item.classList.add("is-open");
    trigger.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const trigger = item.querySelector(".vb-accordion-three-trigger");

    trigger.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const openDefault = accordion.querySelector(".vb-accordion-three-item.is-open");
  if (openDefault) {
    openItem(openDefault);
  }

  window.addEventListener("resize", function () {
    const openItemElement = accordion.querySelector(".vb-accordion-three-item.is-open");
    if (openItemElement) {
      openItem(openItemElement);
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-three-demo"&gt;
  &lt;div class="vb-accordion-three-orb vb-accordion-three-orb-a"&gt;&lt;/div&gt;
  &lt;div class="vb-accordion-three-orb vb-accordion-three-orb-b"&gt;&lt;/div&gt;

  &lt;div class="vb-accordion-three-shell" data-vb-accordion-three&gt;
    &lt;div class="vb-accordion-three-top"&gt;
      &lt;span&gt;Example 03&lt;/span&gt;
      &lt;h3&gt;Dark Glassmorphism Accordion&lt;/h3&gt;
      &lt;p&gt;Use a glowing glass accordion layout for futuristic FAQ, SaaS, AI tool, or dashboard sections.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-three-stack"&gt;
      &lt;section class="vb-accordion-three-item is-open"&gt;
        &lt;button class="vb-accordion-three-trigger" type="button" aria-expanded="true"&gt;
          &lt;span class="vb-accordion-three-number"&gt;01&lt;/span&gt;
          &lt;span class="vb-accordion-three-title"&gt;Can I use this accordion on a SaaS landing page?&lt;/span&gt;
          &lt;span class="vb-accordion-three-icon"&gt;&lt;/span&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-three-panel"&gt;
          &lt;div class="vb-accordion-three-content"&gt;
            &lt;p&gt;Yes. This layout works well for product FAQs, feature explanations, onboarding questions, pricing details, and premium landing page sections.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-three-item"&gt;
        &lt;button class="vb-accordion-three-trigger" type="button" aria-expanded="false"&gt;
          &lt;span class="vb-accordion-three-number"&gt;02&lt;/span&gt;
          &lt;span class="vb-accordion-three-title"&gt;What makes glassmorphism different?&lt;/span&gt;
          &lt;span class="vb-accordion-three-icon"&gt;&lt;/span&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-three-panel"&gt;
          &lt;div class="vb-accordion-three-content"&gt;
            &lt;p&gt;Glassmorphism uses translucent backgrounds, subtle borders, blurred layers, and soft glowing effects to create depth without heavy visual blocks.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-three-item"&gt;
        &lt;button class="vb-accordion-three-trigger" type="button" aria-expanded="false"&gt;
          &lt;span class="vb-accordion-three-number"&gt;03&lt;/span&gt;
          &lt;span class="vb-accordion-three-title"&gt;Does this design support long content?&lt;/span&gt;
          &lt;span class="vb-accordion-three-icon"&gt;&lt;/span&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-three-panel"&gt;
          &lt;div class="vb-accordion-three-content"&gt;
            &lt;p&gt;The JavaScript calculates the panel height dynamically, so longer answers, feature lists, short paragraphs, or documentation notes can open smoothly.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-three-item"&gt;
        &lt;button class="vb-accordion-three-trigger" type="button" aria-expanded="false"&gt;
          &lt;span class="vb-accordion-three-number"&gt;04&lt;/span&gt;
          &lt;span class="vb-accordion-three-title"&gt;Can I change the colors?&lt;/span&gt;
          &lt;span class="vb-accordion-three-icon"&gt;&lt;/span&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-three-panel"&gt;
          &lt;div class="vb-accordion-three-content"&gt;
            &lt;p&gt;Yes. You can adjust the background gradients, glowing borders, text colors, and orb effects to match your brand or website theme.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-three-demo,
.vb-accordion-three-demo * {
  box-sizing: border-box;
}

.vb-accordion-three-demo {
  position: relative;
  isolation: isolate;
  margin: 28px 0;
  padding: 46px;
  border-radius: 18px 58px 18px 58px;
  background:
    radial-gradient(circle at 20% 20%, rgba(34, 211, 238, 0.18), transparent 34%),
    radial-gradient(circle at 80% 14%, rgba(168, 85, 247, 0.20), transparent 34%),
    linear-gradient(135deg, #020617 0%, #111827 48%, #312e81 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  overflow: hidden;
  box-shadow: 0 30px 90px rgba(2, 6, 23, 0.38);
}

.vb-accordion-three-orb {
  position: absolute;
  z-index: -1;
  border-radius: 999px;
  filter: blur(4px);
  opacity: 0.72;
}

.vb-accordion-three-orb-a {
  width: 180px;
  height: 180px;
  left: -52px;
  top: -48px;
  background: rgba(34, 211, 238, 0.22);
}

.vb-accordion-three-orb-b {
  width: 240px;
  height: 240px;
  right: -80px;
  bottom: -90px;
  background: rgba(168, 85, 247, 0.24);
}

.vb-accordion-three-shell {
  max-width: 1040px;
  margin: 0 auto;
}

.vb-accordion-three-top {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(260px, 0.7fr);
  gap: 24px;
  align-items: end;
  margin-bottom: 28px;
}

.vb-accordion-three-top &gt; span {
  grid-column: 1 / -1;
  justify-self: start;
  display: inline-flex;
  padding: 8px 13px;
  border-radius: 0 999px 999px 999px;
  background: rgba(34, 211, 238, 0.12);
  border: 1px solid rgba(34, 211, 238, 0.28);
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.vb-accordion-three-top h3 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-three-top p {
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-three-stack {
  display: grid;
  gap: 12px;
}

.vb-accordion-three-item {
  overflow: hidden;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.075);
  border: 1px solid rgba(255, 255, 255, 0.13);
  backdrop-filter: blur(18px);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
  transition: border-color 0.24s ease, background 0.24s ease, border-radius 0.24s ease, box-shadow 0.24s ease;
}

.vb-accordion-three-item.is-open {
  border-radius: 28px;
  background: rgba(255, 255, 255, 0.105);
  border-color: rgba(34, 211, 238, 0.44);
  box-shadow:
    0 24px 70px rgba(34, 211, 238, 0.10),
    inset 0 1px 0 rgba(255,255,255,0.12);
}

.vb-accordion-three-trigger {
  display: grid;
  grid-template-columns: 54px minmax(0, 1fr) 42px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 72px;
  padding: 12px 16px 12px 12px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-three-number {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 54px;
  height: 54px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.82);
  border: 1px solid rgba(255,255,255,0.12);
  color: #67e8f9 !important;
  -webkit-text-fill-color: #67e8f9 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-accordion-three-title {
  color: #f8fafc !important;
  -webkit-text-fill-color: #f8fafc !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 900;
  letter-spacing: -0.03em;
}

.vb-accordion-three-icon {
  position: relative;
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-accordion-three-icon::before,
.vb-accordion-three-icon::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 16px;
  height: 2px;
  border-radius: 999px;
  background: #ffffff;
  transform: translate(-50%, -50%);
  transition: transform 0.22s ease, opacity 0.22s ease;
}

.vb-accordion-three-icon::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-three-item.is-open .vb-accordion-three-icon {
  background: linear-gradient(135deg, #22d3ee, #8b5cf6) !important;
}

.vb-accordion-three-item.is-open .vb-accordion-three-icon::after {
  opacity: 0;
  transform: translate(-50%, -50%) rotate(0deg);
}

.vb-accordion-three-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-three-content {
  padding: 0 24px 24px 82px;
}

.vb-accordion-three-content p {
  max-width: 720px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 760px) {
  .vb-accordion-three-demo {
    padding: 22px;
    border-radius: 18px 34px 18px 34px;
  }

  .vb-accordion-three-top {
    grid-template-columns: 1fr;
  }

  .vb-accordion-three-top h3 {
    font-size: 38px !important;
  }

  .vb-accordion-three-trigger {
    grid-template-columns: 44px minmax(0, 1fr) 36px;
    gap: 12px;
  }

  .vb-accordion-three-number {
    width: 44px;
    height: 44px;
  }

  .vb-accordion-three-title {
    font-size: 15px;
  }

  .vb-accordion-three-icon {
    width: 36px;
    height: 36px;
  }

  .vb-accordion-three-content {
    padding: 0 18px 20px 68px;
  }
}</pre>



<p class="wp-block-paragraph">This dark glassmorphism accordion is useful for modern SaaS websites, AI product pages, crypto dashboards, premium service sections, and landing pages that need a more futuristic expandable content style.</p>



<h2 class="wp-block-heading">4. Timeline Step Accordion</h2>



<p class="wp-block-paragraph"><strong>A timeline step accordion</strong> is useful when content needs to follow a process, roadmap, onboarding flow, project sequence, or service timeline. Each accordion item represents one stage, and users can open the step they want to read.</p>



<p class="wp-block-paragraph">This example uses a vertical timeline layout with connected dots, offset cards, sharp diagonal labels, and multi-open JavaScript behavior. It looks different from a standard FAQ because the accordion items behave like expandable process steps.</p>



<ul class="wp-block-list">
<li>Timeline-style accordion structure</li>
<li>Multi-open expandable steps</li>
<li>Connected vertical progress line</li>
<li>Diagonal step labels</li>
<li>Useful for processes, onboarding, and roadmaps</li>
</ul>



<div class="vb-accordion-four-demo">
  <div class="vb-accordion-four-shell" data-vb-accordion-four>
    <div class="vb-accordion-four-header">
      <div>
        <span>Example 04</span>
        <h3>Timeline Step Accordion</h3>
      </div>
      <p>Expand each process step to reveal details, deliverables, and useful context inside a vertical timeline layout.</p>
    </div>

    <div class="vb-accordion-four-timeline">
      <article class="vb-accordion-four-step is-open">
        <div class="vb-accordion-four-marker">
          <strong>1</strong>
        </div>

        <div class="vb-accordion-four-card">
          <button class="vb-accordion-four-trigger" type="button" aria-expanded="true">
            <span>Discovery and planning</span>
            <em>Open</em>
          </button>

          <div class="vb-accordion-four-panel">
            <div class="vb-accordion-four-content">
              <p>Start by collecting goals, user needs, content requirements, project scope, page structure, and the main problems the interface should solve.</p>
              <ul>
                <li>Project goals</li>
                <li>Audience needs</li>
                <li>Content structure</li>
              </ul>
            </div>
          </div>
        </div>
      </article>

      <article class="vb-accordion-four-step">
        <div class="vb-accordion-four-marker">
          <strong>2</strong>
        </div>

        <div class="vb-accordion-four-card">
          <button class="vb-accordion-four-trigger" type="button" aria-expanded="false">
            <span>Interface wireframe</span>
            <em>Open</em>
          </button>

          <div class="vb-accordion-four-panel">
            <div class="vb-accordion-four-content">
              <p>Create a simple layout plan before writing final code. This helps define sections, spacing, content hierarchy, and user interaction points.</p>
              <ul>
                <li>Section order</li>
                <li>Accordion placement</li>
                <li>Mobile behavior</li>
              </ul>
            </div>
          </div>
        </div>
      </article>

      <article class="vb-accordion-four-step">
        <div class="vb-accordion-four-marker">
          <strong>3</strong>
        </div>

        <div class="vb-accordion-four-card">
          <button class="vb-accordion-four-trigger" type="button" aria-expanded="false">
            <span>JavaScript interaction</span>
            <em>Open</em>
          </button>

          <div class="vb-accordion-four-panel">
            <div class="vb-accordion-four-content">
              <p>Add the JavaScript toggle logic, active states, ARIA updates, dynamic max-height calculation, and resize handling for smooth expansion.</p>
              <ul>
                <li>Click handling</li>
                <li>Open state</li>
                <li>Height animation</li>
              </ul>
            </div>
          </div>
        </div>
      </article>

      <article class="vb-accordion-four-step">
        <div class="vb-accordion-four-marker">
          <strong>4</strong>
        </div>

        <div class="vb-accordion-four-card">
          <button class="vb-accordion-four-trigger" type="button" aria-expanded="false">
            <span>Testing and polish</span>
            <em>Open</em>
          </button>

          <div class="vb-accordion-four-panel">
            <div class="vb-accordion-four-content">
              <p>Test the accordion on desktop and mobile, check long content, verify keyboard focus, and make sure the visual states are clear.</p>
              <ul>
                <li>Responsive testing</li>
                <li>Content length</li>
                <li>Accessibility check</li>
              </ul>
            </div>
          </div>
        </div>
      </article>
    </div>
  </div>
</div>

<style>
.vb-accordion-four-demo,
.vb-accordion-four-demo * {
  box-sizing: border-box;
}

.vb-accordion-four-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 8px;
  background:
    linear-gradient(90deg, rgba(15, 23, 42, 0.04) 1px, transparent 1px),
    linear-gradient(0deg, rgba(15, 23, 42, 0.04) 1px, transparent 1px),
    linear-gradient(135deg, #f8fafc 0%, #eff6ff 52%, #ffffff 100%) !important;
  background-size: 28px 28px, 28px 28px, auto !important;
  border: 1px solid rgba(30, 64, 175, 0.14);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.10);
}

.vb-accordion-four-shell {
  max-width: 1060px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 10px 42px 10px 42px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 22px 60px rgba(15, 23, 42, 0.09);
}

.vb-accordion-four-header {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(260px, 0.72fr);
  gap: 24px;
  align-items: end;
  margin-bottom: 34px;
}

.vb-accordion-four-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 0;
  background: #1d4ed8;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  clip-path: polygon(0 0, 92% 0, 100% 50%, 92% 100%, 0 100%);
  padding-right: 22px;
}

.vb-accordion-four-header h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5vw, 66px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-four-header p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-four-timeline {
  position: relative;
  display: grid;
  gap: 18px;
}

.vb-accordion-four-timeline::before {
  content: "";
  position: absolute;
  left: 31px;
  top: 18px;
  bottom: 18px;
  width: 3px;
  border-radius: 999px;
  background: linear-gradient(180deg, #2563eb, #06b6d4, #10b981);
}

.vb-accordion-four-step {
  position: relative;
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr);
  gap: 18px;
  align-items: start;
}

.vb-accordion-four-marker {
  position: relative;
  z-index: 2;
  display: flex;
  justify-content: center;
}

.vb-accordion-four-marker strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  border-radius: 18px 18px 18px 4px;
  background: #ffffff;
  border: 3px solid #2563eb;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 20px;
  font-weight: 950;
  box-shadow: 0 14px 30px rgba(37, 99, 235, 0.18);
}

.vb-accordion-four-step.is-open .vb-accordion-four-marker strong {
  background: linear-gradient(135deg, #2563eb, #06b6d4) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-four-card {
  overflow: hidden;
  border-radius: 4px 26px 26px 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.08);
  transition: border-color 0.22s ease, box-shadow 0.22s ease;
}

.vb-accordion-four-step.is-open .vb-accordion-four-card {
  border-color: rgba(37, 99, 235, 0.36);
  box-shadow: 0 24px 62px rgba(37, 99, 235, 0.14);
}

.vb-accordion-four-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  width: 100%;
  min-height: 74px;
  padding: 20px 22px;
  border: 0;
  background:
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-four-trigger span {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 19px;
  line-height: 1.25;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-four-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 76px;
  min-height: 34px;
  padding: 8px 14px;
  border-radius: 0;
  background: #eff6ff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-style: normal;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  clip-path: polygon(10% 0, 100% 0, 90% 100%, 0 100%);
}

.vb-accordion-four-step.is-open .vb-accordion-four-trigger em {
  background: #1d4ed8;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-four-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-four-content {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 210px;
  gap: 22px;
  padding: 0 22px 22px;
}

.vb-accordion-four-content p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-four-content ul {
  display: grid;
  gap: 8px;
  margin: 0 !important;
  padding: 16px 18px !important;
  border-radius: 18px;
  background: #f8fafc;
  list-style-position: inside;
}

.vb-accordion-four-content li {
  margin: 0 !important;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

@media (max-width: 760px) {
  .vb-accordion-four-demo {
    padding: 18px;
  }

  .vb-accordion-four-shell {
    padding: 22px;
    border-radius: 10px 30px 10px 30px;
  }

  .vb-accordion-four-header {
    grid-template-columns: 1fr;
  }

  .vb-accordion-four-header h3 {
    font-size: 38px !important;
  }

  .vb-accordion-four-step {
    grid-template-columns: 48px minmax(0, 1fr);
    gap: 12px;
  }

  .vb-accordion-four-marker strong {
    width: 48px;
    height: 48px;
    border-width: 2px;
  }

  .vb-accordion-four-timeline::before {
    left: 23px;
  }

  .vb-accordion-four-trigger {
    min-height: 64px;
    padding: 18px;
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-accordion-four-content {
    grid-template-columns: 1fr;
    padding: 0 18px 18px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-four]");
  if (!accordion) return;

  const steps = Array.from(accordion.querySelectorAll(".vb-accordion-four-step"));

  function updateStep(step) {
    const button = step.querySelector(".vb-accordion-four-trigger");
    const panel = step.querySelector(".vb-accordion-four-panel");
    const label = button.querySelector("em");
    const isOpen = step.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");
    label.textContent = isOpen ? "Close" : "Open";
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  steps.forEach(function (step) {
    const button = step.querySelector(".vb-accordion-four-trigger");

    button.addEventListener("click", function () {
      step.classList.toggle("is-open");
      updateStep(step);
    });

    updateStep(step);
  });

  window.addEventListener("resize", function () {
    steps.forEach(updateStep);
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-four]");
  if (!accordion) return;

  const steps = Array.from(accordion.querySelectorAll(".vb-accordion-four-step"));

  function updateStep(step) {
    const button = step.querySelector(".vb-accordion-four-trigger");
    const panel = step.querySelector(".vb-accordion-four-panel");
    const label = button.querySelector("em");
    const isOpen = step.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");
    label.textContent = isOpen ? "Close" : "Open";
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  steps.forEach(function (step) {
    const button = step.querySelector(".vb-accordion-four-trigger");

    button.addEventListener("click", function () {
      step.classList.toggle("is-open");
      updateStep(step);
    });

    updateStep(step);
  });

  window.addEventListener("resize", function () {
    steps.forEach(updateStep);
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-four-demo"&gt;
  &lt;div class="vb-accordion-four-shell" data-vb-accordion-four&gt;
    &lt;div class="vb-accordion-four-header"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 04&lt;/span&gt;
        &lt;h3&gt;Timeline Step Accordion&lt;/h3&gt;
      &lt;/div&gt;
      &lt;p&gt;Expand each process step to reveal details, deliverables, and useful context inside a vertical timeline layout.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-four-timeline"&gt;
      &lt;article class="vb-accordion-four-step is-open"&gt;
        &lt;div class="vb-accordion-four-marker"&gt;
          &lt;strong&gt;1&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-accordion-four-card"&gt;
          &lt;button class="vb-accordion-four-trigger" type="button" aria-expanded="true"&gt;
            &lt;span&gt;Discovery and planning&lt;/span&gt;
            &lt;em&gt;Open&lt;/em&gt;
          &lt;/button&gt;

          &lt;div class="vb-accordion-four-panel"&gt;
            &lt;div class="vb-accordion-four-content"&gt;
              &lt;p&gt;Start by collecting goals, user needs, content requirements, project scope, page structure, and the main problems the interface should solve.&lt;/p&gt;
              &lt;ul&gt;
                &lt;li&gt;Project goals&lt;/li&gt;
                &lt;li&gt;Audience needs&lt;/li&gt;
                &lt;li&gt;Content structure&lt;/li&gt;
              &lt;/ul&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-four-step"&gt;
        &lt;div class="vb-accordion-four-marker"&gt;
          &lt;strong&gt;2&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-accordion-four-card"&gt;
          &lt;button class="vb-accordion-four-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;Interface wireframe&lt;/span&gt;
            &lt;em&gt;Open&lt;/em&gt;
          &lt;/button&gt;

          &lt;div class="vb-accordion-four-panel"&gt;
            &lt;div class="vb-accordion-four-content"&gt;
              &lt;p&gt;Create a simple layout plan before writing final code. This helps define sections, spacing, content hierarchy, and user interaction points.&lt;/p&gt;
              &lt;ul&gt;
                &lt;li&gt;Section order&lt;/li&gt;
                &lt;li&gt;Accordion placement&lt;/li&gt;
                &lt;li&gt;Mobile behavior&lt;/li&gt;
              &lt;/ul&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-four-step"&gt;
        &lt;div class="vb-accordion-four-marker"&gt;
          &lt;strong&gt;3&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-accordion-four-card"&gt;
          &lt;button class="vb-accordion-four-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;JavaScript interaction&lt;/span&gt;
            &lt;em&gt;Open&lt;/em&gt;
          &lt;/button&gt;

          &lt;div class="vb-accordion-four-panel"&gt;
            &lt;div class="vb-accordion-four-content"&gt;
              &lt;p&gt;Add the JavaScript toggle logic, active states, ARIA updates, dynamic max-height calculation, and resize handling for smooth expansion.&lt;/p&gt;
              &lt;ul&gt;
                &lt;li&gt;Click handling&lt;/li&gt;
                &lt;li&gt;Open state&lt;/li&gt;
                &lt;li&gt;Height animation&lt;/li&gt;
              &lt;/ul&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-four-step"&gt;
        &lt;div class="vb-accordion-four-marker"&gt;
          &lt;strong&gt;4&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-accordion-four-card"&gt;
          &lt;button class="vb-accordion-four-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;Testing and polish&lt;/span&gt;
            &lt;em&gt;Open&lt;/em&gt;
          &lt;/button&gt;

          &lt;div class="vb-accordion-four-panel"&gt;
            &lt;div class="vb-accordion-four-content"&gt;
              &lt;p&gt;Test the accordion on desktop and mobile, check long content, verify keyboard focus, and make sure the visual states are clear.&lt;/p&gt;
              &lt;ul&gt;
                &lt;li&gt;Responsive testing&lt;/li&gt;
                &lt;li&gt;Content length&lt;/li&gt;
                &lt;li&gt;Accessibility check&lt;/li&gt;
              &lt;/ul&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-four-demo,
.vb-accordion-four-demo * {
  box-sizing: border-box;
}

.vb-accordion-four-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 8px;
  background:
    linear-gradient(90deg, rgba(15, 23, 42, 0.04) 1px, transparent 1px),
    linear-gradient(0deg, rgba(15, 23, 42, 0.04) 1px, transparent 1px),
    linear-gradient(135deg, #f8fafc 0%, #eff6ff 52%, #ffffff 100%) !important;
  background-size: 28px 28px, 28px 28px, auto !important;
  border: 1px solid rgba(30, 64, 175, 0.14);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.10);
}

.vb-accordion-four-shell {
  max-width: 1060px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 10px 42px 10px 42px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 22px 60px rgba(15, 23, 42, 0.09);
}

.vb-accordion-four-header {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(260px, 0.72fr);
  gap: 24px;
  align-items: end;
  margin-bottom: 34px;
}

.vb-accordion-four-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 0;
  background: #1d4ed8;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  clip-path: polygon(0 0, 92% 0, 100% 50%, 92% 100%, 0 100%);
  padding-right: 22px;
}

.vb-accordion-four-header h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5vw, 66px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-four-header p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-four-timeline {
  position: relative;
  display: grid;
  gap: 18px;
}

.vb-accordion-four-timeline::before {
  content: "";
  position: absolute;
  left: 31px;
  top: 18px;
  bottom: 18px;
  width: 3px;
  border-radius: 999px;
  background: linear-gradient(180deg, #2563eb, #06b6d4, #10b981);
}

.vb-accordion-four-step {
  position: relative;
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr);
  gap: 18px;
  align-items: start;
}

.vb-accordion-four-marker {
  position: relative;
  z-index: 2;
  display: flex;
  justify-content: center;
}

.vb-accordion-four-marker strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 64px;
  border-radius: 18px 18px 18px 4px;
  background: #ffffff;
  border: 3px solid #2563eb;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 20px;
  font-weight: 950;
  box-shadow: 0 14px 30px rgba(37, 99, 235, 0.18);
}

.vb-accordion-four-step.is-open .vb-accordion-four-marker strong {
  background: linear-gradient(135deg, #2563eb, #06b6d4) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-four-card {
  overflow: hidden;
  border-radius: 4px 26px 26px 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.08);
  transition: border-color 0.22s ease, box-shadow 0.22s ease;
}

.vb-accordion-four-step.is-open .vb-accordion-four-card {
  border-color: rgba(37, 99, 235, 0.36);
  box-shadow: 0 24px 62px rgba(37, 99, 235, 0.14);
}

.vb-accordion-four-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  width: 100%;
  min-height: 74px;
  padding: 20px 22px;
  border: 0;
  background:
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-four-trigger span {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 19px;
  line-height: 1.25;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-four-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 76px;
  min-height: 34px;
  padding: 8px 14px;
  border-radius: 0;
  background: #eff6ff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-style: normal;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  clip-path: polygon(10% 0, 100% 0, 90% 100%, 0 100%);
}

.vb-accordion-four-step.is-open .vb-accordion-four-trigger em {
  background: #1d4ed8;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-four-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-four-content {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 210px;
  gap: 22px;
  padding: 0 22px 22px;
}

.vb-accordion-four-content p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-four-content ul {
  display: grid;
  gap: 8px;
  margin: 0 !important;
  padding: 16px 18px !important;
  border-radius: 18px;
  background: #f8fafc;
  list-style-position: inside;
}

.vb-accordion-four-content li {
  margin: 0 !important;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 800;
}

@media (max-width: 760px) {
  .vb-accordion-four-demo {
    padding: 18px;
  }

  .vb-accordion-four-shell {
    padding: 22px;
    border-radius: 10px 30px 10px 30px;
  }

  .vb-accordion-four-header {
    grid-template-columns: 1fr;
  }

  .vb-accordion-four-header h3 {
    font-size: 38px !important;
  }

  .vb-accordion-four-step {
    grid-template-columns: 48px minmax(0, 1fr);
    gap: 12px;
  }

  .vb-accordion-four-marker strong {
    width: 48px;
    height: 48px;
    border-width: 2px;
  }

  .vb-accordion-four-timeline::before {
    left: 23px;
  }

  .vb-accordion-four-trigger {
    min-height: 64px;
    padding: 18px;
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-accordion-four-content {
    grid-template-columns: 1fr;
    padding: 0 18px 18px;
  }
}</pre>



<p class="wp-block-paragraph">This timeline step accordion is ideal for process sections, onboarding pages, agency workflows, service roadmaps, project planning pages, and educational step-by-step layouts where each stage needs expandable detail.</p>



<h2 class="wp-block-heading">5. Minimal Border Accordion</h2>



<p class="wp-block-paragraph"><strong>A minimal border accordion</strong> works well for clean editorial websites, documentation pages, product FAQs, portfolio pages, and modern service pages where the design should feel lightweight instead of visually heavy.</p>



<p class="wp-block-paragraph">This example uses thin borders, small uppercase labels, spacious typography, line-based dividers, and a simple arrow button. The JavaScript uses one-open-at-a-time behavior and keeps the visual style calm and professional.</p>



<ul class="wp-block-list">
<li>Minimal line-based accordion design</li>
<li>One-open-at-a-time behavior</li>
<li>Small editorial labels</li>
<li>Clean arrow rotation</li>
<li>Useful for documentation and content pages</li>
</ul>



<div class="vb-accordion-five-demo">
  <div class="vb-accordion-five-shell" data-vb-accordion-five>
    <div class="vb-accordion-five-intro">
      <span>Example 05</span>
      <h3>Minimal Border Accordion</h3>
      <p>A quiet accordion layout with thin lines, simple spacing, and clear expandable content.</p>
    </div>

    <div class="vb-accordion-five-list">
      <div class="vb-accordion-five-item is-open">
        <button class="vb-accordion-five-trigger" type="button" aria-expanded="true">
          <span class="vb-accordion-five-label">Guide</span>
          <span class="vb-accordion-five-title">How does the accordion open?</span>
          <strong>→</strong>
        </button>
        <div class="vb-accordion-five-panel">
          <div class="vb-accordion-five-content">
            <p>The JavaScript listens for a click on each accordion button, closes the other items, opens the selected item, and updates the content height smoothly.</p>
          </div>
        </div>
      </div>

      <div class="vb-accordion-five-item">
        <button class="vb-accordion-five-trigger" type="button" aria-expanded="false">
          <span class="vb-accordion-five-label">Layout</span>
          <span class="vb-accordion-five-title">Why use a minimal accordion?</span>
          <strong>→</strong>
        </button>
        <div class="vb-accordion-five-panel">
          <div class="vb-accordion-five-content">
            <p>A minimal accordion keeps the page light and readable. It is a good fit when content clarity is more important than decorative effects.</p>
          </div>
        </div>
      </div>

      <div class="vb-accordion-five-item">
        <button class="vb-accordion-five-trigger" type="button" aria-expanded="false">
          <span class="vb-accordion-five-label">Content</span>
          <span class="vb-accordion-five-title">What type of content fits here?</span>
          <strong>→</strong>
        </button>
        <div class="vb-accordion-five-panel">
          <div class="vb-accordion-five-content">
            <p>This style works for documentation notes, support questions, course lessons, service explanations, legal text summaries, and clean FAQ pages.</p>
          </div>
        </div>
      </div>

      <div class="vb-accordion-five-item">
        <button class="vb-accordion-five-trigger" type="button" aria-expanded="false">
          <span class="vb-accordion-five-label">Mobile</span>
          <span class="vb-accordion-five-title">Does the layout work on phones?</span>
          <strong>→</strong>
        </button>
        <div class="vb-accordion-five-panel">
          <div class="vb-accordion-five-content">
            <p>Yes. The desktop grid becomes a single-column button layout on smaller screens, keeping the labels and titles readable.</p>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-accordion-five-demo,
.vb-accordion-five-demo * {
  box-sizing: border-box;
}

.vb-accordion-five-demo {
  margin: 28px 0;
  padding: 42px;
  background:
    linear-gradient(135deg, #ffffff 0%, #f8fafc 48%, #f1f5f9 100%) !important;
  border-top: 4px solid #111827;
  border-bottom: 4px solid #111827;
}

.vb-accordion-five-shell {
  max-width: 1040px;
  margin: 0 auto;
}

.vb-accordion-five-intro {
  display: grid;
  grid-template-columns: 180px minmax(0, 1fr);
  gap: 24px;
  align-items: start;
  margin-bottom: 34px;
}

.vb-accordion-five-intro > span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 10px 14px;
  border: 1px solid #111827;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.vb-accordion-five-intro h3 {
  grid-column: 2;
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(38px, 5vw, 72px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
}

.vb-accordion-five-intro p {
  grid-column: 2;
  max-width: 620px;
  margin: -8px 0 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-five-list {
  border-top: 1px solid #cbd5e1;
}

.vb-accordion-five-item {
  border-bottom: 1px solid #cbd5e1;
}

.vb-accordion-five-trigger {
  display: grid;
  grid-template-columns: 140px minmax(0, 1fr) 54px;
  align-items: center;
  gap: 22px;
  width: 100%;
  min-height: 92px;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-five-label {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.vb-accordion-five-title {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(22px, 3vw, 34px);
  line-height: 1.05;
  font-weight: 900;
  letter-spacing: -0.055em;
}

.vb-accordion-five-trigger strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 54px;
  height: 54px;
  border: 1px solid #111827;
  border-radius: 0;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 24px;
  font-weight: 800;
  transform: rotate(0deg);
  transition: transform 0.22s ease, background 0.22s ease, color 0.22s ease;
}

.vb-accordion-five-item.is-open .vb-accordion-five-trigger strong {
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transform: rotate(90deg);
}

.vb-accordion-five-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-five-content {
  display: grid;
  grid-template-columns: 140px minmax(0, 1fr) 54px;
  gap: 22px;
  padding-bottom: 28px;
}

.vb-accordion-five-content p {
  grid-column: 2;
  max-width: 680px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.8;
  font-weight: 650;
}

@media (max-width: 760px) {
  .vb-accordion-five-demo {
    padding: 24px 18px;
  }

  .vb-accordion-five-intro {
    grid-template-columns: 1fr;
    gap: 16px;
  }

  .vb-accordion-five-intro h3,
  .vb-accordion-five-intro p {
    grid-column: auto;
  }

  .vb-accordion-five-intro h3 {
    font-size: 40px !important;
  }

  .vb-accordion-five-trigger {
    grid-template-columns: 1fr 44px;
    gap: 14px;
    min-height: 82px;
  }

  .vb-accordion-five-label {
    grid-column: 1 / -1;
    padding-top: 18px;
  }

  .vb-accordion-five-trigger strong {
    width: 44px;
    height: 44px;
  }

  .vb-accordion-five-content {
    grid-template-columns: 1fr;
    padding-bottom: 22px;
  }

  .vb-accordion-five-content p {
    grid-column: auto;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-five]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-five-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-five-trigger");
    const panel = item.querySelector(".vb-accordion-five-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-five-trigger");
    const panel = item.querySelector(".vb-accordion-five-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-five-trigger");

    button.addEventListener("click", function () {
      const wasOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!wasOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-five-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-five-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-five]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-five-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-five-trigger");
    const panel = item.querySelector(".vb-accordion-five-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-five-trigger");
    const panel = item.querySelector(".vb-accordion-five-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-five-trigger");

    button.addEventListener("click", function () {
      const wasOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!wasOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-five-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-five-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-five-demo"&gt;
  &lt;div class="vb-accordion-five-shell" data-vb-accordion-five&gt;
    &lt;div class="vb-accordion-five-intro"&gt;
      &lt;span&gt;Example 05&lt;/span&gt;
      &lt;h3&gt;Minimal Border Accordion&lt;/h3&gt;
      &lt;p&gt;A quiet accordion layout with thin lines, simple spacing, and clear expandable content.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-five-list"&gt;
      &lt;div class="vb-accordion-five-item is-open"&gt;
        &lt;button class="vb-accordion-five-trigger" type="button" aria-expanded="true"&gt;
          &lt;span class="vb-accordion-five-label"&gt;Guide&lt;/span&gt;
          &lt;span class="vb-accordion-five-title"&gt;How does the accordion open?&lt;/span&gt;
          &lt;strong&gt;→&lt;/strong&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-five-panel"&gt;
          &lt;div class="vb-accordion-five-content"&gt;
            &lt;p&gt;The JavaScript listens for a click on each accordion button, closes the other items, opens the selected item, and updates the content height smoothly.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-five-item"&gt;
        &lt;button class="vb-accordion-five-trigger" type="button" aria-expanded="false"&gt;
          &lt;span class="vb-accordion-five-label"&gt;Layout&lt;/span&gt;
          &lt;span class="vb-accordion-five-title"&gt;Why use a minimal accordion?&lt;/span&gt;
          &lt;strong&gt;→&lt;/strong&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-five-panel"&gt;
          &lt;div class="vb-accordion-five-content"&gt;
            &lt;p&gt;A minimal accordion keeps the page light and readable. It is a good fit when content clarity is more important than decorative effects.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-five-item"&gt;
        &lt;button class="vb-accordion-five-trigger" type="button" aria-expanded="false"&gt;
          &lt;span class="vb-accordion-five-label"&gt;Content&lt;/span&gt;
          &lt;span class="vb-accordion-five-title"&gt;What type of content fits here?&lt;/span&gt;
          &lt;strong&gt;→&lt;/strong&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-five-panel"&gt;
          &lt;div class="vb-accordion-five-content"&gt;
            &lt;p&gt;This style works for documentation notes, support questions, course lessons, service explanations, legal text summaries, and clean FAQ pages.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-five-item"&gt;
        &lt;button class="vb-accordion-five-trigger" type="button" aria-expanded="false"&gt;
          &lt;span class="vb-accordion-five-label"&gt;Mobile&lt;/span&gt;
          &lt;span class="vb-accordion-five-title"&gt;Does the layout work on phones?&lt;/span&gt;
          &lt;strong&gt;→&lt;/strong&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-five-panel"&gt;
          &lt;div class="vb-accordion-five-content"&gt;
            &lt;p&gt;Yes. The desktop grid becomes a single-column button layout on smaller screens, keeping the labels and titles readable.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-five-demo,
.vb-accordion-five-demo * {
  box-sizing: border-box;
}

.vb-accordion-five-demo {
  margin: 28px 0;
  padding: 42px;
  background:
    linear-gradient(135deg, #ffffff 0%, #f8fafc 48%, #f1f5f9 100%) !important;
  border-top: 4px solid #111827;
  border-bottom: 4px solid #111827;
}

.vb-accordion-five-shell {
  max-width: 1040px;
  margin: 0 auto;
}

.vb-accordion-five-intro {
  display: grid;
  grid-template-columns: 180px minmax(0, 1fr);
  gap: 24px;
  align-items: start;
  margin-bottom: 34px;
}

.vb-accordion-five-intro &gt; span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 10px 14px;
  border: 1px solid #111827;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.vb-accordion-five-intro h3 {
  grid-column: 2;
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(38px, 5vw, 72px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
}

.vb-accordion-five-intro p {
  grid-column: 2;
  max-width: 620px;
  margin: -8px 0 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-five-list {
  border-top: 1px solid #cbd5e1;
}

.vb-accordion-five-item {
  border-bottom: 1px solid #cbd5e1;
}

.vb-accordion-five-trigger {
  display: grid;
  grid-template-columns: 140px minmax(0, 1fr) 54px;
  align-items: center;
  gap: 22px;
  width: 100%;
  min-height: 92px;
  padding: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-five-label {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.vb-accordion-five-title {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(22px, 3vw, 34px);
  line-height: 1.05;
  font-weight: 900;
  letter-spacing: -0.055em;
}

.vb-accordion-five-trigger strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 54px;
  height: 54px;
  border: 1px solid #111827;
  border-radius: 0;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 24px;
  font-weight: 800;
  transform: rotate(0deg);
  transition: transform 0.22s ease, background 0.22s ease, color 0.22s ease;
}

.vb-accordion-five-item.is-open .vb-accordion-five-trigger strong {
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transform: rotate(90deg);
}

.vb-accordion-five-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-five-content {
  display: grid;
  grid-template-columns: 140px minmax(0, 1fr) 54px;
  gap: 22px;
  padding-bottom: 28px;
}

.vb-accordion-five-content p {
  grid-column: 2;
  max-width: 680px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.8;
  font-weight: 650;
}

@media (max-width: 760px) {
  .vb-accordion-five-demo {
    padding: 24px 18px;
  }

  .vb-accordion-five-intro {
    grid-template-columns: 1fr;
    gap: 16px;
  }

  .vb-accordion-five-intro h3,
  .vb-accordion-five-intro p {
    grid-column: auto;
  }

  .vb-accordion-five-intro h3 {
    font-size: 40px !important;
  }

  .vb-accordion-five-trigger {
    grid-template-columns: 1fr 44px;
    gap: 14px;
    min-height: 82px;
  }

  .vb-accordion-five-label {
    grid-column: 1 / -1;
    padding-top: 18px;
  }

  .vb-accordion-five-trigger strong {
    width: 44px;
    height: 44px;
  }

  .vb-accordion-five-content {
    grid-template-columns: 1fr;
    padding-bottom: 22px;
  }

  .vb-accordion-five-content p {
    grid-column: auto;
  }
}</pre>



<p class="wp-block-paragraph">This minimal border accordion is useful for documentation pages, editorial websites, knowledge bases, product information sections, and service pages where the interface should stay clean and content-focused.</p>



<h2 class="wp-block-heading">6. Color Block Category Accordion</h2>



<p class="wp-block-paragraph"><strong>A color block category accordion</strong> uses strong visual blocks to separate different content categories. This is useful for dashboards, learning platforms, feature sections, product guides, service pages, and support centers where each accordion item belongs to a clear topic.</p>



<p class="wp-block-paragraph">This example looks different from a normal FAQ accordion because each item has its own color stripe, icon badge, clipped corner, and card-style content area. The JavaScript allows multiple category blocks to stay open at the same time.</p>



<ul class="wp-block-list">
<li>Color-coded accordion categories</li>
<li>Multi-open JavaScript behavior</li>
<li>Icon badge and clipped corner design</li>
<li>Strong visual separation between items</li>
<li>Useful for dashboards, guides, and feature sections</li>
</ul>



<div class="vb-accordion-six-demo">
  <div class="vb-accordion-six-shell" data-vb-accordion-six>
    <div class="vb-accordion-six-header">
      <span>Example 06</span>
      <h3>Color Block Category Accordion</h3>
      <p>Open several colorful content categories at once and keep each topic visually separated.</p>
    </div>

    <div class="vb-accordion-six-grid">
      <article class="vb-accordion-six-item vb-accordion-six-blue is-open">
        <button class="vb-accordion-six-trigger" type="button" aria-expanded="true">
          <span class="vb-accordion-six-icon">⚙</span>
          <span>
            <strong>Setup options</strong>
            <small>Installation, configuration, and first steps</small>
          </span>
          <em>+</em>
        </button>
        <div class="vb-accordion-six-panel">
          <div class="vb-accordion-six-content">
            <p>Use this section to explain setup requirements, recommended defaults, onboarding steps, and the first actions a user should take.</p>
          </div>
        </div>
      </article>

      <article class="vb-accordion-six-item vb-accordion-six-green">
        <button class="vb-accordion-six-trigger" type="button" aria-expanded="false">
          <span class="vb-accordion-six-icon">✓</span>
          <span>
            <strong>Best practices</strong>
            <small>Recommended usage and cleaner workflows</small>
          </span>
          <em>+</em>
        </button>
        <div class="vb-accordion-six-panel">
          <div class="vb-accordion-six-content">
            <p>Use best-practice blocks to guide users toward better decisions, cleaner layouts, faster workflows, and more reliable interaction patterns.</p>
          </div>
        </div>
      </article>

      <article class="vb-accordion-six-item vb-accordion-six-orange">
        <button class="vb-accordion-six-trigger" type="button" aria-expanded="false">
          <span class="vb-accordion-six-icon">!</span>
          <span>
            <strong>Common issues</strong>
            <small>Problems, mistakes, and troubleshooting</small>
          </span>
          <em>+</em>
        </button>
        <div class="vb-accordion-six-panel">
          <div class="vb-accordion-six-content">
            <p>This block can explain layout bugs, missing content, animation issues, JavaScript conflicts, or mobile problems users may run into.</p>
          </div>
        </div>
      </article>

      <article class="vb-accordion-six-item vb-accordion-six-purple">
        <button class="vb-accordion-six-trigger" type="button" aria-expanded="false">
          <span class="vb-accordion-six-icon">★</span>
          <span>
            <strong>Advanced tips</strong>
            <small>Extra ideas for polished UI components</small>
          </span>
          <em>+</em>
        </button>
        <div class="vb-accordion-six-panel">
          <div class="vb-accordion-six-content">
            <p>Advanced accordion sections can include nested panels, search support, keyboard controls, default open states, and custom animation timing.</p>
          </div>
        </div>
      </article>
    </div>
  </div>
</div>

<style>
.vb-accordion-six-demo,
.vb-accordion-six-demo * {
  box-sizing: border-box;
}

.vb-accordion-six-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 40px;
  background:
    radial-gradient(circle at 20% 18%, rgba(59, 130, 246, 0.16), transparent 30%),
    radial-gradient(circle at 86% 20%, rgba(168, 85, 247, 0.15), transparent 32%),
    linear-gradient(135deg, #f8fafc 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(129, 140, 248, 0.24);
  box-shadow: 0 24px 70px rgba(30, 41, 59, 0.10);
}

.vb-accordion-six-shell {
  max-width: 1100px;
  margin: 0 auto;
}

.vb-accordion-six-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 26px;
  margin-bottom: 26px;
}

.vb-accordion-six-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-six-header h3 {
  max-width: 680px;
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-six-header p {
  max-width: 330px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-accordion-six-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
}

.vb-accordion-six-item {
  position: relative;
  overflow: hidden;
  border-radius: 28px 28px 8px 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.08);
}

.vb-accordion-six-item::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 9px;
  background: #2563eb;
}

.vb-accordion-six-item::after {
  content: "";
  position: absolute;
  right: 0;
  top: 0;
  border-top: 34px solid #dbeafe;
  border-left: 34px solid transparent;
}

.vb-accordion-six-green::before {
  background: #10b981;
}

.vb-accordion-six-green::after {
  border-top-color: #d1fae5;
}

.vb-accordion-six-orange::before {
  background: #f97316;
}

.vb-accordion-six-orange::after {
  border-top-color: #ffedd5;
}

.vb-accordion-six-purple::before {
  background: #8b5cf6;
}

.vb-accordion-six-purple::after {
  border-top-color: #ede9fe;
}

.vb-accordion-six-trigger {
  display: grid;
  grid-template-columns: 58px minmax(0, 1fr) 42px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 96px;
  padding: 20px 22px 20px 28px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-six-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 58px;
  height: 58px;
  border-radius: 20px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-accordion-six-green .vb-accordion-six-icon {
  background: #d1fae5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
}

.vb-accordion-six-orange .vb-accordion-six-icon {
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
}

.vb-accordion-six-purple .vb-accordion-six-icon {
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
}

.vb-accordion-six-trigger strong {
  display: block;
  margin-bottom: 5px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px;
  line-height: 1.15;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-six-trigger small {
  display: block;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.4;
  font-weight: 750;
}

.vb-accordion-six-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 14px;
  background: #f8fafc;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-style: normal;
  font-size: 24px;
  line-height: 1;
  font-weight: 950;
  transition: transform 0.22s ease, background 0.22s ease, color 0.22s ease;
}

.vb-accordion-six-item.is-open .vb-accordion-six-trigger em {
  transform: rotate(45deg);
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-six-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-six-content {
  padding: 0 22px 22px 102px;
}

.vb-accordion-six-content p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 880px) {
  .vb-accordion-six-header {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-accordion-six-header p {
    max-width: 680px;
  }

  .vb-accordion-six-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-accordion-six-demo {
    padding: 18px;
    border-radius: 28px;
  }

  .vb-accordion-six-header h3 {
    font-size: 38px !important;
  }

  .vb-accordion-six-trigger {
    grid-template-columns: 48px minmax(0, 1fr) 38px;
    min-height: 86px;
    gap: 12px;
    padding: 18px 18px 18px 24px;
  }

  .vb-accordion-six-icon {
    width: 48px;
    height: 48px;
    border-radius: 16px;
  }

  .vb-accordion-six-trigger strong {
    font-size: 18px;
  }

  .vb-accordion-six-trigger em {
    width: 38px;
    height: 38px;
  }

  .vb-accordion-six-content {
    padding: 0 18px 18px 84px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-six]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-six-item"));

  function updateItem(item) {
    const button = item.querySelector(".vb-accordion-six-trigger");
    const panel = item.querySelector(".vb-accordion-six-panel");
    const isOpen = item.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-six-trigger");

    button.addEventListener("click", function () {
      item.classList.toggle("is-open");
      updateItem(item);
    });

    updateItem(item);
  });

  window.addEventListener("resize", function () {
    items.forEach(updateItem);
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-six]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-six-item"));

  function updateItem(item) {
    const button = item.querySelector(".vb-accordion-six-trigger");
    const panel = item.querySelector(".vb-accordion-six-panel");
    const isOpen = item.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-six-trigger");

    button.addEventListener("click", function () {
      item.classList.toggle("is-open");
      updateItem(item);
    });

    updateItem(item);
  });

  window.addEventListener("resize", function () {
    items.forEach(updateItem);
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-six-demo"&gt;
  &lt;div class="vb-accordion-six-shell" data-vb-accordion-six&gt;
    &lt;div class="vb-accordion-six-header"&gt;
      &lt;span&gt;Example 06&lt;/span&gt;
      &lt;h3&gt;Color Block Category Accordion&lt;/h3&gt;
      &lt;p&gt;Open several colorful content categories at once and keep each topic visually separated.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-six-grid"&gt;
      &lt;article class="vb-accordion-six-item vb-accordion-six-blue is-open"&gt;
        &lt;button class="vb-accordion-six-trigger" type="button" aria-expanded="true"&gt;
          &lt;span class="vb-accordion-six-icon"&gt;⚙&lt;/span&gt;
          &lt;span&gt;
            &lt;strong&gt;Setup options&lt;/strong&gt;
            &lt;small&gt;Installation, configuration, and first steps&lt;/small&gt;
          &lt;/span&gt;
          &lt;em&gt;+&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-six-panel"&gt;
          &lt;div class="vb-accordion-six-content"&gt;
            &lt;p&gt;Use this section to explain setup requirements, recommended defaults, onboarding steps, and the first actions a user should take.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-six-item vb-accordion-six-green"&gt;
        &lt;button class="vb-accordion-six-trigger" type="button" aria-expanded="false"&gt;
          &lt;span class="vb-accordion-six-icon"&gt;✓&lt;/span&gt;
          &lt;span&gt;
            &lt;strong&gt;Best practices&lt;/strong&gt;
            &lt;small&gt;Recommended usage and cleaner workflows&lt;/small&gt;
          &lt;/span&gt;
          &lt;em&gt;+&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-six-panel"&gt;
          &lt;div class="vb-accordion-six-content"&gt;
            &lt;p&gt;Use best-practice blocks to guide users toward better decisions, cleaner layouts, faster workflows, and more reliable interaction patterns.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-six-item vb-accordion-six-orange"&gt;
        &lt;button class="vb-accordion-six-trigger" type="button" aria-expanded="false"&gt;
          &lt;span class="vb-accordion-six-icon"&gt;!&lt;/span&gt;
          &lt;span&gt;
            &lt;strong&gt;Common issues&lt;/strong&gt;
            &lt;small&gt;Problems, mistakes, and troubleshooting&lt;/small&gt;
          &lt;/span&gt;
          &lt;em&gt;+&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-six-panel"&gt;
          &lt;div class="vb-accordion-six-content"&gt;
            &lt;p&gt;This block can explain layout bugs, missing content, animation issues, JavaScript conflicts, or mobile problems users may run into.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-six-item vb-accordion-six-purple"&gt;
        &lt;button class="vb-accordion-six-trigger" type="button" aria-expanded="false"&gt;
          &lt;span class="vb-accordion-six-icon"&gt;★&lt;/span&gt;
          &lt;span&gt;
            &lt;strong&gt;Advanced tips&lt;/strong&gt;
            &lt;small&gt;Extra ideas for polished UI components&lt;/small&gt;
          &lt;/span&gt;
          &lt;em&gt;+&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-six-panel"&gt;
          &lt;div class="vb-accordion-six-content"&gt;
            &lt;p&gt;Advanced accordion sections can include nested panels, search support, keyboard controls, default open states, and custom animation timing.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-six-demo,
.vb-accordion-six-demo * {
  box-sizing: border-box;
}

.vb-accordion-six-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 40px;
  background:
    radial-gradient(circle at 20% 18%, rgba(59, 130, 246, 0.16), transparent 30%),
    radial-gradient(circle at 86% 20%, rgba(168, 85, 247, 0.15), transparent 32%),
    linear-gradient(135deg, #f8fafc 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(129, 140, 248, 0.24);
  box-shadow: 0 24px 70px rgba(30, 41, 59, 0.10);
}

.vb-accordion-six-shell {
  max-width: 1100px;
  margin: 0 auto;
}

.vb-accordion-six-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 26px;
  margin-bottom: 26px;
}

.vb-accordion-six-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-six-header h3 {
  max-width: 680px;
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-six-header p {
  max-width: 330px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-accordion-six-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
}

.vb-accordion-six-item {
  position: relative;
  overflow: hidden;
  border-radius: 28px 28px 8px 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.08);
}

.vb-accordion-six-item::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 9px;
  background: #2563eb;
}

.vb-accordion-six-item::after {
  content: "";
  position: absolute;
  right: 0;
  top: 0;
  border-top: 34px solid #dbeafe;
  border-left: 34px solid transparent;
}

.vb-accordion-six-green::before {
  background: #10b981;
}

.vb-accordion-six-green::after {
  border-top-color: #d1fae5;
}

.vb-accordion-six-orange::before {
  background: #f97316;
}

.vb-accordion-six-orange::after {
  border-top-color: #ffedd5;
}

.vb-accordion-six-purple::before {
  background: #8b5cf6;
}

.vb-accordion-six-purple::after {
  border-top-color: #ede9fe;
}

.vb-accordion-six-trigger {
  display: grid;
  grid-template-columns: 58px minmax(0, 1fr) 42px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 96px;
  padding: 20px 22px 20px 28px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-six-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 58px;
  height: 58px;
  border-radius: 20px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-accordion-six-green .vb-accordion-six-icon {
  background: #d1fae5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
}

.vb-accordion-six-orange .vb-accordion-six-icon {
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
}

.vb-accordion-six-purple .vb-accordion-six-icon {
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
}

.vb-accordion-six-trigger strong {
  display: block;
  margin-bottom: 5px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px;
  line-height: 1.15;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-six-trigger small {
  display: block;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.4;
  font-weight: 750;
}

.vb-accordion-six-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 14px;
  background: #f8fafc;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-style: normal;
  font-size: 24px;
  line-height: 1;
  font-weight: 950;
  transition: transform 0.22s ease, background 0.22s ease, color 0.22s ease;
}

.vb-accordion-six-item.is-open .vb-accordion-six-trigger em {
  transform: rotate(45deg);
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-six-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-six-content {
  padding: 0 22px 22px 102px;
}

.vb-accordion-six-content p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 880px) {
  .vb-accordion-six-header {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-accordion-six-header p {
    max-width: 680px;
  }

  .vb-accordion-six-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-accordion-six-demo {
    padding: 18px;
    border-radius: 28px;
  }

  .vb-accordion-six-header h3 {
    font-size: 38px !important;
  }

  .vb-accordion-six-trigger {
    grid-template-columns: 48px minmax(0, 1fr) 38px;
    min-height: 86px;
    gap: 12px;
    padding: 18px 18px 18px 24px;
  }

  .vb-accordion-six-icon {
    width: 48px;
    height: 48px;
    border-radius: 16px;
  }

  .vb-accordion-six-trigger strong {
    font-size: 18px;
  }

  .vb-accordion-six-trigger em {
    width: 38px;
    height: 38px;
  }

  .vb-accordion-six-content {
    padding: 0 18px 18px 84px;
  }
}</pre>



<p class="wp-block-paragraph">This color block category accordion is useful for feature explainers, learning modules, product guides, dashboard help panels, service categories, and support pages where each topic should feel visually distinct.</p>



<h2 class="wp-block-heading">7. Mobile Filter Accordion</h2>



<p class="wp-block-paragraph"><strong>A mobile filter accordion</strong> is useful for ecommerce stores, directories, listing pages, travel websites, real estate pages, and product catalogs where filter controls take too much space on smaller screens.</p>



<p class="wp-block-paragraph">This example uses a compact mobile-style filter drawer layout with expandable filter groups. The design uses a phone-like frame, rounded pill chips, a sticky action bar, and multi-open JavaScript behavior so users can open several filter groups at once.</p>



<ul class="wp-block-list">
<li>Mobile-friendly filter accordion</li>
<li>Multi-open filter groups</li>
<li>Filter chips and checkbox-style options</li>
<li>Sticky apply/reset action bar</li>
<li>Useful for ecommerce and listing pages</li>
</ul>



<div class="vb-accordion-seven-demo">
  <div class="vb-accordion-seven-phone" data-vb-accordion-seven>
    <div class="vb-accordion-seven-status">
      <span>Example 07</span>
      <strong>Mobile Filters</strong>
    </div>

    <div class="vb-accordion-seven-hero">
      <h3>Mobile Filter Accordion</h3>
      <p>Open product filter groups inside a compact mobile-first accordion layout.</p>
    </div>

    <div class="vb-accordion-seven-list">
      <section class="vb-accordion-seven-item is-open">
        <button class="vb-accordion-seven-trigger" type="button" aria-expanded="true">
          <span>Category</span>
          <em></em>
        </button>
        <div class="vb-accordion-seven-panel">
          <div class="vb-accordion-seven-content">
            <label><input type="checkbox"> Website templates</label>
            <label><input type="checkbox"> UI components</label>
            <label><input type="checkbox"> WordPress plugins</label>
          </div>
        </div>
      </section>

      <section class="vb-accordion-seven-item">
        <button class="vb-accordion-seven-trigger" type="button" aria-expanded="false">
          <span>Price range</span>
          <em></em>
        </button>
        <div class="vb-accordion-seven-panel">
          <div class="vb-accordion-seven-content">
            <label><input type="checkbox"> Under €25</label>
            <label><input type="checkbox"> €25 &#8211; €75</label>
            <label><input type="checkbox"> Over €75</label>
          </div>
        </div>
      </section>

      <section class="vb-accordion-seven-item">
        <button class="vb-accordion-seven-trigger" type="button" aria-expanded="false">
          <span>Features</span>
          <em></em>
        </button>
        <div class="vb-accordion-seven-panel">
          <div class="vb-accordion-seven-content vb-accordion-seven-tags">
            <button type="button">Responsive</button>
            <button type="button">SEO ready</button>
            <button type="button">Dark mode</button>
            <button type="button">No framework</button>
          </div>
        </div>
      </section>

      <section class="vb-accordion-seven-item">
        <button class="vb-accordion-seven-trigger" type="button" aria-expanded="false">
          <span>Rating</span>
          <em></em>
        </button>
        <div class="vb-accordion-seven-panel">
          <div class="vb-accordion-seven-content">
            <label><input type="checkbox"> 5 stars only</label>
            <label><input type="checkbox"> 4 stars and up</label>
            <label><input type="checkbox"> New products</label>
          </div>
        </div>
      </section>
    </div>

    <div class="vb-accordion-seven-actions">
      <button type="button">Reset</button>
      <button type="button">Apply Filters</button>
    </div>
  </div>
</div>

<style>
.vb-accordion-seven-demo,
.vb-accordion-seven-demo * {
  box-sizing: border-box;
}

.vb-accordion-seven-demo {
  margin: 28px 0;
  padding: 42px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 18% 18%, rgba(16, 185, 129, 0.20), transparent 32%),
    radial-gradient(circle at 86% 22%, rgba(14, 165, 233, 0.18), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #f0f9ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(125, 211, 252, 0.36);
  box-shadow: 0 24px 70px rgba(6, 95, 70, 0.12);
}

.vb-accordion-seven-phone {
  max-width: 430px;
  margin: 0 auto;
  padding: 16px;
  border-radius: 42px;
  background: #0f172a;
  border: 8px solid #111827;
  box-shadow: 0 32px 90px rgba(15, 23, 42, 0.28);
}

.vb-accordion-seven-status {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 8px 14px;
}

.vb-accordion-seven-status span {
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.16);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-accordion-seven-status strong {
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-accordion-seven-hero {
  padding: 24px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 20% 18%, rgba(255, 255, 255, 0.22), transparent 34%),
    linear-gradient(135deg, #10b981, #06b6d4) !important;
  margin-bottom: 14px;
}

.vb-accordion-seven-hero h3 {
  margin: 0 0 10px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-accordion-seven-hero p {
  margin: 0 !important;
  color: #ecfeff !important;
  -webkit-text-fill-color: #ecfeff !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

.vb-accordion-seven-list {
  display: grid;
  gap: 10px;
  margin-bottom: 12px;
}

.vb-accordion-seven-item {
  overflow: hidden;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.18);
}

.vb-accordion-seven-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  min-height: 62px;
  padding: 16px 18px;
  border: 0;
  background: #ffffff;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-seven-trigger span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 17px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.03em;
}

.vb-accordion-seven-trigger em {
  position: relative;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: #ecfdf5;
  border: 1px solid rgba(16, 185, 129, 0.18);
}

.vb-accordion-seven-trigger em::before,
.vb-accordion-seven-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 14px;
  height: 2px;
  border-radius: 999px;
  background: #059669;
  transform: translate(-50%, -50%);
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.vb-accordion-seven-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-seven-item.is-open .vb-accordion-seven-trigger em::after {
  opacity: 0;
  transform: translate(-50%, -50%) rotate(0deg);
}

.vb-accordion-seven-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-seven-content {
  display: grid;
  gap: 10px;
  padding: 0 18px 18px;
}

.vb-accordion-seven-content label {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 42px;
  padding: 10px 12px;
  border-radius: 15px;
  background: #f8fafc;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  line-height: 1.35;
  font-weight: 800;
}

.vb-accordion-seven-content input {
  width: 17px;
  height: 17px;
  accent-color: #10b981;
}

.vb-accordion-seven-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-accordion-seven-tags button {
  min-height: 36px;
  padding: 8px 12px;
  border: 0;
  border-radius: 999px;
  background: #ecfeff;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 13px;
  font-weight: 900;
  cursor: pointer;
}

.vb-accordion-seven-actions {
  position: sticky;
  bottom: 0;
  display: grid;
  grid-template-columns: 0.8fr 1.2fr;
  gap: 10px;
  padding: 12px;
  border-radius: 24px;
  background: rgba(15, 23, 42, 0.90);
  backdrop-filter: blur(14px);
}

.vb-accordion-seven-actions button {
  min-height: 46px;
  border: 0;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-accordion-seven-actions button:first-child {
  background: rgba(255,255,255,0.10);
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
}

.vb-accordion-seven-actions button:last-child {
  background: linear-gradient(135deg, #10b981, #06b6d4) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

@media (max-width: 640px) {
  .vb-accordion-seven-demo {
    padding: 18px;
    border-radius: 26px;
  }

  .vb-accordion-seven-phone {
    border-width: 5px;
    border-radius: 32px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-seven]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-seven-item"));

  function updateItem(item) {
    const trigger = item.querySelector(".vb-accordion-seven-trigger");
    const panel = item.querySelector(".vb-accordion-seven-panel");
    const isOpen = item.classList.contains("is-open");

    trigger.setAttribute("aria-expanded", isOpen ? "true" : "false");
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  items.forEach(function (item) {
    const trigger = item.querySelector(".vb-accordion-seven-trigger");

    trigger.addEventListener("click", function () {
      item.classList.toggle("is-open");
      updateItem(item);
    });

    updateItem(item);
  });

  window.addEventListener("resize", function () {
    items.forEach(updateItem);
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-seven]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-seven-item"));

  function updateItem(item) {
    const trigger = item.querySelector(".vb-accordion-seven-trigger");
    const panel = item.querySelector(".vb-accordion-seven-panel");
    const isOpen = item.classList.contains("is-open");

    trigger.setAttribute("aria-expanded", isOpen ? "true" : "false");
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  items.forEach(function (item) {
    const trigger = item.querySelector(".vb-accordion-seven-trigger");

    trigger.addEventListener("click", function () {
      item.classList.toggle("is-open");
      updateItem(item);
    });

    updateItem(item);
  });

  window.addEventListener("resize", function () {
    items.forEach(updateItem);
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-seven-demo"&gt;
  &lt;div class="vb-accordion-seven-phone" data-vb-accordion-seven&gt;
    &lt;div class="vb-accordion-seven-status"&gt;
      &lt;span&gt;Example 07&lt;/span&gt;
      &lt;strong&gt;Mobile Filters&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-seven-hero"&gt;
      &lt;h3&gt;Mobile Filter Accordion&lt;/h3&gt;
      &lt;p&gt;Open product filter groups inside a compact mobile-first accordion layout.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-seven-list"&gt;
      &lt;section class="vb-accordion-seven-item is-open"&gt;
        &lt;button class="vb-accordion-seven-trigger" type="button" aria-expanded="true"&gt;
          &lt;span&gt;Category&lt;/span&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-seven-panel"&gt;
          &lt;div class="vb-accordion-seven-content"&gt;
            &lt;label&gt;&lt;input type="checkbox"&gt; Website templates&lt;/label&gt;
            &lt;label&gt;&lt;input type="checkbox"&gt; UI components&lt;/label&gt;
            &lt;label&gt;&lt;input type="checkbox"&gt; WordPress plugins&lt;/label&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-seven-item"&gt;
        &lt;button class="vb-accordion-seven-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Price range&lt;/span&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-seven-panel"&gt;
          &lt;div class="vb-accordion-seven-content"&gt;
            &lt;label&gt;&lt;input type="checkbox"&gt; Under €25&lt;/label&gt;
            &lt;label&gt;&lt;input type="checkbox"&gt; €25 - €75&lt;/label&gt;
            &lt;label&gt;&lt;input type="checkbox"&gt; Over €75&lt;/label&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-seven-item"&gt;
        &lt;button class="vb-accordion-seven-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Features&lt;/span&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-seven-panel"&gt;
          &lt;div class="vb-accordion-seven-content vb-accordion-seven-tags"&gt;
            &lt;button type="button"&gt;Responsive&lt;/button&gt;
            &lt;button type="button"&gt;SEO ready&lt;/button&gt;
            &lt;button type="button"&gt;Dark mode&lt;/button&gt;
            &lt;button type="button"&gt;No framework&lt;/button&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-seven-item"&gt;
        &lt;button class="vb-accordion-seven-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Rating&lt;/span&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-seven-panel"&gt;
          &lt;div class="vb-accordion-seven-content"&gt;
            &lt;label&gt;&lt;input type="checkbox"&gt; 5 stars only&lt;/label&gt;
            &lt;label&gt;&lt;input type="checkbox"&gt; 4 stars and up&lt;/label&gt;
            &lt;label&gt;&lt;input type="checkbox"&gt; New products&lt;/label&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-seven-actions"&gt;
      &lt;button type="button"&gt;Reset&lt;/button&gt;
      &lt;button type="button"&gt;Apply Filters&lt;/button&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-seven-demo,
.vb-accordion-seven-demo * {
  box-sizing: border-box;
}

.vb-accordion-seven-demo {
  margin: 28px 0;
  padding: 42px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 18% 18%, rgba(16, 185, 129, 0.20), transparent 32%),
    radial-gradient(circle at 86% 22%, rgba(14, 165, 233, 0.18), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #f0f9ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(125, 211, 252, 0.36);
  box-shadow: 0 24px 70px rgba(6, 95, 70, 0.12);
}

.vb-accordion-seven-phone {
  max-width: 430px;
  margin: 0 auto;
  padding: 16px;
  border-radius: 42px;
  background: #0f172a;
  border: 8px solid #111827;
  box-shadow: 0 32px 90px rgba(15, 23, 42, 0.28);
}

.vb-accordion-seven-status {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 6px 8px 14px;
}

.vb-accordion-seven-status span {
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.16);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-accordion-seven-status strong {
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-accordion-seven-hero {
  padding: 24px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 20% 18%, rgba(255, 255, 255, 0.22), transparent 34%),
    linear-gradient(135deg, #10b981, #06b6d4) !important;
  margin-bottom: 14px;
}

.vb-accordion-seven-hero h3 {
  margin: 0 0 10px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-accordion-seven-hero p {
  margin: 0 !important;
  color: #ecfeff !important;
  -webkit-text-fill-color: #ecfeff !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

.vb-accordion-seven-list {
  display: grid;
  gap: 10px;
  margin-bottom: 12px;
}

.vb-accordion-seven-item {
  overflow: hidden;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.18);
}

.vb-accordion-seven-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  min-height: 62px;
  padding: 16px 18px;
  border: 0;
  background: #ffffff;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-seven-trigger span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 17px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.03em;
}

.vb-accordion-seven-trigger em {
  position: relative;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: #ecfdf5;
  border: 1px solid rgba(16, 185, 129, 0.18);
}

.vb-accordion-seven-trigger em::before,
.vb-accordion-seven-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 14px;
  height: 2px;
  border-radius: 999px;
  background: #059669;
  transform: translate(-50%, -50%);
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.vb-accordion-seven-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-seven-item.is-open .vb-accordion-seven-trigger em::after {
  opacity: 0;
  transform: translate(-50%, -50%) rotate(0deg);
}

.vb-accordion-seven-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-seven-content {
  display: grid;
  gap: 10px;
  padding: 0 18px 18px;
}

.vb-accordion-seven-content label {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 42px;
  padding: 10px 12px;
  border-radius: 15px;
  background: #f8fafc;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  line-height: 1.35;
  font-weight: 800;
}

.vb-accordion-seven-content input {
  width: 17px;
  height: 17px;
  accent-color: #10b981;
}

.vb-accordion-seven-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-accordion-seven-tags button {
  min-height: 36px;
  padding: 8px 12px;
  border: 0;
  border-radius: 999px;
  background: #ecfeff;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 13px;
  font-weight: 900;
  cursor: pointer;
}

.vb-accordion-seven-actions {
  position: sticky;
  bottom: 0;
  display: grid;
  grid-template-columns: 0.8fr 1.2fr;
  gap: 10px;
  padding: 12px;
  border-radius: 24px;
  background: rgba(15, 23, 42, 0.90);
  backdrop-filter: blur(14px);
}

.vb-accordion-seven-actions button {
  min-height: 46px;
  border: 0;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-accordion-seven-actions button:first-child {
  background: rgba(255,255,255,0.10);
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
}

.vb-accordion-seven-actions button:last-child {
  background: linear-gradient(135deg, #10b981, #06b6d4) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

@media (max-width: 640px) {
  .vb-accordion-seven-demo {
    padding: 18px;
    border-radius: 26px;
  }

  .vb-accordion-seven-phone {
    border-width: 5px;
    border-radius: 32px;
  }
}</pre>



<p class="wp-block-paragraph">This mobile filter accordion is ideal for ecommerce category pages, product catalogs, directories, real estate listings, travel search pages, job boards, and any mobile interface where filters need to stay compact.</p>



<h2 class="wp-block-heading">8. Split Image Content Accordion</h2>



<p class="wp-block-paragraph"><strong>A split image content accordion</strong> combines expandable text with a strong visual area. It is useful for agency websites, service pages, product showcases, course landing pages, restaurant pages, travel sections, and feature explainers.</p>



<p class="wp-block-paragraph">This example uses a split-screen layout with an abstract image card on the left and stacked accordion panels on the right. The visual card updates through active styling, while the accordion uses one-open-at-a-time JavaScript behavior.</p>



<ul class="wp-block-list">
<li>Split image and accordion layout</li>
<li>One-open-at-a-time behavior</li>
<li>Large visual illustration card</li>
<li>Angled content panels</li>
<li>Useful for services, products, and feature sections</li>
</ul>



<div class="vb-accordion-eight-demo">
  <div class="vb-accordion-eight-layout" data-vb-accordion-eight>
    <div class="vb-accordion-eight-visual">
      <span>Example 08</span>
      <div class="vb-accordion-eight-art">
        <div class="vb-accordion-eight-window">
          <i></i>
          <i></i>
          <i></i>
        </div>
        <div class="vb-accordion-eight-floating vb-accordion-eight-floating-a">UI</div>
        <div class="vb-accordion-eight-floating vb-accordion-eight-floating-b">JS</div>
      </div>
    </div>

    <div class="vb-accordion-eight-content-wrap">
      <div class="vb-accordion-eight-heading">
        <h3>Split Image Content Accordion</h3>
        <p>Use a visual feature area beside expandable content panels for product or service explanations.</p>
      </div>

      <div class="vb-accordion-eight-list">
        <article class="vb-accordion-eight-item is-open">
          <button class="vb-accordion-eight-trigger" type="button" aria-expanded="true">
            <span>01</span>
            <strong>Feature overview</strong>
            <em>View</em>
          </button>
          <div class="vb-accordion-eight-panel">
            <div class="vb-accordion-eight-content">
              <p>Explain the main value of a product, service, or interface section in a compact panel without making the page too long.</p>
            </div>
          </div>
        </article>

        <article class="vb-accordion-eight-item">
          <button class="vb-accordion-eight-trigger" type="button" aria-expanded="false">
            <span>02</span>
            <strong>Design details</strong>
            <em>View</em>
          </button>
          <div class="vb-accordion-eight-panel">
            <div class="vb-accordion-eight-content">
              <p>Use this panel to describe colors, layout choices, animations, responsive behavior, and important visual details.</p>
            </div>
          </div>
        </article>

        <article class="vb-accordion-eight-item">
          <button class="vb-accordion-eight-trigger" type="button" aria-expanded="false">
            <span>03</span>
            <strong>Technical setup</strong>
            <em>View</em>
          </button>
          <div class="vb-accordion-eight-panel">
            <div class="vb-accordion-eight-content">
              <p>The JavaScript controls active classes, ARIA values, max-height animation, and closing other panels when one opens.</p>
            </div>
          </div>
        </article>

        <article class="vb-accordion-eight-item">
          <button class="vb-accordion-eight-trigger" type="button" aria-expanded="false">
            <span>04</span>
            <strong>Best use cases</strong>
            <em>View</em>
          </button>
          <div class="vb-accordion-eight-panel">
            <div class="vb-accordion-eight-content">
              <p>This split accordion works well for service highlights, product features, course modules, agency processes, and startup landing pages.</p>
            </div>
          </div>
        </article>
      </div>
    </div>
  </div>
</div>

<style>
.vb-accordion-eight-demo,
.vb-accordion-eight-demo * {
  box-sizing: border-box;
}

.vb-accordion-eight-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 0 46px 46px 46px;
  background:
    linear-gradient(135deg, #faf5ff 0%, #eff6ff 48%, #ffffff 100%) !important;
  border: 1px solid rgba(167, 139, 250, 0.28);
  box-shadow: 0 24px 70px rgba(88, 28, 135, 0.10);
}

.vb-accordion-eight-layout {
  display: grid;
  grid-template-columns: minmax(290px, 0.92fr) minmax(0, 1.08fr);
  gap: 26px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-accordion-eight-visual {
  position: relative;
  min-height: 620px;
  padding: 28px;
  border-radius: 0 44px 44px 44px;
  background:
    radial-gradient(circle at 24% 18%, rgba(255, 255, 255, 0.30), transparent 32%),
    linear-gradient(135deg, #581c87, #2563eb 58%, #06b6d4) !important;
  overflow: hidden;
  box-shadow: 0 28px 80px rgba(37, 99, 235, 0.22);
}

.vb-accordion-eight-visual > span {
  display: inline-flex;
  position: relative;
  z-index: 2;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.22);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-eight-art {
  position: absolute;
  inset: 86px 28px 28px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 30% 24%, rgba(255,255,255,0.28), transparent 34%),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.18);
}

.vb-accordion-eight-window {
  position: absolute;
  left: 28px;
  right: 28px;
  top: 76px;
  height: 260px;
  border-radius: 28px;
  background: rgba(15, 23, 42, 0.68);
  border: 1px solid rgba(255,255,255,0.16);
  box-shadow: 0 28px 70px rgba(2, 6, 23, 0.28);
  transform: rotate(-3deg);
}

.vb-accordion-eight-window::before {
  content: "";
  position: absolute;
  left: 24px;
  top: 24px;
  width: 78px;
  height: 14px;
  border-radius: 999px;
  background: #22d3ee;
  box-shadow: 0 42px 0 rgba(255,255,255,0.22), 0 84px 0 rgba(255,255,255,0.16);
}

.vb-accordion-eight-window i {
  position: absolute;
  right: 24px;
  height: 48px;
  border-radius: 18px;
  background: rgba(255,255,255,0.12);
}

.vb-accordion-eight-window i:nth-child(1) {
  top: 24px;
  width: 120px;
}

.vb-accordion-eight-window i:nth-child(2) {
  top: 92px;
  width: 170px;
}

.vb-accordion-eight-window i:nth-child(3) {
  top: 160px;
  width: 140px;
}

.vb-accordion-eight-floating {
  position: absolute;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 86px;
  height: 86px;
  border-radius: 28px;
  background: #ffffff;
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 24px;
  font-weight: 950;
  box-shadow: 0 26px 60px rgba(2, 6, 23, 0.24);
}

.vb-accordion-eight-floating-a {
  right: 42px;
  top: 36px;
  transform: rotate(8deg);
}

.vb-accordion-eight-floating-b {
  left: 44px;
  bottom: 54px;
  color: #7c3aed !important;
  -webkit-text-fill-color: #7c3aed !important;
  transform: rotate(-8deg);
}

.vb-accordion-eight-content-wrap {
  align-self: center;
}

.vb-accordion-eight-heading {
  margin-bottom: 24px;
}

.vb-accordion-eight-heading h3 {
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 66px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-eight-heading p {
  max-width: 600px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-eight-list {
  display: grid;
  gap: 13px;
}

.vb-accordion-eight-item {
  overflow: hidden;
  border-radius: 26px 6px 26px 6px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.08);
  transition: transform 0.22s ease, border-color 0.22s ease;
}

.vb-accordion-eight-item.is-open {
  transform: translateX(-8px);
  border-color: rgba(37, 99, 235, 0.36);
}

.vb-accordion-eight-trigger {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr) 72px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 76px;
  padding: 16px 18px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-eight-trigger span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 44px;
  border-radius: 18px 4px 18px 4px;
  background: #eff6ff;
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-accordion-eight-trigger strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 19px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-eight-trigger em {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  min-height: 38px;
  border-radius: 999px;
  background: #f8fafc;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 12px;
  font-style: normal;
  font-weight: 950;
  text-transform: uppercase;
}

.vb-accordion-eight-item.is-open .vb-accordion-eight-trigger em {
  background: #2563eb;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-eight-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-eight-content {
  padding: 0 18px 20px 86px;
}

.vb-accordion-eight-content p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 920px) {
  .vb-accordion-eight-layout {
    grid-template-columns: 1fr;
  }

  .vb-accordion-eight-visual {
    min-height: 420px;
  }
}

@media (max-width: 640px) {
  .vb-accordion-eight-demo {
    padding: 18px;
    border-radius: 0 30px 30px 30px;
  }

  .vb-accordion-eight-visual {
    min-height: 360px;
    padding: 22px;
    border-radius: 0 30px 30px 30px;
  }

  .vb-accordion-eight-heading h3 {
    font-size: 38px !important;
  }

  .vb-accordion-eight-item.is-open {
    transform: none;
  }

  .vb-accordion-eight-trigger {
    grid-template-columns: 46px minmax(0, 1fr);
  }

  .vb-accordion-eight-trigger em {
    grid-column: 2;
    justify-self: start;
    min-width: 70px;
  }

  .vb-accordion-eight-content {
    padding: 0 18px 18px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-eight]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-eight-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-eight-trigger");
    const panel = item.querySelector(".vb-accordion-eight-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-eight-trigger");
    const panel = item.querySelector(".vb-accordion-eight-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-eight-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-eight-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-eight-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-eight]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-eight-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-eight-trigger");
    const panel = item.querySelector(".vb-accordion-eight-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-eight-trigger");
    const panel = item.querySelector(".vb-accordion-eight-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-eight-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-eight-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-eight-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-eight-demo"&gt;
  &lt;div class="vb-accordion-eight-layout" data-vb-accordion-eight&gt;
    &lt;div class="vb-accordion-eight-visual"&gt;
      &lt;span&gt;Example 08&lt;/span&gt;
      &lt;div class="vb-accordion-eight-art"&gt;
        &lt;div class="vb-accordion-eight-window"&gt;
          &lt;i&gt;&lt;/i&gt;
          &lt;i&gt;&lt;/i&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/div&gt;
        &lt;div class="vb-accordion-eight-floating vb-accordion-eight-floating-a"&gt;UI&lt;/div&gt;
        &lt;div class="vb-accordion-eight-floating vb-accordion-eight-floating-b"&gt;JS&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-eight-content-wrap"&gt;
      &lt;div class="vb-accordion-eight-heading"&gt;
        &lt;h3&gt;Split Image Content Accordion&lt;/h3&gt;
        &lt;p&gt;Use a visual feature area beside expandable content panels for product or service explanations.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-eight-list"&gt;
        &lt;article class="vb-accordion-eight-item is-open"&gt;
          &lt;button class="vb-accordion-eight-trigger" type="button" aria-expanded="true"&gt;
            &lt;span&gt;01&lt;/span&gt;
            &lt;strong&gt;Feature overview&lt;/strong&gt;
            &lt;em&gt;View&lt;/em&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-eight-panel"&gt;
            &lt;div class="vb-accordion-eight-content"&gt;
              &lt;p&gt;Explain the main value of a product, service, or interface section in a compact panel without making the page too long.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-accordion-eight-item"&gt;
          &lt;button class="vb-accordion-eight-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;02&lt;/span&gt;
            &lt;strong&gt;Design details&lt;/strong&gt;
            &lt;em&gt;View&lt;/em&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-eight-panel"&gt;
            &lt;div class="vb-accordion-eight-content"&gt;
              &lt;p&gt;Use this panel to describe colors, layout choices, animations, responsive behavior, and important visual details.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-accordion-eight-item"&gt;
          &lt;button class="vb-accordion-eight-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;03&lt;/span&gt;
            &lt;strong&gt;Technical setup&lt;/strong&gt;
            &lt;em&gt;View&lt;/em&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-eight-panel"&gt;
            &lt;div class="vb-accordion-eight-content"&gt;
              &lt;p&gt;The JavaScript controls active classes, ARIA values, max-height animation, and closing other panels when one opens.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/article&gt;

        &lt;article class="vb-accordion-eight-item"&gt;
          &lt;button class="vb-accordion-eight-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;04&lt;/span&gt;
            &lt;strong&gt;Best use cases&lt;/strong&gt;
            &lt;em&gt;View&lt;/em&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-eight-panel"&gt;
            &lt;div class="vb-accordion-eight-content"&gt;
              &lt;p&gt;This split accordion works well for service highlights, product features, course modules, agency processes, and startup landing pages.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/article&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-eight-demo,
.vb-accordion-eight-demo * {
  box-sizing: border-box;
}

.vb-accordion-eight-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 0 46px 46px 46px;
  background:
    linear-gradient(135deg, #faf5ff 0%, #eff6ff 48%, #ffffff 100%) !important;
  border: 1px solid rgba(167, 139, 250, 0.28);
  box-shadow: 0 24px 70px rgba(88, 28, 135, 0.10);
}

.vb-accordion-eight-layout {
  display: grid;
  grid-template-columns: minmax(290px, 0.92fr) minmax(0, 1.08fr);
  gap: 26px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-accordion-eight-visual {
  position: relative;
  min-height: 620px;
  padding: 28px;
  border-radius: 0 44px 44px 44px;
  background:
    radial-gradient(circle at 24% 18%, rgba(255, 255, 255, 0.30), transparent 32%),
    linear-gradient(135deg, #581c87, #2563eb 58%, #06b6d4) !important;
  overflow: hidden;
  box-shadow: 0 28px 80px rgba(37, 99, 235, 0.22);
}

.vb-accordion-eight-visual &gt; span {
  display: inline-flex;
  position: relative;
  z-index: 2;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.22);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-eight-art {
  position: absolute;
  inset: 86px 28px 28px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 30% 24%, rgba(255,255,255,0.28), transparent 34%),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.18);
}

.vb-accordion-eight-window {
  position: absolute;
  left: 28px;
  right: 28px;
  top: 76px;
  height: 260px;
  border-radius: 28px;
  background: rgba(15, 23, 42, 0.68);
  border: 1px solid rgba(255,255,255,0.16);
  box-shadow: 0 28px 70px rgba(2, 6, 23, 0.28);
  transform: rotate(-3deg);
}

.vb-accordion-eight-window::before {
  content: "";
  position: absolute;
  left: 24px;
  top: 24px;
  width: 78px;
  height: 14px;
  border-radius: 999px;
  background: #22d3ee;
  box-shadow: 0 42px 0 rgba(255,255,255,0.22), 0 84px 0 rgba(255,255,255,0.16);
}

.vb-accordion-eight-window i {
  position: absolute;
  right: 24px;
  height: 48px;
  border-radius: 18px;
  background: rgba(255,255,255,0.12);
}

.vb-accordion-eight-window i:nth-child(1) {
  top: 24px;
  width: 120px;
}

.vb-accordion-eight-window i:nth-child(2) {
  top: 92px;
  width: 170px;
}

.vb-accordion-eight-window i:nth-child(3) {
  top: 160px;
  width: 140px;
}

.vb-accordion-eight-floating {
  position: absolute;
  z-index: 3;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 86px;
  height: 86px;
  border-radius: 28px;
  background: #ffffff;
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 24px;
  font-weight: 950;
  box-shadow: 0 26px 60px rgba(2, 6, 23, 0.24);
}

.vb-accordion-eight-floating-a {
  right: 42px;
  top: 36px;
  transform: rotate(8deg);
}

.vb-accordion-eight-floating-b {
  left: 44px;
  bottom: 54px;
  color: #7c3aed !important;
  -webkit-text-fill-color: #7c3aed !important;
  transform: rotate(-8deg);
}

.vb-accordion-eight-content-wrap {
  align-self: center;
}

.vb-accordion-eight-heading {
  margin-bottom: 24px;
}

.vb-accordion-eight-heading h3 {
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 66px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-eight-heading p {
  max-width: 600px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-eight-list {
  display: grid;
  gap: 13px;
}

.vb-accordion-eight-item {
  overflow: hidden;
  border-radius: 26px 6px 26px 6px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.08);
  transition: transform 0.22s ease, border-color 0.22s ease;
}

.vb-accordion-eight-item.is-open {
  transform: translateX(-8px);
  border-color: rgba(37, 99, 235, 0.36);
}

.vb-accordion-eight-trigger {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr) 72px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 76px;
  padding: 16px 18px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-eight-trigger span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 44px;
  border-radius: 18px 4px 18px 4px;
  background: #eff6ff;
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-accordion-eight-trigger strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 19px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-eight-trigger em {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  min-height: 38px;
  border-radius: 999px;
  background: #f8fafc;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 12px;
  font-style: normal;
  font-weight: 950;
  text-transform: uppercase;
}

.vb-accordion-eight-item.is-open .vb-accordion-eight-trigger em {
  background: #2563eb;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-eight-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-eight-content {
  padding: 0 18px 20px 86px;
}

.vb-accordion-eight-content p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 920px) {
  .vb-accordion-eight-layout {
    grid-template-columns: 1fr;
  }

  .vb-accordion-eight-visual {
    min-height: 420px;
  }
}

@media (max-width: 640px) {
  .vb-accordion-eight-demo {
    padding: 18px;
    border-radius: 0 30px 30px 30px;
  }

  .vb-accordion-eight-visual {
    min-height: 360px;
    padding: 22px;
    border-radius: 0 30px 30px 30px;
  }

  .vb-accordion-eight-heading h3 {
    font-size: 38px !important;
  }

  .vb-accordion-eight-item.is-open {
    transform: none;
  }

  .vb-accordion-eight-trigger {
    grid-template-columns: 46px minmax(0, 1fr);
  }

  .vb-accordion-eight-trigger em {
    grid-column: 2;
    justify-self: start;
    min-width: 70px;
  }

  .vb-accordion-eight-content {
    padding: 0 18px 18px;
  }
}</pre>



<p class="wp-block-paragraph">This split image content accordion is useful for landing pages, product features, agency service sections, startup pages, course previews, portfolio case studies, and any layout where expandable text should be supported by a strong visual block.</p>



<h2 class="wp-block-heading">9. Dashboard Settings Accordion</h2>



<p class="wp-block-paragraph"><strong>A dashboard settings accordion</strong> is useful for admin panels, SaaS products, account pages, user dashboards, plugin settings screens, and app configuration pages. It keeps settings grouped into clear sections instead of showing every option at once.</p>



<p class="wp-block-paragraph">This example uses a professional dashboard-style layout with a left settings summary, status badges, toggle switches, and expandable settings panels. The design is different from the previous examples because it looks like a real app settings screen rather than a marketing or FAQ section.</p>



<ul class="wp-block-list">
<li>Dashboard-style accordion layout</li>
<li>Multi-open settings panels</li>
<li>Toggle switch UI elements</li>
<li>Status badges and app-style cards</li>
<li>Useful for admin panels and SaaS dashboards</li>
</ul>



<div class="vb-accordion-nine-demo">
  <div class="vb-accordion-nine-app" data-vb-accordion-nine>
    <aside class="vb-accordion-nine-sidebar">
      <span>Example 09</span>
      <h3>Dashboard Settings Accordion</h3>
      <p>Group app settings into expandable admin panels with clear status indicators.</p>

      <div class="vb-accordion-nine-stats">
        <div>
          <strong>4</strong>
          <small>Setting groups</small>
        </div>
        <div>
          <strong>12</strong>
          <small>Options</small>
        </div>
      </div>
    </aside>

    <main class="vb-accordion-nine-main">
      <section class="vb-accordion-nine-item is-open">
        <button class="vb-accordion-nine-trigger" type="button" aria-expanded="true">
          <span>
            <strong>Profile settings</strong>
            <small>Public profile, avatar, and account details</small>
          </span>
          <em>Active</em>
        </button>

        <div class="vb-accordion-nine-panel">
          <div class="vb-accordion-nine-content">
            <label>
              <span>Show public profile</span>
              <input type="checkbox" checked>
            </label>
            <label>
              <span>Display contact button</span>
              <input type="checkbox" checked>
            </label>
            <label>
              <span>Allow profile indexing</span>
              <input type="checkbox">
            </label>
          </div>
        </div>
      </section>

      <section class="vb-accordion-nine-item">
        <button class="vb-accordion-nine-trigger" type="button" aria-expanded="false">
          <span>
            <strong>Notifications</strong>
            <small>Email alerts, app messages, and weekly reports</small>
          </span>
          <em>Open</em>
        </button>

        <div class="vb-accordion-nine-panel">
          <div class="vb-accordion-nine-content">
            <label>
              <span>Email notifications</span>
              <input type="checkbox" checked>
            </label>
            <label>
              <span>Weekly summary</span>
              <input type="checkbox">
            </label>
            <label>
              <span>Security alerts</span>
              <input type="checkbox" checked>
            </label>
          </div>
        </div>
      </section>

      <section class="vb-accordion-nine-item">
        <button class="vb-accordion-nine-trigger" type="button" aria-expanded="false">
          <span>
            <strong>Privacy controls</strong>
            <small>Data visibility, tracking, and sharing options</small>
          </span>
          <em>Open</em>
        </button>

        <div class="vb-accordion-nine-panel">
          <div class="vb-accordion-nine-content">
            <label>
              <span>Anonymous usage analytics</span>
              <input type="checkbox">
            </label>
            <label>
              <span>Hide activity status</span>
              <input type="checkbox" checked>
            </label>
            <label>
              <span>Download account data</span>
              <button type="button">Export</button>
            </label>
          </div>
        </div>
      </section>

      <section class="vb-accordion-nine-item">
        <button class="vb-accordion-nine-trigger" type="button" aria-expanded="false">
          <span>
            <strong>Billing preferences</strong>
            <small>Invoices, payment method, and plan notices</small>
          </span>
          <em>Open</em>
        </button>

        <div class="vb-accordion-nine-panel">
          <div class="vb-accordion-nine-content">
            <label>
              <span>Send invoice by email</span>
              <input type="checkbox" checked>
            </label>
            <label>
              <span>Renewal reminders</span>
              <input type="checkbox" checked>
            </label>
            <label>
              <span>Payment method</span>
              <button type="button">Update</button>
            </label>
          </div>
        </div>
      </section>
    </main>
  </div>
</div>

<style>
.vb-accordion-nine-demo,
.vb-accordion-nine-demo * {
  box-sizing: border-box;
}

.vb-accordion-nine-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    linear-gradient(135deg, #e2e8f0 0%, #f8fafc 52%, #ffffff 100%) !important;
  border: 1px solid rgba(100, 116, 139, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.11);
}

.vb-accordion-nine-app {
  display: grid;
  grid-template-columns: 330px minmax(0, 1fr);
  gap: 18px;
  max-width: 1120px;
  margin: 0 auto;
  padding: 14px;
  border-radius: 28px;
  background: #020617;
  box-shadow: 0 30px 90px rgba(2, 6, 23, 0.30);
}

.vb-accordion-nine-sidebar {
  min-height: 610px;
  padding: 26px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 20% 16%, rgba(59, 130, 246, 0.26), transparent 34%),
    linear-gradient(135deg, #111827, #1e293b) !important;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.vb-accordion-nine-sidebar > span {
  align-self: flex-start;
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 12px;
  background: rgba(59, 130, 246, 0.16);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-nine-sidebar h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 4vw, 56px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-accordion-nine-sidebar p {
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-accordion-nine-stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-top: 28px;
}

.vb-accordion-nine-stats div {
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-accordion-nine-stats strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 30px;
  line-height: 1;
  font-weight: 950;
}

.vb-accordion-nine-stats small {
  display: block;
  margin-top: 6px;
  color: #94a3b8 !important;
  -webkit-text-fill-color: #94a3b8 !important;
  font-size: 12px;
  font-weight: 800;
}

.vb-accordion-nine-main {
  display: grid;
  align-content: start;
  gap: 12px;
  padding: 10px;
}

.vb-accordion-nine-item {
  overflow: hidden;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(226, 232, 240, 0.18);
}

.vb-accordion-nine-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 84px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 78px;
  padding: 18px 20px;
  border: 0;
  background: #ffffff;
  text-align: left;
  cursor: pointer;
}

.vb-accordion-nine-trigger strong {
  display: block;
  margin-bottom: 4px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 19px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-nine-trigger small {
  display: block;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.4;
  font-weight: 750;
}

.vb-accordion-nine-trigger em {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  min-height: 34px;
  border-radius: 10px;
  background: #f1f5f9;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 12px;
  font-style: normal;
  font-weight: 950;
  text-transform: uppercase;
}

.vb-accordion-nine-item.is-open .vb-accordion-nine-trigger em {
  background: #2563eb;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-nine-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-nine-content {
  display: grid;
  gap: 10px;
  padding: 0 20px 20px;
}

.vb-accordion-nine-content label {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 14px;
  min-height: 50px;
  padding: 12px 14px;
  border-radius: 14px;
  background: #f8fafc;
  border: 1px solid rgba(226, 232, 240, 0.8);
}

.vb-accordion-nine-content label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-accordion-nine-content input[type="checkbox"] {
  position: relative;
  appearance: none;
  width: 46px;
  height: 26px;
  border-radius: 999px;
  background: #cbd5e1;
  cursor: pointer;
  transition: background 0.2s ease;
}

.vb-accordion-nine-content input[type="checkbox"]::before {
  content: "";
  position: absolute;
  width: 20px;
  height: 20px;
  left: 3px;
  top: 3px;
  border-radius: 999px;
  background: #ffffff;
  transition: transform 0.2s ease;
}

.vb-accordion-nine-content input[type="checkbox"]:checked {
  background: #2563eb;
}

.vb-accordion-nine-content input[type="checkbox"]:checked::before {
  transform: translateX(20px);
}

.vb-accordion-nine-content button {
  min-height: 34px;
  padding: 8px 14px;
  border: 0;
  border-radius: 10px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

@media (max-width: 900px) {
  .vb-accordion-nine-app {
    grid-template-columns: 1fr;
  }

  .vb-accordion-nine-sidebar {
    min-height: auto;
  }
}

@media (max-width: 640px) {
  .vb-accordion-nine-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-accordion-nine-app {
    padding: 10px;
    border-radius: 22px;
  }

  .vb-accordion-nine-sidebar {
    padding: 22px;
  }

  .vb-accordion-nine-sidebar h3 {
    font-size: 38px !important;
  }

  .vb-accordion-nine-trigger {
    grid-template-columns: 1fr;
  }

  .vb-accordion-nine-trigger em {
    justify-self: start;
    min-width: 76px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-nine]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-nine-item"));

  function updateItem(item) {
    const button = item.querySelector(".vb-accordion-nine-trigger");
    const panel = item.querySelector(".vb-accordion-nine-panel");
    const badge = button.querySelector("em");
    const isOpen = item.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");
    badge.textContent = isOpen ? "Active" : "Open";
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-nine-trigger");

    button.addEventListener("click", function () {
      item.classList.toggle("is-open");
      updateItem(item);
    });

    updateItem(item);
  });

  window.addEventListener("resize", function () {
    items.forEach(updateItem);
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-nine]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-nine-item"));

  function updateItem(item) {
    const button = item.querySelector(".vb-accordion-nine-trigger");
    const panel = item.querySelector(".vb-accordion-nine-panel");
    const badge = button.querySelector("em");
    const isOpen = item.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");
    badge.textContent = isOpen ? "Active" : "Open";
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-nine-trigger");

    button.addEventListener("click", function () {
      item.classList.toggle("is-open");
      updateItem(item);
    });

    updateItem(item);
  });

  window.addEventListener("resize", function () {
    items.forEach(updateItem);
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-nine-demo"&gt;
  &lt;div class="vb-accordion-nine-app" data-vb-accordion-nine&gt;
    &lt;aside class="vb-accordion-nine-sidebar"&gt;
      &lt;span&gt;Example 09&lt;/span&gt;
      &lt;h3&gt;Dashboard Settings Accordion&lt;/h3&gt;
      &lt;p&gt;Group app settings into expandable admin panels with clear status indicators.&lt;/p&gt;

      &lt;div class="vb-accordion-nine-stats"&gt;
        &lt;div&gt;
          &lt;strong&gt;4&lt;/strong&gt;
          &lt;small&gt;Setting groups&lt;/small&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;strong&gt;12&lt;/strong&gt;
          &lt;small&gt;Options&lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/aside&gt;

    &lt;main class="vb-accordion-nine-main"&gt;
      &lt;section class="vb-accordion-nine-item is-open"&gt;
        &lt;button class="vb-accordion-nine-trigger" type="button" aria-expanded="true"&gt;
          &lt;span&gt;
            &lt;strong&gt;Profile settings&lt;/strong&gt;
            &lt;small&gt;Public profile, avatar, and account details&lt;/small&gt;
          &lt;/span&gt;
          &lt;em&gt;Active&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-nine-panel"&gt;
          &lt;div class="vb-accordion-nine-content"&gt;
            &lt;label&gt;
              &lt;span&gt;Show public profile&lt;/span&gt;
              &lt;input type="checkbox" checked&gt;
            &lt;/label&gt;
            &lt;label&gt;
              &lt;span&gt;Display contact button&lt;/span&gt;
              &lt;input type="checkbox" checked&gt;
            &lt;/label&gt;
            &lt;label&gt;
              &lt;span&gt;Allow profile indexing&lt;/span&gt;
              &lt;input type="checkbox"&gt;
            &lt;/label&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-nine-item"&gt;
        &lt;button class="vb-accordion-nine-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;
            &lt;strong&gt;Notifications&lt;/strong&gt;
            &lt;small&gt;Email alerts, app messages, and weekly reports&lt;/small&gt;
          &lt;/span&gt;
          &lt;em&gt;Open&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-nine-panel"&gt;
          &lt;div class="vb-accordion-nine-content"&gt;
            &lt;label&gt;
              &lt;span&gt;Email notifications&lt;/span&gt;
              &lt;input type="checkbox" checked&gt;
            &lt;/label&gt;
            &lt;label&gt;
              &lt;span&gt;Weekly summary&lt;/span&gt;
              &lt;input type="checkbox"&gt;
            &lt;/label&gt;
            &lt;label&gt;
              &lt;span&gt;Security alerts&lt;/span&gt;
              &lt;input type="checkbox" checked&gt;
            &lt;/label&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-nine-item"&gt;
        &lt;button class="vb-accordion-nine-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;
            &lt;strong&gt;Privacy controls&lt;/strong&gt;
            &lt;small&gt;Data visibility, tracking, and sharing options&lt;/small&gt;
          &lt;/span&gt;
          &lt;em&gt;Open&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-nine-panel"&gt;
          &lt;div class="vb-accordion-nine-content"&gt;
            &lt;label&gt;
              &lt;span&gt;Anonymous usage analytics&lt;/span&gt;
              &lt;input type="checkbox"&gt;
            &lt;/label&gt;
            &lt;label&gt;
              &lt;span&gt;Hide activity status&lt;/span&gt;
              &lt;input type="checkbox" checked&gt;
            &lt;/label&gt;
            &lt;label&gt;
              &lt;span&gt;Download account data&lt;/span&gt;
              &lt;button type="button"&gt;Export&lt;/button&gt;
            &lt;/label&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-nine-item"&gt;
        &lt;button class="vb-accordion-nine-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;
            &lt;strong&gt;Billing preferences&lt;/strong&gt;
            &lt;small&gt;Invoices, payment method, and plan notices&lt;/small&gt;
          &lt;/span&gt;
          &lt;em&gt;Open&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-nine-panel"&gt;
          &lt;div class="vb-accordion-nine-content"&gt;
            &lt;label&gt;
              &lt;span&gt;Send invoice by email&lt;/span&gt;
              &lt;input type="checkbox" checked&gt;
            &lt;/label&gt;
            &lt;label&gt;
              &lt;span&gt;Renewal reminders&lt;/span&gt;
              &lt;input type="checkbox" checked&gt;
            &lt;/label&gt;
            &lt;label&gt;
              &lt;span&gt;Payment method&lt;/span&gt;
              &lt;button type="button"&gt;Update&lt;/button&gt;
            &lt;/label&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/main&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-nine-demo,
.vb-accordion-nine-demo * {
  box-sizing: border-box;
}

.vb-accordion-nine-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    linear-gradient(135deg, #e2e8f0 0%, #f8fafc 52%, #ffffff 100%) !important;
  border: 1px solid rgba(100, 116, 139, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.11);
}

.vb-accordion-nine-app {
  display: grid;
  grid-template-columns: 330px minmax(0, 1fr);
  gap: 18px;
  max-width: 1120px;
  margin: 0 auto;
  padding: 14px;
  border-radius: 28px;
  background: #020617;
  box-shadow: 0 30px 90px rgba(2, 6, 23, 0.30);
}

.vb-accordion-nine-sidebar {
  min-height: 610px;
  padding: 26px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 20% 16%, rgba(59, 130, 246, 0.26), transparent 34%),
    linear-gradient(135deg, #111827, #1e293b) !important;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.vb-accordion-nine-sidebar &gt; span {
  align-self: flex-start;
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 12px;
  background: rgba(59, 130, 246, 0.16);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-nine-sidebar h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 4vw, 56px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-accordion-nine-sidebar p {
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-accordion-nine-stats {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-top: 28px;
}

.vb-accordion-nine-stats div {
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-accordion-nine-stats strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 30px;
  line-height: 1;
  font-weight: 950;
}

.vb-accordion-nine-stats small {
  display: block;
  margin-top: 6px;
  color: #94a3b8 !important;
  -webkit-text-fill-color: #94a3b8 !important;
  font-size: 12px;
  font-weight: 800;
}

.vb-accordion-nine-main {
  display: grid;
  align-content: start;
  gap: 12px;
  padding: 10px;
}

.vb-accordion-nine-item {
  overflow: hidden;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(226, 232, 240, 0.18);
}

.vb-accordion-nine-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 84px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 78px;
  padding: 18px 20px;
  border: 0;
  background: #ffffff;
  text-align: left;
  cursor: pointer;
}

.vb-accordion-nine-trigger strong {
  display: block;
  margin-bottom: 4px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 19px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-nine-trigger small {
  display: block;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.4;
  font-weight: 750;
}

.vb-accordion-nine-trigger em {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  min-height: 34px;
  border-radius: 10px;
  background: #f1f5f9;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 12px;
  font-style: normal;
  font-weight: 950;
  text-transform: uppercase;
}

.vb-accordion-nine-item.is-open .vb-accordion-nine-trigger em {
  background: #2563eb;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-nine-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-nine-content {
  display: grid;
  gap: 10px;
  padding: 0 20px 20px;
}

.vb-accordion-nine-content label {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: 14px;
  min-height: 50px;
  padding: 12px 14px;
  border-radius: 14px;
  background: #f8fafc;
  border: 1px solid rgba(226, 232, 240, 0.8);
}

.vb-accordion-nine-content label span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-accordion-nine-content input[type="checkbox"] {
  position: relative;
  appearance: none;
  width: 46px;
  height: 26px;
  border-radius: 999px;
  background: #cbd5e1;
  cursor: pointer;
  transition: background 0.2s ease;
}

.vb-accordion-nine-content input[type="checkbox"]::before {
  content: "";
  position: absolute;
  width: 20px;
  height: 20px;
  left: 3px;
  top: 3px;
  border-radius: 999px;
  background: #ffffff;
  transition: transform 0.2s ease;
}

.vb-accordion-nine-content input[type="checkbox"]:checked {
  background: #2563eb;
}

.vb-accordion-nine-content input[type="checkbox"]:checked::before {
  transform: translateX(20px);
}

.vb-accordion-nine-content button {
  min-height: 34px;
  padding: 8px 14px;
  border: 0;
  border-radius: 10px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

@media (max-width: 900px) {
  .vb-accordion-nine-app {
    grid-template-columns: 1fr;
  }

  .vb-accordion-nine-sidebar {
    min-height: auto;
  }
}

@media (max-width: 640px) {
  .vb-accordion-nine-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-accordion-nine-app {
    padding: 10px;
    border-radius: 22px;
  }

  .vb-accordion-nine-sidebar {
    padding: 22px;
  }

  .vb-accordion-nine-sidebar h3 {
    font-size: 38px !important;
  }

  .vb-accordion-nine-trigger {
    grid-template-columns: 1fr;
  }

  .vb-accordion-nine-trigger em {
    justify-self: start;
    min-width: 76px;
  }
}</pre>



<p class="wp-block-paragraph">This dashboard settings accordion is useful for SaaS dashboards, plugin settings pages, account areas, admin interfaces, profile pages, billing screens, and app configuration panels.</p>



<h2 class="wp-block-heading">10. Pricing FAQ Accordion</h2>



<p class="wp-block-paragraph"><strong>A pricing FAQ accordion</strong> helps answer common buying questions near a pricing section. It is useful for SaaS pricing pages, agency service packages, subscription products, memberships, hosting plans, and digital product sales pages.</p>



<p class="wp-block-paragraph">This example uses a premium pricing layout with a price card, highlighted plan badge, angled FAQ rows, and one-open-at-a-time JavaScript behavior. The visual structure is different from standard FAQ accordions because it connects the expandable questions directly with a conversion-focused pricing card.</p>



<ul class="wp-block-list">
<li>Pricing-focused FAQ accordion</li>
<li>One-open-at-a-time behavior</li>
<li>Plan card and CTA section</li>
<li>Angled question rows</li>
<li>Useful for SaaS, subscriptions, and service packages</li>
</ul>



<div class="vb-accordion-ten-demo">
  <div class="vb-accordion-ten-layout" data-vb-accordion-ten>
    <div class="vb-accordion-ten-card">
      <span>Example 10</span>
      <h3>Pro Plan</h3>
      <p>For growing websites, product teams, and businesses that need more advanced UI sections.</p>

      <div class="vb-accordion-ten-price">
        <strong>€29</strong>
        <small>/ month</small>
      </div>

      <ul>
        <li>Unlimited UI components</li>
        <li>Responsive templates</li>
        <li>Priority updates</li>
      </ul>

      <a href="#javascript-accordion-examples">Start Building</a>
    </div>

    <div class="vb-accordion-ten-faq">
      <div class="vb-accordion-ten-heading">
        <h3>Pricing FAQ Accordion</h3>
        <p>Answer purchase questions beside a pricing card and keep the conversion section compact.</p>
      </div>

      <div class="vb-accordion-ten-list">
        <section class="vb-accordion-ten-item is-open">
          <button class="vb-accordion-ten-trigger" type="button" aria-expanded="true">
            <span>Can I cancel anytime?</span>
            <strong>+</strong>
          </button>
          <div class="vb-accordion-ten-panel">
            <div class="vb-accordion-ten-content">
              <p>Yes. Users can cancel the subscription whenever they want. The plan remains active until the end of the current billing period.</p>
            </div>
          </div>
        </section>

        <section class="vb-accordion-ten-item">
          <button class="vb-accordion-ten-trigger" type="button" aria-expanded="false">
            <span>Do I get future updates?</span>
            <strong>+</strong>
          </button>
          <div class="vb-accordion-ten-panel">
            <div class="vb-accordion-ten-content">
              <p>Yes. Active users receive product updates, new examples, improvements, bug fixes, and upgraded UI components as they are released.</p>
            </div>
          </div>
        </section>

        <section class="vb-accordion-ten-item">
          <button class="vb-accordion-ten-trigger" type="button" aria-expanded="false">
            <span>Can I use this for client projects?</span>
            <strong>+</strong>
          </button>
          <div class="vb-accordion-ten-panel">
            <div class="vb-accordion-ten-content">
              <p>Yes. You can adapt the layouts and JavaScript patterns for client websites, landing pages, dashboards, and custom interface projects.</p>
            </div>
          </div>
        </section>

        <section class="vb-accordion-ten-item">
          <button class="vb-accordion-ten-trigger" type="button" aria-expanded="false">
            <span>Is the code beginner friendly?</span>
            <strong>+</strong>
          </button>
          <div class="vb-accordion-ten-panel">
            <div class="vb-accordion-ten-content">
              <p>The code uses vanilla JavaScript, structured HTML, and plain CSS, so it is easier to understand, edit, and reuse without extra frameworks.</p>
            </div>
          </div>
        </section>
      </div>
    </div>
  </div>
</div>

<style>
.vb-accordion-ten-demo,
.vb-accordion-ten-demo * {
  box-sizing: border-box;
}

.vb-accordion-ten-demo {
  margin: 28px 0;
  padding: 36px;
  border-radius: 46px 12px 46px 12px;
  background:
    radial-gradient(circle at 16% 20%, rgba(250, 204, 21, 0.22), transparent 32%),
    radial-gradient(circle at 84% 18%, rgba(249, 115, 22, 0.18), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fff7ed 50%, #ffffff 100%) !important;
  border: 1px solid rgba(253, 186, 116, 0.42);
  box-shadow: 0 24px 70px rgba(146, 64, 14, 0.12);
}

.vb-accordion-ten-layout {
  display: grid;
  grid-template-columns: minmax(280px, 0.82fr) minmax(0, 1.18fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
  align-items: stretch;
}

.vb-accordion-ten-card {
  position: relative;
  overflow: hidden;
  padding: 30px;
  border-radius: 38px 10px 38px 10px;
  background:
    radial-gradient(circle at 24% 18%, rgba(255,255,255,0.28), transparent 32%),
    linear-gradient(135deg, #78350f, #ea580c 60%, #facc15) !important;
  box-shadow: 0 30px 90px rgba(154, 52, 18, 0.24);
}

.vb-accordion-ten-card::after {
  content: "";
  position: absolute;
  right: -72px;
  top: -72px;
  width: 180px;
  height: 180px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
}

.vb-accordion-ten-card > span {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  border: 1px solid rgba(255,255,255,0.20);
  color: #fff7ed !important;
  -webkit-text-fill-color: #fff7ed !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-ten-card h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(40px, 5vw, 68px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-ten-card p {
  margin: 0 0 24px !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-accordion-ten-price {
  display: flex;
  align-items: end;
  gap: 8px;
  margin-bottom: 22px;
}

.vb-accordion-ten-price strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 74px;
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.09em;
}

.vb-accordion-ten-price small {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 15px;
  font-weight: 850;
}

.vb-accordion-ten-card ul {
  display: grid;
  gap: 10px;
  margin: 0 0 24px !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb-accordion-ten-card li {
  margin: 0 !important;
  padding: 12px 14px;
  border-radius: 16px;
  background: rgba(255,255,255,0.13);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-accordion-ten-card a {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  min-height: 50px;
  border-radius: 999px;
  background: #ffffff;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 14px;
  font-weight: 950;
  text-decoration: none !important;
}

.vb-accordion-ten-faq {
  align-self: center;
}

.vb-accordion-ten-heading {
  margin-bottom: 22px;
}

.vb-accordion-ten-heading h3 {
  margin: 0 0 12px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-ten-heading p {
  max-width: 590px;
  margin: 0 !important;
  color: #57534e !important;
  -webkit-text-fill-color: #57534e !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-ten-list {
  display: grid;
  gap: 13px;
}

.vb-accordion-ten-item {
  overflow: hidden;
  border-radius: 18px 4px 18px 4px;
  background: #ffffff;
  border: 1px solid rgba(253, 186, 116, 0.36);
  box-shadow: 0 16px 42px rgba(154, 52, 18, 0.08);
}

.vb-accordion-ten-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 42px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 70px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-ten-trigger span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
  letter-spacing: -0.035em;
}

.vb-accordion-ten-trigger strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 12px 2px 12px 2px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 24px;
  line-height: 1;
  font-weight: 950;
  transition: transform 0.22s ease, background 0.22s ease, color 0.22s ease;
}

.vb-accordion-ten-item.is-open .vb-accordion-ten-trigger strong {
  transform: rotate(45deg);
  background: #ea580c;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-ten-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-ten-content {
  padding: 0 20px 20px;
}

.vb-accordion-ten-content p {
  margin: 0 !important;
  color: #57534e !important;
  -webkit-text-fill-color: #57534e !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-accordion-ten-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-accordion-ten-demo {
    padding: 18px;
    border-radius: 32px 10px 32px 10px;
  }

  .vb-accordion-ten-card {
    padding: 24px;
  }

  .vb-accordion-ten-heading h3 {
    font-size: 38px !important;
  }

  .vb-accordion-ten-price strong {
    font-size: 58px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-ten]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-ten-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-ten-trigger");
    const panel = item.querySelector(".vb-accordion-ten-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-ten-trigger");
    const panel = item.querySelector(".vb-accordion-ten-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-ten-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-ten-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-ten-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-ten]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-ten-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-ten-trigger");
    const panel = item.querySelector(".vb-accordion-ten-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-ten-trigger");
    const panel = item.querySelector(".vb-accordion-ten-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-ten-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-ten-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-ten-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-ten-demo"&gt;
  &lt;div class="vb-accordion-ten-layout" data-vb-accordion-ten&gt;
    &lt;div class="vb-accordion-ten-card"&gt;
      &lt;span&gt;Example 10&lt;/span&gt;
      &lt;h3&gt;Pro Plan&lt;/h3&gt;
      &lt;p&gt;For growing websites, product teams, and businesses that need more advanced UI sections.&lt;/p&gt;

      &lt;div class="vb-accordion-ten-price"&gt;
        &lt;strong&gt;€29&lt;/strong&gt;
        &lt;small&gt;/ month&lt;/small&gt;
      &lt;/div&gt;

      &lt;ul&gt;
        &lt;li&gt;Unlimited UI components&lt;/li&gt;
        &lt;li&gt;Responsive templates&lt;/li&gt;
        &lt;li&gt;Priority updates&lt;/li&gt;
      &lt;/ul&gt;

      &lt;a href="#javascript-accordion-examples"&gt;Start Building&lt;/a&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-ten-faq"&gt;
      &lt;div class="vb-accordion-ten-heading"&gt;
        &lt;h3&gt;Pricing FAQ Accordion&lt;/h3&gt;
        &lt;p&gt;Answer purchase questions beside a pricing card and keep the conversion section compact.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-ten-list"&gt;
        &lt;section class="vb-accordion-ten-item is-open"&gt;
          &lt;button class="vb-accordion-ten-trigger" type="button" aria-expanded="true"&gt;
            &lt;span&gt;Can I cancel anytime?&lt;/span&gt;
            &lt;strong&gt;+&lt;/strong&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-ten-panel"&gt;
            &lt;div class="vb-accordion-ten-content"&gt;
              &lt;p&gt;Yes. Users can cancel the subscription whenever they want. The plan remains active until the end of the current billing period.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;

        &lt;section class="vb-accordion-ten-item"&gt;
          &lt;button class="vb-accordion-ten-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;Do I get future updates?&lt;/span&gt;
            &lt;strong&gt;+&lt;/strong&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-ten-panel"&gt;
            &lt;div class="vb-accordion-ten-content"&gt;
              &lt;p&gt;Yes. Active users receive product updates, new examples, improvements, bug fixes, and upgraded UI components as they are released.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;

        &lt;section class="vb-accordion-ten-item"&gt;
          &lt;button class="vb-accordion-ten-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;Can I use this for client projects?&lt;/span&gt;
            &lt;strong&gt;+&lt;/strong&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-ten-panel"&gt;
            &lt;div class="vb-accordion-ten-content"&gt;
              &lt;p&gt;Yes. You can adapt the layouts and JavaScript patterns for client websites, landing pages, dashboards, and custom interface projects.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;

        &lt;section class="vb-accordion-ten-item"&gt;
          &lt;button class="vb-accordion-ten-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;Is the code beginner friendly?&lt;/span&gt;
            &lt;strong&gt;+&lt;/strong&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-ten-panel"&gt;
            &lt;div class="vb-accordion-ten-content"&gt;
              &lt;p&gt;The code uses vanilla JavaScript, structured HTML, and plain CSS, so it is easier to understand, edit, and reuse without extra frameworks.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-ten-demo,
.vb-accordion-ten-demo * {
  box-sizing: border-box;
}

.vb-accordion-ten-demo {
  margin: 28px 0;
  padding: 36px;
  border-radius: 46px 12px 46px 12px;
  background:
    radial-gradient(circle at 16% 20%, rgba(250, 204, 21, 0.22), transparent 32%),
    radial-gradient(circle at 84% 18%, rgba(249, 115, 22, 0.18), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fff7ed 50%, #ffffff 100%) !important;
  border: 1px solid rgba(253, 186, 116, 0.42);
  box-shadow: 0 24px 70px rgba(146, 64, 14, 0.12);
}

.vb-accordion-ten-layout {
  display: grid;
  grid-template-columns: minmax(280px, 0.82fr) minmax(0, 1.18fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
  align-items: stretch;
}

.vb-accordion-ten-card {
  position: relative;
  overflow: hidden;
  padding: 30px;
  border-radius: 38px 10px 38px 10px;
  background:
    radial-gradient(circle at 24% 18%, rgba(255,255,255,0.28), transparent 32%),
    linear-gradient(135deg, #78350f, #ea580c 60%, #facc15) !important;
  box-shadow: 0 30px 90px rgba(154, 52, 18, 0.24);
}

.vb-accordion-ten-card::after {
  content: "";
  position: absolute;
  right: -72px;
  top: -72px;
  width: 180px;
  height: 180px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
}

.vb-accordion-ten-card &gt; span {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  border: 1px solid rgba(255,255,255,0.20);
  color: #fff7ed !important;
  -webkit-text-fill-color: #fff7ed !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-ten-card h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(40px, 5vw, 68px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-ten-card p {
  margin: 0 0 24px !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-accordion-ten-price {
  display: flex;
  align-items: end;
  gap: 8px;
  margin-bottom: 22px;
}

.vb-accordion-ten-price strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 74px;
  line-height: 0.9;
  font-weight: 950;
  letter-spacing: -0.09em;
}

.vb-accordion-ten-price small {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 15px;
  font-weight: 850;
}

.vb-accordion-ten-card ul {
  display: grid;
  gap: 10px;
  margin: 0 0 24px !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb-accordion-ten-card li {
  margin: 0 !important;
  padding: 12px 14px;
  border-radius: 16px;
  background: rgba(255,255,255,0.13);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-accordion-ten-card a {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  width: 100%;
  min-height: 50px;
  border-radius: 999px;
  background: #ffffff;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 14px;
  font-weight: 950;
  text-decoration: none !important;
}

.vb-accordion-ten-faq {
  align-self: center;
}

.vb-accordion-ten-heading {
  margin-bottom: 22px;
}

.vb-accordion-ten-heading h3 {
  margin: 0 0 12px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-ten-heading p {
  max-width: 590px;
  margin: 0 !important;
  color: #57534e !important;
  -webkit-text-fill-color: #57534e !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-ten-list {
  display: grid;
  gap: 13px;
}

.vb-accordion-ten-item {
  overflow: hidden;
  border-radius: 18px 4px 18px 4px;
  background: #ffffff;
  border: 1px solid rgba(253, 186, 116, 0.36);
  box-shadow: 0 16px 42px rgba(154, 52, 18, 0.08);
}

.vb-accordion-ten-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 42px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 70px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-ten-trigger span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
  letter-spacing: -0.035em;
}

.vb-accordion-ten-trigger strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 12px 2px 12px 2px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 24px;
  line-height: 1;
  font-weight: 950;
  transition: transform 0.22s ease, background 0.22s ease, color 0.22s ease;
}

.vb-accordion-ten-item.is-open .vb-accordion-ten-trigger strong {
  transform: rotate(45deg);
  background: #ea580c;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-ten-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-ten-content {
  padding: 0 20px 20px;
}

.vb-accordion-ten-content p {
  margin: 0 !important;
  color: #57534e !important;
  -webkit-text-fill-color: #57534e !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-accordion-ten-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-accordion-ten-demo {
    padding: 18px;
    border-radius: 32px 10px 32px 10px;
  }

  .vb-accordion-ten-card {
    padding: 24px;
  }

  .vb-accordion-ten-heading h3 {
    font-size: 38px !important;
  }

  .vb-accordion-ten-price strong {
    font-size: 58px;
  }
}</pre>



<p class="wp-block-paragraph">This pricing FAQ accordion is useful for SaaS pricing pages, service packages, membership plans, hosting offers, digital product pages, course pricing sections, and conversion-focused landing pages.</p>



<h2 class="wp-block-heading">11. Documentation Sidebar Accordion</h2>



<p class="wp-block-paragraph"><strong>A documentation sidebar accordion</strong> is useful for help centers, developer docs, knowledge bases, plugin documentation, API guides, and tutorial libraries. It keeps many navigation topics compact while still letting users expand the section they need.</p>



<p class="wp-block-paragraph">This example uses a documentation-style layout with a sticky-looking left sidebar, active navigation groups, small status labels, and one-open-at-a-time JavaScript behavior. The design is intentionally more structured and technical than a standard FAQ accordion.</p>



<ul class="wp-block-list">
<li>Documentation-style accordion navigation</li>
<li>One-open-at-a-time behavior</li>
<li>Sidebar layout with content preview</li>
<li>Small labels and active section states</li>
<li>Useful for docs, help centers, and tutorials</li>
</ul>



<div class="vb-accordion-eleven-demo">
  <div class="vb-accordion-eleven-docs" data-vb-accordion-eleven>
    <aside class="vb-accordion-eleven-sidebar">
      <div class="vb-accordion-eleven-brand">
        <span>Example 11</span>
        <h3>Docs Menu</h3>
      </div>

      <nav class="vb-accordion-eleven-nav">
        <section class="vb-accordion-eleven-item is-open">
          <button class="vb-accordion-eleven-trigger" type="button" aria-expanded="true">
            <span>Getting started</span>
            <strong>⌄</strong>
          </button>
          <div class="vb-accordion-eleven-panel">
            <div class="vb-accordion-eleven-links">
              <a href="#javascript-accordion-examples">Installation</a>
              <a href="#javascript-accordion-examples">Basic structure</a>
              <a href="#javascript-accordion-examples">First accordion</a>
            </div>
          </div>
        </section>

        <section class="vb-accordion-eleven-item">
          <button class="vb-accordion-eleven-trigger" type="button" aria-expanded="false">
            <span>Components</span>
            <strong>⌄</strong>
          </button>
          <div class="vb-accordion-eleven-panel">
            <div class="vb-accordion-eleven-links">
              <a href="#javascript-accordion-examples">FAQ accordion</a>
              <a href="#javascript-accordion-examples">Product accordion</a>
              <a href="#javascript-accordion-examples">Nested accordion</a>
            </div>
          </div>
        </section>

        <section class="vb-accordion-eleven-item">
          <button class="vb-accordion-eleven-trigger" type="button" aria-expanded="false">
            <span>Customization</span>
            <strong>⌄</strong>
          </button>
          <div class="vb-accordion-eleven-panel">
            <div class="vb-accordion-eleven-links">
              <a href="#javascript-accordion-examples">Colors</a>
              <a href="#javascript-accordion-examples">Animation speed</a>
              <a href="#javascript-accordion-examples">Icons</a>
            </div>
          </div>
        </section>

        <section class="vb-accordion-eleven-item">
          <button class="vb-accordion-eleven-trigger" type="button" aria-expanded="false">
            <span>Advanced usage</span>
            <strong>⌄</strong>
          </button>
          <div class="vb-accordion-eleven-panel">
            <div class="vb-accordion-eleven-links">
              <a href="#javascript-accordion-examples">ARIA states</a>
              <a href="#javascript-accordion-examples">Multiple instances</a>
              <a href="#javascript-accordion-examples">Dynamic content</a>
            </div>
          </div>
        </section>
      </nav>
    </aside>

    <main class="vb-accordion-eleven-content">
      <span>Documentation UI</span>
      <h3>Documentation Sidebar Accordion</h3>
      <p>Use expandable navigation groups to organize documentation topics, tutorials, plugin settings, component guides, and support resources.</p>

      <div class="vb-accordion-eleven-preview">
        <div>
          <strong>Current section</strong>
          <small>Getting started</small>
        </div>
        <div>
          <strong>Navigation items</strong>
          <small>12 links</small>
        </div>
        <div>
          <strong>Behavior</strong>
          <small>Single open</small>
        </div>
      </div>
    </main>
  </div>
</div>

<style>
.vb-accordion-eleven-demo,
.vb-accordion-eleven-demo * {
  box-sizing: border-box;
}

.vb-accordion-eleven-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 24px;
  background:
    linear-gradient(135deg, #f8fafc 0%, #eef2ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.20);
  box-shadow: 0 24px 70px rgba(30, 41, 59, 0.10);
}

.vb-accordion-eleven-docs {
  display: grid;
  grid-template-columns: 310px minmax(0, 1fr);
  gap: 18px;
  max-width: 1120px;
  margin: 0 auto;
  padding: 14px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 22px 60px rgba(15, 23, 42, 0.08);
}

.vb-accordion-eleven-sidebar {
  padding: 18px;
  border-radius: 16px;
  background:
    linear-gradient(180deg, #0f172a 0%, #111827 100%) !important;
}

.vb-accordion-eleven-brand {
  padding: 10px 10px 18px;
  border-bottom: 1px solid rgba(255,255,255,0.12);
  margin-bottom: 14px;
}

.vb-accordion-eleven-brand span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 7px 10px;
  border-radius: 8px;
  background: rgba(99, 102, 241, 0.18);
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-eleven-brand h3 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-accordion-eleven-nav {
  display: grid;
  gap: 8px;
}

.vb-accordion-eleven-item {
  overflow: hidden;
  border-radius: 14px;
  background: rgba(255,255,255,0.055);
  border: 1px solid rgba(255,255,255,0.08);
}

.vb-accordion-eleven-item.is-open {
  background: rgba(99, 102, 241, 0.16);
  border-color: rgba(129, 140, 248, 0.28);
}

.vb-accordion-eleven-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 32px;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 52px;
  padding: 12px 12px 12px 14px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-eleven-trigger span {
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 14px;
  line-height: 1.25;
  font-weight: 850;
}

.vb-accordion-eleven-trigger strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 9px;
  background: rgba(255,255,255,0.08);
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 20px;
  font-weight: 950;
  transform: rotate(0deg);
  transition: transform 0.22s ease, background 0.22s ease;
}

.vb-accordion-eleven-item.is-open .vb-accordion-eleven-trigger strong {
  transform: rotate(180deg);
  background: rgba(129, 140, 248, 0.26);
}

.vb-accordion-eleven-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-eleven-links {
  display: grid;
  gap: 4px;
  padding: 0 12px 12px 28px;
}

.vb-accordion-eleven-links a {
  display: flex;
  align-items: center;
  min-height: 34px;
  padding: 7px 10px;
  border-radius: 9px;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 13px;
  line-height: 1.25;
  font-weight: 750;
  text-decoration: none !important;
}

.vb-accordion-eleven-links a:hover {
  background: rgba(255,255,255,0.08);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-eleven-content {
  padding: 34px;
  border-radius: 16px;
  background:
    radial-gradient(circle at 18% 18%, rgba(99, 102, 241, 0.14), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
}

.vb-accordion-eleven-content > span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 8px;
  background: #eef2ff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-eleven-content h3 {
  max-width: 680px;
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 66px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-eleven-content p {
  max-width: 660px;
  margin: 0 0 26px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-eleven-preview {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-accordion-eleven-preview div {
  padding: 18px;
  border-radius: 16px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-accordion-eleven-preview strong {
  display: block;
  margin-bottom: 7px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-accordion-eleven-preview small {
  display: block;
  color: #6366f1 !important;
  -webkit-text-fill-color: #6366f1 !important;
  font-size: 13px;
  font-weight: 850;
}

@media (max-width: 900px) {
  .vb-accordion-eleven-docs {
    grid-template-columns: 1fr;
  }

  .vb-accordion-eleven-preview {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-accordion-eleven-demo {
    padding: 18px;
  }

  .vb-accordion-eleven-docs {
    padding: 10px;
  }

  .vb-accordion-eleven-content {
    padding: 22px;
  }

  .vb-accordion-eleven-content h3 {
    font-size: 38px !important;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-eleven]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-eleven-item"));

  function closeItem(item) {
    const trigger = item.querySelector(".vb-accordion-eleven-trigger");
    const panel = item.querySelector(".vb-accordion-eleven-panel");

    item.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const trigger = item.querySelector(".vb-accordion-eleven-trigger");
    const panel = item.querySelector(".vb-accordion-eleven-panel");

    item.classList.add("is-open");
    trigger.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const trigger = item.querySelector(".vb-accordion-eleven-trigger");

    trigger.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-eleven-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-eleven-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-eleven]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-eleven-item"));

  function closeItem(item) {
    const trigger = item.querySelector(".vb-accordion-eleven-trigger");
    const panel = item.querySelector(".vb-accordion-eleven-panel");

    item.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const trigger = item.querySelector(".vb-accordion-eleven-trigger");
    const panel = item.querySelector(".vb-accordion-eleven-panel");

    item.classList.add("is-open");
    trigger.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const trigger = item.querySelector(".vb-accordion-eleven-trigger");

    trigger.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-eleven-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-eleven-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-eleven-demo"&gt;
  &lt;div class="vb-accordion-eleven-docs" data-vb-accordion-eleven&gt;
    &lt;aside class="vb-accordion-eleven-sidebar"&gt;
      &lt;div class="vb-accordion-eleven-brand"&gt;
        &lt;span&gt;Example 11&lt;/span&gt;
        &lt;h3&gt;Docs Menu&lt;/h3&gt;
      &lt;/div&gt;

      &lt;nav class="vb-accordion-eleven-nav"&gt;
        &lt;section class="vb-accordion-eleven-item is-open"&gt;
          &lt;button class="vb-accordion-eleven-trigger" type="button" aria-expanded="true"&gt;
            &lt;span&gt;Getting started&lt;/span&gt;
            &lt;strong&gt;⌄&lt;/strong&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-eleven-panel"&gt;
            &lt;div class="vb-accordion-eleven-links"&gt;
              &lt;a href="#javascript-accordion-examples"&gt;Installation&lt;/a&gt;
              &lt;a href="#javascript-accordion-examples"&gt;Basic structure&lt;/a&gt;
              &lt;a href="#javascript-accordion-examples"&gt;First accordion&lt;/a&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;

        &lt;section class="vb-accordion-eleven-item"&gt;
          &lt;button class="vb-accordion-eleven-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;Components&lt;/span&gt;
            &lt;strong&gt;⌄&lt;/strong&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-eleven-panel"&gt;
            &lt;div class="vb-accordion-eleven-links"&gt;
              &lt;a href="#javascript-accordion-examples"&gt;FAQ accordion&lt;/a&gt;
              &lt;a href="#javascript-accordion-examples"&gt;Product accordion&lt;/a&gt;
              &lt;a href="#javascript-accordion-examples"&gt;Nested accordion&lt;/a&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;

        &lt;section class="vb-accordion-eleven-item"&gt;
          &lt;button class="vb-accordion-eleven-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;Customization&lt;/span&gt;
            &lt;strong&gt;⌄&lt;/strong&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-eleven-panel"&gt;
            &lt;div class="vb-accordion-eleven-links"&gt;
              &lt;a href="#javascript-accordion-examples"&gt;Colors&lt;/a&gt;
              &lt;a href="#javascript-accordion-examples"&gt;Animation speed&lt;/a&gt;
              &lt;a href="#javascript-accordion-examples"&gt;Icons&lt;/a&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;

        &lt;section class="vb-accordion-eleven-item"&gt;
          &lt;button class="vb-accordion-eleven-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;Advanced usage&lt;/span&gt;
            &lt;strong&gt;⌄&lt;/strong&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-eleven-panel"&gt;
            &lt;div class="vb-accordion-eleven-links"&gt;
              &lt;a href="#javascript-accordion-examples"&gt;ARIA states&lt;/a&gt;
              &lt;a href="#javascript-accordion-examples"&gt;Multiple instances&lt;/a&gt;
              &lt;a href="#javascript-accordion-examples"&gt;Dynamic content&lt;/a&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;
      &lt;/nav&gt;
    &lt;/aside&gt;

    &lt;main class="vb-accordion-eleven-content"&gt;
      &lt;span&gt;Documentation UI&lt;/span&gt;
      &lt;h3&gt;Documentation Sidebar Accordion&lt;/h3&gt;
      &lt;p&gt;Use expandable navigation groups to organize documentation topics, tutorials, plugin settings, component guides, and support resources.&lt;/p&gt;

      &lt;div class="vb-accordion-eleven-preview"&gt;
        &lt;div&gt;
          &lt;strong&gt;Current section&lt;/strong&gt;
          &lt;small&gt;Getting started&lt;/small&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;strong&gt;Navigation items&lt;/strong&gt;
          &lt;small&gt;12 links&lt;/small&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;strong&gt;Behavior&lt;/strong&gt;
          &lt;small&gt;Single open&lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/main&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-eleven-demo,
.vb-accordion-eleven-demo * {
  box-sizing: border-box;
}

.vb-accordion-eleven-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 24px;
  background:
    linear-gradient(135deg, #f8fafc 0%, #eef2ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.20);
  box-shadow: 0 24px 70px rgba(30, 41, 59, 0.10);
}

.vb-accordion-eleven-docs {
  display: grid;
  grid-template-columns: 310px minmax(0, 1fr);
  gap: 18px;
  max-width: 1120px;
  margin: 0 auto;
  padding: 14px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 22px 60px rgba(15, 23, 42, 0.08);
}

.vb-accordion-eleven-sidebar {
  padding: 18px;
  border-radius: 16px;
  background:
    linear-gradient(180deg, #0f172a 0%, #111827 100%) !important;
}

.vb-accordion-eleven-brand {
  padding: 10px 10px 18px;
  border-bottom: 1px solid rgba(255,255,255,0.12);
  margin-bottom: 14px;
}

.vb-accordion-eleven-brand span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 7px 10px;
  border-radius: 8px;
  background: rgba(99, 102, 241, 0.18);
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-eleven-brand h3 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-accordion-eleven-nav {
  display: grid;
  gap: 8px;
}

.vb-accordion-eleven-item {
  overflow: hidden;
  border-radius: 14px;
  background: rgba(255,255,255,0.055);
  border: 1px solid rgba(255,255,255,0.08);
}

.vb-accordion-eleven-item.is-open {
  background: rgba(99, 102, 241, 0.16);
  border-color: rgba(129, 140, 248, 0.28);
}

.vb-accordion-eleven-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 32px;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 52px;
  padding: 12px 12px 12px 14px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-eleven-trigger span {
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 14px;
  line-height: 1.25;
  font-weight: 850;
}

.vb-accordion-eleven-trigger strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: 9px;
  background: rgba(255,255,255,0.08);
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 20px;
  font-weight: 950;
  transform: rotate(0deg);
  transition: transform 0.22s ease, background 0.22s ease;
}

.vb-accordion-eleven-item.is-open .vb-accordion-eleven-trigger strong {
  transform: rotate(180deg);
  background: rgba(129, 140, 248, 0.26);
}

.vb-accordion-eleven-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-eleven-links {
  display: grid;
  gap: 4px;
  padding: 0 12px 12px 28px;
}

.vb-accordion-eleven-links a {
  display: flex;
  align-items: center;
  min-height: 34px;
  padding: 7px 10px;
  border-radius: 9px;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 13px;
  line-height: 1.25;
  font-weight: 750;
  text-decoration: none !important;
}

.vb-accordion-eleven-links a:hover {
  background: rgba(255,255,255,0.08);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-eleven-content {
  padding: 34px;
  border-radius: 16px;
  background:
    radial-gradient(circle at 18% 18%, rgba(99, 102, 241, 0.14), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
}

.vb-accordion-eleven-content &gt; span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 8px;
  background: #eef2ff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-eleven-content h3 {
  max-width: 680px;
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 66px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-eleven-content p {
  max-width: 660px;
  margin: 0 0 26px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-eleven-preview {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-accordion-eleven-preview div {
  padding: 18px;
  border-radius: 16px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.06);
}

.vb-accordion-eleven-preview strong {
  display: block;
  margin-bottom: 7px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-accordion-eleven-preview small {
  display: block;
  color: #6366f1 !important;
  -webkit-text-fill-color: #6366f1 !important;
  font-size: 13px;
  font-weight: 850;
}

@media (max-width: 900px) {
  .vb-accordion-eleven-docs {
    grid-template-columns: 1fr;
  }

  .vb-accordion-eleven-preview {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-accordion-eleven-demo {
    padding: 18px;
  }

  .vb-accordion-eleven-docs {
    padding: 10px;
  }

  .vb-accordion-eleven-content {
    padding: 22px;
  }

  .vb-accordion-eleven-content h3 {
    font-size: 38px !important;
  }
}</pre>



<p class="wp-block-paragraph">This documentation sidebar accordion is useful for help centers, plugin docs, SaaS support areas, developer documentation, onboarding guides, tutorial libraries, and knowledge base navigation.</p>



<h2 class="wp-block-heading">12. Neon Card Stack Accordion</h2>



<p class="wp-block-paragraph"><strong>A neon card stack accordion</strong> creates a bold visual style for modern landing pages, creative portfolios, AI tools, gaming websites, tech products, and promotional sections. It uses overlapping cards, neon borders, and animated active states.</p>



<p class="wp-block-paragraph">This example uses a stacked card layout with offset panels, glowing category badges, and multi-open JavaScript behavior. Each accordion row feels like a separate interactive card instead of a standard list item.</p>



<ul class="wp-block-list">
<li>Neon stacked card accordion</li>
<li>Multi-open JavaScript behavior</li>
<li>Overlapping card depth effect</li>
<li>Glowing badges and active states</li>
<li>Useful for tech, AI, gaming, and creative websites</li>
</ul>



<div class="vb-accordion-twelve-demo">
  <div class="vb-accordion-twelve-shell" data-vb-accordion-twelve>
    <div class="vb-accordion-twelve-header">
      <span>Example 12</span>
      <h3>Neon Card Stack Accordion</h3>
      <p>Open glowing stacked cards to reveal feature details inside a high-impact visual section.</p>
    </div>

    <div class="vb-accordion-twelve-stack">
      <article class="vb-accordion-twelve-item is-open">
        <button class="vb-accordion-twelve-trigger" type="button" aria-expanded="true">
          <span>AI</span>
          <strong>Smart automation</strong>
          <em></em>
        </button>
        <div class="vb-accordion-twelve-panel">
          <div class="vb-accordion-twelve-content">
            <p>Use this card to explain automation features, assistant workflows, content generation, smart recommendations, or AI-powered product logic.</p>
          </div>
        </div>
      </article>

      <article class="vb-accordion-twelve-item">
        <button class="vb-accordion-twelve-trigger" type="button" aria-expanded="false">
          <span>UX</span>
          <strong>Interactive interface</strong>
          <em></em>
        </button>
        <div class="vb-accordion-twelve-panel">
          <div class="vb-accordion-twelve-content">
            <p>Highlight interactive UI behavior, smooth transitions, better content organization, and cleaner user journeys for visitors.</p>
          </div>
        </div>
      </article>

      <article class="vb-accordion-twelve-item">
        <button class="vb-accordion-twelve-trigger" type="button" aria-expanded="false">
          <span>API</span>
          <strong>Connected systems</strong>
          <em></em>
        </button>
        <div class="vb-accordion-twelve-panel">
          <div class="vb-accordion-twelve-content">
            <p>Show how connected data, integrations, APIs, dashboards, and external services can be explained in expandable content cards.</p>
          </div>
        </div>
      </article>

      <article class="vb-accordion-twelve-item">
        <button class="vb-accordion-twelve-trigger" type="button" aria-expanded="false">
          <span>SEO</span>
          <strong>Content visibility</strong>
          <em></em>
        </button>
        <div class="vb-accordion-twelve-panel">
          <div class="vb-accordion-twelve-content">
            <p>Use accordion content carefully for FAQs, entity explanations, structured content, product questions, and readable long-form sections.</p>
          </div>
        </div>
      </article>
    </div>
  </div>
</div>

<style>
.vb-accordion-twelve-demo,
.vb-accordion-twelve-demo * {
  box-sizing: border-box;
}

.vb-accordion-twelve-demo {
  margin: 28px 0;
  padding: 44px;
  border-radius: 52px;
  background:
    radial-gradient(circle at 18% 18%, rgba(236, 72, 153, 0.24), transparent 34%),
    radial-gradient(circle at 84% 22%, rgba(34, 211, 238, 0.22), transparent 34%),
    linear-gradient(135deg, #020617 0%, #111827 46%, #2e1065 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 30px 90px rgba(2, 6, 23, 0.42);
  overflow: hidden;
}

.vb-accordion-twelve-shell {
  max-width: 1040px;
  margin: 0 auto;
}

.vb-accordion-twelve-header {
  max-width: 760px;
  margin-bottom: 28px;
}

.vb-accordion-twelve-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(236, 72, 153, 0.16);
  border: 1px solid rgba(244, 114, 182, 0.28);
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-twelve-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 5vw, 72px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
}

.vb-accordion-twelve-header p {
  max-width: 650px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twelve-stack {
  display: grid;
  gap: 16px;
  perspective: 1000px;
}

.vb-accordion-twelve-item {
  position: relative;
  overflow: hidden;
  border-radius: 30px;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.12), rgba(255,255,255,0.06)) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 22px 54px rgba(0,0,0,0.22);
  transform: translateX(0);
  transition: transform 0.22s ease, border-color 0.22s ease, box-shadow 0.22s ease;
}

.vb-accordion-twelve-item:nth-child(2) {
  margin-left: 24px;
}

.vb-accordion-twelve-item:nth-child(3) {
  margin-left: 48px;
}

.vb-accordion-twelve-item:nth-child(4) {
  margin-left: 72px;
}

.vb-accordion-twelve-item::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background:
    linear-gradient(90deg, rgba(236, 72, 153, 0.45), rgba(34, 211, 238, 0.38), rgba(168, 85, 247, 0.40)) !important;
  opacity: 0;
  transition: opacity 0.22s ease;
}

.vb-accordion-twelve-item.is-open {
  transform: translateX(-10px);
  border-color: rgba(34, 211, 238, 0.46);
  box-shadow: 0 28px 76px rgba(34, 211, 238, 0.12);
}

.vb-accordion-twelve-item.is-open::before {
  opacity: 0.16;
}

.vb-accordion-twelve-trigger {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr) 44px;
  align-items: center;
  gap: 18px;
  width: 100%;
  min-height: 82px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-twelve-trigger span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 46px;
  border-radius: 18px;
  background: rgba(236, 72, 153, 0.18);
  border: 1px solid rgba(244, 114, 182, 0.28);
  color: #f9a8d4 !important;
  -webkit-text-fill-color: #f9a8d4 !important;
  font-size: 14px;
  font-weight: 950;
  letter-spacing: 0.08em;
}

.vb-accordion-twelve-trigger strong {
  color: #f8fafc !important;
  -webkit-text-fill-color: #f8fafc !important;
  font-size: 21px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.045em;
}

.vb-accordion-twelve-trigger em {
  position: relative;
  width: 44px;
  height: 44px;
  border-radius: 16px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-accordion-twelve-trigger em::before,
.vb-accordion-twelve-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 16px;
  height: 2px;
  border-radius: 999px;
  background: #ffffff;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease, transform 0.22s ease;
}

.vb-accordion-twelve-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-twelve-item.is-open .vb-accordion-twelve-trigger em {
  background: linear-gradient(135deg, #ec4899, #22d3ee) !important;
}

.vb-accordion-twelve-item.is-open .vb-accordion-twelve-trigger em::after {
  opacity: 0;
  transform: translate(-50%, -50%) rotate(0deg);
}

.vb-accordion-twelve-panel {
  position: relative;
  z-index: 2;
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-twelve-content {
  padding: 0 24px 24px 102px;
}

.vb-accordion-twelve-content p {
  max-width: 720px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 760px) {
  .vb-accordion-twelve-demo {
    padding: 22px;
    border-radius: 34px;
  }

  .vb-accordion-twelve-header h3 {
    font-size: 40px !important;
  }

  .vb-accordion-twelve-item,
  .vb-accordion-twelve-item:nth-child(2),
  .vb-accordion-twelve-item:nth-child(3),
  .vb-accordion-twelve-item:nth-child(4) {
    margin-left: 0;
  }

  .vb-accordion-twelve-item.is-open {
    transform: none;
  }

  .vb-accordion-twelve-trigger {
    grid-template-columns: 54px minmax(0, 1fr) 38px;
    gap: 12px;
  }

  .vb-accordion-twelve-trigger span {
    width: 54px;
    height: 42px;
  }

  .vb-accordion-twelve-trigger strong {
    font-size: 17px;
  }

  .vb-accordion-twelve-trigger em {
    width: 38px;
    height: 38px;
  }

  .vb-accordion-twelve-content {
    padding: 0 18px 20px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-twelve]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-twelve-item"));

  function updateItem(item) {
    const button = item.querySelector(".vb-accordion-twelve-trigger");
    const panel = item.querySelector(".vb-accordion-twelve-panel");
    const isOpen = item.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-twelve-trigger");

    button.addEventListener("click", function () {
      item.classList.toggle("is-open");
      updateItem(item);
    });

    updateItem(item);
  });

  window.addEventListener("resize", function () {
    items.forEach(updateItem);
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-twelve]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-twelve-item"));

  function updateItem(item) {
    const button = item.querySelector(".vb-accordion-twelve-trigger");
    const panel = item.querySelector(".vb-accordion-twelve-panel");
    const isOpen = item.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-twelve-trigger");

    button.addEventListener("click", function () {
      item.classList.toggle("is-open");
      updateItem(item);
    });

    updateItem(item);
  });

  window.addEventListener("resize", function () {
    items.forEach(updateItem);
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-twelve-demo"&gt;
  &lt;div class="vb-accordion-twelve-shell" data-vb-accordion-twelve&gt;
    &lt;div class="vb-accordion-twelve-header"&gt;
      &lt;span&gt;Example 12&lt;/span&gt;
      &lt;h3&gt;Neon Card Stack Accordion&lt;/h3&gt;
      &lt;p&gt;Open glowing stacked cards to reveal feature details inside a high-impact visual section.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-twelve-stack"&gt;
      &lt;article class="vb-accordion-twelve-item is-open"&gt;
        &lt;button class="vb-accordion-twelve-trigger" type="button" aria-expanded="true"&gt;
          &lt;span&gt;AI&lt;/span&gt;
          &lt;strong&gt;Smart automation&lt;/strong&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-twelve-panel"&gt;
          &lt;div class="vb-accordion-twelve-content"&gt;
            &lt;p&gt;Use this card to explain automation features, assistant workflows, content generation, smart recommendations, or AI-powered product logic.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-twelve-item"&gt;
        &lt;button class="vb-accordion-twelve-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;UX&lt;/span&gt;
          &lt;strong&gt;Interactive interface&lt;/strong&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-twelve-panel"&gt;
          &lt;div class="vb-accordion-twelve-content"&gt;
            &lt;p&gt;Highlight interactive UI behavior, smooth transitions, better content organization, and cleaner user journeys for visitors.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-twelve-item"&gt;
        &lt;button class="vb-accordion-twelve-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;API&lt;/span&gt;
          &lt;strong&gt;Connected systems&lt;/strong&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-twelve-panel"&gt;
          &lt;div class="vb-accordion-twelve-content"&gt;
            &lt;p&gt;Show how connected data, integrations, APIs, dashboards, and external services can be explained in expandable content cards.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-twelve-item"&gt;
        &lt;button class="vb-accordion-twelve-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;SEO&lt;/span&gt;
          &lt;strong&gt;Content visibility&lt;/strong&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-twelve-panel"&gt;
          &lt;div class="vb-accordion-twelve-content"&gt;
            &lt;p&gt;Use accordion content carefully for FAQs, entity explanations, structured content, product questions, and readable long-form sections.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-twelve-demo,
.vb-accordion-twelve-demo * {
  box-sizing: border-box;
}

.vb-accordion-twelve-demo {
  margin: 28px 0;
  padding: 44px;
  border-radius: 52px;
  background:
    radial-gradient(circle at 18% 18%, rgba(236, 72, 153, 0.24), transparent 34%),
    radial-gradient(circle at 84% 22%, rgba(34, 211, 238, 0.22), transparent 34%),
    linear-gradient(135deg, #020617 0%, #111827 46%, #2e1065 100%) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 30px 90px rgba(2, 6, 23, 0.42);
  overflow: hidden;
}

.vb-accordion-twelve-shell {
  max-width: 1040px;
  margin: 0 auto;
}

.vb-accordion-twelve-header {
  max-width: 760px;
  margin-bottom: 28px;
}

.vb-accordion-twelve-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(236, 72, 153, 0.16);
  border: 1px solid rgba(244, 114, 182, 0.28);
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-twelve-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 5vw, 72px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
}

.vb-accordion-twelve-header p {
  max-width: 650px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twelve-stack {
  display: grid;
  gap: 16px;
  perspective: 1000px;
}

.vb-accordion-twelve-item {
  position: relative;
  overflow: hidden;
  border-radius: 30px;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.12), rgba(255,255,255,0.06)) !important;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 22px 54px rgba(0,0,0,0.22);
  transform: translateX(0);
  transition: transform 0.22s ease, border-color 0.22s ease, box-shadow 0.22s ease;
}

.vb-accordion-twelve-item:nth-child(2) {
  margin-left: 24px;
}

.vb-accordion-twelve-item:nth-child(3) {
  margin-left: 48px;
}

.vb-accordion-twelve-item:nth-child(4) {
  margin-left: 72px;
}

.vb-accordion-twelve-item::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background:
    linear-gradient(90deg, rgba(236, 72, 153, 0.45), rgba(34, 211, 238, 0.38), rgba(168, 85, 247, 0.40)) !important;
  opacity: 0;
  transition: opacity 0.22s ease;
}

.vb-accordion-twelve-item.is-open {
  transform: translateX(-10px);
  border-color: rgba(34, 211, 238, 0.46);
  box-shadow: 0 28px 76px rgba(34, 211, 238, 0.12);
}

.vb-accordion-twelve-item.is-open::before {
  opacity: 0.16;
}

.vb-accordion-twelve-trigger {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr) 44px;
  align-items: center;
  gap: 18px;
  width: 100%;
  min-height: 82px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-twelve-trigger span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 64px;
  height: 46px;
  border-radius: 18px;
  background: rgba(236, 72, 153, 0.18);
  border: 1px solid rgba(244, 114, 182, 0.28);
  color: #f9a8d4 !important;
  -webkit-text-fill-color: #f9a8d4 !important;
  font-size: 14px;
  font-weight: 950;
  letter-spacing: 0.08em;
}

.vb-accordion-twelve-trigger strong {
  color: #f8fafc !important;
  -webkit-text-fill-color: #f8fafc !important;
  font-size: 21px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.045em;
}

.vb-accordion-twelve-trigger em {
  position: relative;
  width: 44px;
  height: 44px;
  border-radius: 16px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-accordion-twelve-trigger em::before,
.vb-accordion-twelve-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 16px;
  height: 2px;
  border-radius: 999px;
  background: #ffffff;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease, transform 0.22s ease;
}

.vb-accordion-twelve-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-twelve-item.is-open .vb-accordion-twelve-trigger em {
  background: linear-gradient(135deg, #ec4899, #22d3ee) !important;
}

.vb-accordion-twelve-item.is-open .vb-accordion-twelve-trigger em::after {
  opacity: 0;
  transform: translate(-50%, -50%) rotate(0deg);
}

.vb-accordion-twelve-panel {
  position: relative;
  z-index: 2;
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-twelve-content {
  padding: 0 24px 24px 102px;
}

.vb-accordion-twelve-content p {
  max-width: 720px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 760px) {
  .vb-accordion-twelve-demo {
    padding: 22px;
    border-radius: 34px;
  }

  .vb-accordion-twelve-header h3 {
    font-size: 40px !important;
  }

  .vb-accordion-twelve-item,
  .vb-accordion-twelve-item:nth-child(2),
  .vb-accordion-twelve-item:nth-child(3),
  .vb-accordion-twelve-item:nth-child(4) {
    margin-left: 0;
  }

  .vb-accordion-twelve-item.is-open {
    transform: none;
  }

  .vb-accordion-twelve-trigger {
    grid-template-columns: 54px minmax(0, 1fr) 38px;
    gap: 12px;
  }

  .vb-accordion-twelve-trigger span {
    width: 54px;
    height: 42px;
  }

  .vb-accordion-twelve-trigger strong {
    font-size: 17px;
  }

  .vb-accordion-twelve-trigger em {
    width: 38px;
    height: 38px;
  }

  .vb-accordion-twelve-content {
    padding: 0 18px 20px;
  }
}</pre>



<p class="wp-block-paragraph">This neon card stack accordion is useful for AI product pages, technology websites, gaming landing pages, creative portfolios, startup websites, and bold feature sections where the accordion should feel more visual and energetic.</p>



<h2 class="wp-block-heading">13. Support Center Accordion</h2>



<p class="wp-block-paragraph"><strong>A support center accordion</strong> is useful for customer help pages, SaaS support sections, ecommerce help centers, plugin support pages, and service websites where users need quick answers grouped by topic.</p>



<p class="wp-block-paragraph">This example uses a help-desk inspired layout with a support ticket card, category badges, soft rounded panels, and one-open-at-a-time JavaScript behavior. The design is calmer and more service-oriented than the previous neon and dashboard examples.</p>



<ul class="wp-block-list">
<li>Support center accordion layout</li>
<li>One-open-at-a-time behavior</li>
<li>Help ticket visual card</li>
<li>Category badges and soft panels</li>
<li>Useful for FAQ, support, and help center pages</li>
</ul>



<div class="vb-accordion-thirteen-demo">
  <div class="vb-accordion-thirteen-help" data-vb-accordion-thirteen>
    <div class="vb-accordion-thirteen-card">
      <span>Example 13</span>
      <h3>Need Help?</h3>
      <p>Find quick answers before opening a support ticket.</p>

      <div class="vb-accordion-thirteen-ticket">
        <strong>#SUP-2048</strong>
        <small>Average reply time: 2 hours</small>
      </div>

      <div class="vb-accordion-thirteen-agents">
        <i></i>
        <i></i>
        <i></i>
        <em>3 agents online</em>
      </div>
    </div>

    <div class="vb-accordion-thirteen-main">
      <div class="vb-accordion-thirteen-heading">
        <h3>Support Center Accordion</h3>
        <p>Organize help questions into expandable support topics with clear category labels.</p>
      </div>

      <div class="vb-accordion-thirteen-list">
        <section class="vb-accordion-thirteen-item is-open">
          <button class="vb-accordion-thirteen-trigger" type="button" aria-expanded="true">
            <span>
              <small>Account</small>
              <strong>How do I reset my password?</strong>
            </span>
            <em></em>
          </button>
          <div class="vb-accordion-thirteen-panel">
            <div class="vb-accordion-thirteen-content">
              <p>Go to the login page, choose the password reset option, enter your account email, and follow the secure link sent to your inbox.</p>
            </div>
          </div>
        </section>

        <section class="vb-accordion-thirteen-item">
          <button class="vb-accordion-thirteen-trigger" type="button" aria-expanded="false">
            <span>
              <small>Billing</small>
              <strong>Where can I download invoices?</strong>
            </span>
            <em></em>
          </button>
          <div class="vb-accordion-thirteen-panel">
            <div class="vb-accordion-thirteen-content">
              <p>Invoices are usually available inside the billing section of the account dashboard. You can download PDF invoices for each completed payment.</p>
            </div>
          </div>
        </section>

        <section class="vb-accordion-thirteen-item">
          <button class="vb-accordion-thirteen-trigger" type="button" aria-expanded="false">
            <span>
              <small>Technical</small>
              <strong>Why is my component not opening?</strong>
            </span>
            <em></em>
          </button>
          <div class="vb-accordion-thirteen-panel">
            <div class="vb-accordion-thirteen-content">
              <p>Check that the JavaScript selector matches the HTML attribute, the script is loaded after the HTML, and no duplicate class names conflict with another accordion.</p>
            </div>
          </div>
        </section>

        <section class="vb-accordion-thirteen-item">
          <button class="vb-accordion-thirteen-trigger" type="button" aria-expanded="false">
            <span>
              <small>Updates</small>
              <strong>How do I get product updates?</strong>
            </span>
            <em></em>
          </button>
          <div class="vb-accordion-thirteen-panel">
            <div class="vb-accordion-thirteen-content">
              <p>Active customers can receive updates through the account dashboard, download area, email notifications, or the product update page.</p>
            </div>
          </div>
        </section>
      </div>
    </div>
  </div>
</div>

<style>
.vb-accordion-thirteen-demo,
.vb-accordion-thirteen-demo * {
  box-sizing: border-box;
}

.vb-accordion-thirteen-demo {
  margin: 28px 0;
  padding: 36px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 14% 18%, rgba(14, 165, 233, 0.18), transparent 32%),
    radial-gradient(circle at 88% 18%, rgba(16, 185, 129, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #ecfdf5 52%, #ffffff 100%) !important;
  border: 1px solid rgba(125, 211, 252, 0.36);
  box-shadow: 0 24px 70px rgba(8, 47, 73, 0.10);
}

.vb-accordion-thirteen-help {
  display: grid;
  grid-template-columns: minmax(270px, 0.75fr) minmax(0, 1.25fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-accordion-thirteen-card {
  align-self: start;
  padding: 28px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 20% 18%, rgba(255,255,255,0.28), transparent 34%),
    linear-gradient(135deg, #0369a1, #0f766e) !important;
  box-shadow: 0 28px 80px rgba(8, 145, 178, 0.22);
}

.vb-accordion-thirteen-card > span {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  border: 1px solid rgba(255,255,255,0.20);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-thirteen-card h3 {
  margin: 0 0 12px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(40px, 5vw, 68px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-thirteen-card p {
  margin: 0 0 24px !important;
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-accordion-thirteen-ticket {
  padding: 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.18);
  margin-bottom: 20px;
}

.vb-accordion-thirteen-ticket strong {
  display: block;
  margin-bottom: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-thirteen-ticket small {
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-accordion-thirteen-agents {
  display: flex;
  align-items: center;
}

.vb-accordion-thirteen-agents i {
  display: inline-flex;
  width: 42px;
  height: 42px;
  margin-right: -10px;
  border-radius: 999px;
  border: 3px solid rgba(255,255,255,0.82);
  background: linear-gradient(135deg, #bae6fd, #99f6e4) !important;
}

.vb-accordion-thirteen-agents i:nth-child(2) {
  background: linear-gradient(135deg, #fde68a, #fbcfe8) !important;
}

.vb-accordion-thirteen-agents i:nth-child(3) {
  background: linear-gradient(135deg, #c4b5fd, #a7f3d0) !important;
}

.vb-accordion-thirteen-agents em {
  margin-left: 20px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-style: normal;
  font-weight: 900;
}

.vb-accordion-thirteen-main {
  align-self: center;
}

.vb-accordion-thirteen-heading {
  margin-bottom: 22px;
}

.vb-accordion-thirteen-heading h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-thirteen-heading p {
  max-width: 620px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-thirteen-list {
  display: grid;
  gap: 12px;
}

.vb-accordion-thirteen-item {
  overflow: hidden;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 44px rgba(15, 23, 42, 0.07);
}

.vb-accordion-thirteen-item.is-open {
  border-color: rgba(14, 165, 233, 0.34);
  box-shadow: 0 22px 60px rgba(14, 165, 233, 0.12);
}

.vb-accordion-thirteen-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 42px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 78px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  text-align: left;
  cursor: pointer;
}

.vb-accordion-thirteen-trigger small {
  display: inline-flex;
  margin-bottom: 7px;
  padding: 5px 9px;
  border-radius: 999px;
  background: #ecfeff;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 11px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-accordion-thirteen-trigger strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 19px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-thirteen-trigger em {
  position: relative;
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: #f0f9ff;
  border: 1px solid rgba(14, 165, 233, 0.18);
}

.vb-accordion-thirteen-trigger em::before,
.vb-accordion-thirteen-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 15px;
  height: 2px;
  border-radius: 999px;
  background: #0284c7;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease, transform 0.22s ease;
}

.vb-accordion-thirteen-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-thirteen-item.is-open .vb-accordion-thirteen-trigger em {
  background: linear-gradient(135deg, #0ea5e9, #10b981) !important;
}

.vb-accordion-thirteen-item.is-open .vb-accordion-thirteen-trigger em::before,
.vb-accordion-thirteen-item.is-open .vb-accordion-thirteen-trigger em::after {
  background: #ffffff;
}

.vb-accordion-thirteen-item.is-open .vb-accordion-thirteen-trigger em::after {
  opacity: 0;
  transform: translate(-50%, -50%) rotate(0deg);
}

.vb-accordion-thirteen-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-thirteen-content {
  padding: 0 20px 20px;
}

.vb-accordion-thirteen-content p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-accordion-thirteen-help {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-accordion-thirteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-accordion-thirteen-card {
    padding: 22px;
  }

  .vb-accordion-thirteen-heading h3 {
    font-size: 38px !important;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-thirteen]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-thirteen-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-thirteen-trigger");
    const panel = item.querySelector(".vb-accordion-thirteen-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-thirteen-trigger");
    const panel = item.querySelector(".vb-accordion-thirteen-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-thirteen-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-thirteen-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-thirteen-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-thirteen]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-thirteen-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-thirteen-trigger");
    const panel = item.querySelector(".vb-accordion-thirteen-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-thirteen-trigger");
    const panel = item.querySelector(".vb-accordion-thirteen-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-thirteen-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-thirteen-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-thirteen-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-thirteen-demo"&gt;
  &lt;div class="vb-accordion-thirteen-help" data-vb-accordion-thirteen&gt;
    &lt;div class="vb-accordion-thirteen-card"&gt;
      &lt;span&gt;Example 13&lt;/span&gt;
      &lt;h3&gt;Need Help?&lt;/h3&gt;
      &lt;p&gt;Find quick answers before opening a support ticket.&lt;/p&gt;

      &lt;div class="vb-accordion-thirteen-ticket"&gt;
        &lt;strong&gt;#SUP-2048&lt;/strong&gt;
        &lt;small&gt;Average reply time: 2 hours&lt;/small&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-thirteen-agents"&gt;
        &lt;i&gt;&lt;/i&gt;
        &lt;i&gt;&lt;/i&gt;
        &lt;i&gt;&lt;/i&gt;
        &lt;em&gt;3 agents online&lt;/em&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-thirteen-main"&gt;
      &lt;div class="vb-accordion-thirteen-heading"&gt;
        &lt;h3&gt;Support Center Accordion&lt;/h3&gt;
        &lt;p&gt;Organize help questions into expandable support topics with clear category labels.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-thirteen-list"&gt;
        &lt;section class="vb-accordion-thirteen-item is-open"&gt;
          &lt;button class="vb-accordion-thirteen-trigger" type="button" aria-expanded="true"&gt;
            &lt;span&gt;
              &lt;small&gt;Account&lt;/small&gt;
              &lt;strong&gt;How do I reset my password?&lt;/strong&gt;
            &lt;/span&gt;
            &lt;em&gt;&lt;/em&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-thirteen-panel"&gt;
            &lt;div class="vb-accordion-thirteen-content"&gt;
              &lt;p&gt;Go to the login page, choose the password reset option, enter your account email, and follow the secure link sent to your inbox.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;

        &lt;section class="vb-accordion-thirteen-item"&gt;
          &lt;button class="vb-accordion-thirteen-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;
              &lt;small&gt;Billing&lt;/small&gt;
              &lt;strong&gt;Where can I download invoices?&lt;/strong&gt;
            &lt;/span&gt;
            &lt;em&gt;&lt;/em&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-thirteen-panel"&gt;
            &lt;div class="vb-accordion-thirteen-content"&gt;
              &lt;p&gt;Invoices are usually available inside the billing section of the account dashboard. You can download PDF invoices for each completed payment.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;

        &lt;section class="vb-accordion-thirteen-item"&gt;
          &lt;button class="vb-accordion-thirteen-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;
              &lt;small&gt;Technical&lt;/small&gt;
              &lt;strong&gt;Why is my component not opening?&lt;/strong&gt;
            &lt;/span&gt;
            &lt;em&gt;&lt;/em&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-thirteen-panel"&gt;
            &lt;div class="vb-accordion-thirteen-content"&gt;
              &lt;p&gt;Check that the JavaScript selector matches the HTML attribute, the script is loaded after the HTML, and no duplicate class names conflict with another accordion.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;

        &lt;section class="vb-accordion-thirteen-item"&gt;
          &lt;button class="vb-accordion-thirteen-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;
              &lt;small&gt;Updates&lt;/small&gt;
              &lt;strong&gt;How do I get product updates?&lt;/strong&gt;
            &lt;/span&gt;
            &lt;em&gt;&lt;/em&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-thirteen-panel"&gt;
            &lt;div class="vb-accordion-thirteen-content"&gt;
              &lt;p&gt;Active customers can receive updates through the account dashboard, download area, email notifications, or the product update page.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-thirteen-demo,
.vb-accordion-thirteen-demo * {
  box-sizing: border-box;
}

.vb-accordion-thirteen-demo {
  margin: 28px 0;
  padding: 36px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 14% 18%, rgba(14, 165, 233, 0.18), transparent 32%),
    radial-gradient(circle at 88% 18%, rgba(16, 185, 129, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #ecfdf5 52%, #ffffff 100%) !important;
  border: 1px solid rgba(125, 211, 252, 0.36);
  box-shadow: 0 24px 70px rgba(8, 47, 73, 0.10);
}

.vb-accordion-thirteen-help {
  display: grid;
  grid-template-columns: minmax(270px, 0.75fr) minmax(0, 1.25fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-accordion-thirteen-card {
  align-self: start;
  padding: 28px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 20% 18%, rgba(255,255,255,0.28), transparent 34%),
    linear-gradient(135deg, #0369a1, #0f766e) !important;
  box-shadow: 0 28px 80px rgba(8, 145, 178, 0.22);
}

.vb-accordion-thirteen-card &gt; span {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  border: 1px solid rgba(255,255,255,0.20);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-thirteen-card h3 {
  margin: 0 0 12px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(40px, 5vw, 68px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-thirteen-card p {
  margin: 0 0 24px !important;
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-accordion-thirteen-ticket {
  padding: 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.18);
  margin-bottom: 20px;
}

.vb-accordion-thirteen-ticket strong {
  display: block;
  margin-bottom: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-thirteen-ticket small {
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-accordion-thirteen-agents {
  display: flex;
  align-items: center;
}

.vb-accordion-thirteen-agents i {
  display: inline-flex;
  width: 42px;
  height: 42px;
  margin-right: -10px;
  border-radius: 999px;
  border: 3px solid rgba(255,255,255,0.82);
  background: linear-gradient(135deg, #bae6fd, #99f6e4) !important;
}

.vb-accordion-thirteen-agents i:nth-child(2) {
  background: linear-gradient(135deg, #fde68a, #fbcfe8) !important;
}

.vb-accordion-thirteen-agents i:nth-child(3) {
  background: linear-gradient(135deg, #c4b5fd, #a7f3d0) !important;
}

.vb-accordion-thirteen-agents em {
  margin-left: 20px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-style: normal;
  font-weight: 900;
}

.vb-accordion-thirteen-main {
  align-self: center;
}

.vb-accordion-thirteen-heading {
  margin-bottom: 22px;
}

.vb-accordion-thirteen-heading h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-thirteen-heading p {
  max-width: 620px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-thirteen-list {
  display: grid;
  gap: 12px;
}

.vb-accordion-thirteen-item {
  overflow: hidden;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 44px rgba(15, 23, 42, 0.07);
}

.vb-accordion-thirteen-item.is-open {
  border-color: rgba(14, 165, 233, 0.34);
  box-shadow: 0 22px 60px rgba(14, 165, 233, 0.12);
}

.vb-accordion-thirteen-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 42px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 78px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  text-align: left;
  cursor: pointer;
}

.vb-accordion-thirteen-trigger small {
  display: inline-flex;
  margin-bottom: 7px;
  padding: 5px 9px;
  border-radius: 999px;
  background: #ecfeff;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 11px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-accordion-thirteen-trigger strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 19px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-thirteen-trigger em {
  position: relative;
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: #f0f9ff;
  border: 1px solid rgba(14, 165, 233, 0.18);
}

.vb-accordion-thirteen-trigger em::before,
.vb-accordion-thirteen-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 15px;
  height: 2px;
  border-radius: 999px;
  background: #0284c7;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease, transform 0.22s ease;
}

.vb-accordion-thirteen-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-thirteen-item.is-open .vb-accordion-thirteen-trigger em {
  background: linear-gradient(135deg, #0ea5e9, #10b981) !important;
}

.vb-accordion-thirteen-item.is-open .vb-accordion-thirteen-trigger em::before,
.vb-accordion-thirteen-item.is-open .vb-accordion-thirteen-trigger em::after {
  background: #ffffff;
}

.vb-accordion-thirteen-item.is-open .vb-accordion-thirteen-trigger em::after {
  opacity: 0;
  transform: translate(-50%, -50%) rotate(0deg);
}

.vb-accordion-thirteen-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-thirteen-content {
  padding: 0 20px 20px;
}

.vb-accordion-thirteen-content p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-accordion-thirteen-help {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-accordion-thirteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-accordion-thirteen-card {
    padding: 22px;
  }

  .vb-accordion-thirteen-heading h3 {
    font-size: 38px !important;
  }
}</pre>



<p class="wp-block-paragraph">This support center accordion is useful for help desks, SaaS support pages, ecommerce support sections, customer service FAQs, plugin support pages, and onboarding help sections.</p>



<h2 class="wp-block-heading">14. Horizontal Feature Accordion</h2>



<p class="wp-block-paragraph"><strong>A horizontal feature accordion</strong> is useful for landing pages, SaaS feature sections, app showcases, product explainers, and homepage sections where several feature cards need to share one visual row.</p>



<p class="wp-block-paragraph">This example uses a horizontal card row on desktop and turns into stacked cards on mobile. The active card expands visually, while the JavaScript switches the selected feature and updates ARIA states without using external libraries.</p>



<ul class="wp-block-list">
<li>Horizontal feature accordion layout</li>
<li>Active card expands on desktop</li>
<li>One-active-card behavior</li>
<li>Responsive stacked mobile layout</li>
<li>Useful for features, services, and product highlights</li>
</ul>



<div class="vb-accordion-fourteen-demo">
  <div class="vb-accordion-fourteen-shell" data-vb-accordion-fourteen>
    <div class="vb-accordion-fourteen-header">
      <span>Example 14</span>
      <h3>Horizontal Feature Accordion</h3>
      <p>Click a feature card to expand it and highlight the selected value proposition.</p>
    </div>

    <div class="vb-accordion-fourteen-row">
      <article class="vb-accordion-fourteen-card is-open">
        <button class="vb-accordion-fourteen-trigger" type="button" aria-expanded="true">
          <span>01</span>
          <strong>Fast setup</strong>
        </button>
        <div class="vb-accordion-fourteen-panel">
          <p>Launch a clean accordion interface quickly with scoped JavaScript, simple HTML, and responsive CSS.</p>
          <a href="#javascript-accordion-examples">View example</a>
        </div>
      </article>

      <article class="vb-accordion-fourteen-card">
        <button class="vb-accordion-fourteen-trigger" type="button" aria-expanded="false">
          <span>02</span>
          <strong>Reusable code</strong>
        </button>
        <div class="vb-accordion-fourteen-panel">
          <p>Use unique class names and scoped selectors so multiple accordions can exist on the same page.</p>
          <a href="#javascript-accordion-examples">View example</a>
        </div>
      </article>

      <article class="vb-accordion-fourteen-card">
        <button class="vb-accordion-fourteen-trigger" type="button" aria-expanded="false">
          <span>03</span>
          <strong>Responsive UI</strong>
        </button>
        <div class="vb-accordion-fourteen-panel">
          <p>The horizontal desktop layout changes into a readable stacked layout on smaller screens.</p>
          <a href="#javascript-accordion-examples">View example</a>
        </div>
      </article>

      <article class="vb-accordion-fourteen-card">
        <button class="vb-accordion-fourteen-trigger" type="button" aria-expanded="false">
          <span>04</span>
          <strong>Clear states</strong>
        </button>
        <div class="vb-accordion-fourteen-panel">
          <p>Active styling, expanded content, and ARIA attributes help users understand which feature is selected.</p>
          <a href="#javascript-accordion-examples">View example</a>
        </div>
      </article>
    </div>
  </div>
</div>

<style>
.vb-accordion-fourteen-demo,
.vb-accordion-fourteen-demo * {
  box-sizing: border-box;
}

.vb-accordion-fourteen-demo {
  margin: 28px 0;
  padding: 36px;
  border-radius: 14px 54px 54px 14px;
  background:
    radial-gradient(circle at 16% 18%, rgba(59, 130, 246, 0.18), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(16, 185, 129, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 52%, #ffffff 100%) !important;
  border: 1px solid rgba(96, 165, 250, 0.30);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.10);
}

.vb-accordion-fourteen-shell {
  max-width: 1140px;
  margin: 0 auto;
}

.vb-accordion-fourteen-header {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(260px, 0.68fr);
  gap: 26px;
  align-items: end;
  margin-bottom: 28px;
}

.vb-accordion-fourteen-header span {
  grid-column: 1 / -1;
  justify-self: start;
  display: inline-flex;
  padding: 8px 12px;
  border-radius: 999px;
  background: #1d4ed8;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-fourteen-header h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
}

.vb-accordion-fourteen-header p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-fourteen-row {
  display: flex;
  gap: 14px;
  min-height: 430px;
}

.vb-accordion-fourteen-card {
  position: relative;
  flex: 0.72;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  min-width: 0;
  padding: 20px;
  border-radius: 32px;
  background:
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.08);
  transition: flex 0.32s ease, background 0.24s ease, transform 0.24s ease, border-color 0.24s ease;
}

.vb-accordion-fourteen-card::after {
  content: "";
  position: absolute;
  right: -60px;
  bottom: -60px;
  width: 180px;
  height: 180px;
  border-radius: 999px;
  background: rgba(37, 99, 235, 0.08);
  transition: background 0.24s ease;
}

.vb-accordion-fourteen-card.is-open {
  flex: 1.85;
  transform: translateY(-8px);
  background:
    radial-gradient(circle at 20% 20%, rgba(255,255,255,0.24), transparent 34%),
    linear-gradient(135deg, #1d4ed8, #0891b2 58%, #059669) !important;
  border-color: rgba(37, 99, 235, 0.38);
  box-shadow: 0 28px 80px rgba(37, 99, 235, 0.18);
}

.vb-accordion-fourteen-card.is-open::after {
  background: rgba(255,255,255,0.14);
}

.vb-accordion-fourteen-trigger {
  position: relative;
  z-index: 2;
  display: grid;
  gap: 18px;
  width: 100%;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-fourteen-trigger span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 54px;
  height: 54px;
  border-radius: 18px;
  background: #eff6ff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-accordion-fourteen-card.is-open .vb-accordion-fourteen-trigger span {
  background: rgba(255,255,255,0.16);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  border: 1px solid rgba(255,255,255,0.20);
}

.vb-accordion-fourteen-trigger strong {
  display: block;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 26px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
  transition: writing-mode 0.1s ease, transform 0.1s ease, color 0.2s ease;
}

.vb-accordion-fourteen-card.is-open .vb-accordion-fourteen-trigger strong {
  writing-mode: horizontal-tb;
  transform: rotate(0deg);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 4vw, 56px);
  line-height: 0.95;
}

.vb-accordion-fourteen-panel {
  position: relative;
  z-index: 2;
  display: none;
  max-width: 500px;
}

.vb-accordion-fourteen-card.is-open .vb-accordion-fourteen-panel {
  display: block;
}

.vb-accordion-fourteen-panel p {
  margin: 0 0 18px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-fourteen-panel a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 11px 16px;
  border-radius: 999px;
  background: #ffffff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
}

@media (max-width: 900px) {
  .vb-accordion-fourteen-header {
    grid-template-columns: 1fr;
  }

  .vb-accordion-fourteen-row {
    flex-direction: column;
    min-height: auto;
  }

  .vb-accordion-fourteen-card,
  .vb-accordion-fourteen-card.is-open {
    flex: none;
    transform: none;
  }

  .vb-accordion-fourteen-trigger strong,
  .vb-accordion-fourteen-card.is-open .vb-accordion-fourteen-trigger strong {
    writing-mode: horizontal-tb;
    transform: none;
    font-size: 28px;
  }

  .vb-accordion-fourteen-panel,
  .vb-accordion-fourteen-card.is-open .vb-accordion-fourteen-panel {
    display: block;
    max-height: 0;
    overflow: hidden;
  }

  .vb-accordion-fourteen-card.is-open .vb-accordion-fourteen-panel {
    max-height: 220px;
  }
}

@media (max-width: 640px) {
  .vb-accordion-fourteen-demo {
    padding: 18px;
    border-radius: 14px 34px 34px 14px;
  }

  .vb-accordion-fourteen-header h3 {
    font-size: 38px !important;
  }

  .vb-accordion-fourteen-card {
    padding: 18px;
    border-radius: 24px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-fourteen]");
  if (!accordion) return;

  const cards = Array.from(accordion.querySelectorAll(".vb-accordion-fourteen-card"));

  function activateCard(selectedCard) {
    cards.forEach(function (card) {
      const button = card.querySelector(".vb-accordion-fourteen-trigger");
      const isSelected = card === selectedCard;

      card.classList.toggle("is-open", isSelected);
      button.setAttribute("aria-expanded", isSelected ? "true" : "false");
    });
  }

  cards.forEach(function (card) {
    const button = card.querySelector(".vb-accordion-fourteen-trigger");

    button.addEventListener("click", function () {
      activateCard(card);
    });
  });

  const defaultCard = accordion.querySelector(".vb-accordion-fourteen-card.is-open") || cards[0];
  if (defaultCard) {
    activateCard(defaultCard);
  }
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-fourteen]");
  if (!accordion) return;

  const cards = Array.from(accordion.querySelectorAll(".vb-accordion-fourteen-card"));

  function activateCard(selectedCard) {
    cards.forEach(function (card) {
      const button = card.querySelector(".vb-accordion-fourteen-trigger");
      const isSelected = card === selectedCard;

      card.classList.toggle("is-open", isSelected);
      button.setAttribute("aria-expanded", isSelected ? "true" : "false");
    });
  }

  cards.forEach(function (card) {
    const button = card.querySelector(".vb-accordion-fourteen-trigger");

    button.addEventListener("click", function () {
      activateCard(card);
    });
  });

  const defaultCard = accordion.querySelector(".vb-accordion-fourteen-card.is-open") || cards[0];
  if (defaultCard) {
    activateCard(defaultCard);
  }
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-fourteen-demo"&gt;
  &lt;div class="vb-accordion-fourteen-shell" data-vb-accordion-fourteen&gt;
    &lt;div class="vb-accordion-fourteen-header"&gt;
      &lt;span&gt;Example 14&lt;/span&gt;
      &lt;h3&gt;Horizontal Feature Accordion&lt;/h3&gt;
      &lt;p&gt;Click a feature card to expand it and highlight the selected value proposition.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-fourteen-row"&gt;
      &lt;article class="vb-accordion-fourteen-card is-open"&gt;
        &lt;button class="vb-accordion-fourteen-trigger" type="button" aria-expanded="true"&gt;
          &lt;span&gt;01&lt;/span&gt;
          &lt;strong&gt;Fast setup&lt;/strong&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-fourteen-panel"&gt;
          &lt;p&gt;Launch a clean accordion interface quickly with scoped JavaScript, simple HTML, and responsive CSS.&lt;/p&gt;
          &lt;a href="#javascript-accordion-examples"&gt;View example&lt;/a&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-fourteen-card"&gt;
        &lt;button class="vb-accordion-fourteen-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;02&lt;/span&gt;
          &lt;strong&gt;Reusable code&lt;/strong&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-fourteen-panel"&gt;
          &lt;p&gt;Use unique class names and scoped selectors so multiple accordions can exist on the same page.&lt;/p&gt;
          &lt;a href="#javascript-accordion-examples"&gt;View example&lt;/a&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-fourteen-card"&gt;
        &lt;button class="vb-accordion-fourteen-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;03&lt;/span&gt;
          &lt;strong&gt;Responsive UI&lt;/strong&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-fourteen-panel"&gt;
          &lt;p&gt;The horizontal desktop layout changes into a readable stacked layout on smaller screens.&lt;/p&gt;
          &lt;a href="#javascript-accordion-examples"&gt;View example&lt;/a&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-fourteen-card"&gt;
        &lt;button class="vb-accordion-fourteen-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;04&lt;/span&gt;
          &lt;strong&gt;Clear states&lt;/strong&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-fourteen-panel"&gt;
          &lt;p&gt;Active styling, expanded content, and ARIA attributes help users understand which feature is selected.&lt;/p&gt;
          &lt;a href="#javascript-accordion-examples"&gt;View example&lt;/a&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-fourteen-demo,
.vb-accordion-fourteen-demo * {
  box-sizing: border-box;
}

.vb-accordion-fourteen-demo {
  margin: 28px 0;
  padding: 36px;
  border-radius: 14px 54px 54px 14px;
  background:
    radial-gradient(circle at 16% 18%, rgba(59, 130, 246, 0.18), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(16, 185, 129, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 52%, #ffffff 100%) !important;
  border: 1px solid rgba(96, 165, 250, 0.30);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.10);
}

.vb-accordion-fourteen-shell {
  max-width: 1140px;
  margin: 0 auto;
}

.vb-accordion-fourteen-header {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(260px, 0.68fr);
  gap: 26px;
  align-items: end;
  margin-bottom: 28px;
}

.vb-accordion-fourteen-header span {
  grid-column: 1 / -1;
  justify-self: start;
  display: inline-flex;
  padding: 8px 12px;
  border-radius: 999px;
  background: #1d4ed8;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-fourteen-header h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
}

.vb-accordion-fourteen-header p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-fourteen-row {
  display: flex;
  gap: 14px;
  min-height: 430px;
}

.vb-accordion-fourteen-card {
  position: relative;
  flex: 0.72;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  min-width: 0;
  padding: 20px;
  border-radius: 32px;
  background:
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.08);
  transition: flex 0.32s ease, background 0.24s ease, transform 0.24s ease, border-color 0.24s ease;
}

.vb-accordion-fourteen-card::after {
  content: "";
  position: absolute;
  right: -60px;
  bottom: -60px;
  width: 180px;
  height: 180px;
  border-radius: 999px;
  background: rgba(37, 99, 235, 0.08);
  transition: background 0.24s ease;
}

.vb-accordion-fourteen-card.is-open {
  flex: 1.85;
  transform: translateY(-8px);
  background:
    radial-gradient(circle at 20% 20%, rgba(255,255,255,0.24), transparent 34%),
    linear-gradient(135deg, #1d4ed8, #0891b2 58%, #059669) !important;
  border-color: rgba(37, 99, 235, 0.38);
  box-shadow: 0 28px 80px rgba(37, 99, 235, 0.18);
}

.vb-accordion-fourteen-card.is-open::after {
  background: rgba(255,255,255,0.14);
}

.vb-accordion-fourteen-trigger {
  position: relative;
  z-index: 2;
  display: grid;
  gap: 18px;
  width: 100%;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-fourteen-trigger span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 54px;
  height: 54px;
  border-radius: 18px;
  background: #eff6ff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-accordion-fourteen-card.is-open .vb-accordion-fourteen-trigger span {
  background: rgba(255,255,255,0.16);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  border: 1px solid rgba(255,255,255,0.20);
}

.vb-accordion-fourteen-trigger strong {
  display: block;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 26px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
  transition: writing-mode 0.1s ease, transform 0.1s ease, color 0.2s ease;
}

.vb-accordion-fourteen-card.is-open .vb-accordion-fourteen-trigger strong {
  writing-mode: horizontal-tb;
  transform: rotate(0deg);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 4vw, 56px);
  line-height: 0.95;
}

.vb-accordion-fourteen-panel {
  position: relative;
  z-index: 2;
  display: none;
  max-width: 500px;
}

.vb-accordion-fourteen-card.is-open .vb-accordion-fourteen-panel {
  display: block;
}

.vb-accordion-fourteen-panel p {
  margin: 0 0 18px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-fourteen-panel a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 11px 16px;
  border-radius: 999px;
  background: #ffffff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
}

@media (max-width: 900px) {
  .vb-accordion-fourteen-header {
    grid-template-columns: 1fr;
  }

  .vb-accordion-fourteen-row {
    flex-direction: column;
    min-height: auto;
  }

  .vb-accordion-fourteen-card,
  .vb-accordion-fourteen-card.is-open {
    flex: none;
    transform: none;
  }

  .vb-accordion-fourteen-trigger strong,
  .vb-accordion-fourteen-card.is-open .vb-accordion-fourteen-trigger strong {
    writing-mode: horizontal-tb;
    transform: none;
    font-size: 28px;
  }

  .vb-accordion-fourteen-panel,
  .vb-accordion-fourteen-card.is-open .vb-accordion-fourteen-panel {
    display: block;
    max-height: 0;
    overflow: hidden;
  }

  .vb-accordion-fourteen-card.is-open .vb-accordion-fourteen-panel {
    max-height: 220px;
  }
}

@media (max-width: 640px) {
  .vb-accordion-fourteen-demo {
    padding: 18px;
    border-radius: 14px 34px 34px 14px;
  }

  .vb-accordion-fourteen-header h3 {
    font-size: 38px !important;
  }

  .vb-accordion-fourteen-card {
    padding: 18px;
    border-radius: 24px;
  }
}</pre>



<p class="wp-block-paragraph">This horizontal feature accordion is useful for SaaS feature sections, homepage highlights, product explainers, startup landing pages, service previews, app features, and interactive marketing sections.</p>



<h2 class="wp-block-heading">15. Nested Accordion Menu</h2>



<p class="wp-block-paragraph"><strong>A nested accordion menu</strong> is useful when content has more than one level, such as documentation categories, dashboard navigation, mobile menus, product filters, learning modules, and help center topics.</p>



<p class="wp-block-paragraph">This example uses a two-level accordion structure with parent sections and child panels. The design uses a compact navigation layout, nested indentation, soft shadows, and separate JavaScript logic for parent and child accordion items.</p>



<ul class="wp-block-list">
<li>Two-level nested accordion structure</li>
<li>Parent and child toggle behavior</li>
<li>Compact navigation-style design</li>
<li>Indented child panels</li>
<li>Useful for docs, menus, filters, and learning platforms</li>
</ul>



<div class="vb-accordion-fifteen-demo">
  <div class="vb-accordion-fifteen-shell" data-vb-accordion-fifteen>
    <div class="vb-accordion-fifteen-header">
      <span>Example 15</span>
      <h3>Nested Accordion Menu</h3>
      <p>Open parent categories and reveal nested child accordions inside each section.</p>
    </div>

    <div class="vb-accordion-fifteen-menu">
      <section class="vb-accordion-fifteen-parent is-open">
        <button class="vb-accordion-fifteen-parent-trigger" type="button" aria-expanded="true">
          <span>01</span>
          <strong>Website Components</strong>
          <em></em>
        </button>

        <div class="vb-accordion-fifteen-parent-panel">
          <div class="vb-accordion-fifteen-child-list">
            <div class="vb-accordion-fifteen-child is-open">
              <button class="vb-accordion-fifteen-child-trigger" type="button" aria-expanded="true">
                <span>Hero sections</span>
                <strong>+</strong>
              </button>
              <div class="vb-accordion-fifteen-child-panel">
                <p>Hero sections introduce the page with a strong title, supporting text, visuals, and calls to action.</p>
              </div>
            </div>

            <div class="vb-accordion-fifteen-child">
              <button class="vb-accordion-fifteen-child-trigger" type="button" aria-expanded="false">
                <span>Pricing tables</span>
                <strong>+</strong>
              </button>
              <div class="vb-accordion-fifteen-child-panel">
                <p>Pricing tables compare plans, features, monthly cost, yearly discounts, and purchase options.</p>
              </div>
            </div>
          </div>
        </div>
      </section>

      <section class="vb-accordion-fifteen-parent">
        <button class="vb-accordion-fifteen-parent-trigger" type="button" aria-expanded="false">
          <span>02</span>
          <strong>JavaScript UI</strong>
          <em></em>
        </button>

        <div class="vb-accordion-fifteen-parent-panel">
          <div class="vb-accordion-fifteen-child-list">
            <div class="vb-accordion-fifteen-child">
              <button class="vb-accordion-fifteen-child-trigger" type="button" aria-expanded="false">
                <span>Modals</span>
                <strong>+</strong>
              </button>
              <div class="vb-accordion-fifteen-child-panel">
                <p>Modals display focused overlays for login forms, alerts, product previews, and confirmation dialogs.</p>
              </div>
            </div>

            <div class="vb-accordion-fifteen-child">
              <button class="vb-accordion-fifteen-child-trigger" type="button" aria-expanded="false">
                <span>Search filters</span>
                <strong>+</strong>
              </button>
              <div class="vb-accordion-fifteen-child-panel">
                <p>Search filters help users narrow cards, tables, products, directories, and content lists instantly.</p>
              </div>
            </div>
          </div>
        </div>
      </section>

      <section class="vb-accordion-fifteen-parent">
        <button class="vb-accordion-fifteen-parent-trigger" type="button" aria-expanded="false">
          <span>03</span>
          <strong>Content Sections</strong>
          <em></em>
        </button>

        <div class="vb-accordion-fifteen-parent-panel">
          <div class="vb-accordion-fifteen-child-list">
            <div class="vb-accordion-fifteen-child">
              <button class="vb-accordion-fifteen-child-trigger" type="button" aria-expanded="false">
                <span>FAQ blocks</span>
                <strong>+</strong>
              </button>
              <div class="vb-accordion-fifteen-child-panel">
                <p>FAQ blocks answer common visitor questions and can support SEO when structured clearly.</p>
              </div>
            </div>

            <div class="vb-accordion-fifteen-child">
              <button class="vb-accordion-fifteen-child-trigger" type="button" aria-expanded="false">
                <span>Testimonials</span>
                <strong>+</strong>
              </button>
              <div class="vb-accordion-fifteen-child-panel">
                <p>Testimonials add trust by showing customer reviews, quotes, ratings, and social proof.</p>
              </div>
            </div>
          </div>
        </div>
      </section>
    </div>
  </div>
</div>

<style>
.vb-accordion-fifteen-demo,
.vb-accordion-fifteen-demo * {
  box-sizing: border-box;
}

.vb-accordion-fifteen-demo {
  margin: 28px 0;
  padding: 36px;
  border-radius: 12px 12px 48px 48px;
  background:
    linear-gradient(135deg, #f8fafc 0%, #f5f3ff 48%, #ffffff 100%) !important;
  border: 1px solid rgba(139, 92, 246, 0.22);
  box-shadow: 0 24px 70px rgba(88, 28, 135, 0.10);
}

.vb-accordion-fifteen-shell {
  max-width: 1040px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(280px, 0.78fr) minmax(0, 1.22fr);
  gap: 28px;
  align-items: start;
}

.vb-accordion-fifteen-header {
  position: sticky;
  top: 24px;
  padding: 26px;
  border-radius: 34px 34px 8px 34px;
  background:
    radial-gradient(circle at 20% 18%, rgba(255,255,255,0.24), transparent 34%),
    linear-gradient(135deg, #4c1d95, #7c3aed 58%, #06b6d4) !important;
  box-shadow: 0 28px 80px rgba(109, 40, 217, 0.22);
}

.vb-accordion-fifteen-header span {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.15);
  border: 1px solid rgba(255,255,255,0.20);
  color: #ede9fe !important;
  -webkit-text-fill-color: #ede9fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-fifteen-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 60px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-fifteen-header p {
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-accordion-fifteen-menu {
  display: grid;
  gap: 14px;
}

.vb-accordion-fifteen-parent {
  overflow: hidden;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.08);
}

.vb-accordion-fifteen-parent.is-open {
  border-color: rgba(124, 58, 237, 0.34);
  box-shadow: 0 24px 64px rgba(124, 58, 237, 0.12);
}

.vb-accordion-fifteen-parent-trigger {
  display: grid;
  grid-template-columns: 54px minmax(0, 1fr) 42px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 82px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-fifteen-parent-trigger > span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 54px;
  height: 54px;
  border-radius: 18px 18px 4px 18px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-accordion-fifteen-parent-trigger strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-fifteen-parent-trigger em {
  position: relative;
  width: 42px;
  height: 42px;
  border-radius: 16px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-accordion-fifteen-parent-trigger em::before,
.vb-accordion-fifteen-parent-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 15px;
  height: 2px;
  border-radius: 999px;
  background: #6d28d9;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease, transform 0.22s ease;
}

.vb-accordion-fifteen-parent-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-fifteen-parent.is-open .vb-accordion-fifteen-parent-trigger em {
  background: #6d28d9;
}

.vb-accordion-fifteen-parent.is-open .vb-accordion-fifteen-parent-trigger em::before,
.vb-accordion-fifteen-parent.is-open .vb-accordion-fifteen-parent-trigger em::after {
  background: #ffffff;
}

.vb-accordion-fifteen-parent.is-open .vb-accordion-fifteen-parent-trigger em::after {
  opacity: 0;
}

.vb-accordion-fifteen-parent-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s ease;
}

.vb-accordion-fifteen-child-list {
  display: grid;
  gap: 10px;
  padding: 0 20px 20px 90px;
}

.vb-accordion-fifteen-child {
  overflow: hidden;
  border-radius: 18px 18px 18px 4px;
  background: #f8fafc;
  border: 1px solid rgba(226, 232, 240, 0.9);
}

.vb-accordion-fifteen-child-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 34px;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 52px;
  padding: 13px 14px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-fifteen-child-trigger span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  line-height: 1.25;
  font-weight: 900;
}

.vb-accordion-fifteen-child-trigger strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 12px;
  background: #ffffff;
  color: #7c3aed !important;
  -webkit-text-fill-color: #7c3aed !important;
  font-size: 20px;
  font-weight: 950;
  transition: transform 0.22s ease, background 0.22s ease, color 0.22s ease;
}

.vb-accordion-fifteen-child.is-open .vb-accordion-fifteen-child-trigger strong {
  transform: rotate(45deg);
  background: #7c3aed;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-fifteen-child-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-fifteen-child-panel p {
  margin: 0 !important;
  padding: 0 14px 14px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.65;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-accordion-fifteen-shell {
    grid-template-columns: 1fr;
  }

  .vb-accordion-fifteen-header {
    position: static;
  }
}

@media (max-width: 640px) {
  .vb-accordion-fifteen-demo {
    padding: 18px;
    border-radius: 10px 10px 34px 34px;
  }

  .vb-accordion-fifteen-header {
    padding: 22px;
  }

  .vb-accordion-fifteen-header h3 {
    font-size: 38px !important;
  }

  .vb-accordion-fifteen-parent-trigger {
    grid-template-columns: 46px minmax(0, 1fr) 38px;
    gap: 12px;
    padding: 16px;
  }

  .vb-accordion-fifteen-parent-trigger > span {
    width: 46px;
    height: 46px;
  }

  .vb-accordion-fifteen-child-list {
    padding: 0 16px 16px 62px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-fifteen]");
  if (!accordion) return;

  const parents = Array.from(accordion.querySelectorAll(".vb-accordion-fifteen-parent"));
  const children = Array.from(accordion.querySelectorAll(".vb-accordion-fifteen-child"));

  function updateChild(child) {
    const button = child.querySelector(".vb-accordion-fifteen-child-trigger");
    const panel = child.querySelector(".vb-accordion-fifteen-child-panel");
    const isOpen = child.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  function updateParent(parent) {
    const button = parent.querySelector(".vb-accordion-fifteen-parent-trigger");
    const panel = parent.querySelector(".vb-accordion-fifteen-parent-panel");
    const isOpen = parent.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");

    if (isOpen) {
      panel.style.maxHeight = panel.scrollHeight + "px";
    } else {
      panel.style.maxHeight = "0px";
    }
  }

  children.forEach(function (child) {
    const button = child.querySelector(".vb-accordion-fifteen-child-trigger");

    button.addEventListener("click", function () {
      const parent = child.closest(".vb-accordion-fifteen-parent");

      child.classList.toggle("is-open");
      updateChild(child);
      updateParent(parent);
    });

    updateChild(child);
  });

  parents.forEach(function (parent) {
    const button = parent.querySelector(".vb-accordion-fifteen-parent-trigger");

    button.addEventListener("click", function () {
      parent.classList.toggle("is-open");
      updateParent(parent);
    });

    updateParent(parent);
  });

  window.addEventListener("resize", function () {
    children.forEach(updateChild);
    parents.forEach(updateParent);
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-fifteen]");
  if (!accordion) return;

  const parents = Array.from(accordion.querySelectorAll(".vb-accordion-fifteen-parent"));
  const children = Array.from(accordion.querySelectorAll(".vb-accordion-fifteen-child"));

  function updateChild(child) {
    const button = child.querySelector(".vb-accordion-fifteen-child-trigger");
    const panel = child.querySelector(".vb-accordion-fifteen-child-panel");
    const isOpen = child.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  function updateParent(parent) {
    const button = parent.querySelector(".vb-accordion-fifteen-parent-trigger");
    const panel = parent.querySelector(".vb-accordion-fifteen-parent-panel");
    const isOpen = parent.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");

    if (isOpen) {
      panel.style.maxHeight = panel.scrollHeight + "px";
    } else {
      panel.style.maxHeight = "0px";
    }
  }

  children.forEach(function (child) {
    const button = child.querySelector(".vb-accordion-fifteen-child-trigger");

    button.addEventListener("click", function () {
      const parent = child.closest(".vb-accordion-fifteen-parent");

      child.classList.toggle("is-open");
      updateChild(child);
      updateParent(parent);
    });

    updateChild(child);
  });

  parents.forEach(function (parent) {
    const button = parent.querySelector(".vb-accordion-fifteen-parent-trigger");

    button.addEventListener("click", function () {
      parent.classList.toggle("is-open");
      updateParent(parent);
    });

    updateParent(parent);
  });

  window.addEventListener("resize", function () {
    children.forEach(updateChild);
    parents.forEach(updateParent);
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-fifteen-demo"&gt;
  &lt;div class="vb-accordion-fifteen-shell" data-vb-accordion-fifteen&gt;
    &lt;div class="vb-accordion-fifteen-header"&gt;
      &lt;span&gt;Example 15&lt;/span&gt;
      &lt;h3&gt;Nested Accordion Menu&lt;/h3&gt;
      &lt;p&gt;Open parent categories and reveal nested child accordions inside each section.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-fifteen-menu"&gt;
      &lt;section class="vb-accordion-fifteen-parent is-open"&gt;
        &lt;button class="vb-accordion-fifteen-parent-trigger" type="button" aria-expanded="true"&gt;
          &lt;span&gt;01&lt;/span&gt;
          &lt;strong&gt;Website Components&lt;/strong&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-fifteen-parent-panel"&gt;
          &lt;div class="vb-accordion-fifteen-child-list"&gt;
            &lt;div class="vb-accordion-fifteen-child is-open"&gt;
              &lt;button class="vb-accordion-fifteen-child-trigger" type="button" aria-expanded="true"&gt;
                &lt;span&gt;Hero sections&lt;/span&gt;
                &lt;strong&gt;+&lt;/strong&gt;
              &lt;/button&gt;
              &lt;div class="vb-accordion-fifteen-child-panel"&gt;
                &lt;p&gt;Hero sections introduce the page with a strong title, supporting text, visuals, and calls to action.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;div class="vb-accordion-fifteen-child"&gt;
              &lt;button class="vb-accordion-fifteen-child-trigger" type="button" aria-expanded="false"&gt;
                &lt;span&gt;Pricing tables&lt;/span&gt;
                &lt;strong&gt;+&lt;/strong&gt;
              &lt;/button&gt;
              &lt;div class="vb-accordion-fifteen-child-panel"&gt;
                &lt;p&gt;Pricing tables compare plans, features, monthly cost, yearly discounts, and purchase options.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-fifteen-parent"&gt;
        &lt;button class="vb-accordion-fifteen-parent-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;02&lt;/span&gt;
          &lt;strong&gt;JavaScript UI&lt;/strong&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-fifteen-parent-panel"&gt;
          &lt;div class="vb-accordion-fifteen-child-list"&gt;
            &lt;div class="vb-accordion-fifteen-child"&gt;
              &lt;button class="vb-accordion-fifteen-child-trigger" type="button" aria-expanded="false"&gt;
                &lt;span&gt;Modals&lt;/span&gt;
                &lt;strong&gt;+&lt;/strong&gt;
              &lt;/button&gt;
              &lt;div class="vb-accordion-fifteen-child-panel"&gt;
                &lt;p&gt;Modals display focused overlays for login forms, alerts, product previews, and confirmation dialogs.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;div class="vb-accordion-fifteen-child"&gt;
              &lt;button class="vb-accordion-fifteen-child-trigger" type="button" aria-expanded="false"&gt;
                &lt;span&gt;Search filters&lt;/span&gt;
                &lt;strong&gt;+&lt;/strong&gt;
              &lt;/button&gt;
              &lt;div class="vb-accordion-fifteen-child-panel"&gt;
                &lt;p&gt;Search filters help users narrow cards, tables, products, directories, and content lists instantly.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-fifteen-parent"&gt;
        &lt;button class="vb-accordion-fifteen-parent-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;03&lt;/span&gt;
          &lt;strong&gt;Content Sections&lt;/strong&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-fifteen-parent-panel"&gt;
          &lt;div class="vb-accordion-fifteen-child-list"&gt;
            &lt;div class="vb-accordion-fifteen-child"&gt;
              &lt;button class="vb-accordion-fifteen-child-trigger" type="button" aria-expanded="false"&gt;
                &lt;span&gt;FAQ blocks&lt;/span&gt;
                &lt;strong&gt;+&lt;/strong&gt;
              &lt;/button&gt;
              &lt;div class="vb-accordion-fifteen-child-panel"&gt;
                &lt;p&gt;FAQ blocks answer common visitor questions and can support SEO when structured clearly.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;div class="vb-accordion-fifteen-child"&gt;
              &lt;button class="vb-accordion-fifteen-child-trigger" type="button" aria-expanded="false"&gt;
                &lt;span&gt;Testimonials&lt;/span&gt;
                &lt;strong&gt;+&lt;/strong&gt;
              &lt;/button&gt;
              &lt;div class="vb-accordion-fifteen-child-panel"&gt;
                &lt;p&gt;Testimonials add trust by showing customer reviews, quotes, ratings, and social proof.&lt;/p&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-fifteen-demo,
.vb-accordion-fifteen-demo * {
  box-sizing: border-box;
}

.vb-accordion-fifteen-demo {
  margin: 28px 0;
  padding: 36px;
  border-radius: 12px 12px 48px 48px;
  background:
    linear-gradient(135deg, #f8fafc 0%, #f5f3ff 48%, #ffffff 100%) !important;
  border: 1px solid rgba(139, 92, 246, 0.22);
  box-shadow: 0 24px 70px rgba(88, 28, 135, 0.10);
}

.vb-accordion-fifteen-shell {
  max-width: 1040px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(280px, 0.78fr) minmax(0, 1.22fr);
  gap: 28px;
  align-items: start;
}

.vb-accordion-fifteen-header {
  position: sticky;
  top: 24px;
  padding: 26px;
  border-radius: 34px 34px 8px 34px;
  background:
    radial-gradient(circle at 20% 18%, rgba(255,255,255,0.24), transparent 34%),
    linear-gradient(135deg, #4c1d95, #7c3aed 58%, #06b6d4) !important;
  box-shadow: 0 28px 80px rgba(109, 40, 217, 0.22);
}

.vb-accordion-fifteen-header span {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.15);
  border: 1px solid rgba(255,255,255,0.20);
  color: #ede9fe !important;
  -webkit-text-fill-color: #ede9fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-fifteen-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 60px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-fifteen-header p {
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-accordion-fifteen-menu {
  display: grid;
  gap: 14px;
}

.vb-accordion-fifteen-parent {
  overflow: hidden;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.08);
}

.vb-accordion-fifteen-parent.is-open {
  border-color: rgba(124, 58, 237, 0.34);
  box-shadow: 0 24px 64px rgba(124, 58, 237, 0.12);
}

.vb-accordion-fifteen-parent-trigger {
  display: grid;
  grid-template-columns: 54px minmax(0, 1fr) 42px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 82px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-fifteen-parent-trigger &gt; span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 54px;
  height: 54px;
  border-radius: 18px 18px 4px 18px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-accordion-fifteen-parent-trigger strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-fifteen-parent-trigger em {
  position: relative;
  width: 42px;
  height: 42px;
  border-radius: 16px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-accordion-fifteen-parent-trigger em::before,
.vb-accordion-fifteen-parent-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 15px;
  height: 2px;
  border-radius: 999px;
  background: #6d28d9;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease, transform 0.22s ease;
}

.vb-accordion-fifteen-parent-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-fifteen-parent.is-open .vb-accordion-fifteen-parent-trigger em {
  background: #6d28d9;
}

.vb-accordion-fifteen-parent.is-open .vb-accordion-fifteen-parent-trigger em::before,
.vb-accordion-fifteen-parent.is-open .vb-accordion-fifteen-parent-trigger em::after {
  background: #ffffff;
}

.vb-accordion-fifteen-parent.is-open .vb-accordion-fifteen-parent-trigger em::after {
  opacity: 0;
}

.vb-accordion-fifteen-parent-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s ease;
}

.vb-accordion-fifteen-child-list {
  display: grid;
  gap: 10px;
  padding: 0 20px 20px 90px;
}

.vb-accordion-fifteen-child {
  overflow: hidden;
  border-radius: 18px 18px 18px 4px;
  background: #f8fafc;
  border: 1px solid rgba(226, 232, 240, 0.9);
}

.vb-accordion-fifteen-child-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 34px;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 52px;
  padding: 13px 14px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-fifteen-child-trigger span {
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  line-height: 1.25;
  font-weight: 900;
}

.vb-accordion-fifteen-child-trigger strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 12px;
  background: #ffffff;
  color: #7c3aed !important;
  -webkit-text-fill-color: #7c3aed !important;
  font-size: 20px;
  font-weight: 950;
  transition: transform 0.22s ease, background 0.22s ease, color 0.22s ease;
}

.vb-accordion-fifteen-child.is-open .vb-accordion-fifteen-child-trigger strong {
  transform: rotate(45deg);
  background: #7c3aed;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-fifteen-child-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-fifteen-child-panel p {
  margin: 0 !important;
  padding: 0 14px 14px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.65;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-accordion-fifteen-shell {
    grid-template-columns: 1fr;
  }

  .vb-accordion-fifteen-header {
    position: static;
  }
}

@media (max-width: 640px) {
  .vb-accordion-fifteen-demo {
    padding: 18px;
    border-radius: 10px 10px 34px 34px;
  }

  .vb-accordion-fifteen-header {
    padding: 22px;
  }

  .vb-accordion-fifteen-header h3 {
    font-size: 38px !important;
  }

  .vb-accordion-fifteen-parent-trigger {
    grid-template-columns: 46px minmax(0, 1fr) 38px;
    gap: 12px;
    padding: 16px;
  }

  .vb-accordion-fifteen-parent-trigger &gt; span {
    width: 46px;
    height: 46px;
  }

  .vb-accordion-fifteen-child-list {
    padding: 0 16px 16px 62px;
  }
}</pre>



<p class="wp-block-paragraph">This nested accordion menu is useful for documentation navigation, mobile menus, product filters, course modules, dashboard sidebars, help centers, and any content structure that needs expandable parent and child levels.</p>



<h2 class="wp-block-heading">16. Searchable FAQ Accordion</h2>



<p class="wp-block-paragraph"><strong>A searchable FAQ accordion</strong> combines live search filtering with expandable JavaScript FAQ panels. It is useful for support pages, help centers, product FAQs, documentation pages, and long FAQ sections where users need to find answers quickly.</p>



<p class="wp-block-paragraph">This example uses a search input, result count, no-results message, and accordion behavior. The layout has a clean support-search design, and the JavaScript filters FAQ items while still allowing users to expand matching answers.</p>



<ul class="wp-block-list">
<li>FAQ search input</li>
<li>Live filtering by question and answer text</li>
<li>Result count and empty state</li>
<li>One-open-at-a-time accordion behavior</li>
<li>Useful for large FAQ and help sections</li>
</ul>



<div class="vb-accordion-sixteen-demo">
  <div class="vb-accordion-sixteen-shell" data-vb-accordion-sixteen>
    <div class="vb-accordion-sixteen-hero">
      <span>Example 16</span>
      <h3>Searchable FAQ Accordion</h3>
      <p>Search questions and open matching answers inside one reusable JavaScript component.</p>

      <div class="vb-accordion-sixteen-search">
        <label for="vb-accordion-sixteen-input">Search FAQ</label>
        <input id="vb-accordion-sixteen-input" type="search" placeholder="Try billing, password, updates, support..." data-vb-accordion-sixteen-search>
      </div>
    </div>

    <div class="vb-accordion-sixteen-meta">
      <strong data-vb-accordion-sixteen-count>5 questions found</strong>
      <button type="button" data-vb-accordion-sixteen-clear>Clear search</button>
    </div>

    <div class="vb-accordion-sixteen-list">
      <section class="vb-accordion-sixteen-item is-open" data-faq-text="billing invoice payment receipt subscription plan">
        <button class="vb-accordion-sixteen-trigger" type="button" aria-expanded="true">
          <span>How can I download my invoice?</span>
          <em></em>
        </button>
        <div class="vb-accordion-sixteen-panel">
          <div class="vb-accordion-sixteen-content">
            <p>You can download invoices from your account billing page. Each completed payment should include invoice date, plan name, and receipt details.</p>
          </div>
        </div>
      </section>

      <section class="vb-accordion-sixteen-item" data-faq-text="password reset login account email security">
        <button class="vb-accordion-sixteen-trigger" type="button" aria-expanded="false">
          <span>How do I reset my password?</span>
          <em></em>
        </button>
        <div class="vb-accordion-sixteen-panel">
          <div class="vb-accordion-sixteen-content">
            <p>Use the password reset link on the login screen, enter your email address, and follow the secure reset link sent to your inbox.</p>
          </div>
        </div>
      </section>

      <section class="vb-accordion-sixteen-item" data-faq-text="updates product download new version changelog release">
        <button class="vb-accordion-sixteen-trigger" type="button" aria-expanded="false">
          <span>Where do I get product updates?</span>
          <em></em>
        </button>
        <div class="vb-accordion-sixteen-panel">
          <div class="vb-accordion-sixteen-content">
            <p>Updates are usually available through the account dashboard, product downloads area, email notifications, or the product changelog page.</p>
          </div>
        </div>
      </section>

      <section class="vb-accordion-sixteen-item" data-faq-text="support help contact ticket issue bug problem">
        <button class="vb-accordion-sixteen-trigger" type="button" aria-expanded="false">
          <span>How do I contact support?</span>
          <em></em>
        </button>
        <div class="vb-accordion-sixteen-panel">
          <div class="vb-accordion-sixteen-content">
            <p>Open a support ticket with your account email, describe the problem clearly, and include screenshots or error messages when possible.</p>
          </div>
        </div>
      </section>

      <section class="vb-accordion-sixteen-item" data-faq-text="license activation domain website client projects">
        <button class="vb-accordion-sixteen-trigger" type="button" aria-expanded="false">
          <span>Can I use it on client projects?</span>
          <em></em>
        </button>
        <div class="vb-accordion-sixteen-panel">
          <div class="vb-accordion-sixteen-content">
            <p>Yes, if your license allows client work. Always check the product license terms before using templates or components in commercial projects.</p>
          </div>
        </div>
      </section>
    </div>

    <div class="vb-accordion-sixteen-empty" data-vb-accordion-sixteen-empty>
      <strong>No matching questions found.</strong>
      <p>Try another keyword such as billing, password, updates, support, or license.</p>
    </div>
  </div>
</div>

<style>
.vb-accordion-sixteen-demo,
.vb-accordion-sixteen-demo * {
  box-sizing: border-box;
}

.vb-accordion-sixteen-demo {
  margin: 28px 0;
  padding: 36px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 20%, rgba(6, 182, 212, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #ecfeff 0%, #eff6ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(103, 232, 249, 0.36);
  box-shadow: 0 24px 70px rgba(8, 47, 73, 0.10);
}

.vb-accordion-sixteen-shell {
  max-width: 980px;
  margin: 0 auto;
}

.vb-accordion-sixteen-hero {
  padding: 30px;
  border-radius: 34px 34px 12px 34px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.24), transparent 34%),
    linear-gradient(135deg, #0e7490, #2563eb) !important;
  box-shadow: 0 28px 80px rgba(37, 99, 235, 0.18);
  margin-bottom: 16px;
}

.vb-accordion-sixteen-hero > span {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  border: 1px solid rgba(255,255,255,0.22);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-sixteen-hero h3 {
  max-width: 720px;
  margin: 0 0 12px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 5vw, 70px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
}

.vb-accordion-sixteen-hero p {
  max-width: 640px;
  margin: 0 0 24px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-accordion-sixteen-search {
  display: grid;
  gap: 9px;
}

.vb-accordion-sixteen-search label {
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-accordion-sixteen-search input {
  width: 100%;
  min-height: 62px;
  padding: 0 18px;
  border: 1px solid rgba(255,255,255,0.24);
  border-radius: 20px;
  outline: 0;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 800;
}

.vb-accordion-sixteen-search input::placeholder {
  color: rgba(255,255,255,0.66);
  -webkit-text-fill-color: rgba(255,255,255,0.66);
}

.vb-accordion-sixteen-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin: 0 0 14px;
  padding: 12px 4px;
}

.vb-accordion-sixteen-meta strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-accordion-sixteen-meta button {
  min-height: 40px;
  padding: 9px 14px;
  border: 0;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-accordion-sixteen-list {
  display: grid;
  gap: 12px;
}

.vb-accordion-sixteen-item {
  overflow: hidden;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 44px rgba(15, 23, 42, 0.07);
}

.vb-accordion-sixteen-item.is-hidden {
  display: none;
}

.vb-accordion-sixteen-item.is-open {
  border-color: rgba(37, 99, 235, 0.34);
  box-shadow: 0 22px 62px rgba(37, 99, 235, 0.12);
}

.vb-accordion-sixteen-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 42px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 72px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-sixteen-trigger span {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-sixteen-trigger em {
  position: relative;
  width: 42px;
  height: 42px;
  border-radius: 16px;
  background: #eff6ff;
  border: 1px solid rgba(37, 99, 235, 0.16);
}

.vb-accordion-sixteen-trigger em::before,
.vb-accordion-sixteen-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 15px;
  height: 2px;
  border-radius: 999px;
  background: #2563eb;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease, transform 0.22s ease;
}

.vb-accordion-sixteen-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-sixteen-item.is-open .vb-accordion-sixteen-trigger em {
  background: #2563eb;
}

.vb-accordion-sixteen-item.is-open .vb-accordion-sixteen-trigger em::before,
.vb-accordion-sixteen-item.is-open .vb-accordion-sixteen-trigger em::after {
  background: #ffffff;
}

.vb-accordion-sixteen-item.is-open .vb-accordion-sixteen-trigger em::after {
  opacity: 0;
}

.vb-accordion-sixteen-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-sixteen-content {
  padding: 0 20px 20px;
}

.vb-accordion-sixteen-content p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-sixteen-empty {
  display: none;
  margin-top: 14px;
  padding: 22px;
  border-radius: 22px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.28);
}

.vb-accordion-sixteen-empty.is-visible {
  display: block;
}

.vb-accordion-sixteen-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-accordion-sixteen-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

@media (max-width: 640px) {
  .vb-accordion-sixteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-accordion-sixteen-hero {
    padding: 22px;
    border-radius: 26px 26px 10px 26px;
  }

  .vb-accordion-sixteen-hero h3 {
    font-size: 38px !important;
  }

  .vb-accordion-sixteen-meta {
    align-items: stretch;
    flex-direction: column;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-sixteen]");
  if (!accordion) return;

  const input = accordion.querySelector("[data-vb-accordion-sixteen-search]");
  const clearButton = accordion.querySelector("[data-vb-accordion-sixteen-clear]");
  const count = accordion.querySelector("[data-vb-accordion-sixteen-count]");
  const empty = accordion.querySelector("[data-vb-accordion-sixteen-empty]");
  const items = Array.from(accordion.querySelectorAll(".vb-accordion-sixteen-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-sixteen-trigger");
    const panel = item.querySelector(".vb-accordion-sixteen-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-sixteen-trigger");
    const panel = item.querySelector(".vb-accordion-sixteen-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  function updateSearch() {
    const query = input.value.trim().toLowerCase();
    let visibleCount = 0;

    items.forEach(function (item) {
      const question = item.querySelector(".vb-accordion-sixteen-trigger span").textContent.toLowerCase();
      const answer = item.querySelector(".vb-accordion-sixteen-content p").textContent.toLowerCase();
      const keywords = item.getAttribute("data-faq-text").toLowerCase();
      const match = question.includes(query) || answer.includes(query) || keywords.includes(query);

      item.classList.toggle("is-hidden", !match);

      if (match) {
        visibleCount += 1;
      } else {
        closeItem(item);
      }
    });

    count.textContent = visibleCount === 1 ? "1 question found" : visibleCount + " questions found";
    empty.classList.toggle("is-visible", visibleCount === 0);
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-sixteen-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  input.addEventListener("input", updateSearch);

  clearButton.addEventListener("click", function () {
    input.value = "";
    input.focus();
    updateSearch();
  });

  const defaultItem = accordion.querySelector(".vb-accordion-sixteen-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  updateSearch();

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-sixteen-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-sixteen]");
  if (!accordion) return;

  const input = accordion.querySelector("[data-vb-accordion-sixteen-search]");
  const clearButton = accordion.querySelector("[data-vb-accordion-sixteen-clear]");
  const count = accordion.querySelector("[data-vb-accordion-sixteen-count]");
  const empty = accordion.querySelector("[data-vb-accordion-sixteen-empty]");
  const items = Array.from(accordion.querySelectorAll(".vb-accordion-sixteen-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-sixteen-trigger");
    const panel = item.querySelector(".vb-accordion-sixteen-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-sixteen-trigger");
    const panel = item.querySelector(".vb-accordion-sixteen-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  function updateSearch() {
    const query = input.value.trim().toLowerCase();
    let visibleCount = 0;

    items.forEach(function (item) {
      const question = item.querySelector(".vb-accordion-sixteen-trigger span").textContent.toLowerCase();
      const answer = item.querySelector(".vb-accordion-sixteen-content p").textContent.toLowerCase();
      const keywords = item.getAttribute("data-faq-text").toLowerCase();
      const match = question.includes(query) || answer.includes(query) || keywords.includes(query);

      item.classList.toggle("is-hidden", !match);

      if (match) {
        visibleCount += 1;
      } else {
        closeItem(item);
      }
    });

    count.textContent = visibleCount === 1 ? "1 question found" : visibleCount + " questions found";
    empty.classList.toggle("is-visible", visibleCount === 0);
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-sixteen-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  input.addEventListener("input", updateSearch);

  clearButton.addEventListener("click", function () {
    input.value = "";
    input.focus();
    updateSearch();
  });

  const defaultItem = accordion.querySelector(".vb-accordion-sixteen-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  updateSearch();

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-sixteen-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-sixteen-demo"&gt;
  &lt;div class="vb-accordion-sixteen-shell" data-vb-accordion-sixteen&gt;
    &lt;div class="vb-accordion-sixteen-hero"&gt;
      &lt;span&gt;Example 16&lt;/span&gt;
      &lt;h3&gt;Searchable FAQ Accordion&lt;/h3&gt;
      &lt;p&gt;Search questions and open matching answers inside one reusable JavaScript component.&lt;/p&gt;

      &lt;div class="vb-accordion-sixteen-search"&gt;
        &lt;label for="vb-accordion-sixteen-input"&gt;Search FAQ&lt;/label&gt;
        &lt;input id="vb-accordion-sixteen-input" type="search" placeholder="Try billing, password, updates, support..." data-vb-accordion-sixteen-search&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-sixteen-meta"&gt;
      &lt;strong data-vb-accordion-sixteen-count&gt;5 questions found&lt;/strong&gt;
      &lt;button type="button" data-vb-accordion-sixteen-clear&gt;Clear search&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-sixteen-list"&gt;
      &lt;section class="vb-accordion-sixteen-item is-open" data-faq-text="billing invoice payment receipt subscription plan"&gt;
        &lt;button class="vb-accordion-sixteen-trigger" type="button" aria-expanded="true"&gt;
          &lt;span&gt;How can I download my invoice?&lt;/span&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-sixteen-panel"&gt;
          &lt;div class="vb-accordion-sixteen-content"&gt;
            &lt;p&gt;You can download invoices from your account billing page. Each completed payment should include invoice date, plan name, and receipt details.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-sixteen-item" data-faq-text="password reset login account email security"&gt;
        &lt;button class="vb-accordion-sixteen-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;How do I reset my password?&lt;/span&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-sixteen-panel"&gt;
          &lt;div class="vb-accordion-sixteen-content"&gt;
            &lt;p&gt;Use the password reset link on the login screen, enter your email address, and follow the secure reset link sent to your inbox.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-sixteen-item" data-faq-text="updates product download new version changelog release"&gt;
        &lt;button class="vb-accordion-sixteen-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Where do I get product updates?&lt;/span&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-sixteen-panel"&gt;
          &lt;div class="vb-accordion-sixteen-content"&gt;
            &lt;p&gt;Updates are usually available through the account dashboard, product downloads area, email notifications, or the product changelog page.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-sixteen-item" data-faq-text="support help contact ticket issue bug problem"&gt;
        &lt;button class="vb-accordion-sixteen-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;How do I contact support?&lt;/span&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-sixteen-panel"&gt;
          &lt;div class="vb-accordion-sixteen-content"&gt;
            &lt;p&gt;Open a support ticket with your account email, describe the problem clearly, and include screenshots or error messages when possible.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-sixteen-item" data-faq-text="license activation domain website client projects"&gt;
        &lt;button class="vb-accordion-sixteen-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Can I use it on client projects?&lt;/span&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-sixteen-panel"&gt;
          &lt;div class="vb-accordion-sixteen-content"&gt;
            &lt;p&gt;Yes, if your license allows client work. Always check the product license terms before using templates or components in commercial projects.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-sixteen-empty" data-vb-accordion-sixteen-empty&gt;
      &lt;strong&gt;No matching questions found.&lt;/strong&gt;
      &lt;p&gt;Try another keyword such as billing, password, updates, support, or license.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-sixteen-demo,
.vb-accordion-sixteen-demo * {
  box-sizing: border-box;
}

.vb-accordion-sixteen-demo {
  margin: 28px 0;
  padding: 36px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 20%, rgba(6, 182, 212, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #ecfeff 0%, #eff6ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(103, 232, 249, 0.36);
  box-shadow: 0 24px 70px rgba(8, 47, 73, 0.10);
}

.vb-accordion-sixteen-shell {
  max-width: 980px;
  margin: 0 auto;
}

.vb-accordion-sixteen-hero {
  padding: 30px;
  border-radius: 34px 34px 12px 34px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.24), transparent 34%),
    linear-gradient(135deg, #0e7490, #2563eb) !important;
  box-shadow: 0 28px 80px rgba(37, 99, 235, 0.18);
  margin-bottom: 16px;
}

.vb-accordion-sixteen-hero &gt; span {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  border: 1px solid rgba(255,255,255,0.22);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-sixteen-hero h3 {
  max-width: 720px;
  margin: 0 0 12px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 5vw, 70px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
}

.vb-accordion-sixteen-hero p {
  max-width: 640px;
  margin: 0 0 24px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-accordion-sixteen-search {
  display: grid;
  gap: 9px;
}

.vb-accordion-sixteen-search label {
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-accordion-sixteen-search input {
  width: 100%;
  min-height: 62px;
  padding: 0 18px;
  border: 1px solid rgba(255,255,255,0.24);
  border-radius: 20px;
  outline: 0;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 800;
}

.vb-accordion-sixteen-search input::placeholder {
  color: rgba(255,255,255,0.66);
  -webkit-text-fill-color: rgba(255,255,255,0.66);
}

.vb-accordion-sixteen-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin: 0 0 14px;
  padding: 12px 4px;
}

.vb-accordion-sixteen-meta strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-accordion-sixteen-meta button {
  min-height: 40px;
  padding: 9px 14px;
  border: 0;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-accordion-sixteen-list {
  display: grid;
  gap: 12px;
}

.vb-accordion-sixteen-item {
  overflow: hidden;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 44px rgba(15, 23, 42, 0.07);
}

.vb-accordion-sixteen-item.is-hidden {
  display: none;
}

.vb-accordion-sixteen-item.is-open {
  border-color: rgba(37, 99, 235, 0.34);
  box-shadow: 0 22px 62px rgba(37, 99, 235, 0.12);
}

.vb-accordion-sixteen-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 42px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 72px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-sixteen-trigger span {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-sixteen-trigger em {
  position: relative;
  width: 42px;
  height: 42px;
  border-radius: 16px;
  background: #eff6ff;
  border: 1px solid rgba(37, 99, 235, 0.16);
}

.vb-accordion-sixteen-trigger em::before,
.vb-accordion-sixteen-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 15px;
  height: 2px;
  border-radius: 999px;
  background: #2563eb;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease, transform 0.22s ease;
}

.vb-accordion-sixteen-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-sixteen-item.is-open .vb-accordion-sixteen-trigger em {
  background: #2563eb;
}

.vb-accordion-sixteen-item.is-open .vb-accordion-sixteen-trigger em::before,
.vb-accordion-sixteen-item.is-open .vb-accordion-sixteen-trigger em::after {
  background: #ffffff;
}

.vb-accordion-sixteen-item.is-open .vb-accordion-sixteen-trigger em::after {
  opacity: 0;
}

.vb-accordion-sixteen-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-sixteen-content {
  padding: 0 20px 20px;
}

.vb-accordion-sixteen-content p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-sixteen-empty {
  display: none;
  margin-top: 14px;
  padding: 22px;
  border-radius: 22px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.28);
}

.vb-accordion-sixteen-empty.is-visible {
  display: block;
}

.vb-accordion-sixteen-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-accordion-sixteen-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

@media (max-width: 640px) {
  .vb-accordion-sixteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-accordion-sixteen-hero {
    padding: 22px;
    border-radius: 26px 26px 10px 26px;
  }

  .vb-accordion-sixteen-hero h3 {
    font-size: 38px !important;
  }

  .vb-accordion-sixteen-meta {
    align-items: stretch;
    flex-direction: column;
  }
}</pre>



<p class="wp-block-paragraph">This searchable FAQ accordion is ideal for large FAQ pages, support centers, documentation sections, product help pages, onboarding resources, and any long answer section where users need both search and expandable content.</p>



<h2 class="wp-block-heading">17. Comparison Accordion</h2>



<p class="wp-block-paragraph"><strong>A comparison accordion</strong> is useful when visitors need to compare options, plans, services, product versions, features, or packages without reading a long comparison table on mobile.</p>



<p class="wp-block-paragraph">This example uses a side-by-side comparison layout on desktop and a compact accordion structure on smaller screens. Each expandable row compares two options with clear labels, checkmarks, and a bold active state.</p>



<ul class="wp-block-list">
<li>Comparison-focused accordion layout</li>
<li>One-open-at-a-time behavior</li>
<li>Two-column feature comparison</li>
<li>Checkmark and difference labels</li>
<li>Useful for plans, services, and products</li>
</ul>



<div class="vb-accordion-seventeen-demo">
  <div class="vb-accordion-seventeen-shell" data-vb-accordion-seventeen>
    <div class="vb-accordion-seventeen-header">
      <span>Example 17</span>
      <h3>Comparison Accordion</h3>
      <p>Compare two options inside expandable rows without showing a large table at once.</p>
    </div>

    <div class="vb-accordion-seventeen-board">
      <div class="vb-accordion-seventeen-labels">
        <strong>Starter</strong>
        <strong>Professional</strong>
      </div>

      <section class="vb-accordion-seventeen-item is-open">
        <button class="vb-accordion-seventeen-trigger" type="button" aria-expanded="true">
          <span>Feature access</span>
          <em></em>
        </button>
        <div class="vb-accordion-seventeen-panel">
          <div class="vb-accordion-seventeen-content">
            <div>
              <small>Starter</small>
              <strong>Basic components</strong>
              <p>Includes essential layouts, simple UI blocks, and standard support.</p>
            </div>
            <div>
              <small>Professional</small>
              <strong>Advanced components</strong>
              <p>Includes advanced UI sections, reusable patterns, and premium layouts.</p>
            </div>
          </div>
        </div>
      </section>

      <section class="vb-accordion-seventeen-item">
        <button class="vb-accordion-seventeen-trigger" type="button" aria-expanded="false">
          <span>Customization options</span>
          <em></em>
        </button>
        <div class="vb-accordion-seventeen-panel">
          <div class="vb-accordion-seventeen-content">
            <div>
              <small>Starter</small>
              <strong>Limited styling</strong>
              <p>Good for simple websites that only need small color and spacing changes.</p>
            </div>
            <div>
              <small>Professional</small>
              <strong>Full styling control</strong>
              <p>Better for agencies, custom client projects, dashboards, and advanced landing pages.</p>
            </div>
          </div>
        </div>
      </section>

      <section class="vb-accordion-seventeen-item">
        <button class="vb-accordion-seventeen-trigger" type="button" aria-expanded="false">
          <span>Best use case</span>
          <em></em>
        </button>
        <div class="vb-accordion-seventeen-panel">
          <div class="vb-accordion-seventeen-content">
            <div>
              <small>Starter</small>
              <strong>Small websites</strong>
              <p>Useful for portfolios, simple blogs, small business pages, and basic landing pages.</p>
            </div>
            <div>
              <small>Professional</small>
              <strong>Client projects</strong>
              <p>Useful for SaaS websites, ecommerce pages, agency work, and reusable UI systems.</p>
            </div>
          </div>
        </div>
      </section>

      <section class="vb-accordion-seventeen-item">
        <button class="vb-accordion-seventeen-trigger" type="button" aria-expanded="false">
          <span>Support level</span>
          <em></em>
        </button>
        <div class="vb-accordion-seventeen-panel">
          <div class="vb-accordion-seventeen-content">
            <div>
              <small>Starter</small>
              <strong>Email support</strong>
              <p>Basic support for setup questions, simple issues, and general usage help.</p>
            </div>
            <div>
              <small>Professional</small>
              <strong>Priority support</strong>
              <p>Faster help for implementation questions, advanced layouts, and project-specific problems.</p>
            </div>
          </div>
        </div>
      </section>
    </div>
  </div>
</div>

<style>
.vb-accordion-seventeen-demo,
.vb-accordion-seventeen-demo * {
  box-sizing: border-box;
}

.vb-accordion-seventeen-demo {
  margin: 28px 0;
  padding: 38px;
  border-radius: 8px 48px 8px 48px;
  background:
    linear-gradient(135deg, #f8fafc 0%, #fefce8 48%, #ffffff 100%) !important;
  border: 1px solid rgba(202, 138, 4, 0.22);
  box-shadow: 0 24px 70px rgba(113, 63, 18, 0.10);
}

.vb-accordion-seventeen-shell {
  max-width: 1100px;
  margin: 0 auto;
}

.vb-accordion-seventeen-header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 0.62fr);
  gap: 26px;
  align-items: end;
  margin-bottom: 28px;
}

.vb-accordion-seventeen-header span {
  grid-column: 1 / -1;
  justify-self: start;
  display: inline-flex;
  padding: 8px 12px;
  border-radius: 0;
  background: #854d0e;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-seventeen-header h3 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(38px, 5vw, 72px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
}

.vb-accordion-seventeen-header p {
  margin: 0 !important;
  color: #57534e !important;
  -webkit-text-fill-color: #57534e !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-seventeen-board {
  padding: 18px;
  border-radius: 28px 8px 28px 8px;
  background: #ffffff;
  border: 1px solid rgba(161, 98, 7, 0.18);
  box-shadow: 0 20px 56px rgba(113, 63, 18, 0.08);
}

.vb-accordion-seventeen-labels {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  margin-bottom: 12px;
  padding-left: 18px;
  padding-right: 18px;
}

.vb-accordion-seventeen-labels strong {
  padding: 12px 16px;
  border-radius: 16px 4px 16px 4px;
  background: #fef3c7;
  color: #854d0e !important;
  -webkit-text-fill-color: #854d0e !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-accordion-seventeen-item {
  overflow: hidden;
  border-radius: 22px 6px 22px 6px;
  border: 1px solid rgba(202, 138, 4, 0.20);
  background: #ffffff;
  margin-bottom: 12px;
}

.vb-accordion-seventeen-item:last-child {
  margin-bottom: 0;
}

.vb-accordion-seventeen-item.is-open {
  box-shadow: 0 20px 54px rgba(202, 138, 4, 0.12);
  border-color: rgba(202, 138, 4, 0.36);
}

.vb-accordion-seventeen-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 44px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 72px;
  padding: 18px 20px;
  border: 0;
  background: linear-gradient(135deg, #ffffff, #fffbeb) !important;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-seventeen-trigger span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 20px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.045em;
}

.vb-accordion-seventeen-trigger em {
  position: relative;
  width: 44px;
  height: 44px;
  border-radius: 6px 18px 6px 18px;
  background: #fef3c7;
  border: 1px solid rgba(202, 138, 4, 0.22);
}

.vb-accordion-seventeen-trigger em::before,
.vb-accordion-seventeen-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 16px;
  height: 2px;
  border-radius: 999px;
  background: #a16207;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease, transform 0.22s ease;
}

.vb-accordion-seventeen-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-seventeen-item.is-open .vb-accordion-seventeen-trigger em {
  background: #ca8a04;
}

.vb-accordion-seventeen-item.is-open .vb-accordion-seventeen-trigger em::before,
.vb-accordion-seventeen-item.is-open .vb-accordion-seventeen-trigger em::after {
  background: #ffffff;
}

.vb-accordion-seventeen-item.is-open .vb-accordion-seventeen-trigger em::after {
  opacity: 0;
}

.vb-accordion-seventeen-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-seventeen-content {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  padding: 0 18px 18px;
}

.vb-accordion-seventeen-content div {
  padding: 18px;
  border-radius: 18px 4px 18px 4px;
  background: #f8fafc;
  border: 1px solid rgba(226, 232, 240, 0.9);
}

.vb-accordion-seventeen-content div:last-child {
  background: #fffbeb;
  border-color: rgba(202, 138, 4, 0.22);
}

.vb-accordion-seventeen-content small {
  display: inline-flex;
  margin-bottom: 9px;
  padding: 5px 8px;
  border-radius: 999px;
  background: #ffffff;
  color: #854d0e !important;
  -webkit-text-fill-color: #854d0e !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-accordion-seventeen-content strong {
  display: block;
  margin-bottom: 8px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-accordion-seventeen-content p {
  margin: 0 !important;
  color: #57534e !important;
  -webkit-text-fill-color: #57534e !important;
  font-size: 14px;
  line-height: 1.7;
  font-weight: 650;
}

@media (max-width: 760px) {
  .vb-accordion-seventeen-demo {
    padding: 18px;
    border-radius: 8px 32px 8px 32px;
  }

  .vb-accordion-seventeen-header {
    grid-template-columns: 1fr;
  }

  .vb-accordion-seventeen-header h3 {
    font-size: 40px !important;
  }

  .vb-accordion-seventeen-labels,
  .vb-accordion-seventeen-content {
    grid-template-columns: 1fr;
  }

  .vb-accordion-seventeen-labels {
    display: none;
  }

  .vb-accordion-seventeen-board {
    padding: 12px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-seventeen]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-seventeen-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-seventeen-trigger");
    const panel = item.querySelector(".vb-accordion-seventeen-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-seventeen-trigger");
    const panel = item.querySelector(".vb-accordion-seventeen-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-seventeen-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-seventeen-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-seventeen-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-seventeen]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-seventeen-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-seventeen-trigger");
    const panel = item.querySelector(".vb-accordion-seventeen-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-seventeen-trigger");
    const panel = item.querySelector(".vb-accordion-seventeen-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-seventeen-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-seventeen-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-seventeen-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-seventeen-demo"&gt;
  &lt;div class="vb-accordion-seventeen-shell" data-vb-accordion-seventeen&gt;
    &lt;div class="vb-accordion-seventeen-header"&gt;
      &lt;span&gt;Example 17&lt;/span&gt;
      &lt;h3&gt;Comparison Accordion&lt;/h3&gt;
      &lt;p&gt;Compare two options inside expandable rows without showing a large table at once.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-seventeen-board"&gt;
      &lt;div class="vb-accordion-seventeen-labels"&gt;
        &lt;strong&gt;Starter&lt;/strong&gt;
        &lt;strong&gt;Professional&lt;/strong&gt;
      &lt;/div&gt;

      &lt;section class="vb-accordion-seventeen-item is-open"&gt;
        &lt;button class="vb-accordion-seventeen-trigger" type="button" aria-expanded="true"&gt;
          &lt;span&gt;Feature access&lt;/span&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-seventeen-panel"&gt;
          &lt;div class="vb-accordion-seventeen-content"&gt;
            &lt;div&gt;
              &lt;small&gt;Starter&lt;/small&gt;
              &lt;strong&gt;Basic components&lt;/strong&gt;
              &lt;p&gt;Includes essential layouts, simple UI blocks, and standard support.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div&gt;
              &lt;small&gt;Professional&lt;/small&gt;
              &lt;strong&gt;Advanced components&lt;/strong&gt;
              &lt;p&gt;Includes advanced UI sections, reusable patterns, and premium layouts.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-seventeen-item"&gt;
        &lt;button class="vb-accordion-seventeen-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Customization options&lt;/span&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-seventeen-panel"&gt;
          &lt;div class="vb-accordion-seventeen-content"&gt;
            &lt;div&gt;
              &lt;small&gt;Starter&lt;/small&gt;
              &lt;strong&gt;Limited styling&lt;/strong&gt;
              &lt;p&gt;Good for simple websites that only need small color and spacing changes.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div&gt;
              &lt;small&gt;Professional&lt;/small&gt;
              &lt;strong&gt;Full styling control&lt;/strong&gt;
              &lt;p&gt;Better for agencies, custom client projects, dashboards, and advanced landing pages.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-seventeen-item"&gt;
        &lt;button class="vb-accordion-seventeen-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Best use case&lt;/span&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-seventeen-panel"&gt;
          &lt;div class="vb-accordion-seventeen-content"&gt;
            &lt;div&gt;
              &lt;small&gt;Starter&lt;/small&gt;
              &lt;strong&gt;Small websites&lt;/strong&gt;
              &lt;p&gt;Useful for portfolios, simple blogs, small business pages, and basic landing pages.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div&gt;
              &lt;small&gt;Professional&lt;/small&gt;
              &lt;strong&gt;Client projects&lt;/strong&gt;
              &lt;p&gt;Useful for SaaS websites, ecommerce pages, agency work, and reusable UI systems.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-seventeen-item"&gt;
        &lt;button class="vb-accordion-seventeen-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Support level&lt;/span&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-seventeen-panel"&gt;
          &lt;div class="vb-accordion-seventeen-content"&gt;
            &lt;div&gt;
              &lt;small&gt;Starter&lt;/small&gt;
              &lt;strong&gt;Email support&lt;/strong&gt;
              &lt;p&gt;Basic support for setup questions, simple issues, and general usage help.&lt;/p&gt;
            &lt;/div&gt;
            &lt;div&gt;
              &lt;small&gt;Professional&lt;/small&gt;
              &lt;strong&gt;Priority support&lt;/strong&gt;
              &lt;p&gt;Faster help for implementation questions, advanced layouts, and project-specific problems.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-seventeen-demo,
.vb-accordion-seventeen-demo * {
  box-sizing: border-box;
}

.vb-accordion-seventeen-demo {
  margin: 28px 0;
  padding: 38px;
  border-radius: 8px 48px 8px 48px;
  background:
    linear-gradient(135deg, #f8fafc 0%, #fefce8 48%, #ffffff 100%) !important;
  border: 1px solid rgba(202, 138, 4, 0.22);
  box-shadow: 0 24px 70px rgba(113, 63, 18, 0.10);
}

.vb-accordion-seventeen-shell {
  max-width: 1100px;
  margin: 0 auto;
}

.vb-accordion-seventeen-header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 0.62fr);
  gap: 26px;
  align-items: end;
  margin-bottom: 28px;
}

.vb-accordion-seventeen-header span {
  grid-column: 1 / -1;
  justify-self: start;
  display: inline-flex;
  padding: 8px 12px;
  border-radius: 0;
  background: #854d0e;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-seventeen-header h3 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(38px, 5vw, 72px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
}

.vb-accordion-seventeen-header p {
  margin: 0 !important;
  color: #57534e !important;
  -webkit-text-fill-color: #57534e !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-seventeen-board {
  padding: 18px;
  border-radius: 28px 8px 28px 8px;
  background: #ffffff;
  border: 1px solid rgba(161, 98, 7, 0.18);
  box-shadow: 0 20px 56px rgba(113, 63, 18, 0.08);
}

.vb-accordion-seventeen-labels {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  margin-bottom: 12px;
  padding-left: 18px;
  padding-right: 18px;
}

.vb-accordion-seventeen-labels strong {
  padding: 12px 16px;
  border-radius: 16px 4px 16px 4px;
  background: #fef3c7;
  color: #854d0e !important;
  -webkit-text-fill-color: #854d0e !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-accordion-seventeen-item {
  overflow: hidden;
  border-radius: 22px 6px 22px 6px;
  border: 1px solid rgba(202, 138, 4, 0.20);
  background: #ffffff;
  margin-bottom: 12px;
}

.vb-accordion-seventeen-item:last-child {
  margin-bottom: 0;
}

.vb-accordion-seventeen-item.is-open {
  box-shadow: 0 20px 54px rgba(202, 138, 4, 0.12);
  border-color: rgba(202, 138, 4, 0.36);
}

.vb-accordion-seventeen-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 44px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 72px;
  padding: 18px 20px;
  border: 0;
  background: linear-gradient(135deg, #ffffff, #fffbeb) !important;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-seventeen-trigger span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 20px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.045em;
}

.vb-accordion-seventeen-trigger em {
  position: relative;
  width: 44px;
  height: 44px;
  border-radius: 6px 18px 6px 18px;
  background: #fef3c7;
  border: 1px solid rgba(202, 138, 4, 0.22);
}

.vb-accordion-seventeen-trigger em::before,
.vb-accordion-seventeen-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 16px;
  height: 2px;
  border-radius: 999px;
  background: #a16207;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease, transform 0.22s ease;
}

.vb-accordion-seventeen-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-seventeen-item.is-open .vb-accordion-seventeen-trigger em {
  background: #ca8a04;
}

.vb-accordion-seventeen-item.is-open .vb-accordion-seventeen-trigger em::before,
.vb-accordion-seventeen-item.is-open .vb-accordion-seventeen-trigger em::after {
  background: #ffffff;
}

.vb-accordion-seventeen-item.is-open .vb-accordion-seventeen-trigger em::after {
  opacity: 0;
}

.vb-accordion-seventeen-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-seventeen-content {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 14px;
  padding: 0 18px 18px;
}

.vb-accordion-seventeen-content div {
  padding: 18px;
  border-radius: 18px 4px 18px 4px;
  background: #f8fafc;
  border: 1px solid rgba(226, 232, 240, 0.9);
}

.vb-accordion-seventeen-content div:last-child {
  background: #fffbeb;
  border-color: rgba(202, 138, 4, 0.22);
}

.vb-accordion-seventeen-content small {
  display: inline-flex;
  margin-bottom: 9px;
  padding: 5px 8px;
  border-radius: 999px;
  background: #ffffff;
  color: #854d0e !important;
  -webkit-text-fill-color: #854d0e !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-accordion-seventeen-content strong {
  display: block;
  margin-bottom: 8px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-accordion-seventeen-content p {
  margin: 0 !important;
  color: #57534e !important;
  -webkit-text-fill-color: #57534e !important;
  font-size: 14px;
  line-height: 1.7;
  font-weight: 650;
}

@media (max-width: 760px) {
  .vb-accordion-seventeen-demo {
    padding: 18px;
    border-radius: 8px 32px 8px 32px;
  }

  .vb-accordion-seventeen-header {
    grid-template-columns: 1fr;
  }

  .vb-accordion-seventeen-header h3 {
    font-size: 40px !important;
  }

  .vb-accordion-seventeen-labels,
  .vb-accordion-seventeen-content {
    grid-template-columns: 1fr;
  }

  .vb-accordion-seventeen-labels {
    display: none;
  }

  .vb-accordion-seventeen-board {
    padding: 12px;
  }
}</pre>



<p class="wp-block-paragraph">This comparison accordion is useful for pricing plans, service packages, product versions, feature comparisons, mobile comparison sections, and landing pages where users need structured differences without a large table.</p>



<h2 class="wp-block-heading">18. Notification Accordion</h2>



<p class="wp-block-paragraph"><strong>A notification accordion</strong> is useful for dashboards, admin panels, account pages, app inboxes, update centers, CRM screens, and project management interfaces where messages need to expand into more detail.</p>



<p class="wp-block-paragraph">This example uses an inbox-inspired accordion with unread indicators, message timestamps, priority badges, and multi-open behavior. It has a completely different visual feel from FAQ or content accordions because it is designed like a compact notification center.</p>



<ul class="wp-block-list">
<li>Notification center accordion layout</li>
<li>Multi-open message behavior</li>
<li>Unread dots and timestamps</li>
<li>Priority and status badges</li>
<li>Useful for dashboards, inboxes, and admin screens</li>
</ul>



<div class="vb-accordion-eighteen-demo">
  <div class="vb-accordion-eighteen-inbox" data-vb-accordion-eighteen>
    <div class="vb-accordion-eighteen-top">
      <div>
        <span>Example 18</span>
        <h3>Notification Accordion</h3>
      </div>
      <p>Expand notification rows to read more details without leaving the dashboard.</p>
    </div>

    <div class="vb-accordion-eighteen-toolbar">
      <strong>Inbox updates</strong>
      <button type="button">Mark all read</button>
    </div>

    <div class="vb-accordion-eighteen-list">
      <article class="vb-accordion-eighteen-item is-open is-unread">
        <button class="vb-accordion-eighteen-trigger" type="button" aria-expanded="true">
          <i></i>
          <span>
            <strong>New account login detected</strong>
            <small>Security · 2 minutes ago</small>
          </span>
          <em>High</em>
        </button>
        <div class="vb-accordion-eighteen-panel">
          <div class="vb-accordion-eighteen-content">
            <p>A new login was detected from a different browser. Review the session details and confirm that this activity belongs to you.</p>
            <a href="#javascript-accordion-examples">Review activity</a>
          </div>
        </div>
      </article>

      <article class="vb-accordion-eighteen-item is-unread">
        <button class="vb-accordion-eighteen-trigger" type="button" aria-expanded="false">
          <i></i>
          <span>
            <strong>Weekly report is ready</strong>
            <small>Analytics · 1 hour ago</small>
          </span>
          <em>Info</em>
        </button>
        <div class="vb-accordion-eighteen-panel">
          <div class="vb-accordion-eighteen-content">
            <p>Your weekly performance report has been generated. Open the report to review traffic, conversions, engagement, and content changes.</p>
            <a href="#javascript-accordion-examples">Open report</a>
          </div>
        </div>
      </article>

      <article class="vb-accordion-eighteen-item">
        <button class="vb-accordion-eighteen-trigger" type="button" aria-expanded="false">
          <i></i>
          <span>
            <strong>Plugin update available</strong>
            <small>System · Yesterday</small>
          </span>
          <em>Update</em>
        </button>
        <div class="vb-accordion-eighteen-panel">
          <div class="vb-accordion-eighteen-content">
            <p>A new version is available with security improvements, UI fixes, and compatibility updates. Back up your site before updating.</p>
            <a href="#javascript-accordion-examples">View changelog</a>
          </div>
        </div>
      </article>

      <article class="vb-accordion-eighteen-item">
        <button class="vb-accordion-eighteen-trigger" type="button" aria-expanded="false">
          <i></i>
          <span>
            <strong>Comment needs approval</strong>
            <small>Content · 2 days ago</small>
          </span>
          <em>Task</em>
        </button>
        <div class="vb-accordion-eighteen-panel">
          <div class="vb-accordion-eighteen-content">
            <p>A new comment is waiting for review. Check the message, approve it, reply to the user, or move it to spam if needed.</p>
            <a href="#javascript-accordion-examples">Moderate comment</a>
          </div>
        </div>
      </article>
    </div>
  </div>
</div>

<style>
.vb-accordion-eighteen-demo,
.vb-accordion-eighteen-demo * {
  box-sizing: border-box;
}

.vb-accordion-eighteen-demo {
  margin: 28px 0;
  padding: 36px;
  border-radius: 38px;
  background:
    radial-gradient(circle at 16% 18%, rgba(248, 113, 113, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #fff1f2 50%, #eff6ff 100%) !important;
  border: 1px solid rgba(248, 113, 113, 0.24);
  box-shadow: 0 24px 70px rgba(127, 29, 29, 0.10);
}

.vb-accordion-eighteen-inbox {
  max-width: 980px;
  margin: 0 auto;
  padding: 18px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 22px 60px rgba(15, 23, 42, 0.10);
}

.vb-accordion-eighteen-top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 0.55fr);
  gap: 24px;
  align-items: end;
  padding: 16px 16px 22px;
}

.vb-accordion-eighteen-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 12px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-eighteen-top h3 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(38px, 5vw, 68px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-eighteen-top p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-eighteen-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 12px;
  padding: 14px 16px;
  border-radius: 20px;
  background: #f8fafc;
}

.vb-accordion-eighteen-toolbar strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-accordion-eighteen-toolbar button {
  min-height: 38px;
  padding: 9px 14px;
  border: 0;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-accordion-eighteen-list {
  display: grid;
  gap: 10px;
}

.vb-accordion-eighteen-item {
  overflow: hidden;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(226, 232, 240, 0.9);
}

.vb-accordion-eighteen-item.is-unread {
  border-color: rgba(248, 113, 113, 0.32);
  background: linear-gradient(135deg, #ffffff, #fff7ed) !important;
}

.vb-accordion-eighteen-item.is-open {
  box-shadow: 0 18px 52px rgba(127, 29, 29, 0.10);
}

.vb-accordion-eighteen-trigger {
  display: grid;
  grid-template-columns: 18px minmax(0, 1fr) 74px;
  align-items: center;
  gap: 14px;
  width: 100%;
  min-height: 76px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-eighteen-trigger i {
  width: 11px;
  height: 11px;
  border-radius: 999px;
  background: #cbd5e1;
}

.vb-accordion-eighteen-item.is-unread .vb-accordion-eighteen-trigger i {
  background: #ef4444;
  box-shadow: 0 0 0 6px rgba(239, 68, 68, 0.12);
}

.vb-accordion-eighteen-trigger strong {
  display: block;
  margin-bottom: 5px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.035em;
}

.vb-accordion-eighteen-trigger small {
  display: block;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 750;
}

.vb-accordion-eighteen-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 34px;
  border-radius: 999px;
  background: #f1f5f9;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 12px;
  font-style: normal;
  font-weight: 950;
}

.vb-accordion-eighteen-item.is-unread .vb-accordion-eighteen-trigger em {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-accordion-eighteen-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-eighteen-content {
  padding: 0 20px 20px 52px;
}

.vb-accordion-eighteen-content p {
  max-width: 720px;
  margin: 0 0 14px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-eighteen-content a {
  display: inline-flex;
  min-height: 38px;
  align-items: center;
  justify-content: center;
  padding: 9px 14px;
  border-radius: 999px;
  background: #eff6ff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
}

@media (max-width: 760px) {
  .vb-accordion-eighteen-demo {
    padding: 18px;
    border-radius: 28px;
  }

  .vb-accordion-eighteen-inbox {
    padding: 12px;
    border-radius: 24px;
  }

  .vb-accordion-eighteen-top {
    grid-template-columns: 1fr;
    padding: 12px 10px 18px;
  }

  .vb-accordion-eighteen-top h3 {
    font-size: 38px !important;
  }

  .vb-accordion-eighteen-toolbar {
    flex-direction: column;
    align-items: stretch;
  }

  .vb-accordion-eighteen-trigger {
    grid-template-columns: 14px minmax(0, 1fr);
  }

  .vb-accordion-eighteen-trigger em {
    grid-column: 2;
    justify-self: start;
    min-width: 74px;
  }

  .vb-accordion-eighteen-content {
    padding: 0 18px 18px 46px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-eighteen]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-eighteen-item"));

  function updateItem(item) {
    const button = item.querySelector(".vb-accordion-eighteen-trigger");
    const panel = item.querySelector(".vb-accordion-eighteen-panel");
    const isOpen = item.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-eighteen-trigger");

    button.addEventListener("click", function () {
      item.classList.toggle("is-open");
      item.classList.remove("is-unread");
      updateItem(item);
    });

    updateItem(item);
  });

  window.addEventListener("resize", function () {
    items.forEach(updateItem);
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-eighteen]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-eighteen-item"));

  function updateItem(item) {
    const button = item.querySelector(".vb-accordion-eighteen-trigger");
    const panel = item.querySelector(".vb-accordion-eighteen-panel");
    const isOpen = item.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-eighteen-trigger");

    button.addEventListener("click", function () {
      item.classList.toggle("is-open");
      item.classList.remove("is-unread");
      updateItem(item);
    });

    updateItem(item);
  });

  window.addEventListener("resize", function () {
    items.forEach(updateItem);
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-eighteen-demo"&gt;
  &lt;div class="vb-accordion-eighteen-inbox" data-vb-accordion-eighteen&gt;
    &lt;div class="vb-accordion-eighteen-top"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 18&lt;/span&gt;
        &lt;h3&gt;Notification Accordion&lt;/h3&gt;
      &lt;/div&gt;
      &lt;p&gt;Expand notification rows to read more details without leaving the dashboard.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-eighteen-toolbar"&gt;
      &lt;strong&gt;Inbox updates&lt;/strong&gt;
      &lt;button type="button"&gt;Mark all read&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-eighteen-list"&gt;
      &lt;article class="vb-accordion-eighteen-item is-open is-unread"&gt;
        &lt;button class="vb-accordion-eighteen-trigger" type="button" aria-expanded="true"&gt;
          &lt;i&gt;&lt;/i&gt;
          &lt;span&gt;
            &lt;strong&gt;New account login detected&lt;/strong&gt;
            &lt;small&gt;Security · 2 minutes ago&lt;/small&gt;
          &lt;/span&gt;
          &lt;em&gt;High&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-eighteen-panel"&gt;
          &lt;div class="vb-accordion-eighteen-content"&gt;
            &lt;p&gt;A new login was detected from a different browser. Review the session details and confirm that this activity belongs to you.&lt;/p&gt;
            &lt;a href="#javascript-accordion-examples"&gt;Review activity&lt;/a&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-eighteen-item is-unread"&gt;
        &lt;button class="vb-accordion-eighteen-trigger" type="button" aria-expanded="false"&gt;
          &lt;i&gt;&lt;/i&gt;
          &lt;span&gt;
            &lt;strong&gt;Weekly report is ready&lt;/strong&gt;
            &lt;small&gt;Analytics · 1 hour ago&lt;/small&gt;
          &lt;/span&gt;
          &lt;em&gt;Info&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-eighteen-panel"&gt;
          &lt;div class="vb-accordion-eighteen-content"&gt;
            &lt;p&gt;Your weekly performance report has been generated. Open the report to review traffic, conversions, engagement, and content changes.&lt;/p&gt;
            &lt;a href="#javascript-accordion-examples"&gt;Open report&lt;/a&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-eighteen-item"&gt;
        &lt;button class="vb-accordion-eighteen-trigger" type="button" aria-expanded="false"&gt;
          &lt;i&gt;&lt;/i&gt;
          &lt;span&gt;
            &lt;strong&gt;Plugin update available&lt;/strong&gt;
            &lt;small&gt;System · Yesterday&lt;/small&gt;
          &lt;/span&gt;
          &lt;em&gt;Update&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-eighteen-panel"&gt;
          &lt;div class="vb-accordion-eighteen-content"&gt;
            &lt;p&gt;A new version is available with security improvements, UI fixes, and compatibility updates. Back up your site before updating.&lt;/p&gt;
            &lt;a href="#javascript-accordion-examples"&gt;View changelog&lt;/a&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-eighteen-item"&gt;
        &lt;button class="vb-accordion-eighteen-trigger" type="button" aria-expanded="false"&gt;
          &lt;i&gt;&lt;/i&gt;
          &lt;span&gt;
            &lt;strong&gt;Comment needs approval&lt;/strong&gt;
            &lt;small&gt;Content · 2 days ago&lt;/small&gt;
          &lt;/span&gt;
          &lt;em&gt;Task&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-eighteen-panel"&gt;
          &lt;div class="vb-accordion-eighteen-content"&gt;
            &lt;p&gt;A new comment is waiting for review. Check the message, approve it, reply to the user, or move it to spam if needed.&lt;/p&gt;
            &lt;a href="#javascript-accordion-examples"&gt;Moderate comment&lt;/a&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-eighteen-demo,
.vb-accordion-eighteen-demo * {
  box-sizing: border-box;
}

.vb-accordion-eighteen-demo {
  margin: 28px 0;
  padding: 36px;
  border-radius: 38px;
  background:
    radial-gradient(circle at 16% 18%, rgba(248, 113, 113, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #fff1f2 50%, #eff6ff 100%) !important;
  border: 1px solid rgba(248, 113, 113, 0.24);
  box-shadow: 0 24px 70px rgba(127, 29, 29, 0.10);
}

.vb-accordion-eighteen-inbox {
  max-width: 980px;
  margin: 0 auto;
  padding: 18px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 22px 60px rgba(15, 23, 42, 0.10);
}

.vb-accordion-eighteen-top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 0.55fr);
  gap: 24px;
  align-items: end;
  padding: 16px 16px 22px;
}

.vb-accordion-eighteen-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 12px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-eighteen-top h3 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(38px, 5vw, 68px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-eighteen-top p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-eighteen-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 12px;
  padding: 14px 16px;
  border-radius: 20px;
  background: #f8fafc;
}

.vb-accordion-eighteen-toolbar strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-accordion-eighteen-toolbar button {
  min-height: 38px;
  padding: 9px 14px;
  border: 0;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-accordion-eighteen-list {
  display: grid;
  gap: 10px;
}

.vb-accordion-eighteen-item {
  overflow: hidden;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(226, 232, 240, 0.9);
}

.vb-accordion-eighteen-item.is-unread {
  border-color: rgba(248, 113, 113, 0.32);
  background: linear-gradient(135deg, #ffffff, #fff7ed) !important;
}

.vb-accordion-eighteen-item.is-open {
  box-shadow: 0 18px 52px rgba(127, 29, 29, 0.10);
}

.vb-accordion-eighteen-trigger {
  display: grid;
  grid-template-columns: 18px minmax(0, 1fr) 74px;
  align-items: center;
  gap: 14px;
  width: 100%;
  min-height: 76px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-eighteen-trigger i {
  width: 11px;
  height: 11px;
  border-radius: 999px;
  background: #cbd5e1;
}

.vb-accordion-eighteen-item.is-unread .vb-accordion-eighteen-trigger i {
  background: #ef4444;
  box-shadow: 0 0 0 6px rgba(239, 68, 68, 0.12);
}

.vb-accordion-eighteen-trigger strong {
  display: block;
  margin-bottom: 5px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.035em;
}

.vb-accordion-eighteen-trigger small {
  display: block;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 750;
}

.vb-accordion-eighteen-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 34px;
  border-radius: 999px;
  background: #f1f5f9;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 12px;
  font-style: normal;
  font-weight: 950;
}

.vb-accordion-eighteen-item.is-unread .vb-accordion-eighteen-trigger em {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-accordion-eighteen-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-eighteen-content {
  padding: 0 20px 20px 52px;
}

.vb-accordion-eighteen-content p {
  max-width: 720px;
  margin: 0 0 14px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-eighteen-content a {
  display: inline-flex;
  min-height: 38px;
  align-items: center;
  justify-content: center;
  padding: 9px 14px;
  border-radius: 999px;
  background: #eff6ff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
}

@media (max-width: 760px) {
  .vb-accordion-eighteen-demo {
    padding: 18px;
    border-radius: 28px;
  }

  .vb-accordion-eighteen-inbox {
    padding: 12px;
    border-radius: 24px;
  }

  .vb-accordion-eighteen-top {
    grid-template-columns: 1fr;
    padding: 12px 10px 18px;
  }

  .vb-accordion-eighteen-top h3 {
    font-size: 38px !important;
  }

  .vb-accordion-eighteen-toolbar {
    flex-direction: column;
    align-items: stretch;
  }

  .vb-accordion-eighteen-trigger {
    grid-template-columns: 14px minmax(0, 1fr);
  }

  .vb-accordion-eighteen-trigger em {
    grid-column: 2;
    justify-self: start;
    min-width: 74px;
  }

  .vb-accordion-eighteen-content {
    padding: 0 18px 18px 46px;
  }
}</pre>



<p class="wp-block-paragraph">This notification accordion is useful for dashboard inboxes, admin messages, CRM notifications, account activity logs, update centers, project management tools, and SaaS app interfaces.</p>



<h2 class="wp-block-heading">19. Course Module Accordion</h2>



<p class="wp-block-paragraph"><strong>A course module accordion</strong> is useful for online course pages, learning platforms, coaching websites, workshop pages, lesson previews, and educational landing pages where lessons need to stay organized and easy to scan.</p>



<p class="wp-block-paragraph">This example uses a learning-dashboard style with lesson progress, module numbers, duration labels, progress bars, and multi-open JavaScript behavior. It is visually different from standard FAQ accordions because it feels like a structured course curriculum preview.</p>



<ul class="wp-block-list">
<li>Course curriculum accordion layout</li>
<li>Multi-open module behavior</li>
<li>Lesson duration and progress indicators</li>
<li>Learning platform visual style</li>
<li>Useful for courses, workshops, and tutorials</li>
</ul>



<div class="vb-accordion-nineteen-demo">
  <div class="vb-accordion-nineteen-course" data-vb-accordion-nineteen>
    <div class="vb-accordion-nineteen-hero">
      <span>Example 19</span>
      <h3>Course Module Accordion</h3>
      <p>Preview course lessons, module progress, and learning outcomes inside expandable curriculum cards.</p>

      <div class="vb-accordion-nineteen-progress">
        <strong>Course progress</strong>
        <div><i></i></div>
        <small>42% complete</small>
      </div>
    </div>

    <div class="vb-accordion-nineteen-list">
      <section class="vb-accordion-nineteen-item is-open">
        <button class="vb-accordion-nineteen-trigger" type="button" aria-expanded="true">
          <span>01</span>
          <strong>Accordion fundamentals</strong>
          <small>4 lessons · 28 min</small>
          <em></em>
        </button>
        <div class="vb-accordion-nineteen-panel">
          <div class="vb-accordion-nineteen-content">
            <ul>
              <li>What an accordion component does</li>
              <li>Basic HTML structure</li>
              <li>Simple open and close states</li>
            </ul>
          </div>
        </div>
      </section>

      <section class="vb-accordion-nineteen-item">
        <button class="vb-accordion-nineteen-trigger" type="button" aria-expanded="false">
          <span>02</span>
          <strong>JavaScript interaction</strong>
          <small>5 lessons · 36 min</small>
          <em></em>
        </button>
        <div class="vb-accordion-nineteen-panel">
          <div class="vb-accordion-nineteen-content">
            <ul>
              <li>Click event listeners</li>
              <li>Dynamic max-height animation</li>
              <li>ARIA expanded state updates</li>
            </ul>
          </div>
        </div>
      </section>

      <section class="vb-accordion-nineteen-item">
        <button class="vb-accordion-nineteen-trigger" type="button" aria-expanded="false">
          <span>03</span>
          <strong>Responsive styling</strong>
          <small>3 lessons · 22 min</small>
          <em></em>
        </button>
        <div class="vb-accordion-nineteen-panel">
          <div class="vb-accordion-nineteen-content">
            <ul>
              <li>Mobile spacing and readable tap targets</li>
              <li>Content wrapping and compact layouts</li>
              <li>Better spacing for small screens</li>
            </ul>
          </div>
        </div>
      </section>

      <section class="vb-accordion-nineteen-item">
        <button class="vb-accordion-nineteen-trigger" type="button" aria-expanded="false">
          <span>04</span>
          <strong>Advanced accordion patterns</strong>
          <small>6 lessons · 48 min</small>
          <em></em>
        </button>
        <div class="vb-accordion-nineteen-panel">
          <div class="vb-accordion-nineteen-content">
            <ul>
              <li>Nested accordions</li>
              <li>Searchable FAQ sections</li>
              <li>Reusable multi-instance components</li>
            </ul>
          </div>
        </div>
      </section>
    </div>
  </div>
</div>

<style>
.vb-accordion-nineteen-demo,
.vb-accordion-nineteen-demo * {
  box-sizing: border-box;
}

.vb-accordion-nineteen-demo {
  margin: 28px 0;
  padding: 38px;
  border-radius: 42px 42px 14px 14px;
  background:
    radial-gradient(circle at 18% 20%, rgba(34, 197, 94, 0.16), transparent 34%),
    radial-gradient(circle at 84% 18%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #ecfeff 50%, #ffffff 100%) !important;
  border: 1px solid rgba(74, 222, 128, 0.28);
  box-shadow: 0 24px 70px rgba(22, 101, 52, 0.10);
}

.vb-accordion-nineteen-course {
  display: grid;
  grid-template-columns: minmax(280px, 0.82fr) minmax(0, 1.18fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-accordion-nineteen-hero {
  padding: 30px;
  border-radius: 34px 34px 8px 34px;
  background:
    radial-gradient(circle at 24% 16%, rgba(255,255,255,0.28), transparent 34%),
    linear-gradient(135deg, #065f46, #0891b2) !important;
  box-shadow: 0 28px 80px rgba(8, 145, 178, 0.22);
}

.vb-accordion-nineteen-hero > span {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.20);
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-nineteen-hero h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 5vw, 64px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
}

.vb-accordion-nineteen-hero p {
  margin: 0 0 26px !important;
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-accordion-nineteen-progress {
  padding: 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
}

.vb-accordion-nineteen-progress strong {
  display: block;
  margin-bottom: 12px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-accordion-nineteen-progress div {
  overflow: hidden;
  height: 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.18);
  margin-bottom: 10px;
}

.vb-accordion-nineteen-progress i {
  display: block;
  width: 42%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #bbf7d0, #67e8f9) !important;
}

.vb-accordion-nineteen-progress small {
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-accordion-nineteen-list {
  display: grid;
  align-content: start;
  gap: 14px;
}

.vb-accordion-nineteen-item {
  overflow: hidden;
  border-radius: 26px 26px 26px 8px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.08);
}

.vb-accordion-nineteen-item.is-open {
  border-color: rgba(16, 185, 129, 0.38);
  box-shadow: 0 24px 64px rgba(16, 185, 129, 0.13);
}

.vb-accordion-nineteen-trigger {
  display: grid;
  grid-template-columns: 58px minmax(0, 1fr) 120px 42px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 86px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-nineteen-trigger > span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 58px;
  height: 58px;
  border-radius: 18px;
  background: #dcfce7;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-accordion-nineteen-trigger strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-nineteen-trigger small {
  justify-self: end;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-accordion-nineteen-trigger em {
  position: relative;
  width: 42px;
  height: 42px;
  border-radius: 14px;
  background: #f0fdfa;
  border: 1px solid rgba(20, 184, 166, 0.18);
}

.vb-accordion-nineteen-trigger em::before,
.vb-accordion-nineteen-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 15px;
  height: 2px;
  border-radius: 999px;
  background: #0f766e;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease, transform 0.22s ease;
}

.vb-accordion-nineteen-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-nineteen-item.is-open .vb-accordion-nineteen-trigger em {
  background: #0f766e;
}

.vb-accordion-nineteen-item.is-open .vb-accordion-nineteen-trigger em::before,
.vb-accordion-nineteen-item.is-open .vb-accordion-nineteen-trigger em::after {
  background: #ffffff;
}

.vb-accordion-nineteen-item.is-open .vb-accordion-nineteen-trigger em::after {
  opacity: 0;
}

.vb-accordion-nineteen-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-nineteen-content {
  padding: 0 20px 20px 94px;
}

.vb-accordion-nineteen-content ul {
  display: grid;
  gap: 10px;
  margin: 0 !important;
  padding: 16px 18px !important;
  border-radius: 18px;
  background: #f8fafc;
  list-style: none !important;
}

.vb-accordion-nineteen-content li {
  position: relative;
  margin: 0 !important;
  padding-left: 24px;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 800;
}

.vb-accordion-nineteen-content li::before {
  content: "✓";
  position: absolute;
  left: 0;
  top: 0;
  color: #059669;
  -webkit-text-fill-color: #059669;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vb-accordion-nineteen-course {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 700px) {
  .vb-accordion-nineteen-demo {
    padding: 18px;
    border-radius: 28px 28px 10px 10px;
  }

  .vb-accordion-nineteen-hero {
    padding: 22px;
  }

  .vb-accordion-nineteen-hero h3 {
    font-size: 38px !important;
  }

  .vb-accordion-nineteen-trigger {
    grid-template-columns: 48px minmax(0, 1fr) 38px;
    gap: 12px;
    padding: 16px;
  }

  .vb-accordion-nineteen-trigger > span {
    width: 48px;
    height: 48px;
  }

  .vb-accordion-nineteen-trigger small {
    grid-column: 2;
    justify-self: start;
  }

  .vb-accordion-nineteen-content {
    padding: 0 16px 16px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-nineteen]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-nineteen-item"));

  function updateItem(item) {
    const button = item.querySelector(".vb-accordion-nineteen-trigger");
    const panel = item.querySelector(".vb-accordion-nineteen-panel");
    const isOpen = item.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-nineteen-trigger");

    button.addEventListener("click", function () {
      item.classList.toggle("is-open");
      updateItem(item);
    });

    updateItem(item);
  });

  window.addEventListener("resize", function () {
    items.forEach(updateItem);
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-nineteen]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-nineteen-item"));

  function updateItem(item) {
    const button = item.querySelector(".vb-accordion-nineteen-trigger");
    const panel = item.querySelector(".vb-accordion-nineteen-panel");
    const isOpen = item.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-nineteen-trigger");

    button.addEventListener("click", function () {
      item.classList.toggle("is-open");
      updateItem(item);
    });

    updateItem(item);
  });

  window.addEventListener("resize", function () {
    items.forEach(updateItem);
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-nineteen-demo"&gt;
  &lt;div class="vb-accordion-nineteen-course" data-vb-accordion-nineteen&gt;
    &lt;div class="vb-accordion-nineteen-hero"&gt;
      &lt;span&gt;Example 19&lt;/span&gt;
      &lt;h3&gt;Course Module Accordion&lt;/h3&gt;
      &lt;p&gt;Preview course lessons, module progress, and learning outcomes inside expandable curriculum cards.&lt;/p&gt;

      &lt;div class="vb-accordion-nineteen-progress"&gt;
        &lt;strong&gt;Course progress&lt;/strong&gt;
        &lt;div&gt;&lt;i&gt;&lt;/i&gt;&lt;/div&gt;
        &lt;small&gt;42% complete&lt;/small&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-nineteen-list"&gt;
      &lt;section class="vb-accordion-nineteen-item is-open"&gt;
        &lt;button class="vb-accordion-nineteen-trigger" type="button" aria-expanded="true"&gt;
          &lt;span&gt;01&lt;/span&gt;
          &lt;strong&gt;Accordion fundamentals&lt;/strong&gt;
          &lt;small&gt;4 lessons · 28 min&lt;/small&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-nineteen-panel"&gt;
          &lt;div class="vb-accordion-nineteen-content"&gt;
            &lt;ul&gt;
              &lt;li&gt;What an accordion component does&lt;/li&gt;
              &lt;li&gt;Basic HTML structure&lt;/li&gt;
              &lt;li&gt;Simple open and close states&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-nineteen-item"&gt;
        &lt;button class="vb-accordion-nineteen-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;02&lt;/span&gt;
          &lt;strong&gt;JavaScript interaction&lt;/strong&gt;
          &lt;small&gt;5 lessons · 36 min&lt;/small&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-nineteen-panel"&gt;
          &lt;div class="vb-accordion-nineteen-content"&gt;
            &lt;ul&gt;
              &lt;li&gt;Click event listeners&lt;/li&gt;
              &lt;li&gt;Dynamic max-height animation&lt;/li&gt;
              &lt;li&gt;ARIA expanded state updates&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-nineteen-item"&gt;
        &lt;button class="vb-accordion-nineteen-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;03&lt;/span&gt;
          &lt;strong&gt;Responsive styling&lt;/strong&gt;
          &lt;small&gt;3 lessons · 22 min&lt;/small&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-nineteen-panel"&gt;
          &lt;div class="vb-accordion-nineteen-content"&gt;
            &lt;ul&gt;
              &lt;li&gt;Mobile spacing and readable tap targets&lt;/li&gt;
              &lt;li&gt;Content wrapping and compact layouts&lt;/li&gt;
              &lt;li&gt;Better spacing for small screens&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-nineteen-item"&gt;
        &lt;button class="vb-accordion-nineteen-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;04&lt;/span&gt;
          &lt;strong&gt;Advanced accordion patterns&lt;/strong&gt;
          &lt;small&gt;6 lessons · 48 min&lt;/small&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-nineteen-panel"&gt;
          &lt;div class="vb-accordion-nineteen-content"&gt;
            &lt;ul&gt;
              &lt;li&gt;Nested accordions&lt;/li&gt;
              &lt;li&gt;Searchable FAQ sections&lt;/li&gt;
              &lt;li&gt;Reusable multi-instance components&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-nineteen-demo,
.vb-accordion-nineteen-demo * {
  box-sizing: border-box;
}

.vb-accordion-nineteen-demo {
  margin: 28px 0;
  padding: 38px;
  border-radius: 42px 42px 14px 14px;
  background:
    radial-gradient(circle at 18% 20%, rgba(34, 197, 94, 0.16), transparent 34%),
    radial-gradient(circle at 84% 18%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #ecfeff 50%, #ffffff 100%) !important;
  border: 1px solid rgba(74, 222, 128, 0.28);
  box-shadow: 0 24px 70px rgba(22, 101, 52, 0.10);
}

.vb-accordion-nineteen-course {
  display: grid;
  grid-template-columns: minmax(280px, 0.82fr) minmax(0, 1.18fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-accordion-nineteen-hero {
  padding: 30px;
  border-radius: 34px 34px 8px 34px;
  background:
    radial-gradient(circle at 24% 16%, rgba(255,255,255,0.28), transparent 34%),
    linear-gradient(135deg, #065f46, #0891b2) !important;
  box-shadow: 0 28px 80px rgba(8, 145, 178, 0.22);
}

.vb-accordion-nineteen-hero &gt; span {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.20);
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-nineteen-hero h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 5vw, 64px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
}

.vb-accordion-nineteen-hero p {
  margin: 0 0 26px !important;
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-accordion-nineteen-progress {
  padding: 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
}

.vb-accordion-nineteen-progress strong {
  display: block;
  margin-bottom: 12px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-accordion-nineteen-progress div {
  overflow: hidden;
  height: 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.18);
  margin-bottom: 10px;
}

.vb-accordion-nineteen-progress i {
  display: block;
  width: 42%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #bbf7d0, #67e8f9) !important;
}

.vb-accordion-nineteen-progress small {
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-accordion-nineteen-list {
  display: grid;
  align-content: start;
  gap: 14px;
}

.vb-accordion-nineteen-item {
  overflow: hidden;
  border-radius: 26px 26px 26px 8px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.08);
}

.vb-accordion-nineteen-item.is-open {
  border-color: rgba(16, 185, 129, 0.38);
  box-shadow: 0 24px 64px rgba(16, 185, 129, 0.13);
}

.vb-accordion-nineteen-trigger {
  display: grid;
  grid-template-columns: 58px minmax(0, 1fr) 120px 42px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 86px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-nineteen-trigger &gt; span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 58px;
  height: 58px;
  border-radius: 18px;
  background: #dcfce7;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-accordion-nineteen-trigger strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-nineteen-trigger small {
  justify-self: end;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-accordion-nineteen-trigger em {
  position: relative;
  width: 42px;
  height: 42px;
  border-radius: 14px;
  background: #f0fdfa;
  border: 1px solid rgba(20, 184, 166, 0.18);
}

.vb-accordion-nineteen-trigger em::before,
.vb-accordion-nineteen-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 15px;
  height: 2px;
  border-radius: 999px;
  background: #0f766e;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease, transform 0.22s ease;
}

.vb-accordion-nineteen-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-nineteen-item.is-open .vb-accordion-nineteen-trigger em {
  background: #0f766e;
}

.vb-accordion-nineteen-item.is-open .vb-accordion-nineteen-trigger em::before,
.vb-accordion-nineteen-item.is-open .vb-accordion-nineteen-trigger em::after {
  background: #ffffff;
}

.vb-accordion-nineteen-item.is-open .vb-accordion-nineteen-trigger em::after {
  opacity: 0;
}

.vb-accordion-nineteen-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-nineteen-content {
  padding: 0 20px 20px 94px;
}

.vb-accordion-nineteen-content ul {
  display: grid;
  gap: 10px;
  margin: 0 !important;
  padding: 16px 18px !important;
  border-radius: 18px;
  background: #f8fafc;
  list-style: none !important;
}

.vb-accordion-nineteen-content li {
  position: relative;
  margin: 0 !important;
  padding-left: 24px;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 800;
}

.vb-accordion-nineteen-content li::before {
  content: "✓";
  position: absolute;
  left: 0;
  top: 0;
  color: #059669;
  -webkit-text-fill-color: #059669;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vb-accordion-nineteen-course {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 700px) {
  .vb-accordion-nineteen-demo {
    padding: 18px;
    border-radius: 28px 28px 10px 10px;
  }

  .vb-accordion-nineteen-hero {
    padding: 22px;
  }

  .vb-accordion-nineteen-hero h3 {
    font-size: 38px !important;
  }

  .vb-accordion-nineteen-trigger {
    grid-template-columns: 48px minmax(0, 1fr) 38px;
    gap: 12px;
    padding: 16px;
  }

  .vb-accordion-nineteen-trigger &gt; span {
    width: 48px;
    height: 48px;
  }

  .vb-accordion-nineteen-trigger small {
    grid-column: 2;
    justify-self: start;
  }

  .vb-accordion-nineteen-content {
    padding: 0 16px 16px;
  }
}</pre>



<p class="wp-block-paragraph">This course module accordion is useful for online courses, tutorial libraries, workshop landing pages, coaching programs, digital learning platforms, and educational websites that need structured lesson previews.</p>



<h2 class="wp-block-heading">20. Restaurant Menu Accordion</h2>



<p class="wp-block-paragraph"><strong>A restaurant menu accordion</strong> is useful for restaurant websites, cafe pages, food delivery menus, catering services, recipe sections, and hospitality landing pages where food categories need to stay compact and easy to browse.</p>



<p class="wp-block-paragraph">This example uses a warm restaurant-style layout with menu categories, price tags, decorative dividers, and one-open-at-a-time JavaScript behavior. The design is intentionally different from dashboard or SaaS accordions because it uses a hospitality-inspired visual style.</p>



<ul class="wp-block-list">
<li>Restaurant menu accordion layout</li>
<li>One-open-at-a-time category behavior</li>
<li>Food items with prices and descriptions</li>
<li>Warm hospitality-inspired design</li>
<li>Useful for restaurants, cafes, and catering websites</li>
</ul>



<div class="vb-accordion-twenty-demo">
  <div class="vb-accordion-twenty-menu" data-vb-accordion-twenty>
    <div class="vb-accordion-twenty-cover">
      <span>Example 20</span>
      <h3>Restaurant Menu Accordion</h3>
      <p>Browse menu categories and reveal dishes without overwhelming the page.</p>
      <div class="vb-accordion-twenty-hours">
        <strong>Open today</strong>
        <small>12:00 &#8211; 22:00</small>
      </div>
    </div>

    <div class="vb-accordion-twenty-board">
      <section class="vb-accordion-twenty-item is-open">
        <button class="vb-accordion-twenty-trigger" type="button" aria-expanded="true">
          <span>Starters</span>
          <small>4 dishes</small>
          <em></em>
        </button>
        <div class="vb-accordion-twenty-panel">
          <div class="vb-accordion-twenty-content">
            <article>
              <div>
                <strong>Roasted tomato bruschetta</strong>
                <p>Toasted sourdough, basil, garlic, olive oil, and slow-roasted tomatoes.</p>
              </div>
              <span>€8</span>
            </article>
            <article>
              <div>
                <strong>Crispy halloumi bites</strong>
                <p>Golden halloumi, lemon yogurt, herbs, and chili honey.</p>
              </div>
              <span>€9</span>
            </article>
          </div>
        </div>
      </section>

      <section class="vb-accordion-twenty-item">
        <button class="vb-accordion-twenty-trigger" type="button" aria-expanded="false">
          <span>Main courses</span>
          <small>6 dishes</small>
          <em></em>
        </button>
        <div class="vb-accordion-twenty-panel">
          <div class="vb-accordion-twenty-content">
            <article>
              <div>
                <strong>Herb grilled chicken</strong>
                <p>Charred vegetables, garlic potatoes, lemon butter, and fresh herbs.</p>
              </div>
              <span>€18</span>
            </article>
            <article>
              <div>
                <strong>Mushroom truffle risotto</strong>
                <p>Creamy arborio rice, parmesan, wild mushrooms, and truffle oil.</p>
              </div>
              <span>€17</span>
            </article>
          </div>
        </div>
      </section>

      <section class="vb-accordion-twenty-item">
        <button class="vb-accordion-twenty-trigger" type="button" aria-expanded="false">
          <span>Desserts</span>
          <small>3 dishes</small>
          <em></em>
        </button>
        <div class="vb-accordion-twenty-panel">
          <div class="vb-accordion-twenty-content">
            <article>
              <div>
                <strong>Vanilla panna cotta</strong>
                <p>Berry compote, mint, toasted almonds, and smooth vanilla cream.</p>
              </div>
              <span>€7</span>
            </article>
            <article>
              <div>
                <strong>Chocolate lava cake</strong>
                <p>Warm chocolate cake, soft center, sea salt, and vanilla ice cream.</p>
              </div>
              <span>€8</span>
            </article>
          </div>
        </div>
      </section>

      <section class="vb-accordion-twenty-item">
        <button class="vb-accordion-twenty-trigger" type="button" aria-expanded="false">
          <span>Drinks</span>
          <small>8 options</small>
          <em></em>
        </button>
        <div class="vb-accordion-twenty-panel">
          <div class="vb-accordion-twenty-content">
            <article>
              <div>
                <strong>Fresh citrus lemonade</strong>
                <p>Lemon, orange, mint, sparkling water, and crushed ice.</p>
              </div>
              <span>€5</span>
            </article>
            <article>
              <div>
                <strong>Iced berry tea</strong>
                <p>Cold black tea, forest berries, lime, and light syrup.</p>
              </div>
              <span>€5</span>
            </article>
          </div>
        </div>
      </section>
    </div>
  </div>
</div>

<style>
.vb-accordion-twenty-demo,
.vb-accordion-twenty-demo * {
  box-sizing: border-box;
}

.vb-accordion-twenty-demo {
  margin: 28px 0;
  padding: 38px;
  border-radius: 14px;
  background:
    radial-gradient(circle at 16% 18%, rgba(251, 146, 60, 0.18), transparent 34%),
    radial-gradient(circle at 84% 22%, rgba(120, 53, 15, 0.12), transparent 36%),
    linear-gradient(135deg, #fff7ed 0%, #fef3c7 52%, #ffffff 100%) !important;
  border: 1px solid rgba(251, 146, 60, 0.30);
  box-shadow: 0 24px 70px rgba(120, 53, 15, 0.12);
}

.vb-accordion-twenty-menu {
  display: grid;
  grid-template-columns: minmax(280px, 0.78fr) minmax(0, 1.22fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-accordion-twenty-cover {
  position: relative;
  overflow: hidden;
  min-height: 560px;
  padding: 30px;
  border-radius: 12px 44px 12px 44px;
  background:
    radial-gradient(circle at 26% 18%, rgba(255,255,255,0.26), transparent 34%),
    linear-gradient(135deg, #7c2d12, #b45309 56%, #f97316) !important;
  box-shadow: 0 30px 90px rgba(154, 52, 18, 0.24);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.vb-accordion-twenty-cover::before {
  content: "";
  position: absolute;
  right: -90px;
  top: -90px;
  width: 240px;
  height: 240px;
  border-radius: 999px;
  border: 34px solid rgba(255,255,255,0.10);
}

.vb-accordion-twenty-cover > span {
  align-self: flex-start;
  display: inline-flex;
  position: relative;
  z-index: 2;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.20);
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-twenty-cover h3 {
  position: relative;
  z-index: 2;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(42px, 5vw, 72px) !important;
  line-height: 0.88 !important;
  font-weight: 950 !important;
  letter-spacing: -0.09em;
}

.vb-accordion-twenty-cover p {
  position: relative;
  z-index: 2;
  margin: 0 !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-accordion-twenty-hours {
  position: relative;
  z-index: 2;
  padding: 18px;
  border-radius: 24px 8px 24px 8px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  margin-top: 28px;
}

.vb-accordion-twenty-hours strong {
  display: block;
  margin-bottom: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-accordion-twenty-hours small {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-accordion-twenty-board {
  display: grid;
  align-content: start;
  gap: 13px;
}

.vb-accordion-twenty-item {
  overflow: hidden;
  border-radius: 8px 28px 8px 28px;
  background: #fffaf0;
  border: 1px solid rgba(180, 83, 9, 0.20);
  box-shadow: 0 18px 46px rgba(120, 53, 15, 0.08);
}

.vb-accordion-twenty-item.is-open {
  border-color: rgba(180, 83, 9, 0.42);
  box-shadow: 0 24px 62px rgba(180, 83, 9, 0.14);
}

.vb-accordion-twenty-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 86px 42px;
  align-items: center;
  gap: 14px;
  width: 100%;
  min-height: 82px;
  padding: 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-twenty-trigger span {
  color: #431407 !important;
  -webkit-text-fill-color: #431407 !important;
  font-size: 24px;
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-accordion-twenty-trigger small {
  justify-self: end;
  padding: 8px 11px;
  border-radius: 999px;
  background: #ffedd5;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-accordion-twenty-trigger em {
  position: relative;
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: #ffffff;
  border: 1px solid rgba(180, 83, 9, 0.22);
}

.vb-accordion-twenty-trigger em::before,
.vb-accordion-twenty-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 15px;
  height: 2px;
  border-radius: 999px;
  background: #9a3412;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease, transform 0.22s ease;
}

.vb-accordion-twenty-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-twenty-item.is-open .vb-accordion-twenty-trigger em {
  background: #9a3412;
}

.vb-accordion-twenty-item.is-open .vb-accordion-twenty-trigger em::before,
.vb-accordion-twenty-item.is-open .vb-accordion-twenty-trigger em::after {
  background: #ffffff;
}

.vb-accordion-twenty-item.is-open .vb-accordion-twenty-trigger em::after {
  opacity: 0;
}

.vb-accordion-twenty-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-twenty-content {
  display: grid;
  gap: 12px;
  padding: 0 20px 20px;
}

.vb-accordion-twenty-content article {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 54px;
  gap: 14px;
  align-items: start;
  padding: 16px;
  border-radius: 18px 6px 18px 6px;
  background: #ffffff;
  border: 1px solid rgba(254, 215, 170, 0.9);
}

.vb-accordion-twenty-content strong {
  display: block;
  margin-bottom: 6px;
  color: #431407 !important;
  -webkit-text-fill-color: #431407 !important;
  font-size: 17px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-accordion-twenty-content p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-accordion-twenty-content article > span {
  justify-self: end;
  color: #b45309 !important;
  -webkit-text-fill-color: #b45309 !important;
  font-size: 20px;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vb-accordion-twenty-menu {
    grid-template-columns: 1fr;
  }

  .vb-accordion-twenty-cover {
    min-height: auto;
  }
}

@media (max-width: 640px) {
  .vb-accordion-twenty-demo {
    padding: 18px;
  }

  .vb-accordion-twenty-cover {
    padding: 24px;
    border-radius: 10px 32px 10px 32px;
  }

  .vb-accordion-twenty-cover h3 {
    font-size: 42px !important;
  }

  .vb-accordion-twenty-trigger {
    grid-template-columns: 1fr 40px;
    padding: 18px;
  }

  .vb-accordion-twenty-trigger small {
    grid-column: 1;
    justify-self: start;
  }

  .vb-accordion-twenty-content article {
    grid-template-columns: 1fr;
  }

  .vb-accordion-twenty-content article > span {
    justify-self: start;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-twenty]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-twenty-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-twenty-trigger");
    const panel = item.querySelector(".vb-accordion-twenty-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-twenty-trigger");
    const panel = item.querySelector(".vb-accordion-twenty-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-twenty-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-twenty-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-twenty-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-twenty]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-twenty-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-twenty-trigger");
    const panel = item.querySelector(".vb-accordion-twenty-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-twenty-trigger");
    const panel = item.querySelector(".vb-accordion-twenty-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-twenty-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-twenty-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-twenty-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-twenty-demo"&gt;
  &lt;div class="vb-accordion-twenty-menu" data-vb-accordion-twenty&gt;
    &lt;div class="vb-accordion-twenty-cover"&gt;
      &lt;span&gt;Example 20&lt;/span&gt;
      &lt;h3&gt;Restaurant Menu Accordion&lt;/h3&gt;
      &lt;p&gt;Browse menu categories and reveal dishes without overwhelming the page.&lt;/p&gt;
      &lt;div class="vb-accordion-twenty-hours"&gt;
        &lt;strong&gt;Open today&lt;/strong&gt;
        &lt;small&gt;12:00 - 22:00&lt;/small&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-twenty-board"&gt;
      &lt;section class="vb-accordion-twenty-item is-open"&gt;
        &lt;button class="vb-accordion-twenty-trigger" type="button" aria-expanded="true"&gt;
          &lt;span&gt;Starters&lt;/span&gt;
          &lt;small&gt;4 dishes&lt;/small&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-twenty-panel"&gt;
          &lt;div class="vb-accordion-twenty-content"&gt;
            &lt;article&gt;
              &lt;div&gt;
                &lt;strong&gt;Roasted tomato bruschetta&lt;/strong&gt;
                &lt;p&gt;Toasted sourdough, basil, garlic, olive oil, and slow-roasted tomatoes.&lt;/p&gt;
              &lt;/div&gt;
              &lt;span&gt;€8&lt;/span&gt;
            &lt;/article&gt;
            &lt;article&gt;
              &lt;div&gt;
                &lt;strong&gt;Crispy halloumi bites&lt;/strong&gt;
                &lt;p&gt;Golden halloumi, lemon yogurt, herbs, and chili honey.&lt;/p&gt;
              &lt;/div&gt;
              &lt;span&gt;€9&lt;/span&gt;
            &lt;/article&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-twenty-item"&gt;
        &lt;button class="vb-accordion-twenty-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Main courses&lt;/span&gt;
          &lt;small&gt;6 dishes&lt;/small&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-twenty-panel"&gt;
          &lt;div class="vb-accordion-twenty-content"&gt;
            &lt;article&gt;
              &lt;div&gt;
                &lt;strong&gt;Herb grilled chicken&lt;/strong&gt;
                &lt;p&gt;Charred vegetables, garlic potatoes, lemon butter, and fresh herbs.&lt;/p&gt;
              &lt;/div&gt;
              &lt;span&gt;€18&lt;/span&gt;
            &lt;/article&gt;
            &lt;article&gt;
              &lt;div&gt;
                &lt;strong&gt;Mushroom truffle risotto&lt;/strong&gt;
                &lt;p&gt;Creamy arborio rice, parmesan, wild mushrooms, and truffle oil.&lt;/p&gt;
              &lt;/div&gt;
              &lt;span&gt;€17&lt;/span&gt;
            &lt;/article&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-twenty-item"&gt;
        &lt;button class="vb-accordion-twenty-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Desserts&lt;/span&gt;
          &lt;small&gt;3 dishes&lt;/small&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-twenty-panel"&gt;
          &lt;div class="vb-accordion-twenty-content"&gt;
            &lt;article&gt;
              &lt;div&gt;
                &lt;strong&gt;Vanilla panna cotta&lt;/strong&gt;
                &lt;p&gt;Berry compote, mint, toasted almonds, and smooth vanilla cream.&lt;/p&gt;
              &lt;/div&gt;
              &lt;span&gt;€7&lt;/span&gt;
            &lt;/article&gt;
            &lt;article&gt;
              &lt;div&gt;
                &lt;strong&gt;Chocolate lava cake&lt;/strong&gt;
                &lt;p&gt;Warm chocolate cake, soft center, sea salt, and vanilla ice cream.&lt;/p&gt;
              &lt;/div&gt;
              &lt;span&gt;€8&lt;/span&gt;
            &lt;/article&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-twenty-item"&gt;
        &lt;button class="vb-accordion-twenty-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Drinks&lt;/span&gt;
          &lt;small&gt;8 options&lt;/small&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-twenty-panel"&gt;
          &lt;div class="vb-accordion-twenty-content"&gt;
            &lt;article&gt;
              &lt;div&gt;
                &lt;strong&gt;Fresh citrus lemonade&lt;/strong&gt;
                &lt;p&gt;Lemon, orange, mint, sparkling water, and crushed ice.&lt;/p&gt;
              &lt;/div&gt;
              &lt;span&gt;€5&lt;/span&gt;
            &lt;/article&gt;
            &lt;article&gt;
              &lt;div&gt;
                &lt;strong&gt;Iced berry tea&lt;/strong&gt;
                &lt;p&gt;Cold black tea, forest berries, lime, and light syrup.&lt;/p&gt;
              &lt;/div&gt;
              &lt;span&gt;€5&lt;/span&gt;
            &lt;/article&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-twenty-demo,
.vb-accordion-twenty-demo * {
  box-sizing: border-box;
}

.vb-accordion-twenty-demo {
  margin: 28px 0;
  padding: 38px;
  border-radius: 14px;
  background:
    radial-gradient(circle at 16% 18%, rgba(251, 146, 60, 0.18), transparent 34%),
    radial-gradient(circle at 84% 22%, rgba(120, 53, 15, 0.12), transparent 36%),
    linear-gradient(135deg, #fff7ed 0%, #fef3c7 52%, #ffffff 100%) !important;
  border: 1px solid rgba(251, 146, 60, 0.30);
  box-shadow: 0 24px 70px rgba(120, 53, 15, 0.12);
}

.vb-accordion-twenty-menu {
  display: grid;
  grid-template-columns: minmax(280px, 0.78fr) minmax(0, 1.22fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-accordion-twenty-cover {
  position: relative;
  overflow: hidden;
  min-height: 560px;
  padding: 30px;
  border-radius: 12px 44px 12px 44px;
  background:
    radial-gradient(circle at 26% 18%, rgba(255,255,255,0.26), transparent 34%),
    linear-gradient(135deg, #7c2d12, #b45309 56%, #f97316) !important;
  box-shadow: 0 30px 90px rgba(154, 52, 18, 0.24);
  display: flex;
  flex-direction: column;
  justify-content: space-between;
}

.vb-accordion-twenty-cover::before {
  content: "";
  position: absolute;
  right: -90px;
  top: -90px;
  width: 240px;
  height: 240px;
  border-radius: 999px;
  border: 34px solid rgba(255,255,255,0.10);
}

.vb-accordion-twenty-cover &gt; span {
  align-self: flex-start;
  display: inline-flex;
  position: relative;
  z-index: 2;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.20);
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-twenty-cover h3 {
  position: relative;
  z-index: 2;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(42px, 5vw, 72px) !important;
  line-height: 0.88 !important;
  font-weight: 950 !important;
  letter-spacing: -0.09em;
}

.vb-accordion-twenty-cover p {
  position: relative;
  z-index: 2;
  margin: 0 !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-accordion-twenty-hours {
  position: relative;
  z-index: 2;
  padding: 18px;
  border-radius: 24px 8px 24px 8px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  margin-top: 28px;
}

.vb-accordion-twenty-hours strong {
  display: block;
  margin-bottom: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-accordion-twenty-hours small {
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-accordion-twenty-board {
  display: grid;
  align-content: start;
  gap: 13px;
}

.vb-accordion-twenty-item {
  overflow: hidden;
  border-radius: 8px 28px 8px 28px;
  background: #fffaf0;
  border: 1px solid rgba(180, 83, 9, 0.20);
  box-shadow: 0 18px 46px rgba(120, 53, 15, 0.08);
}

.vb-accordion-twenty-item.is-open {
  border-color: rgba(180, 83, 9, 0.42);
  box-shadow: 0 24px 62px rgba(180, 83, 9, 0.14);
}

.vb-accordion-twenty-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 86px 42px;
  align-items: center;
  gap: 14px;
  width: 100%;
  min-height: 82px;
  padding: 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-twenty-trigger span {
  color: #431407 !important;
  -webkit-text-fill-color: #431407 !important;
  font-size: 24px;
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-accordion-twenty-trigger small {
  justify-self: end;
  padding: 8px 11px;
  border-radius: 999px;
  background: #ffedd5;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-accordion-twenty-trigger em {
  position: relative;
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: #ffffff;
  border: 1px solid rgba(180, 83, 9, 0.22);
}

.vb-accordion-twenty-trigger em::before,
.vb-accordion-twenty-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 15px;
  height: 2px;
  border-radius: 999px;
  background: #9a3412;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease, transform 0.22s ease;
}

.vb-accordion-twenty-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-twenty-item.is-open .vb-accordion-twenty-trigger em {
  background: #9a3412;
}

.vb-accordion-twenty-item.is-open .vb-accordion-twenty-trigger em::before,
.vb-accordion-twenty-item.is-open .vb-accordion-twenty-trigger em::after {
  background: #ffffff;
}

.vb-accordion-twenty-item.is-open .vb-accordion-twenty-trigger em::after {
  opacity: 0;
}

.vb-accordion-twenty-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-twenty-content {
  display: grid;
  gap: 12px;
  padding: 0 20px 20px;
}

.vb-accordion-twenty-content article {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 54px;
  gap: 14px;
  align-items: start;
  padding: 16px;
  border-radius: 18px 6px 18px 6px;
  background: #ffffff;
  border: 1px solid rgba(254, 215, 170, 0.9);
}

.vb-accordion-twenty-content strong {
  display: block;
  margin-bottom: 6px;
  color: #431407 !important;
  -webkit-text-fill-color: #431407 !important;
  font-size: 17px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-accordion-twenty-content p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-accordion-twenty-content article &gt; span {
  justify-self: end;
  color: #b45309 !important;
  -webkit-text-fill-color: #b45309 !important;
  font-size: 20px;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vb-accordion-twenty-menu {
    grid-template-columns: 1fr;
  }

  .vb-accordion-twenty-cover {
    min-height: auto;
  }
}

@media (max-width: 640px) {
  .vb-accordion-twenty-demo {
    padding: 18px;
  }

  .vb-accordion-twenty-cover {
    padding: 24px;
    border-radius: 10px 32px 10px 32px;
  }

  .vb-accordion-twenty-cover h3 {
    font-size: 42px !important;
  }

  .vb-accordion-twenty-trigger {
    grid-template-columns: 1fr 40px;
    padding: 18px;
  }

  .vb-accordion-twenty-trigger small {
    grid-column: 1;
    justify-self: start;
  }

  .vb-accordion-twenty-content article {
    grid-template-columns: 1fr;
  }

  .vb-accordion-twenty-content article &gt; span {
    justify-self: start;
  }
}</pre>



<p class="wp-block-paragraph">This restaurant menu accordion is useful for restaurants, cafes, bakeries, food delivery websites, catering pages, hotel dining sections, recipe collections, and any hospitality website that needs expandable menu categories.</p>



<h2 class="wp-block-heading">21. Product Details Accordion</h2>



<p class="wp-block-paragraph"><strong>A product details accordion</strong> is useful for ecommerce product pages where technical information, shipping details, materials, sizing, warranty information, and care instructions should stay organized without making the product page too long.</p>



<p class="wp-block-paragraph">This example uses a premium product page layout with a product card, stock badge, specification rows, and one-open-at-a-time JavaScript behavior. It is designed for ecommerce and product information sections rather than a normal FAQ block.</p>



<ul class="wp-block-list">
<li>Ecommerce product details accordion</li>
<li>One-open-at-a-time behavior</li>
<li>Specification rows and product information</li>
<li>Stock badge and product-style card</li>
<li>Useful for product pages and online stores</li>
</ul>



<div class="vb-accordion-twentyone-demo">
  <div class="vb-accordion-twentyone-layout" data-vb-accordion-twentyone>
    <div class="vb-accordion-twentyone-product">
      <span>Example 21</span>
      <div class="vb-accordion-twentyone-image">
        <div class="vb-accordion-twentyone-box">
          <i></i>
          <i></i>
          <i></i>
        </div>
      </div>
      <h3>Product Details Accordion</h3>
      <p>Use expandable product information blocks to keep ecommerce pages clean and easy to scan.</p>
      <div class="vb-accordion-twentyone-stock">
        <strong>In stock</strong>
        <small>Ships in 1-2 business days</small>
      </div>
    </div>

    <div class="vb-accordion-twentyone-info">
      <section class="vb-accordion-twentyone-item is-open">
        <button class="vb-accordion-twentyone-trigger" type="button" aria-expanded="true">
          <span>Materials and build</span>
          <em></em>
        </button>
        <div class="vb-accordion-twentyone-panel">
          <div class="vb-accordion-twentyone-content">
            <div class="vb-accordion-twentyone-spec">
              <strong>Frame</strong>
              <span>Powder-coated aluminum</span>
            </div>
            <div class="vb-accordion-twentyone-spec">
              <strong>Surface</strong>
              <span>Scratch-resistant finish</span>
            </div>
            <p>The accordion can be used to show material quality, construction details, certifications, and product durability notes.</p>
          </div>
        </div>
      </section>

      <section class="vb-accordion-twentyone-item">
        <button class="vb-accordion-twentyone-trigger" type="button" aria-expanded="false">
          <span>Dimensions and sizing</span>
          <em></em>
        </button>
        <div class="vb-accordion-twentyone-panel">
          <div class="vb-accordion-twentyone-content">
            <div class="vb-accordion-twentyone-spec">
              <strong>Width</strong>
              <span>120 cm</span>
            </div>
            <div class="vb-accordion-twentyone-spec">
              <strong>Height</strong>
              <span>86 cm</span>
            </div>
            <p>Use this panel for size charts, measurement notes, product variations, and fitting information.</p>
          </div>
        </div>
      </section>

      <section class="vb-accordion-twentyone-item">
        <button class="vb-accordion-twentyone-trigger" type="button" aria-expanded="false">
          <span>Shipping and delivery</span>
          <em></em>
        </button>
        <div class="vb-accordion-twentyone-panel">
          <div class="vb-accordion-twentyone-content">
            <div class="vb-accordion-twentyone-spec">
              <strong>Dispatch</strong>
              <span>1-2 business days</span>
            </div>
            <div class="vb-accordion-twentyone-spec">
              <strong>Delivery</strong>
              <span>Tracked courier</span>
            </div>
            <p>This section can explain shipping regions, delivery time, packaging, pickup options, and tracking details.</p>
          </div>
        </div>
      </section>

      <section class="vb-accordion-twentyone-item">
        <button class="vb-accordion-twentyone-trigger" type="button" aria-expanded="false">
          <span>Warranty and returns</span>
          <em></em>
        </button>
        <div class="vb-accordion-twentyone-panel">
          <div class="vb-accordion-twentyone-content">
            <div class="vb-accordion-twentyone-spec">
              <strong>Warranty</strong>
              <span>24 months</span>
            </div>
            <div class="vb-accordion-twentyone-spec">
              <strong>Returns</strong>
              <span>14-day return window</span>
            </div>
            <p>Use this area for return rules, warranty coverage, replacement details, and customer support information.</p>
          </div>
        </div>
      </section>
    </div>
  </div>
</div>

<style>
.vb-accordion-twentyone-demo,
.vb-accordion-twentyone-demo * {
  box-sizing: border-box;
}

.vb-accordion-twentyone-demo {
  margin: 28px 0;
  padding: 38px;
  border-radius: 46px 46px 46px 10px;
  background:
    radial-gradient(circle at 16% 20%, rgba(15, 23, 42, 0.08), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(59, 130, 246, 0.14), transparent 36%),
    linear-gradient(135deg, #f8fafc 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.22);
  box-shadow: 0 24px 70px rgba(30, 41, 59, 0.10);
}

.vb-accordion-twentyone-layout {
  display: grid;
  grid-template-columns: minmax(280px, 0.78fr) minmax(0, 1.22fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-accordion-twentyone-product {
  overflow: hidden;
  padding: 28px;
  border-radius: 36px 36px 36px 8px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-accordion-twentyone-product > span {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-twentyone-image {
  position: relative;
  min-height: 260px;
  margin-bottom: 24px;
  border-radius: 30px 30px 30px 8px;
  background:
    radial-gradient(circle at 25% 18%, rgba(255,255,255,0.24), transparent 34%),
    linear-gradient(135deg, #1e293b, #2563eb 58%, #06b6d4) !important;
  overflow: hidden;
}

.vb-accordion-twentyone-box {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 170px;
  height: 150px;
  border-radius: 28px;
  background: rgba(255,255,255,0.16);
  border: 1px solid rgba(255,255,255,0.20);
  transform: translate(-50%, -50%) rotate(-8deg);
  box-shadow: 0 28px 70px rgba(2, 6, 23, 0.26);
}

.vb-accordion-twentyone-box i {
  position: absolute;
  display: block;
  border-radius: 999px;
  background: rgba(255,255,255,0.55);
}

.vb-accordion-twentyone-box i:nth-child(1) {
  left: 24px;
  top: 28px;
  width: 74px;
  height: 12px;
}

.vb-accordion-twentyone-box i:nth-child(2) {
  left: 24px;
  top: 58px;
  width: 118px;
  height: 12px;
}

.vb-accordion-twentyone-box i:nth-child(3) {
  left: 24px;
  top: 92px;
  width: 92px;
  height: 34px;
  border-radius: 14px;
  background: #ffffff;
}

.vb-accordion-twentyone-product h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 58px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-twentyone-product p {
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-accordion-twentyone-stock {
  display: grid;
  gap: 4px;
  padding: 16px;
  border-radius: 20px;
  background: #ecfdf5;
  border: 1px solid rgba(16, 185, 129, 0.18);
}

.vb-accordion-twentyone-stock strong {
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-accordion-twentyone-stock small {
  color: #065f46 !important;
  -webkit-text-fill-color: #065f46 !important;
  font-size: 13px;
  font-weight: 800;
}

.vb-accordion-twentyone-info {
  display: grid;
  align-content: start;
  gap: 13px;
}

.vb-accordion-twentyone-item {
  overflow: hidden;
  border-radius: 8px 28px 28px 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.07);
}

.vb-accordion-twentyone-item.is-open {
  border-color: rgba(37, 99, 235, 0.34);
  box-shadow: 0 24px 64px rgba(37, 99, 235, 0.12);
}

.vb-accordion-twentyone-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 44px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 76px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-twentyone-trigger span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 20px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.045em;
}

.vb-accordion-twentyone-trigger em {
  position: relative;
  width: 44px;
  height: 44px;
  border-radius: 16px;
  background: #eff6ff;
  border: 1px solid rgba(37, 99, 235, 0.16);
}

.vb-accordion-twentyone-trigger em::before,
.vb-accordion-twentyone-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 16px;
  height: 2px;
  border-radius: 999px;
  background: #2563eb;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease, transform 0.22s ease;
}

.vb-accordion-twentyone-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-twentyone-item.is-open .vb-accordion-twentyone-trigger em {
  background: #2563eb;
}

.vb-accordion-twentyone-item.is-open .vb-accordion-twentyone-trigger em::before,
.vb-accordion-twentyone-item.is-open .vb-accordion-twentyone-trigger em::after {
  background: #ffffff;
}

.vb-accordion-twentyone-item.is-open .vb-accordion-twentyone-trigger em::after {
  opacity: 0;
}

.vb-accordion-twentyone-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-twentyone-content {
  display: grid;
  gap: 10px;
  padding: 0 20px 20px;
}

.vb-accordion-twentyone-spec {
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr);
  gap: 14px;
  padding: 13px 14px;
  border-radius: 16px;
  background: #f8fafc;
}

.vb-accordion-twentyone-spec strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-accordion-twentyone-spec span {
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  font-weight: 800;
}

.vb-accordion-twentyone-content p {
  margin: 6px 0 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-accordion-twentyone-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-accordion-twentyone-demo {
    padding: 18px;
    border-radius: 32px 32px 32px 10px;
  }

  .vb-accordion-twentyone-product {
    padding: 22px;
  }

  .vb-accordion-twentyone-product h3 {
    font-size: 38px !important;
  }

  .vb-accordion-twentyone-spec {
    grid-template-columns: 1fr;
    gap: 4px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-twentyone]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-twentyone-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-twentyone-trigger");
    const panel = item.querySelector(".vb-accordion-twentyone-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-twentyone-trigger");
    const panel = item.querySelector(".vb-accordion-twentyone-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-twentyone-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-twentyone-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-twentyone-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-twentyone]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-twentyone-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-twentyone-trigger");
    const panel = item.querySelector(".vb-accordion-twentyone-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-twentyone-trigger");
    const panel = item.querySelector(".vb-accordion-twentyone-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-twentyone-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-twentyone-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-twentyone-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-twentyone-demo"&gt;
  &lt;div class="vb-accordion-twentyone-layout" data-vb-accordion-twentyone&gt;
    &lt;div class="vb-accordion-twentyone-product"&gt;
      &lt;span&gt;Example 21&lt;/span&gt;
      &lt;div class="vb-accordion-twentyone-image"&gt;
        &lt;div class="vb-accordion-twentyone-box"&gt;
          &lt;i&gt;&lt;/i&gt;
          &lt;i&gt;&lt;/i&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;h3&gt;Product Details Accordion&lt;/h3&gt;
      &lt;p&gt;Use expandable product information blocks to keep ecommerce pages clean and easy to scan.&lt;/p&gt;
      &lt;div class="vb-accordion-twentyone-stock"&gt;
        &lt;strong&gt;In stock&lt;/strong&gt;
        &lt;small&gt;Ships in 1-2 business days&lt;/small&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-twentyone-info"&gt;
      &lt;section class="vb-accordion-twentyone-item is-open"&gt;
        &lt;button class="vb-accordion-twentyone-trigger" type="button" aria-expanded="true"&gt;
          &lt;span&gt;Materials and build&lt;/span&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-twentyone-panel"&gt;
          &lt;div class="vb-accordion-twentyone-content"&gt;
            &lt;div class="vb-accordion-twentyone-spec"&gt;
              &lt;strong&gt;Frame&lt;/strong&gt;
              &lt;span&gt;Powder-coated aluminum&lt;/span&gt;
            &lt;/div&gt;
            &lt;div class="vb-accordion-twentyone-spec"&gt;
              &lt;strong&gt;Surface&lt;/strong&gt;
              &lt;span&gt;Scratch-resistant finish&lt;/span&gt;
            &lt;/div&gt;
            &lt;p&gt;The accordion can be used to show material quality, construction details, certifications, and product durability notes.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-twentyone-item"&gt;
        &lt;button class="vb-accordion-twentyone-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Dimensions and sizing&lt;/span&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-twentyone-panel"&gt;
          &lt;div class="vb-accordion-twentyone-content"&gt;
            &lt;div class="vb-accordion-twentyone-spec"&gt;
              &lt;strong&gt;Width&lt;/strong&gt;
              &lt;span&gt;120 cm&lt;/span&gt;
            &lt;/div&gt;
            &lt;div class="vb-accordion-twentyone-spec"&gt;
              &lt;strong&gt;Height&lt;/strong&gt;
              &lt;span&gt;86 cm&lt;/span&gt;
            &lt;/div&gt;
            &lt;p&gt;Use this panel for size charts, measurement notes, product variations, and fitting information.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-twentyone-item"&gt;
        &lt;button class="vb-accordion-twentyone-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Shipping and delivery&lt;/span&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-twentyone-panel"&gt;
          &lt;div class="vb-accordion-twentyone-content"&gt;
            &lt;div class="vb-accordion-twentyone-spec"&gt;
              &lt;strong&gt;Dispatch&lt;/strong&gt;
              &lt;span&gt;1-2 business days&lt;/span&gt;
            &lt;/div&gt;
            &lt;div class="vb-accordion-twentyone-spec"&gt;
              &lt;strong&gt;Delivery&lt;/strong&gt;
              &lt;span&gt;Tracked courier&lt;/span&gt;
            &lt;/div&gt;
            &lt;p&gt;This section can explain shipping regions, delivery time, packaging, pickup options, and tracking details.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-twentyone-item"&gt;
        &lt;button class="vb-accordion-twentyone-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Warranty and returns&lt;/span&gt;
          &lt;em&gt;&lt;/em&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-twentyone-panel"&gt;
          &lt;div class="vb-accordion-twentyone-content"&gt;
            &lt;div class="vb-accordion-twentyone-spec"&gt;
              &lt;strong&gt;Warranty&lt;/strong&gt;
              &lt;span&gt;24 months&lt;/span&gt;
            &lt;/div&gt;
            &lt;div class="vb-accordion-twentyone-spec"&gt;
              &lt;strong&gt;Returns&lt;/strong&gt;
              &lt;span&gt;14-day return window&lt;/span&gt;
            &lt;/div&gt;
            &lt;p&gt;Use this area for return rules, warranty coverage, replacement details, and customer support information.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-twentyone-demo,
.vb-accordion-twentyone-demo * {
  box-sizing: border-box;
}

.vb-accordion-twentyone-demo {
  margin: 28px 0;
  padding: 38px;
  border-radius: 46px 46px 46px 10px;
  background:
    radial-gradient(circle at 16% 20%, rgba(15, 23, 42, 0.08), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(59, 130, 246, 0.14), transparent 36%),
    linear-gradient(135deg, #f8fafc 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.22);
  box-shadow: 0 24px 70px rgba(30, 41, 59, 0.10);
}

.vb-accordion-twentyone-layout {
  display: grid;
  grid-template-columns: minmax(280px, 0.78fr) minmax(0, 1.22fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-accordion-twentyone-product {
  overflow: hidden;
  padding: 28px;
  border-radius: 36px 36px 36px 8px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-accordion-twentyone-product &gt; span {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-twentyone-image {
  position: relative;
  min-height: 260px;
  margin-bottom: 24px;
  border-radius: 30px 30px 30px 8px;
  background:
    radial-gradient(circle at 25% 18%, rgba(255,255,255,0.24), transparent 34%),
    linear-gradient(135deg, #1e293b, #2563eb 58%, #06b6d4) !important;
  overflow: hidden;
}

.vb-accordion-twentyone-box {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 170px;
  height: 150px;
  border-radius: 28px;
  background: rgba(255,255,255,0.16);
  border: 1px solid rgba(255,255,255,0.20);
  transform: translate(-50%, -50%) rotate(-8deg);
  box-shadow: 0 28px 70px rgba(2, 6, 23, 0.26);
}

.vb-accordion-twentyone-box i {
  position: absolute;
  display: block;
  border-radius: 999px;
  background: rgba(255,255,255,0.55);
}

.vb-accordion-twentyone-box i:nth-child(1) {
  left: 24px;
  top: 28px;
  width: 74px;
  height: 12px;
}

.vb-accordion-twentyone-box i:nth-child(2) {
  left: 24px;
  top: 58px;
  width: 118px;
  height: 12px;
}

.vb-accordion-twentyone-box i:nth-child(3) {
  left: 24px;
  top: 92px;
  width: 92px;
  height: 34px;
  border-radius: 14px;
  background: #ffffff;
}

.vb-accordion-twentyone-product h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 58px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-accordion-twentyone-product p {
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-accordion-twentyone-stock {
  display: grid;
  gap: 4px;
  padding: 16px;
  border-radius: 20px;
  background: #ecfdf5;
  border: 1px solid rgba(16, 185, 129, 0.18);
}

.vb-accordion-twentyone-stock strong {
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-accordion-twentyone-stock small {
  color: #065f46 !important;
  -webkit-text-fill-color: #065f46 !important;
  font-size: 13px;
  font-weight: 800;
}

.vb-accordion-twentyone-info {
  display: grid;
  align-content: start;
  gap: 13px;
}

.vb-accordion-twentyone-item {
  overflow: hidden;
  border-radius: 8px 28px 28px 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.07);
}

.vb-accordion-twentyone-item.is-open {
  border-color: rgba(37, 99, 235, 0.34);
  box-shadow: 0 24px 64px rgba(37, 99, 235, 0.12);
}

.vb-accordion-twentyone-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 44px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 76px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-twentyone-trigger span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 20px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.045em;
}

.vb-accordion-twentyone-trigger em {
  position: relative;
  width: 44px;
  height: 44px;
  border-radius: 16px;
  background: #eff6ff;
  border: 1px solid rgba(37, 99, 235, 0.16);
}

.vb-accordion-twentyone-trigger em::before,
.vb-accordion-twentyone-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 16px;
  height: 2px;
  border-radius: 999px;
  background: #2563eb;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease, transform 0.22s ease;
}

.vb-accordion-twentyone-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-twentyone-item.is-open .vb-accordion-twentyone-trigger em {
  background: #2563eb;
}

.vb-accordion-twentyone-item.is-open .vb-accordion-twentyone-trigger em::before,
.vb-accordion-twentyone-item.is-open .vb-accordion-twentyone-trigger em::after {
  background: #ffffff;
}

.vb-accordion-twentyone-item.is-open .vb-accordion-twentyone-trigger em::after {
  opacity: 0;
}

.vb-accordion-twentyone-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-twentyone-content {
  display: grid;
  gap: 10px;
  padding: 0 20px 20px;
}

.vb-accordion-twentyone-spec {
  display: grid;
  grid-template-columns: 150px minmax(0, 1fr);
  gap: 14px;
  padding: 13px 14px;
  border-radius: 16px;
  background: #f8fafc;
}

.vb-accordion-twentyone-spec strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-accordion-twentyone-spec span {
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  font-weight: 800;
}

.vb-accordion-twentyone-content p {
  margin: 6px 0 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-accordion-twentyone-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-accordion-twentyone-demo {
    padding: 18px;
    border-radius: 32px 32px 32px 10px;
  }

  .vb-accordion-twentyone-product {
    padding: 22px;
  }

  .vb-accordion-twentyone-product h3 {
    font-size: 38px !important;
  }

  .vb-accordion-twentyone-spec {
    grid-template-columns: 1fr;
    gap: 4px;
  }
}</pre>



<p class="wp-block-paragraph">This product details accordion is useful for WooCommerce product pages, ecommerce stores, product comparison pages, technical product sheets, size guides, shipping information sections, and warranty blocks.</p>



<h2 class="wp-block-heading">22. Event Schedule Accordion</h2>



<p class="wp-block-paragraph"><strong>An event schedule accordion</strong> is useful for conferences, webinars, workshops, festivals, online summits, meetups, and event landing pages where users need to browse sessions without seeing the full agenda at once.</p>



<p class="wp-block-paragraph">This example uses an agenda-style layout with time blocks, speaker labels, session tracks, and multi-open JavaScript behavior. It has a clear event schedule structure instead of a generic question-and-answer layout.</p>



<ul class="wp-block-list">
<li>Event agenda accordion layout</li>
<li>Multi-open session behavior</li>
<li>Time, speaker, and track labels</li>
<li>Conference-style visual design</li>
<li>Useful for webinars, workshops, and events</li>
</ul>



<div class="vb-accordion-twentytwo-demo">
  <div class="vb-accordion-twentytwo-schedule" data-vb-accordion-twentytwo>
    <div class="vb-accordion-twentytwo-header">
      <span>Example 22</span>
      <h3>Event Schedule Accordion</h3>
      <p>Show event sessions, speakers, tracks, and time slots inside expandable schedule rows.</p>
    </div>

    <div class="vb-accordion-twentytwo-day">
      <strong>Day 1</strong>
      <small>Conference agenda</small>
    </div>

    <div class="vb-accordion-twentytwo-list">
      <article class="vb-accordion-twentytwo-item is-open">
        <button class="vb-accordion-twentytwo-trigger" type="button" aria-expanded="true">
          <time>09:00</time>
          <span>
            <strong>Opening keynote</strong>
            <small>Main stage · 45 min</small>
          </span>
          <em>Keynote</em>
          <i></i>
        </button>
        <div class="vb-accordion-twentytwo-panel">
          <div class="vb-accordion-twentytwo-content">
            <p>A focused opening session covering the event theme, main ideas, and what attendees can expect during the day.</p>
            <div>
              <strong>Speaker</strong>
              <span>Alex Morgan</span>
            </div>
          </div>
        </div>
      </article>

      <article class="vb-accordion-twentytwo-item">
        <button class="vb-accordion-twentytwo-trigger" type="button" aria-expanded="false">
          <time>10:15</time>
          <span>
            <strong>JavaScript UI workshop</strong>
            <small>Workshop room · 90 min</small>
          </span>
          <em>Workshop</em>
          <i></i>
        </button>
        <div class="vb-accordion-twentytwo-panel">
          <div class="vb-accordion-twentytwo-content">
            <p>A practical session where attendees build interactive components using vanilla JavaScript, semantic HTML, and modern CSS.</p>
            <div>
              <strong>Speaker</strong>
              <span>Jordan Lee</span>
            </div>
          </div>
        </div>
      </article>

      <article class="vb-accordion-twentytwo-item">
        <button class="vb-accordion-twentytwo-trigger" type="button" aria-expanded="false">
          <time>13:30</time>
          <span>
            <strong>Design systems panel</strong>
            <small>Panel room · 60 min</small>
          </span>
          <em>Panel</em>
          <i></i>
        </button>
        <div class="vb-accordion-twentytwo-panel">
          <div class="vb-accordion-twentytwo-content">
            <p>A panel discussion about reusable components, interface consistency, accessibility, documentation, and scalable design systems.</p>
            <div>
              <strong>Speakers</strong>
              <span>4 panelists</span>
            </div>
          </div>
        </div>
      </article>

      <article class="vb-accordion-twentytwo-item">
        <button class="vb-accordion-twentytwo-trigger" type="button" aria-expanded="false">
          <time>15:00</time>
          <span>
            <strong>Live component review</strong>
            <small>Main stage · 50 min</small>
          </span>
          <em>Live</em>
          <i></i>
        </button>
        <div class="vb-accordion-twentytwo-panel">
          <div class="vb-accordion-twentytwo-content">
            <p>A live review session where real UI components are improved for clarity, responsiveness, accessibility, and better user experience.</p>
            <div>
              <strong>Format</strong>
              <span>Interactive review</span>
            </div>
          </div>
        </div>
      </article>
    </div>
  </div>
</div>

<style>
.vb-accordion-twentytwo-demo,
.vb-accordion-twentytwo-demo * {
  box-sizing: border-box;
}

.vb-accordion-twentytwo-demo {
  margin: 28px 0;
  padding: 38px;
  border-radius: 10px 50px 50px 50px;
  background:
    linear-gradient(90deg, rgba(15, 23, 42, 0.04) 1px, transparent 1px),
    linear-gradient(0deg, rgba(15, 23, 42, 0.04) 1px, transparent 1px),
    linear-gradient(135deg, #f8fafc 0%, #f0f9ff 48%, #ffffff 100%) !important;
  background-size: 30px 30px, 30px 30px, auto !important;
  border: 1px solid rgba(14, 165, 233, 0.22);
  box-shadow: 0 24px 70px rgba(8, 47, 73, 0.10);
}

.vb-accordion-twentytwo-schedule {
  max-width: 1080px;
  margin: 0 auto;
}

.vb-accordion-twentytwo-header {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(260px, 0.65fr);
  gap: 26px;
  align-items: end;
  margin-bottom: 22px;
}

.vb-accordion-twentytwo-header span {
  grid-column: 1 / -1;
  justify-self: start;
  display: inline-flex;
  padding: 8px 12px;
  border-radius: 999px;
  background: #0369a1;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-twentytwo-header h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(38px, 5vw, 72px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
}

.vb-accordion-twentytwo-header p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twentytwo-day {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 14px;
  padding: 16px 18px;
  border-radius: 22px 22px 6px 22px;
  background: #0f172a;
}

.vb-accordion-twentytwo-day strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-twentytwo-day small {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-accordion-twentytwo-list {
  position: relative;
  display: grid;
  gap: 12px;
}

.vb-accordion-twentytwo-list::before {
  content: "";
  position: absolute;
  left: 46px;
  top: 24px;
  bottom: 24px;
  width: 3px;
  border-radius: 999px;
  background: linear-gradient(180deg, #0ea5e9, #2563eb, #7c3aed);
}

.vb-accordion-twentytwo-item {
  position: relative;
  overflow: hidden;
  border-radius: 28px 8px 28px 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.08);
}

.vb-accordion-twentytwo-item.is-open {
  border-color: rgba(14, 165, 233, 0.38);
  box-shadow: 0 24px 64px rgba(14, 165, 233, 0.14);
}

.vb-accordion-twentytwo-trigger {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: 92px minmax(0, 1fr) 96px 42px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 86px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-twentytwo-trigger time {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 74px;
  min-height: 46px;
  border-radius: 18px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 15px;
  font-weight: 950;
  border: 4px solid #ffffff;
  box-shadow: 0 0 0 2px rgba(14, 165, 233, 0.20);
}

.vb-accordion-twentytwo-trigger strong {
  display: block;
  margin-bottom: 4px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 20px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-twentytwo-trigger small {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 800;
}

.vb-accordion-twentytwo-trigger em {
  justify-self: end;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 34px;
  padding: 8px 11px;
  border-radius: 999px;
  background: #eef2ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 12px;
  font-style: normal;
  font-weight: 950;
}

.vb-accordion-twentytwo-trigger i {
  position: relative;
  width: 42px;
  height: 42px;
  border-radius: 14px;
  background: #f0f9ff;
  border: 1px solid rgba(14, 165, 233, 0.18);
}

.vb-accordion-twentytwo-trigger i::before,
.vb-accordion-twentytwo-trigger i::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 15px;
  height: 2px;
  border-radius: 999px;
  background: #0284c7;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease, transform 0.22s ease;
}

.vb-accordion-twentytwo-trigger i::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-twentytwo-item.is-open .vb-accordion-twentytwo-trigger i {
  background: #0284c7;
}

.vb-accordion-twentytwo-item.is-open .vb-accordion-twentytwo-trigger i::before,
.vb-accordion-twentytwo-item.is-open .vb-accordion-twentytwo-trigger i::after {
  background: #ffffff;
}

.vb-accordion-twentytwo-item.is-open .vb-accordion-twentytwo-trigger i::after {
  opacity: 0;
}

.vb-accordion-twentytwo-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-twentytwo-content {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 190px;
  gap: 16px;
  padding: 0 20px 20px 128px;
}

.vb-accordion-twentytwo-content p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twentytwo-content div {
  padding: 14px;
  border-radius: 18px;
  background: #f8fafc;
}

.vb-accordion-twentytwo-content div strong {
  display: block;
  margin-bottom: 5px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-accordion-twentytwo-content div span {
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 13px;
  font-weight: 850;
}

@media (max-width: 840px) {
  .vb-accordion-twentytwo-header {
    grid-template-columns: 1fr;
  }

  .vb-accordion-twentytwo-trigger {
    grid-template-columns: 80px minmax(0, 1fr) 42px;
  }

  .vb-accordion-twentytwo-trigger em {
    grid-column: 2;
    justify-self: start;
  }

  .vb-accordion-twentytwo-content {
    grid-template-columns: 1fr;
    padding-left: 112px;
  }
}

@media (max-width: 640px) {
  .vb-accordion-twentytwo-demo {
    padding: 18px;
    border-radius: 10px 34px 34px 34px;
  }

  .vb-accordion-twentytwo-header h3 {
    font-size: 38px !important;
  }

  .vb-accordion-twentytwo-list::before {
    display: none;
  }

  .vb-accordion-twentytwo-trigger {
    grid-template-columns: 1fr 38px;
    padding: 18px;
  }

  .vb-accordion-twentytwo-trigger time,
  .vb-accordion-twentytwo-trigger span,
  .vb-accordion-twentytwo-trigger em {
    grid-column: 1;
    justify-self: start;
  }

  .vb-accordion-twentytwo-trigger i {
    grid-column: 2;
    grid-row: 1;
    width: 38px;
    height: 38px;
  }

  .vb-accordion-twentytwo-content {
    padding: 0 18px 18px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-twentytwo]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-twentytwo-item"));

  function updateItem(item) {
    const button = item.querySelector(".vb-accordion-twentytwo-trigger");
    const panel = item.querySelector(".vb-accordion-twentytwo-panel");
    const isOpen = item.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-twentytwo-trigger");

    button.addEventListener("click", function () {
      item.classList.toggle("is-open");
      updateItem(item);
    });

    updateItem(item);
  });

  window.addEventListener("resize", function () {
    items.forEach(updateItem);
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-twentytwo]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-twentytwo-item"));

  function updateItem(item) {
    const button = item.querySelector(".vb-accordion-twentytwo-trigger");
    const panel = item.querySelector(".vb-accordion-twentytwo-panel");
    const isOpen = item.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-twentytwo-trigger");

    button.addEventListener("click", function () {
      item.classList.toggle("is-open");
      updateItem(item);
    });

    updateItem(item);
  });

  window.addEventListener("resize", function () {
    items.forEach(updateItem);
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-twentytwo-demo"&gt;
  &lt;div class="vb-accordion-twentytwo-schedule" data-vb-accordion-twentytwo&gt;
    &lt;div class="vb-accordion-twentytwo-header"&gt;
      &lt;span&gt;Example 22&lt;/span&gt;
      &lt;h3&gt;Event Schedule Accordion&lt;/h3&gt;
      &lt;p&gt;Show event sessions, speakers, tracks, and time slots inside expandable schedule rows.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-twentytwo-day"&gt;
      &lt;strong&gt;Day 1&lt;/strong&gt;
      &lt;small&gt;Conference agenda&lt;/small&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-twentytwo-list"&gt;
      &lt;article class="vb-accordion-twentytwo-item is-open"&gt;
        &lt;button class="vb-accordion-twentytwo-trigger" type="button" aria-expanded="true"&gt;
          &lt;time&gt;09:00&lt;/time&gt;
          &lt;span&gt;
            &lt;strong&gt;Opening keynote&lt;/strong&gt;
            &lt;small&gt;Main stage · 45 min&lt;/small&gt;
          &lt;/span&gt;
          &lt;em&gt;Keynote&lt;/em&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-twentytwo-panel"&gt;
          &lt;div class="vb-accordion-twentytwo-content"&gt;
            &lt;p&gt;A focused opening session covering the event theme, main ideas, and what attendees can expect during the day.&lt;/p&gt;
            &lt;div&gt;
              &lt;strong&gt;Speaker&lt;/strong&gt;
              &lt;span&gt;Alex Morgan&lt;/span&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-twentytwo-item"&gt;
        &lt;button class="vb-accordion-twentytwo-trigger" type="button" aria-expanded="false"&gt;
          &lt;time&gt;10:15&lt;/time&gt;
          &lt;span&gt;
            &lt;strong&gt;JavaScript UI workshop&lt;/strong&gt;
            &lt;small&gt;Workshop room · 90 min&lt;/small&gt;
          &lt;/span&gt;
          &lt;em&gt;Workshop&lt;/em&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-twentytwo-panel"&gt;
          &lt;div class="vb-accordion-twentytwo-content"&gt;
            &lt;p&gt;A practical session where attendees build interactive components using vanilla JavaScript, semantic HTML, and modern CSS.&lt;/p&gt;
            &lt;div&gt;
              &lt;strong&gt;Speaker&lt;/strong&gt;
              &lt;span&gt;Jordan Lee&lt;/span&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-twentytwo-item"&gt;
        &lt;button class="vb-accordion-twentytwo-trigger" type="button" aria-expanded="false"&gt;
          &lt;time&gt;13:30&lt;/time&gt;
          &lt;span&gt;
            &lt;strong&gt;Design systems panel&lt;/strong&gt;
            &lt;small&gt;Panel room · 60 min&lt;/small&gt;
          &lt;/span&gt;
          &lt;em&gt;Panel&lt;/em&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-twentytwo-panel"&gt;
          &lt;div class="vb-accordion-twentytwo-content"&gt;
            &lt;p&gt;A panel discussion about reusable components, interface consistency, accessibility, documentation, and scalable design systems.&lt;/p&gt;
            &lt;div&gt;
              &lt;strong&gt;Speakers&lt;/strong&gt;
              &lt;span&gt;4 panelists&lt;/span&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-twentytwo-item"&gt;
        &lt;button class="vb-accordion-twentytwo-trigger" type="button" aria-expanded="false"&gt;
          &lt;time&gt;15:00&lt;/time&gt;
          &lt;span&gt;
            &lt;strong&gt;Live component review&lt;/strong&gt;
            &lt;small&gt;Main stage · 50 min&lt;/small&gt;
          &lt;/span&gt;
          &lt;em&gt;Live&lt;/em&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/button&gt;
        &lt;div class="vb-accordion-twentytwo-panel"&gt;
          &lt;div class="vb-accordion-twentytwo-content"&gt;
            &lt;p&gt;A live review session where real UI components are improved for clarity, responsiveness, accessibility, and better user experience.&lt;/p&gt;
            &lt;div&gt;
              &lt;strong&gt;Format&lt;/strong&gt;
              &lt;span&gt;Interactive review&lt;/span&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-twentytwo-demo,
.vb-accordion-twentytwo-demo * {
  box-sizing: border-box;
}

.vb-accordion-twentytwo-demo {
  margin: 28px 0;
  padding: 38px;
  border-radius: 10px 50px 50px 50px;
  background:
    linear-gradient(90deg, rgba(15, 23, 42, 0.04) 1px, transparent 1px),
    linear-gradient(0deg, rgba(15, 23, 42, 0.04) 1px, transparent 1px),
    linear-gradient(135deg, #f8fafc 0%, #f0f9ff 48%, #ffffff 100%) !important;
  background-size: 30px 30px, 30px 30px, auto !important;
  border: 1px solid rgba(14, 165, 233, 0.22);
  box-shadow: 0 24px 70px rgba(8, 47, 73, 0.10);
}

.vb-accordion-twentytwo-schedule {
  max-width: 1080px;
  margin: 0 auto;
}

.vb-accordion-twentytwo-header {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(260px, 0.65fr);
  gap: 26px;
  align-items: end;
  margin-bottom: 22px;
}

.vb-accordion-twentytwo-header span {
  grid-column: 1 / -1;
  justify-self: start;
  display: inline-flex;
  padding: 8px 12px;
  border-radius: 999px;
  background: #0369a1;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-twentytwo-header h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(38px, 5vw, 72px) !important;
  line-height: 0.92 !important;
  font-weight: 950 !important;
  letter-spacing: -0.085em;
}

.vb-accordion-twentytwo-header p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twentytwo-day {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 14px;
  padding: 16px 18px;
  border-radius: 22px 22px 6px 22px;
  background: #0f172a;
}

.vb-accordion-twentytwo-day strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-twentytwo-day small {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-accordion-twentytwo-list {
  position: relative;
  display: grid;
  gap: 12px;
}

.vb-accordion-twentytwo-list::before {
  content: "";
  position: absolute;
  left: 46px;
  top: 24px;
  bottom: 24px;
  width: 3px;
  border-radius: 999px;
  background: linear-gradient(180deg, #0ea5e9, #2563eb, #7c3aed);
}

.vb-accordion-twentytwo-item {
  position: relative;
  overflow: hidden;
  border-radius: 28px 8px 28px 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.08);
}

.vb-accordion-twentytwo-item.is-open {
  border-color: rgba(14, 165, 233, 0.38);
  box-shadow: 0 24px 64px rgba(14, 165, 233, 0.14);
}

.vb-accordion-twentytwo-trigger {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: 92px minmax(0, 1fr) 96px 42px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 86px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-twentytwo-trigger time {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 74px;
  min-height: 46px;
  border-radius: 18px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 15px;
  font-weight: 950;
  border: 4px solid #ffffff;
  box-shadow: 0 0 0 2px rgba(14, 165, 233, 0.20);
}

.vb-accordion-twentytwo-trigger strong {
  display: block;
  margin-bottom: 4px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 20px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-twentytwo-trigger small {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 800;
}

.vb-accordion-twentytwo-trigger em {
  justify-self: end;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 34px;
  padding: 8px 11px;
  border-radius: 999px;
  background: #eef2ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 12px;
  font-style: normal;
  font-weight: 950;
}

.vb-accordion-twentytwo-trigger i {
  position: relative;
  width: 42px;
  height: 42px;
  border-radius: 14px;
  background: #f0f9ff;
  border: 1px solid rgba(14, 165, 233, 0.18);
}

.vb-accordion-twentytwo-trigger i::before,
.vb-accordion-twentytwo-trigger i::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 15px;
  height: 2px;
  border-radius: 999px;
  background: #0284c7;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease, transform 0.22s ease;
}

.vb-accordion-twentytwo-trigger i::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-twentytwo-item.is-open .vb-accordion-twentytwo-trigger i {
  background: #0284c7;
}

.vb-accordion-twentytwo-item.is-open .vb-accordion-twentytwo-trigger i::before,
.vb-accordion-twentytwo-item.is-open .vb-accordion-twentytwo-trigger i::after {
  background: #ffffff;
}

.vb-accordion-twentytwo-item.is-open .vb-accordion-twentytwo-trigger i::after {
  opacity: 0;
}

.vb-accordion-twentytwo-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-twentytwo-content {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 190px;
  gap: 16px;
  padding: 0 20px 20px 128px;
}

.vb-accordion-twentytwo-content p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twentytwo-content div {
  padding: 14px;
  border-radius: 18px;
  background: #f8fafc;
}

.vb-accordion-twentytwo-content div strong {
  display: block;
  margin-bottom: 5px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-accordion-twentytwo-content div span {
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 13px;
  font-weight: 850;
}

@media (max-width: 840px) {
  .vb-accordion-twentytwo-header {
    grid-template-columns: 1fr;
  }

  .vb-accordion-twentytwo-trigger {
    grid-template-columns: 80px minmax(0, 1fr) 42px;
  }

  .vb-accordion-twentytwo-trigger em {
    grid-column: 2;
    justify-self: start;
  }

  .vb-accordion-twentytwo-content {
    grid-template-columns: 1fr;
    padding-left: 112px;
  }
}

@media (max-width: 640px) {
  .vb-accordion-twentytwo-demo {
    padding: 18px;
    border-radius: 10px 34px 34px 34px;
  }

  .vb-accordion-twentytwo-header h3 {
    font-size: 38px !important;
  }

  .vb-accordion-twentytwo-list::before {
    display: none;
  }

  .vb-accordion-twentytwo-trigger {
    grid-template-columns: 1fr 38px;
    padding: 18px;
  }

  .vb-accordion-twentytwo-trigger time,
  .vb-accordion-twentytwo-trigger span,
  .vb-accordion-twentytwo-trigger em {
    grid-column: 1;
    justify-self: start;
  }

  .vb-accordion-twentytwo-trigger i {
    grid-column: 2;
    grid-row: 1;
    width: 38px;
    height: 38px;
  }

  .vb-accordion-twentytwo-content {
    padding: 0 18px 18px;
  }
}</pre>



<p class="wp-block-paragraph">This event schedule accordion is useful for conferences, webinars, workshops, online events, product launches, festivals, meetups, training days, and event landing pages that need a compact expandable agenda.</p>



<h2 class="wp-block-heading">23. Timeline Accordion</h2>



<p class="wp-block-paragraph"><strong>A timeline accordion</strong> is useful for project roadmaps, company history sections, launch timelines, onboarding flows, process pages, and case studies where events should be shown in a chronological order.</p>



<p class="wp-block-paragraph">This example uses a vertical timeline with connected markers, year labels, milestone cards, and one-open-at-a-time JavaScript behavior. The layout feels like a roadmap instead of a normal stacked FAQ accordion.</p>



<ul class="wp-block-list">
<li>Timeline-style accordion layout</li>
<li>Connected vertical milestone line</li>
<li>One-open-at-a-time interaction</li>
<li>Year labels and milestone details</li>
<li>Useful for roadmaps, history, and process sections</li>
</ul>



<div class="vb-accordion-twentythree-demo">
  <div class="vb-accordion-twentythree-wrap" data-vb-accordion-twentythree>
    <div class="vb-accordion-twentythree-head">
      <span>Example 23</span>
      <h3>Timeline Accordion</h3>
      <p>Open each milestone to reveal project phases, company history, launch steps, or roadmap details.</p>
    </div>

    <div class="vb-accordion-twentythree-line">
      <article class="vb-accordion-twentythree-step is-open">
        <div class="vb-accordion-twentythree-marker">
          <strong>01</strong>
        </div>

        <div class="vb-accordion-twentythree-card">
          <button class="vb-accordion-twentythree-trigger" type="button" aria-expanded="true">
            <span>
              <small>January 2026</small>
              <strong>Research and planning</strong>
            </span>
            <em>Open</em>
          </button>

          <div class="vb-accordion-twentythree-panel">
            <div class="vb-accordion-twentythree-content">
              <p>The first phase defines goals, audience needs, content structure, design direction, technical requirements, and launch priorities.</p>
              <ul>
                <li>Audience research</li>
                <li>Feature planning</li>
                <li>Initial wireframes</li>
              </ul>
            </div>
          </div>
        </div>
      </article>

      <article class="vb-accordion-twentythree-step">
        <div class="vb-accordion-twentythree-marker">
          <strong>02</strong>
        </div>

        <div class="vb-accordion-twentythree-card">
          <button class="vb-accordion-twentythree-trigger" type="button" aria-expanded="false">
            <span>
              <small>February 2026</small>
              <strong>Interface design</strong>
            </span>
            <em>Open</em>
          </button>

          <div class="vb-accordion-twentythree-panel">
            <div class="vb-accordion-twentythree-content">
              <p>The second phase turns the plan into visual sections, responsive layouts, reusable components, and polished interaction states.</p>
              <ul>
                <li>UI direction</li>
                <li>Responsive layouts</li>
                <li>Component styling</li>
              </ul>
            </div>
          </div>
        </div>
      </article>

      <article class="vb-accordion-twentythree-step">
        <div class="vb-accordion-twentythree-marker">
          <strong>03</strong>
        </div>

        <div class="vb-accordion-twentythree-card">
          <button class="vb-accordion-twentythree-trigger" type="button" aria-expanded="false">
            <span>
              <small>March 2026</small>
              <strong>Development sprint</strong>
            </span>
            <em>Open</em>
          </button>

          <div class="vb-accordion-twentythree-panel">
            <div class="vb-accordion-twentythree-content">
              <p>The development phase connects markup, styling, JavaScript interactions, accessibility states, and reusable content patterns.</p>
              <ul>
                <li>HTML structure</li>
                <li>JavaScript behavior</li>
                <li>Testing and fixes</li>
              </ul>
            </div>
          </div>
        </div>
      </article>

      <article class="vb-accordion-twentythree-step">
        <div class="vb-accordion-twentythree-marker">
          <strong>04</strong>
        </div>

        <div class="vb-accordion-twentythree-card">
          <button class="vb-accordion-twentythree-trigger" type="button" aria-expanded="false">
            <span>
              <small>April 2026</small>
              <strong>Launch and review</strong>
            </span>
            <em>Open</em>
          </button>

          <div class="vb-accordion-twentythree-panel">
            <div class="vb-accordion-twentythree-content">
              <p>The final phase includes publishing, analytics review, user feedback, speed improvements, content updates, and conversion improvements.</p>
              <ul>
                <li>Launch checklist</li>
                <li>Performance review</li>
                <li>Content improvements</li>
              </ul>
            </div>
          </div>
        </div>
      </article>
    </div>
  </div>
</div>

<style>
.vb-accordion-twentythree-demo,
.vb-accordion-twentythree-demo * {
  box-sizing: border-box;
}

.vb-accordion-twentythree-demo {
  margin: 28px 0;
  padding: 42px;
  border-radius: 60px 6px 60px 6px;
  background:
    conic-gradient(from 180deg at 20% 20%, rgba(168, 85, 247, 0.18), transparent 26%, rgba(14, 165, 233, 0.18), transparent 58%, rgba(236, 72, 153, 0.14), transparent 78%),
    linear-gradient(135deg, #fdf4ff 0%, #eff6ff 48%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.24);
  box-shadow: 0 28px 80px rgba(88, 28, 135, 0.12);
}

.vb-accordion-twentythree-wrap {
  max-width: 1080px;
  margin: 0 auto;
}

.vb-accordion-twentythree-head {
  position: relative;
  max-width: 760px;
  margin-bottom: 34px;
  padding-left: 30px;
}

.vb-accordion-twentythree-head::before {
  content: "";
  position: absolute;
  left: 0;
  top: 6px;
  bottom: 6px;
  width: 8px;
  border-radius: 999px;
  background: linear-gradient(180deg, #7c3aed, #0ea5e9, #ec4899);
}

.vb-accordion-twentythree-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 4px 18px 4px 18px;
  background: #581c87;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-twentythree-head h3 {
  margin: 0 0 12px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(40px, 5vw, 76px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.09em;
}

.vb-accordion-twentythree-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twentythree-line {
  position: relative;
  display: grid;
  gap: 18px;
}

.vb-accordion-twentythree-line::before {
  content: "";
  position: absolute;
  left: 39px;
  top: 30px;
  bottom: 30px;
  width: 4px;
  border-radius: 999px;
  background: linear-gradient(180deg, #7c3aed, #0ea5e9, #ec4899);
  opacity: 0.45;
}

.vb-accordion-twentythree-step {
  position: relative;
  display: grid;
  grid-template-columns: 82px minmax(0, 1fr);
  gap: 20px;
  align-items: start;
}

.vb-accordion-twentythree-marker {
  position: relative;
  z-index: 3;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  padding: 8px;
  background: #ffffff;
  box-shadow: 0 14px 38px rgba(88, 28, 135, 0.14);
}

.vb-accordion-twentythree-marker strong {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  border-radius: inherit;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-accordion-twentythree-step.is-open .vb-accordion-twentythree-marker strong {
  background: linear-gradient(135deg, #7c3aed, #0ea5e9) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-twentythree-card {
  overflow: hidden;
  border-radius: 30px 30px 30px 6px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.08);
}

.vb-accordion-twentythree-step.is-open .vb-accordion-twentythree-card {
  border-color: rgba(124, 58, 237, 0.34);
  box-shadow: 0 26px 70px rgba(124, 58, 237, 0.13);
}

.vb-accordion-twentythree-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 74px;
  align-items: center;
  gap: 18px;
  width: 100%;
  min-height: 88px;
  padding: 20px 22px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-twentythree-trigger small {
  display: inline-flex;
  margin-bottom: 7px;
  padding: 5px 9px;
  border-radius: 999px;
  background: #f5f3ff;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-accordion-twentythree-trigger strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px;
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.045em;
}

.vb-accordion-twentythree-trigger em {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  min-height: 42px;
  border-radius: 4px 16px 4px 16px;
  background: #f8fafc;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 12px;
  font-style: normal;
  font-weight: 950;
  text-transform: uppercase;
}

.vb-accordion-twentythree-step.is-open .vb-accordion-twentythree-trigger em {
  background: #7c3aed;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-twentythree-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.32s ease;
}

.vb-accordion-twentythree-content {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 220px;
  gap: 18px;
  padding: 0 22px 22px;
}

.vb-accordion-twentythree-content p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twentythree-content ul {
  display: grid;
  gap: 8px;
  margin: 0 !important;
  padding: 14px !important;
  border-radius: 18px 18px 18px 4px;
  background: #f8fafc;
  list-style: none !important;
}

.vb-accordion-twentythree-content li {
  position: relative;
  margin: 0 !important;
  padding-left: 19px;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  line-height: 1.45;
  font-weight: 850;
}

.vb-accordion-twentythree-content li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: #7c3aed;
}

@media (max-width: 780px) {
  .vb-accordion-twentythree-demo {
    padding: 20px;
    border-radius: 40px 6px 40px 6px;
  }

  .vb-accordion-twentythree-head {
    padding-left: 22px;
  }

  .vb-accordion-twentythree-head h3 {
    font-size: 40px !important;
  }

  .vb-accordion-twentythree-line::before {
    left: 24px;
  }

  .vb-accordion-twentythree-step {
    grid-template-columns: 54px minmax(0, 1fr);
    gap: 12px;
  }

  .vb-accordion-twentythree-marker {
    width: 54px;
    height: 54px;
    padding: 5px;
  }

  .vb-accordion-twentythree-marker strong {
    font-size: 13px;
  }

  .vb-accordion-twentythree-trigger {
    grid-template-columns: 1fr;
    min-height: auto;
    padding: 18px;
  }

  .vb-accordion-twentythree-trigger em {
    justify-self: start;
    min-width: 70px;
  }

  .vb-accordion-twentythree-content {
    grid-template-columns: 1fr;
    padding: 0 18px 18px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-twentythree]");
  if (!accordion) return;

  const steps = Array.from(accordion.querySelectorAll(".vb-accordion-twentythree-step"));

  function closeStep(step) {
    const button = step.querySelector(".vb-accordion-twentythree-trigger");
    const panel = step.querySelector(".vb-accordion-twentythree-panel");
    const label = button.querySelector("em");

    step.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    label.textContent = "Open";
    panel.style.maxHeight = "0px";
  }

  function openStep(step) {
    const button = step.querySelector(".vb-accordion-twentythree-trigger");
    const panel = step.querySelector(".vb-accordion-twentythree-panel");
    const label = button.querySelector("em");

    step.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    label.textContent = "Active";
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  steps.forEach(function (step) {
    const button = step.querySelector(".vb-accordion-twentythree-trigger");

    button.addEventListener("click", function () {
      const isOpen = step.classList.contains("is-open");

      steps.forEach(closeStep);

      if (!isOpen) {
        openStep(step);
      }
    });
  });

  const defaultStep = accordion.querySelector(".vb-accordion-twentythree-step.is-open");
  if (defaultStep) {
    openStep(defaultStep);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-twentythree-step.is-open");
    if (open) {
      openStep(open);
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-twentythree]");
  if (!accordion) return;

  const steps = Array.from(accordion.querySelectorAll(".vb-accordion-twentythree-step"));

  function closeStep(step) {
    const button = step.querySelector(".vb-accordion-twentythree-trigger");
    const panel = step.querySelector(".vb-accordion-twentythree-panel");
    const label = button.querySelector("em");

    step.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    label.textContent = "Open";
    panel.style.maxHeight = "0px";
  }

  function openStep(step) {
    const button = step.querySelector(".vb-accordion-twentythree-trigger");
    const panel = step.querySelector(".vb-accordion-twentythree-panel");
    const label = button.querySelector("em");

    step.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    label.textContent = "Active";
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  steps.forEach(function (step) {
    const button = step.querySelector(".vb-accordion-twentythree-trigger");

    button.addEventListener("click", function () {
      const isOpen = step.classList.contains("is-open");

      steps.forEach(closeStep);

      if (!isOpen) {
        openStep(step);
      }
    });
  });

  const defaultStep = accordion.querySelector(".vb-accordion-twentythree-step.is-open");
  if (defaultStep) {
    openStep(defaultStep);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-twentythree-step.is-open");
    if (open) {
      openStep(open);
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-twentythree-demo"&gt;
  &lt;div class="vb-accordion-twentythree-wrap" data-vb-accordion-twentythree&gt;
    &lt;div class="vb-accordion-twentythree-head"&gt;
      &lt;span&gt;Example 23&lt;/span&gt;
      &lt;h3&gt;Timeline Accordion&lt;/h3&gt;
      &lt;p&gt;Open each milestone to reveal project phases, company history, launch steps, or roadmap details.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-twentythree-line"&gt;
      &lt;article class="vb-accordion-twentythree-step is-open"&gt;
        &lt;div class="vb-accordion-twentythree-marker"&gt;
          &lt;strong&gt;01&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-accordion-twentythree-card"&gt;
          &lt;button class="vb-accordion-twentythree-trigger" type="button" aria-expanded="true"&gt;
            &lt;span&gt;
              &lt;small&gt;January 2026&lt;/small&gt;
              &lt;strong&gt;Research and planning&lt;/strong&gt;
            &lt;/span&gt;
            &lt;em&gt;Open&lt;/em&gt;
          &lt;/button&gt;

          &lt;div class="vb-accordion-twentythree-panel"&gt;
            &lt;div class="vb-accordion-twentythree-content"&gt;
              &lt;p&gt;The first phase defines goals, audience needs, content structure, design direction, technical requirements, and launch priorities.&lt;/p&gt;
              &lt;ul&gt;
                &lt;li&gt;Audience research&lt;/li&gt;
                &lt;li&gt;Feature planning&lt;/li&gt;
                &lt;li&gt;Initial wireframes&lt;/li&gt;
              &lt;/ul&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-twentythree-step"&gt;
        &lt;div class="vb-accordion-twentythree-marker"&gt;
          &lt;strong&gt;02&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-accordion-twentythree-card"&gt;
          &lt;button class="vb-accordion-twentythree-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;
              &lt;small&gt;February 2026&lt;/small&gt;
              &lt;strong&gt;Interface design&lt;/strong&gt;
            &lt;/span&gt;
            &lt;em&gt;Open&lt;/em&gt;
          &lt;/button&gt;

          &lt;div class="vb-accordion-twentythree-panel"&gt;
            &lt;div class="vb-accordion-twentythree-content"&gt;
              &lt;p&gt;The second phase turns the plan into visual sections, responsive layouts, reusable components, and polished interaction states.&lt;/p&gt;
              &lt;ul&gt;
                &lt;li&gt;UI direction&lt;/li&gt;
                &lt;li&gt;Responsive layouts&lt;/li&gt;
                &lt;li&gt;Component styling&lt;/li&gt;
              &lt;/ul&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-twentythree-step"&gt;
        &lt;div class="vb-accordion-twentythree-marker"&gt;
          &lt;strong&gt;03&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-accordion-twentythree-card"&gt;
          &lt;button class="vb-accordion-twentythree-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;
              &lt;small&gt;March 2026&lt;/small&gt;
              &lt;strong&gt;Development sprint&lt;/strong&gt;
            &lt;/span&gt;
            &lt;em&gt;Open&lt;/em&gt;
          &lt;/button&gt;

          &lt;div class="vb-accordion-twentythree-panel"&gt;
            &lt;div class="vb-accordion-twentythree-content"&gt;
              &lt;p&gt;The development phase connects markup, styling, JavaScript interactions, accessibility states, and reusable content patterns.&lt;/p&gt;
              &lt;ul&gt;
                &lt;li&gt;HTML structure&lt;/li&gt;
                &lt;li&gt;JavaScript behavior&lt;/li&gt;
                &lt;li&gt;Testing and fixes&lt;/li&gt;
              &lt;/ul&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-twentythree-step"&gt;
        &lt;div class="vb-accordion-twentythree-marker"&gt;
          &lt;strong&gt;04&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-accordion-twentythree-card"&gt;
          &lt;button class="vb-accordion-twentythree-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;
              &lt;small&gt;April 2026&lt;/small&gt;
              &lt;strong&gt;Launch and review&lt;/strong&gt;
            &lt;/span&gt;
            &lt;em&gt;Open&lt;/em&gt;
          &lt;/button&gt;

          &lt;div class="vb-accordion-twentythree-panel"&gt;
            &lt;div class="vb-accordion-twentythree-content"&gt;
              &lt;p&gt;The final phase includes publishing, analytics review, user feedback, speed improvements, content updates, and conversion improvements.&lt;/p&gt;
              &lt;ul&gt;
                &lt;li&gt;Launch checklist&lt;/li&gt;
                &lt;li&gt;Performance review&lt;/li&gt;
                &lt;li&gt;Content improvements&lt;/li&gt;
              &lt;/ul&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-twentythree-demo,
.vb-accordion-twentythree-demo * {
  box-sizing: border-box;
}

.vb-accordion-twentythree-demo {
  margin: 28px 0;
  padding: 42px;
  border-radius: 60px 6px 60px 6px;
  background:
    conic-gradient(from 180deg at 20% 20%, rgba(168, 85, 247, 0.18), transparent 26%, rgba(14, 165, 233, 0.18), transparent 58%, rgba(236, 72, 153, 0.14), transparent 78%),
    linear-gradient(135deg, #fdf4ff 0%, #eff6ff 48%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.24);
  box-shadow: 0 28px 80px rgba(88, 28, 135, 0.12);
}

.vb-accordion-twentythree-wrap {
  max-width: 1080px;
  margin: 0 auto;
}

.vb-accordion-twentythree-head {
  position: relative;
  max-width: 760px;
  margin-bottom: 34px;
  padding-left: 30px;
}

.vb-accordion-twentythree-head::before {
  content: "";
  position: absolute;
  left: 0;
  top: 6px;
  bottom: 6px;
  width: 8px;
  border-radius: 999px;
  background: linear-gradient(180deg, #7c3aed, #0ea5e9, #ec4899);
}

.vb-accordion-twentythree-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 4px 18px 4px 18px;
  background: #581c87;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-twentythree-head h3 {
  margin: 0 0 12px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(40px, 5vw, 76px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.09em;
}

.vb-accordion-twentythree-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twentythree-line {
  position: relative;
  display: grid;
  gap: 18px;
}

.vb-accordion-twentythree-line::before {
  content: "";
  position: absolute;
  left: 39px;
  top: 30px;
  bottom: 30px;
  width: 4px;
  border-radius: 999px;
  background: linear-gradient(180deg, #7c3aed, #0ea5e9, #ec4899);
  opacity: 0.45;
}

.vb-accordion-twentythree-step {
  position: relative;
  display: grid;
  grid-template-columns: 82px minmax(0, 1fr);
  gap: 20px;
  align-items: start;
}

.vb-accordion-twentythree-marker {
  position: relative;
  z-index: 3;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  padding: 8px;
  background: #ffffff;
  box-shadow: 0 14px 38px rgba(88, 28, 135, 0.14);
}

.vb-accordion-twentythree-marker strong {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100%;
  height: 100%;
  border-radius: inherit;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-accordion-twentythree-step.is-open .vb-accordion-twentythree-marker strong {
  background: linear-gradient(135deg, #7c3aed, #0ea5e9) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-twentythree-card {
  overflow: hidden;
  border-radius: 30px 30px 30px 6px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.08);
}

.vb-accordion-twentythree-step.is-open .vb-accordion-twentythree-card {
  border-color: rgba(124, 58, 237, 0.34);
  box-shadow: 0 26px 70px rgba(124, 58, 237, 0.13);
}

.vb-accordion-twentythree-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 74px;
  align-items: center;
  gap: 18px;
  width: 100%;
  min-height: 88px;
  padding: 20px 22px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-twentythree-trigger small {
  display: inline-flex;
  margin-bottom: 7px;
  padding: 5px 9px;
  border-radius: 999px;
  background: #f5f3ff;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-accordion-twentythree-trigger strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px;
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.045em;
}

.vb-accordion-twentythree-trigger em {
  display: inline-flex;
  justify-content: center;
  align-items: center;
  min-height: 42px;
  border-radius: 4px 16px 4px 16px;
  background: #f8fafc;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 12px;
  font-style: normal;
  font-weight: 950;
  text-transform: uppercase;
}

.vb-accordion-twentythree-step.is-open .vb-accordion-twentythree-trigger em {
  background: #7c3aed;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-twentythree-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.32s ease;
}

.vb-accordion-twentythree-content {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 220px;
  gap: 18px;
  padding: 0 22px 22px;
}

.vb-accordion-twentythree-content p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twentythree-content ul {
  display: grid;
  gap: 8px;
  margin: 0 !important;
  padding: 14px !important;
  border-radius: 18px 18px 18px 4px;
  background: #f8fafc;
  list-style: none !important;
}

.vb-accordion-twentythree-content li {
  position: relative;
  margin: 0 !important;
  padding-left: 19px;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  line-height: 1.45;
  font-weight: 850;
}

.vb-accordion-twentythree-content li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.55em;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: #7c3aed;
}

@media (max-width: 780px) {
  .vb-accordion-twentythree-demo {
    padding: 20px;
    border-radius: 40px 6px 40px 6px;
  }

  .vb-accordion-twentythree-head {
    padding-left: 22px;
  }

  .vb-accordion-twentythree-head h3 {
    font-size: 40px !important;
  }

  .vb-accordion-twentythree-line::before {
    left: 24px;
  }

  .vb-accordion-twentythree-step {
    grid-template-columns: 54px minmax(0, 1fr);
    gap: 12px;
  }

  .vb-accordion-twentythree-marker {
    width: 54px;
    height: 54px;
    padding: 5px;
  }

  .vb-accordion-twentythree-marker strong {
    font-size: 13px;
  }

  .vb-accordion-twentythree-trigger {
    grid-template-columns: 1fr;
    min-height: auto;
    padding: 18px;
  }

  .vb-accordion-twentythree-trigger em {
    justify-self: start;
    min-width: 70px;
  }

  .vb-accordion-twentythree-content {
    grid-template-columns: 1fr;
    padding: 0 18px 18px;
  }
}</pre>



<p class="wp-block-paragraph">This timeline accordion is useful for product roadmaps, agency process sections, company history pages, startup launch plans, case studies, onboarding flows, and project milestone sections.</p>



<h2 class="wp-block-heading">24. Magazine Story Accordion</h2>



<p class="wp-block-paragraph"><strong>A magazine story accordion</strong> is useful for editorial websites, online magazines, storytelling landing pages, article collections, news features, portfolio case studies, and content-rich brand pages.</p>



<p class="wp-block-paragraph">This example uses a large editorial cover panel, numbered story cards, image-like CSS blocks, pull-quote styling, and multi-open JavaScript behavior. It is visually built like a magazine feature instead of a support, dashboard, or product accordion.</p>



<ul class="wp-block-list">
<li>Editorial magazine-style accordion</li>
<li>Multi-open JavaScript behavior</li>
<li>Large story cover and article cards</li>
<li>Pull-quote and feature labels</li>
<li>Useful for magazines, blogs, and storytelling pages</li>
</ul>



<div class="vb-accordion-twentyfour-demo">
  <div class="vb-accordion-twentyfour-layout" data-vb-accordion-twentyfour>
    <aside class="vb-accordion-twentyfour-cover">
      <span>Example 24</span>
      <h3>Magazine Story Accordion</h3>
      <p>Reveal editorial story sections with a content-first accordion layout inspired by modern magazine pages.</p>
      <div class="vb-accordion-twentyfour-quote">
        <strong>“Design becomes stronger when content has rhythm.”</strong>
      </div>
    </aside>

    <section class="vb-accordion-twentyfour-stories">
      <article class="vb-accordion-twentyfour-story is-open">
        <button class="vb-accordion-twentyfour-trigger" type="button" aria-expanded="true">
          <span>Feature 01</span>
          <strong>The opening idea</strong>
          <em>+</em>
        </button>

        <div class="vb-accordion-twentyfour-panel">
          <div class="vb-accordion-twentyfour-content">
            <div class="vb-accordion-twentyfour-thumb vb-accordion-twentyfour-thumb-a"></div>
            <p>Use this section to introduce the core idea of an article, case study, brand story, or editorial feature.</p>
          </div>
        </div>
      </article>

      <article class="vb-accordion-twentyfour-story">
        <button class="vb-accordion-twentyfour-trigger" type="button" aria-expanded="false">
          <span>Feature 02</span>
          <strong>Behind the process</strong>
          <em>+</em>
        </button>

        <div class="vb-accordion-twentyfour-panel">
          <div class="vb-accordion-twentyfour-content">
            <div class="vb-accordion-twentyfour-thumb vb-accordion-twentyfour-thumb-b"></div>
            <p>This panel can explain the process, research, decisions, mistakes, improvements, or the thinking behind the final result.</p>
          </div>
        </div>
      </article>

      <article class="vb-accordion-twentyfour-story">
        <button class="vb-accordion-twentyfour-trigger" type="button" aria-expanded="false">
          <span>Feature 03</span>
          <strong>Visual direction</strong>
          <em>+</em>
        </button>

        <div class="vb-accordion-twentyfour-panel">
          <div class="vb-accordion-twentyfour-content">
            <div class="vb-accordion-twentyfour-thumb vb-accordion-twentyfour-thumb-c"></div>
            <p>Use this section for visual decisions, layout notes, typography choices, color direction, and interface details.</p>
          </div>
        </div>
      </article>

      <article class="vb-accordion-twentyfour-story">
        <button class="vb-accordion-twentyfour-trigger" type="button" aria-expanded="false">
          <span>Feature 04</span>
          <strong>Final outcome</strong>
          <em>+</em>
        </button>

        <div class="vb-accordion-twentyfour-panel">
          <div class="vb-accordion-twentyfour-content">
            <div class="vb-accordion-twentyfour-thumb vb-accordion-twentyfour-thumb-d"></div>
            <p>The final panel can summarize the result, measurable improvements, lessons learned, and next steps for the project.</p>
          </div>
        </div>
      </article>
    </section>
  </div>
</div>

<style>
.vb-accordion-twentyfour-demo,
.vb-accordion-twentyfour-demo * {
  box-sizing: border-box;
}

.vb-accordion-twentyfour-demo {
  margin: 28px 0;
  padding: 40px;
  background:
    linear-gradient(90deg, rgba(17, 24, 39, 0.07) 1px, transparent 1px),
    linear-gradient(135deg, #fff7ed 0%, #fdf2f8 48%, #ffffff 100%) !important;
  background-size: 18px 18px, auto !important;
  border: 1px solid rgba(190, 24, 93, 0.18);
  border-radius: 0;
  box-shadow: 0 28px 80px rgba(131, 24, 67, 0.10);
}

.vb-accordion-twentyfour-layout {
  display: grid;
  grid-template-columns: minmax(300px, 0.86fr) minmax(0, 1.14fr);
  gap: 28px;
  max-width: 1140px;
  margin: 0 auto;
}

.vb-accordion-twentyfour-cover {
  position: relative;
  min-height: 650px;
  padding: 34px;
  background:
    radial-gradient(circle at 24% 18%, rgba(255,255,255,0.24), transparent 34%),
    linear-gradient(135deg, #831843, #be123c 56%, #f97316) !important;
  color: #ffffff;
  overflow: hidden;
}

.vb-accordion-twentyfour-cover::before {
  content: "";
  position: absolute;
  left: 34px;
  right: 34px;
  top: 120px;
  height: 1px;
  background: rgba(255,255,255,0.24);
}

.vb-accordion-twentyfour-cover::after {
  content: "24";
  position: absolute;
  right: -20px;
  bottom: -34px;
  color: rgba(255,255,255,0.10);
  -webkit-text-fill-color: rgba(255,255,255,0.10);
  font-size: 220px;
  line-height: 0.8;
  font-weight: 950;
  letter-spacing: -0.12em;
}

.vb-accordion-twentyfour-cover span {
  display: inline-flex;
  margin-bottom: 82px;
  padding: 8px 12px;
  border: 1px solid rgba(255,255,255,0.30);
  color: #fff7ed !important;
  -webkit-text-fill-color: #fff7ed !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.15em;
  text-transform: uppercase;
}

.vb-accordion-twentyfour-cover h3 {
  position: relative;
  z-index: 2;
  margin: 0 0 18px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(44px, 5vw, 78px) !important;
  line-height: 0.86 !important;
  font-weight: 950 !important;
  letter-spacing: -0.1em;
}

.vb-accordion-twentyfour-cover p {
  position: relative;
  z-index: 2;
  max-width: 390px;
  margin: 0 !important;
  color: #ffe4e6 !important;
  -webkit-text-fill-color: #ffe4e6 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twentyfour-quote {
  position: absolute;
  left: 34px;
  right: 34px;
  bottom: 34px;
  z-index: 2;
  padding: 22px;
  border-left: 5px solid #ffffff;
  background: rgba(255,255,255,0.12);
}

.vb-accordion-twentyfour-quote strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 21px;
  line-height: 1.25;
  font-weight: 950;
  letter-spacing: -0.045em;
}

.vb-accordion-twentyfour-stories {
  display: grid;
  gap: 18px;
  align-content: center;
}

.vb-accordion-twentyfour-story {
  overflow: hidden;
  background: #ffffff;
  border: 1px solid rgba(190, 24, 93, 0.18);
  box-shadow: 0 18px 46px rgba(131, 24, 67, 0.08);
}

.vb-accordion-twentyfour-story:nth-child(2) {
  margin-left: 34px;
}

.vb-accordion-twentyfour-story:nth-child(3) {
  margin-right: 34px;
}

.vb-accordion-twentyfour-story.is-open {
  box-shadow: 0 28px 72px rgba(190, 24, 93, 0.15);
  border-color: rgba(190, 24, 93, 0.34);
}

.vb-accordion-twentyfour-trigger {
  display: grid;
  grid-template-columns: 110px minmax(0, 1fr) 48px;
  align-items: center;
  gap: 18px;
  width: 100%;
  min-height: 88px;
  padding: 20px 22px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-twentyfour-trigger span {
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.vb-accordion-twentyfour-trigger strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 26px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vb-accordion-twentyfour-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border: 1px solid #111827;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 28px;
  line-height: 1;
  font-style: normal;
  font-weight: 950;
  transition: transform 0.22s ease, background 0.22s ease, color 0.22s ease;
}

.vb-accordion-twentyfour-story.is-open .vb-accordion-twentyfour-trigger em {
  transform: rotate(45deg);
  background: #be123c;
  border-color: #be123c;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-twentyfour-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s ease;
}

.vb-accordion-twentyfour-content {
  display: grid;
  grid-template-columns: 210px minmax(0, 1fr);
  gap: 20px;
  padding: 0 22px 22px;
  align-items: stretch;
}

.vb-accordion-twentyfour-thumb {
  min-height: 150px;
  background: #f9a8d4;
}

.vb-accordion-twentyfour-thumb-a {
  background:
    linear-gradient(135deg, rgba(255,255,255,0.34), transparent 40%),
    linear-gradient(135deg, #be123c, #fb7185) !important;
}

.vb-accordion-twentyfour-thumb-b {
  background:
    repeating-linear-gradient(45deg, rgba(255,255,255,0.26) 0 8px, transparent 8px 16px),
    linear-gradient(135deg, #7c2d12, #f97316) !important;
}

.vb-accordion-twentyfour-thumb-c {
  background:
    radial-gradient(circle at 30% 30%, rgba(255,255,255,0.55), transparent 22%),
    linear-gradient(135deg, #4c1d95, #c026d3) !important;
}

.vb-accordion-twentyfour-thumb-d {
  background:
    linear-gradient(90deg, rgba(255,255,255,0.35) 1px, transparent 1px),
    linear-gradient(135deg, #0f172a, #be123c) !important;
  background-size: 16px 16px, auto !important;
}

.vb-accordion-twentyfour-content p {
  margin: 0 !important;
  padding: 18px 0;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.8;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-accordion-twentyfour-layout {
    grid-template-columns: 1fr;
  }

  .vb-accordion-twentyfour-cover {
    min-height: 520px;
  }
}

@media (max-width: 680px) {
  .vb-accordion-twentyfour-demo {
    padding: 18px;
  }

  .vb-accordion-twentyfour-cover {
    min-height: 520px;
    padding: 24px;
  }

  .vb-accordion-twentyfour-cover h3 {
    font-size: 42px !important;
  }

  .vb-accordion-twentyfour-quote {
    left: 24px;
    right: 24px;
    bottom: 24px;
  }

  .vb-accordion-twentyfour-story:nth-child(2),
  .vb-accordion-twentyfour-story:nth-child(3) {
    margin-left: 0;
    margin-right: 0;
  }

  .vb-accordion-twentyfour-trigger {
    grid-template-columns: 1fr 44px;
    gap: 12px;
  }

  .vb-accordion-twentyfour-trigger span,
  .vb-accordion-twentyfour-trigger strong {
    grid-column: 1;
  }

  .vb-accordion-twentyfour-trigger em {
    grid-column: 2;
    grid-row: 1 / span 2;
    width: 44px;
    height: 44px;
  }

  .vb-accordion-twentyfour-content {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-twentyfour]");
  if (!accordion) return;

  const stories = Array.from(accordion.querySelectorAll(".vb-accordion-twentyfour-story"));

  function updateStory(story) {
    const button = story.querySelector(".vb-accordion-twentyfour-trigger");
    const panel = story.querySelector(".vb-accordion-twentyfour-panel");
    const isOpen = story.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  stories.forEach(function (story) {
    const button = story.querySelector(".vb-accordion-twentyfour-trigger");

    button.addEventListener("click", function () {
      story.classList.toggle("is-open");
      updateStory(story);
    });

    updateStory(story);
  });

  window.addEventListener("resize", function () {
    stories.forEach(updateStory);
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-twentyfour]");
  if (!accordion) return;

  const stories = Array.from(accordion.querySelectorAll(".vb-accordion-twentyfour-story"));

  function updateStory(story) {
    const button = story.querySelector(".vb-accordion-twentyfour-trigger");
    const panel = story.querySelector(".vb-accordion-twentyfour-panel");
    const isOpen = story.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  stories.forEach(function (story) {
    const button = story.querySelector(".vb-accordion-twentyfour-trigger");

    button.addEventListener("click", function () {
      story.classList.toggle("is-open");
      updateStory(story);
    });

    updateStory(story);
  });

  window.addEventListener("resize", function () {
    stories.forEach(updateStory);
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-twentyfour-demo"&gt;
  &lt;div class="vb-accordion-twentyfour-layout" data-vb-accordion-twentyfour&gt;
    &lt;aside class="vb-accordion-twentyfour-cover"&gt;
      &lt;span&gt;Example 24&lt;/span&gt;
      &lt;h3&gt;Magazine Story Accordion&lt;/h3&gt;
      &lt;p&gt;Reveal editorial story sections with a content-first accordion layout inspired by modern magazine pages.&lt;/p&gt;
      &lt;div class="vb-accordion-twentyfour-quote"&gt;
        &lt;strong&gt;“Design becomes stronger when content has rhythm.”&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/aside&gt;

    &lt;section class="vb-accordion-twentyfour-stories"&gt;
      &lt;article class="vb-accordion-twentyfour-story is-open"&gt;
        &lt;button class="vb-accordion-twentyfour-trigger" type="button" aria-expanded="true"&gt;
          &lt;span&gt;Feature 01&lt;/span&gt;
          &lt;strong&gt;The opening idea&lt;/strong&gt;
          &lt;em&gt;+&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-twentyfour-panel"&gt;
          &lt;div class="vb-accordion-twentyfour-content"&gt;
            &lt;div class="vb-accordion-twentyfour-thumb vb-accordion-twentyfour-thumb-a"&gt;&lt;/div&gt;
            &lt;p&gt;Use this section to introduce the core idea of an article, case study, brand story, or editorial feature.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-twentyfour-story"&gt;
        &lt;button class="vb-accordion-twentyfour-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Feature 02&lt;/span&gt;
          &lt;strong&gt;Behind the process&lt;/strong&gt;
          &lt;em&gt;+&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-twentyfour-panel"&gt;
          &lt;div class="vb-accordion-twentyfour-content"&gt;
            &lt;div class="vb-accordion-twentyfour-thumb vb-accordion-twentyfour-thumb-b"&gt;&lt;/div&gt;
            &lt;p&gt;This panel can explain the process, research, decisions, mistakes, improvements, or the thinking behind the final result.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-twentyfour-story"&gt;
        &lt;button class="vb-accordion-twentyfour-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Feature 03&lt;/span&gt;
          &lt;strong&gt;Visual direction&lt;/strong&gt;
          &lt;em&gt;+&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-twentyfour-panel"&gt;
          &lt;div class="vb-accordion-twentyfour-content"&gt;
            &lt;div class="vb-accordion-twentyfour-thumb vb-accordion-twentyfour-thumb-c"&gt;&lt;/div&gt;
            &lt;p&gt;Use this section for visual decisions, layout notes, typography choices, color direction, and interface details.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-accordion-twentyfour-story"&gt;
        &lt;button class="vb-accordion-twentyfour-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;Feature 04&lt;/span&gt;
          &lt;strong&gt;Final outcome&lt;/strong&gt;
          &lt;em&gt;+&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-twentyfour-panel"&gt;
          &lt;div class="vb-accordion-twentyfour-content"&gt;
            &lt;div class="vb-accordion-twentyfour-thumb vb-accordion-twentyfour-thumb-d"&gt;&lt;/div&gt;
            &lt;p&gt;The final panel can summarize the result, measurable improvements, lessons learned, and next steps for the project.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    &lt;/section&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-twentyfour-demo,
.vb-accordion-twentyfour-demo * {
  box-sizing: border-box;
}

.vb-accordion-twentyfour-demo {
  margin: 28px 0;
  padding: 40px;
  background:
    linear-gradient(90deg, rgba(17, 24, 39, 0.07) 1px, transparent 1px),
    linear-gradient(135deg, #fff7ed 0%, #fdf2f8 48%, #ffffff 100%) !important;
  background-size: 18px 18px, auto !important;
  border: 1px solid rgba(190, 24, 93, 0.18);
  border-radius: 0;
  box-shadow: 0 28px 80px rgba(131, 24, 67, 0.10);
}

.vb-accordion-twentyfour-layout {
  display: grid;
  grid-template-columns: minmax(300px, 0.86fr) minmax(0, 1.14fr);
  gap: 28px;
  max-width: 1140px;
  margin: 0 auto;
}

.vb-accordion-twentyfour-cover {
  position: relative;
  min-height: 650px;
  padding: 34px;
  background:
    radial-gradient(circle at 24% 18%, rgba(255,255,255,0.24), transparent 34%),
    linear-gradient(135deg, #831843, #be123c 56%, #f97316) !important;
  color: #ffffff;
  overflow: hidden;
}

.vb-accordion-twentyfour-cover::before {
  content: "";
  position: absolute;
  left: 34px;
  right: 34px;
  top: 120px;
  height: 1px;
  background: rgba(255,255,255,0.24);
}

.vb-accordion-twentyfour-cover::after {
  content: "24";
  position: absolute;
  right: -20px;
  bottom: -34px;
  color: rgba(255,255,255,0.10);
  -webkit-text-fill-color: rgba(255,255,255,0.10);
  font-size: 220px;
  line-height: 0.8;
  font-weight: 950;
  letter-spacing: -0.12em;
}

.vb-accordion-twentyfour-cover span {
  display: inline-flex;
  margin-bottom: 82px;
  padding: 8px 12px;
  border: 1px solid rgba(255,255,255,0.30);
  color: #fff7ed !important;
  -webkit-text-fill-color: #fff7ed !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.15em;
  text-transform: uppercase;
}

.vb-accordion-twentyfour-cover h3 {
  position: relative;
  z-index: 2;
  margin: 0 0 18px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(44px, 5vw, 78px) !important;
  line-height: 0.86 !important;
  font-weight: 950 !important;
  letter-spacing: -0.1em;
}

.vb-accordion-twentyfour-cover p {
  position: relative;
  z-index: 2;
  max-width: 390px;
  margin: 0 !important;
  color: #ffe4e6 !important;
  -webkit-text-fill-color: #ffe4e6 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twentyfour-quote {
  position: absolute;
  left: 34px;
  right: 34px;
  bottom: 34px;
  z-index: 2;
  padding: 22px;
  border-left: 5px solid #ffffff;
  background: rgba(255,255,255,0.12);
}

.vb-accordion-twentyfour-quote strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 21px;
  line-height: 1.25;
  font-weight: 950;
  letter-spacing: -0.045em;
}

.vb-accordion-twentyfour-stories {
  display: grid;
  gap: 18px;
  align-content: center;
}

.vb-accordion-twentyfour-story {
  overflow: hidden;
  background: #ffffff;
  border: 1px solid rgba(190, 24, 93, 0.18);
  box-shadow: 0 18px 46px rgba(131, 24, 67, 0.08);
}

.vb-accordion-twentyfour-story:nth-child(2) {
  margin-left: 34px;
}

.vb-accordion-twentyfour-story:nth-child(3) {
  margin-right: 34px;
}

.vb-accordion-twentyfour-story.is-open {
  box-shadow: 0 28px 72px rgba(190, 24, 93, 0.15);
  border-color: rgba(190, 24, 93, 0.34);
}

.vb-accordion-twentyfour-trigger {
  display: grid;
  grid-template-columns: 110px minmax(0, 1fr) 48px;
  align-items: center;
  gap: 18px;
  width: 100%;
  min-height: 88px;
  padding: 20px 22px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-twentyfour-trigger span {
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.14em;
  text-transform: uppercase;
}

.vb-accordion-twentyfour-trigger strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 26px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vb-accordion-twentyfour-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border: 1px solid #111827;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 28px;
  line-height: 1;
  font-style: normal;
  font-weight: 950;
  transition: transform 0.22s ease, background 0.22s ease, color 0.22s ease;
}

.vb-accordion-twentyfour-story.is-open .vb-accordion-twentyfour-trigger em {
  transform: rotate(45deg);
  background: #be123c;
  border-color: #be123c;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-twentyfour-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s ease;
}

.vb-accordion-twentyfour-content {
  display: grid;
  grid-template-columns: 210px minmax(0, 1fr);
  gap: 20px;
  padding: 0 22px 22px;
  align-items: stretch;
}

.vb-accordion-twentyfour-thumb {
  min-height: 150px;
  background: #f9a8d4;
}

.vb-accordion-twentyfour-thumb-a {
  background:
    linear-gradient(135deg, rgba(255,255,255,0.34), transparent 40%),
    linear-gradient(135deg, #be123c, #fb7185) !important;
}

.vb-accordion-twentyfour-thumb-b {
  background:
    repeating-linear-gradient(45deg, rgba(255,255,255,0.26) 0 8px, transparent 8px 16px),
    linear-gradient(135deg, #7c2d12, #f97316) !important;
}

.vb-accordion-twentyfour-thumb-c {
  background:
    radial-gradient(circle at 30% 30%, rgba(255,255,255,0.55), transparent 22%),
    linear-gradient(135deg, #4c1d95, #c026d3) !important;
}

.vb-accordion-twentyfour-thumb-d {
  background:
    linear-gradient(90deg, rgba(255,255,255,0.35) 1px, transparent 1px),
    linear-gradient(135deg, #0f172a, #be123c) !important;
  background-size: 16px 16px, auto !important;
}

.vb-accordion-twentyfour-content p {
  margin: 0 !important;
  padding: 18px 0;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.8;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-accordion-twentyfour-layout {
    grid-template-columns: 1fr;
  }

  .vb-accordion-twentyfour-cover {
    min-height: 520px;
  }
}

@media (max-width: 680px) {
  .vb-accordion-twentyfour-demo {
    padding: 18px;
  }

  .vb-accordion-twentyfour-cover {
    min-height: 520px;
    padding: 24px;
  }

  .vb-accordion-twentyfour-cover h3 {
    font-size: 42px !important;
  }

  .vb-accordion-twentyfour-quote {
    left: 24px;
    right: 24px;
    bottom: 24px;
  }

  .vb-accordion-twentyfour-story:nth-child(2),
  .vb-accordion-twentyfour-story:nth-child(3) {
    margin-left: 0;
    margin-right: 0;
  }

  .vb-accordion-twentyfour-trigger {
    grid-template-columns: 1fr 44px;
    gap: 12px;
  }

  .vb-accordion-twentyfour-trigger span,
  .vb-accordion-twentyfour-trigger strong {
    grid-column: 1;
  }

  .vb-accordion-twentyfour-trigger em {
    grid-column: 2;
    grid-row: 1 / span 2;
    width: 44px;
    height: 44px;
  }

  .vb-accordion-twentyfour-content {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This magazine story accordion is useful for online magazines, editorial landing pages, storytelling sections, blog feature pages, portfolio case studies, brand stories, article collections, and content-rich modern websites.</p>



<h2 class="wp-block-heading">25. Analytics Report Accordion</h2>



<p class="wp-block-paragraph"><strong>An analytics report accordion</strong> is useful for dashboards, SEO reports, marketing summaries, SaaS analytics screens, client reports, performance audits, and admin panels where data sections need to be opened one by one.</p>



<p class="wp-block-paragraph">This example uses a data-report layout with metric cards, chart-like CSS bars, percentage badges, and one-open-at-a-time JavaScript behavior. The visual style is built around analytics and reporting, not standard FAQ rows.</p>



<ul class="wp-block-list">
<li>Analytics dashboard accordion design</li>
<li>One-open-at-a-time report sections</li>
<li>Metric cards and chart-style bars</li>
<li>Performance badges and data rows</li>
<li>Useful for reports, dashboards, and audits</li>
</ul>



<div class="vb-accordion-twentyfive-demo">
  <div class="vb-accordion-twentyfive-report" data-vb-accordion-twentyfive>
    <div class="vb-accordion-twentyfive-dashboard">
      <div class="vb-accordion-twentyfive-title">
        <span>Example 25</span>
        <h3>Analytics Report Accordion</h3>
        <p>Open each report block to reveal metrics, traffic insights, and dashboard-style performance notes.</p>
      </div>

      <div class="vb-accordion-twentyfive-metrics">
        <div>
          <strong>48K</strong>
          <small>Visitors</small>
        </div>
        <div>
          <strong>12.4%</strong>
          <small>Conversion</small>
        </div>
        <div>
          <strong>91</strong>
          <small>SEO score</small>
        </div>
      </div>
    </div>

    <div class="vb-accordion-twentyfive-list">
      <section class="vb-accordion-twentyfive-item is-open">
        <button class="vb-accordion-twentyfive-trigger" type="button" aria-expanded="true">
          <span>
            <small>Traffic</small>
            <strong>Organic search growth</strong>
          </span>
          <em>+24%</em>
          <i></i>
        </button>

        <div class="vb-accordion-twentyfive-panel">
          <div class="vb-accordion-twentyfive-content">
            <p>Organic search traffic increased after publishing more practical JavaScript examples and improving internal linking between related posts.</p>

            <div class="vb-accordion-twentyfive-bars">
              <div><span style="width: 72%"></span></div>
              <div><span style="width: 48%"></span></div>
              <div><span style="width: 88%"></span></div>
            </div>
          </div>
        </div>
      </section>

      <section class="vb-accordion-twentyfive-item">
        <button class="vb-accordion-twentyfive-trigger" type="button" aria-expanded="false">
          <span>
            <small>Engagement</small>
            <strong>Longer reading time</strong>
          </span>
          <em>+18%</em>
          <i></i>
        </button>

        <div class="vb-accordion-twentyfive-panel">
          <div class="vb-accordion-twentyfive-content">
            <p>Readers spent more time on pages with full visible code blocks, live previews, practical examples, and jump links to example sections.</p>

            <div class="vb-accordion-twentyfive-bars">
              <div><span style="width: 64%"></span></div>
              <div><span style="width: 76%"></span></div>
              <div><span style="width: 54%"></span></div>
            </div>
          </div>
        </div>
      </section>

      <section class="vb-accordion-twentyfive-item">
        <button class="vb-accordion-twentyfive-trigger" type="button" aria-expanded="false">
          <span>
            <small>Content</small>
            <strong>Example section performance</strong>
          </span>
          <em>+31%</em>
          <i></i>
        </button>

        <div class="vb-accordion-twentyfive-panel">
          <div class="vb-accordion-twentyfive-content">
            <p>Examples with unique layouts, different visual patterns, and complete JavaScript, HTML, and CSS code performed better than repeated designs.</p>

            <div class="vb-accordion-twentyfive-bars">
              <div><span style="width: 92%"></span></div>
              <div><span style="width: 61%"></span></div>
              <div><span style="width: 83%"></span></div>
            </div>
          </div>
        </div>
      </section>

      <section class="vb-accordion-twentyfive-item">
        <button class="vb-accordion-twentyfive-trigger" type="button" aria-expanded="false">
          <span>
            <small>Technical</small>
            <strong>Page experience score</strong>
          </span>
          <em>+9%</em>
          <i></i>
        </button>

        <div class="vb-accordion-twentyfive-panel">
          <div class="vb-accordion-twentyfive-content">
            <p>Cleaner layout spacing, responsive code previews, faster components, and reduced visual repetition improved the overall page experience.</p>

            <div class="vb-accordion-twentyfive-bars">
              <div><span style="width: 70%"></span></div>
              <div><span style="width: 86%"></span></div>
              <div><span style="width: 78%"></span></div>
            </div>
          </div>
        </div>
      </section>
    </div>
  </div>
</div>

<style>
.vb-accordion-twentyfive-demo,
.vb-accordion-twentyfive-demo * {
  box-sizing: border-box;
}

.vb-accordion-twentyfive-demo {
  margin: 28px 0;
  padding: 40px;
  border-radius: 28px;
  background:
    radial-gradient(circle at 12% 18%, rgba(34, 197, 94, 0.16), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(59, 130, 246, 0.18), transparent 34%),
    linear-gradient(135deg, #020617 0%, #0f172a 52%, #111827 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(2, 6, 23, 0.42);
}

.vb-accordion-twentyfive-report {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-accordion-twentyfive-dashboard {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 390px;
  gap: 24px;
  align-items: stretch;
  margin-bottom: 22px;
}

.vb-accordion-twentyfive-title {
  padding: 30px;
  border-radius: 24px;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.10), rgba(255,255,255,0.04)) !important;
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-accordion-twentyfive-title span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 12px;
  background: rgba(34, 197, 94, 0.14);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-twentyfive-title h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(40px, 5vw, 74px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.09em;
}

.vb-accordion-twentyfive-title p {
  max-width: 700px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twentyfive-metrics {
  display: grid;
  gap: 12px;
}

.vb-accordion-twentyfive-metrics div {
  padding: 22px;
  border-radius: 24px;
  background: #ffffff;
  box-shadow: 0 18px 48px rgba(2, 6, 23, 0.22);
}

.vb-accordion-twentyfive-metrics strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 42px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.08em;
}

.vb-accordion-twentyfive-metrics small {
  display: block;
  margin-top: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-accordion-twentyfive-list {
  display: grid;
  gap: 12px;
}

.vb-accordion-twentyfive-item {
  overflow: hidden;
  border-radius: 22px;
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-accordion-twentyfive-item.is-open {
  background: rgba(255,255,255,0.10);
  border-color: rgba(34, 197, 94, 0.30);
}

.vb-accordion-twentyfive-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 88px 44px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 86px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-twentyfive-trigger small {
  display: inline-flex;
  margin-bottom: 7px;
  padding: 5px 9px;
  border-radius: 999px;
  background: rgba(59, 130, 246, 0.14);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-accordion-twentyfive-trigger strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 21px;
  line-height: 1.15;
  font-weight: 950;
  letter-spacing: -0.045em;
}

.vb-accordion-twentyfive-trigger em {
  justify-self: end;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 38px;
  padding: 9px 12px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.14);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 13px;
  font-style: normal;
  font-weight: 950;
}

.vb-accordion-twentyfive-trigger i {
  position: relative;
  width: 44px;
  height: 44px;
  border-radius: 14px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-accordion-twentyfive-trigger i::before,
.vb-accordion-twentyfive-trigger i::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 15px;
  height: 2px;
  border-radius: 999px;
  background: #ffffff;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease, transform 0.22s ease;
}

.vb-accordion-twentyfive-trigger i::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-twentyfive-item.is-open .vb-accordion-twentyfive-trigger i {
  background: #22c55e;
}

.vb-accordion-twentyfive-item.is-open .vb-accordion-twentyfive-trigger i::after {
  opacity: 0;
}

.vb-accordion-twentyfive-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s ease;
}

.vb-accordion-twentyfive-content {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 240px;
  gap: 22px;
  padding: 0 20px 20px;
}

.vb-accordion-twentyfive-content p {
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twentyfive-bars {
  display: grid;
  gap: 10px;
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.06);
}

.vb-accordion-twentyfive-bars div {
  overflow: hidden;
  height: 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
}

.vb-accordion-twentyfive-bars span {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #22c55e, #38bdf8) !important;
}

@media (max-width: 860px) {
  .vb-accordion-twentyfive-dashboard,
  .vb-accordion-twentyfive-content {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-accordion-twentyfive-demo {
    padding: 18px;
    border-radius: 22px;
  }

  .vb-accordion-twentyfive-title {
    padding: 22px;
  }

  .vb-accordion-twentyfive-title h3 {
    font-size: 40px !important;
  }

  .vb-accordion-twentyfive-trigger {
    grid-template-columns: 1fr 40px;
  }

  .vb-accordion-twentyfive-trigger em {
    grid-column: 1;
    justify-self: start;
  }

  .vb-accordion-twentyfive-trigger i {
    grid-column: 2;
    grid-row: 1;
    width: 40px;
    height: 40px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-twentyfive]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-twentyfive-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-twentyfive-trigger");
    const panel = item.querySelector(".vb-accordion-twentyfive-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-twentyfive-trigger");
    const panel = item.querySelector(".vb-accordion-twentyfive-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-twentyfive-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-twentyfive-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-twentyfive-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-twentyfive]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-twentyfive-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-twentyfive-trigger");
    const panel = item.querySelector(".vb-accordion-twentyfive-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-twentyfive-trigger");
    const panel = item.querySelector(".vb-accordion-twentyfive-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-twentyfive-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-twentyfive-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-twentyfive-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-twentyfive-demo"&gt;
  &lt;div class="vb-accordion-twentyfive-report" data-vb-accordion-twentyfive&gt;
    &lt;div class="vb-accordion-twentyfive-dashboard"&gt;
      &lt;div class="vb-accordion-twentyfive-title"&gt;
        &lt;span&gt;Example 25&lt;/span&gt;
        &lt;h3&gt;Analytics Report Accordion&lt;/h3&gt;
        &lt;p&gt;Open each report block to reveal metrics, traffic insights, and dashboard-style performance notes.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-twentyfive-metrics"&gt;
        &lt;div&gt;
          &lt;strong&gt;48K&lt;/strong&gt;
          &lt;small&gt;Visitors&lt;/small&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;strong&gt;12.4%&lt;/strong&gt;
          &lt;small&gt;Conversion&lt;/small&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;strong&gt;91&lt;/strong&gt;
          &lt;small&gt;SEO score&lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-twentyfive-list"&gt;
      &lt;section class="vb-accordion-twentyfive-item is-open"&gt;
        &lt;button class="vb-accordion-twentyfive-trigger" type="button" aria-expanded="true"&gt;
          &lt;span&gt;
            &lt;small&gt;Traffic&lt;/small&gt;
            &lt;strong&gt;Organic search growth&lt;/strong&gt;
          &lt;/span&gt;
          &lt;em&gt;+24%&lt;/em&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-twentyfive-panel"&gt;
          &lt;div class="vb-accordion-twentyfive-content"&gt;
            &lt;p&gt;Organic search traffic increased after publishing more practical JavaScript examples and improving internal linking between related posts.&lt;/p&gt;

            &lt;div class="vb-accordion-twentyfive-bars"&gt;
              &lt;div&gt;&lt;span style="width: 72%"&gt;&lt;/span&gt;&lt;/div&gt;
              &lt;div&gt;&lt;span style="width: 48%"&gt;&lt;/span&gt;&lt;/div&gt;
              &lt;div&gt;&lt;span style="width: 88%"&gt;&lt;/span&gt;&lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-twentyfive-item"&gt;
        &lt;button class="vb-accordion-twentyfive-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;
            &lt;small&gt;Engagement&lt;/small&gt;
            &lt;strong&gt;Longer reading time&lt;/strong&gt;
          &lt;/span&gt;
          &lt;em&gt;+18%&lt;/em&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-twentyfive-panel"&gt;
          &lt;div class="vb-accordion-twentyfive-content"&gt;
            &lt;p&gt;Readers spent more time on pages with full visible code blocks, live previews, practical examples, and jump links to example sections.&lt;/p&gt;

            &lt;div class="vb-accordion-twentyfive-bars"&gt;
              &lt;div&gt;&lt;span style="width: 64%"&gt;&lt;/span&gt;&lt;/div&gt;
              &lt;div&gt;&lt;span style="width: 76%"&gt;&lt;/span&gt;&lt;/div&gt;
              &lt;div&gt;&lt;span style="width: 54%"&gt;&lt;/span&gt;&lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-twentyfive-item"&gt;
        &lt;button class="vb-accordion-twentyfive-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;
            &lt;small&gt;Content&lt;/small&gt;
            &lt;strong&gt;Example section performance&lt;/strong&gt;
          &lt;/span&gt;
          &lt;em&gt;+31%&lt;/em&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-twentyfive-panel"&gt;
          &lt;div class="vb-accordion-twentyfive-content"&gt;
            &lt;p&gt;Examples with unique layouts, different visual patterns, and complete JavaScript, HTML, and CSS code performed better than repeated designs.&lt;/p&gt;

            &lt;div class="vb-accordion-twentyfive-bars"&gt;
              &lt;div&gt;&lt;span style="width: 92%"&gt;&lt;/span&gt;&lt;/div&gt;
              &lt;div&gt;&lt;span style="width: 61%"&gt;&lt;/span&gt;&lt;/div&gt;
              &lt;div&gt;&lt;span style="width: 83%"&gt;&lt;/span&gt;&lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-twentyfive-item"&gt;
        &lt;button class="vb-accordion-twentyfive-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;
            &lt;small&gt;Technical&lt;/small&gt;
            &lt;strong&gt;Page experience score&lt;/strong&gt;
          &lt;/span&gt;
          &lt;em&gt;+9%&lt;/em&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-twentyfive-panel"&gt;
          &lt;div class="vb-accordion-twentyfive-content"&gt;
            &lt;p&gt;Cleaner layout spacing, responsive code previews, faster components, and reduced visual repetition improved the overall page experience.&lt;/p&gt;

            &lt;div class="vb-accordion-twentyfive-bars"&gt;
              &lt;div&gt;&lt;span style="width: 70%"&gt;&lt;/span&gt;&lt;/div&gt;
              &lt;div&gt;&lt;span style="width: 86%"&gt;&lt;/span&gt;&lt;/div&gt;
              &lt;div&gt;&lt;span style="width: 78%"&gt;&lt;/span&gt;&lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-twentyfive-demo,
.vb-accordion-twentyfive-demo * {
  box-sizing: border-box;
}

.vb-accordion-twentyfive-demo {
  margin: 28px 0;
  padding: 40px;
  border-radius: 28px;
  background:
    radial-gradient(circle at 12% 18%, rgba(34, 197, 94, 0.16), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(59, 130, 246, 0.18), transparent 34%),
    linear-gradient(135deg, #020617 0%, #0f172a 52%, #111827 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(2, 6, 23, 0.42);
}

.vb-accordion-twentyfive-report {
  max-width: 1120px;
  margin: 0 auto;
}

.vb-accordion-twentyfive-dashboard {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 390px;
  gap: 24px;
  align-items: stretch;
  margin-bottom: 22px;
}

.vb-accordion-twentyfive-title {
  padding: 30px;
  border-radius: 24px;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.10), rgba(255,255,255,0.04)) !important;
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-accordion-twentyfive-title span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 12px;
  background: rgba(34, 197, 94, 0.14);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-twentyfive-title h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(40px, 5vw, 74px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.09em;
}

.vb-accordion-twentyfive-title p {
  max-width: 700px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twentyfive-metrics {
  display: grid;
  gap: 12px;
}

.vb-accordion-twentyfive-metrics div {
  padding: 22px;
  border-radius: 24px;
  background: #ffffff;
  box-shadow: 0 18px 48px rgba(2, 6, 23, 0.22);
}

.vb-accordion-twentyfive-metrics strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 42px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.08em;
}

.vb-accordion-twentyfive-metrics small {
  display: block;
  margin-top: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-accordion-twentyfive-list {
  display: grid;
  gap: 12px;
}

.vb-accordion-twentyfive-item {
  overflow: hidden;
  border-radius: 22px;
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-accordion-twentyfive-item.is-open {
  background: rgba(255,255,255,0.10);
  border-color: rgba(34, 197, 94, 0.30);
}

.vb-accordion-twentyfive-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 88px 44px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 86px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-twentyfive-trigger small {
  display: inline-flex;
  margin-bottom: 7px;
  padding: 5px 9px;
  border-radius: 999px;
  background: rgba(59, 130, 246, 0.14);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-accordion-twentyfive-trigger strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 21px;
  line-height: 1.15;
  font-weight: 950;
  letter-spacing: -0.045em;
}

.vb-accordion-twentyfive-trigger em {
  justify-self: end;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 38px;
  padding: 9px 12px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.14);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 13px;
  font-style: normal;
  font-weight: 950;
}

.vb-accordion-twentyfive-trigger i {
  position: relative;
  width: 44px;
  height: 44px;
  border-radius: 14px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-accordion-twentyfive-trigger i::before,
.vb-accordion-twentyfive-trigger i::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 15px;
  height: 2px;
  border-radius: 999px;
  background: #ffffff;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease, transform 0.22s ease;
}

.vb-accordion-twentyfive-trigger i::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-twentyfive-item.is-open .vb-accordion-twentyfive-trigger i {
  background: #22c55e;
}

.vb-accordion-twentyfive-item.is-open .vb-accordion-twentyfive-trigger i::after {
  opacity: 0;
}

.vb-accordion-twentyfive-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s ease;
}

.vb-accordion-twentyfive-content {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 240px;
  gap: 22px;
  padding: 0 20px 20px;
}

.vb-accordion-twentyfive-content p {
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twentyfive-bars {
  display: grid;
  gap: 10px;
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.06);
}

.vb-accordion-twentyfive-bars div {
  overflow: hidden;
  height: 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
}

.vb-accordion-twentyfive-bars span {
  display: block;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #22c55e, #38bdf8) !important;
}

@media (max-width: 860px) {
  .vb-accordion-twentyfive-dashboard,
  .vb-accordion-twentyfive-content {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-accordion-twentyfive-demo {
    padding: 18px;
    border-radius: 22px;
  }

  .vb-accordion-twentyfive-title {
    padding: 22px;
  }

  .vb-accordion-twentyfive-title h3 {
    font-size: 40px !important;
  }

  .vb-accordion-twentyfive-trigger {
    grid-template-columns: 1fr 40px;
  }

  .vb-accordion-twentyfive-trigger em {
    grid-column: 1;
    justify-self: start;
  }

  .vb-accordion-twentyfive-trigger i {
    grid-column: 2;
    grid-row: 1;
    width: 40px;
    height: 40px;
  }
}</pre>



<p class="wp-block-paragraph">This analytics report accordion is useful for SEO reports, marketing dashboards, client audits, SaaS metrics, performance summaries, traffic reports, and admin analytics interfaces.</p>



<h2 class="wp-block-heading">26. Mobile App Settings Accordion</h2>



<p class="wp-block-paragraph"><strong>A mobile app settings accordion</strong> is useful for mobile app landing pages, profile screens, account settings pages, app dashboards, onboarding previews, and product UI sections that need compact expandable settings.</p>



<p class="wp-block-paragraph">This example looks like a phone screen with segmented settings cards, toggle rows, app-style icons, and multi-open JavaScript behavior. It is intentionally designed as a mobile interface preview instead of a wide website accordion.</p>



<ul class="wp-block-list">
<li>Phone-style app settings accordion</li>
<li>Multi-open settings behavior</li>
<li>Toggle controls and icon rows</li>
<li>Mobile-first visual structure</li>
<li>Useful for app UI and profile settings sections</li>
</ul>



<div class="vb-accordion-twentysix-demo">
  <div class="vb-accordion-twentysix-stage" data-vb-accordion-twentysix>
    <div class="vb-accordion-twentysix-copy">
      <span>Example 26</span>
      <h3>Mobile App Settings Accordion</h3>
      <p>Show app settings, privacy controls, notification options, and account preferences inside a phone-like accordion interface.</p>
    </div>

    <div class="vb-accordion-twentysix-phone">
      <div class="vb-accordion-twentysix-status">
        <strong>9:41</strong>
        <span></span>
      </div>

      <div class="vb-accordion-twentysix-profile">
        <i></i>
        <div>
          <strong>App Settings</strong>
          <small>4 sections available</small>
        </div>
      </div>

      <div class="vb-accordion-twentysix-list">
        <section class="vb-accordion-twentysix-item is-open">
          <button class="vb-accordion-twentysix-trigger" type="button" aria-expanded="true">
            <span class="vb-accordion-twentysix-icon">🔔</span>
            <strong>Notifications</strong>
            <em></em>
          </button>

          <div class="vb-accordion-twentysix-panel">
            <div class="vb-accordion-twentysix-content">
              <label>
                <span>Push alerts</span>
                <input type="checkbox" checked>
              </label>
              <label>
                <span>Weekly summary</span>
                <input type="checkbox">
              </label>
            </div>
          </div>
        </section>

        <section class="vb-accordion-twentysix-item">
          <button class="vb-accordion-twentysix-trigger" type="button" aria-expanded="false">
            <span class="vb-accordion-twentysix-icon">🔒</span>
            <strong>Privacy</strong>
            <em></em>
          </button>

          <div class="vb-accordion-twentysix-panel">
            <div class="vb-accordion-twentysix-content">
              <label>
                <span>Hide activity</span>
                <input type="checkbox" checked>
              </label>
              <label>
                <span>Personalized content</span>
                <input type="checkbox">
              </label>
            </div>
          </div>
        </section>

        <section class="vb-accordion-twentysix-item">
          <button class="vb-accordion-twentysix-trigger" type="button" aria-expanded="false">
            <span class="vb-accordion-twentysix-icon">🎨</span>
            <strong>Appearance</strong>
            <em></em>
          </button>

          <div class="vb-accordion-twentysix-panel">
            <div class="vb-accordion-twentysix-content">
              <label>
                <span>Dark mode</span>
                <input type="checkbox" checked>
              </label>
              <label>
                <span>Reduce motion</span>
                <input type="checkbox">
              </label>
            </div>
          </div>
        </section>

        <section class="vb-accordion-twentysix-item">
          <button class="vb-accordion-twentysix-trigger" type="button" aria-expanded="false">
            <span class="vb-accordion-twentysix-icon">💳</span>
            <strong>Billing</strong>
            <em></em>
          </button>

          <div class="vb-accordion-twentysix-panel">
            <div class="vb-accordion-twentysix-content">
              <label>
                <span>Renewal reminders</span>
                <input type="checkbox" checked>
              </label>
              <label>
                <span>Email invoices</span>
                <input type="checkbox" checked>
              </label>
            </div>
          </div>
        </section>
      </div>
    </div>
  </div>
</div>

<style>
.vb-accordion-twentysix-demo,
.vb-accordion-twentysix-demo * {
  box-sizing: border-box;
}

.vb-accordion-twentysix-demo {
  margin: 28px 0;
  padding: 42px;
  border-radius: 52px;
  background:
    radial-gradient(circle at 18% 18%, rgba(244, 114, 182, 0.20), transparent 32%),
    radial-gradient(circle at 82% 22%, rgba(99, 102, 241, 0.20), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(244, 114, 182, 0.26);
  box-shadow: 0 28px 80px rgba(88, 28, 135, 0.12);
}

.vb-accordion-twentysix-stage {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 380px;
  gap: 34px;
  align-items: center;
  max-width: 1060px;
  margin: 0 auto;
}

.vb-accordion-twentysix-copy {
  max-width: 620px;
}

.vb-accordion-twentysix-copy span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 9px 13px;
  border-radius: 999px;
  background: #db2777;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-twentysix-copy h3 {
  margin: 0 0 16px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(42px, 5vw, 78px) !important;
  line-height: 0.88 !important;
  font-weight: 950 !important;
  letter-spacing: -0.095em;
}

.vb-accordion-twentysix-copy p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.8;
  font-weight: 650;
}

.vb-accordion-twentysix-phone {
  position: relative;
  overflow: hidden;
  min-height: 710px;
  padding: 18px;
  border-radius: 42px;
  background: #111827;
  border: 10px solid #020617;
  box-shadow:
    0 36px 90px rgba(15, 23, 42, 0.28),
    inset 0 0 0 1px rgba(255,255,255,0.08);
}

.vb-accordion-twentysix-phone::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 10px;
  width: 98px;
  height: 24px;
  border-radius: 0 0 18px 18px;
  background: #020617;
  transform: translateX(-50%);
  z-index: 3;
}

.vb-accordion-twentysix-status {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 18px 16px 14px;
  color: #ffffff;
}

.vb-accordion-twentysix-status strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-accordion-twentysix-status span {
  width: 54px;
  height: 12px;
  border-radius: 999px;
  background: linear-gradient(90deg, #ffffff 0 36%, rgba(255,255,255,0.42) 36% 62%, rgba(255,255,255,0.24) 62% 100%) !important;
}

.vb-accordion-twentysix-profile {
  display: grid;
  grid-template-columns: 58px minmax(0, 1fr);
  gap: 14px;
  align-items: center;
  margin: 10px 0 16px;
  padding: 16px;
  border-radius: 28px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 36%),
    linear-gradient(135deg, #db2777, #6366f1) !important;
}

.vb-accordion-twentysix-profile i {
  width: 58px;
  height: 58px;
  border-radius: 20px;
  background:
    radial-gradient(circle at 32% 28%, #ffffff 0 12px, transparent 13px),
    linear-gradient(135deg, rgba(255,255,255,0.38), rgba(255,255,255,0.16)) !important;
  border: 1px solid rgba(255,255,255,0.20);
}

.vb-accordion-twentysix-profile strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-accordion-twentysix-profile small {
  display: block;
  margin-top: 5px;
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 13px;
  font-weight: 800;
}

.vb-accordion-twentysix-list {
  display: grid;
  gap: 11px;
}

.vb-accordion-twentysix-item {
  overflow: hidden;
  border-radius: 24px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.09);
}

.vb-accordion-twentysix-item.is-open {
  background: rgba(255,255,255,0.12);
  border-color: rgba(244, 114, 182, 0.34);
}

.vb-accordion-twentysix-trigger {
  display: grid;
  grid-template-columns: 46px minmax(0, 1fr) 36px;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 72px;
  padding: 14px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-twentysix-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  border-radius: 16px;
  background: rgba(255,255,255,0.10);
  font-size: 20px;
}

.vb-accordion-twentysix-trigger strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 17px;
  line-height: 1.2;
  font-weight: 900;
}

.vb-accordion-twentysix-trigger em {
  position: relative;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
}

.vb-accordion-twentysix-trigger em::before,
.vb-accordion-twentysix-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 14px;
  height: 2px;
  border-radius: 999px;
  background: #ffffff;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease;
}

.vb-accordion-twentysix-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-twentysix-item.is-open .vb-accordion-twentysix-trigger em {
  background: #db2777;
}

.vb-accordion-twentysix-item.is-open .vb-accordion-twentysix-trigger em::after {
  opacity: 0;
}

.vb-accordion-twentysix-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-twentysix-content {
  display: grid;
  gap: 8px;
  padding: 0 14px 14px 72px;
}

.vb-accordion-twentysix-content label {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 44px;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  border-radius: 16px;
  background: rgba(255,255,255,0.07);
}

.vb-accordion-twentysix-content label span {
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 13px;
  font-weight: 800;
}

.vb-accordion-twentysix-content input {
  appearance: none;
  position: relative;
  width: 44px;
  height: 26px;
  border-radius: 999px;
  background: rgba(255,255,255,0.18);
  cursor: pointer;
}

.vb-accordion-twentysix-content input::before {
  content: "";
  position: absolute;
  left: 3px;
  top: 3px;
  width: 20px;
  height: 20px;
  border-radius: 999px;
  background: #ffffff;
  transition: transform 0.2s ease;
}

.vb-accordion-twentysix-content input:checked {
  background: #ec4899;
}

.vb-accordion-twentysix-content input:checked::before {
  transform: translateX(18px);
}

@media (max-width: 860px) {
  .vb-accordion-twentysix-stage {
    grid-template-columns: 1fr;
  }

  .vb-accordion-twentysix-phone {
    max-width: 380px;
    width: 100%;
    margin: 0 auto;
  }
}

@media (max-width: 520px) {
  .vb-accordion-twentysix-demo {
    padding: 18px;
    border-radius: 34px;
  }

  .vb-accordion-twentysix-copy h3 {
    font-size: 40px !important;
  }

  .vb-accordion-twentysix-phone {
    min-height: 680px;
    border-width: 7px;
    border-radius: 36px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-twentysix]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-twentysix-item"));

  function updateItem(item) {
    const button = item.querySelector(".vb-accordion-twentysix-trigger");
    const panel = item.querySelector(".vb-accordion-twentysix-panel");
    const isOpen = item.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-twentysix-trigger");

    button.addEventListener("click", function () {
      item.classList.toggle("is-open");
      updateItem(item);
    });

    updateItem(item);
  });

  window.addEventListener("resize", function () {
    items.forEach(updateItem);
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-twentysix]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-twentysix-item"));

  function updateItem(item) {
    const button = item.querySelector(".vb-accordion-twentysix-trigger");
    const panel = item.querySelector(".vb-accordion-twentysix-panel");
    const isOpen = item.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-twentysix-trigger");

    button.addEventListener("click", function () {
      item.classList.toggle("is-open");
      updateItem(item);
    });

    updateItem(item);
  });

  window.addEventListener("resize", function () {
    items.forEach(updateItem);
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-twentysix-demo"&gt;
  &lt;div class="vb-accordion-twentysix-stage" data-vb-accordion-twentysix&gt;
    &lt;div class="vb-accordion-twentysix-copy"&gt;
      &lt;span&gt;Example 26&lt;/span&gt;
      &lt;h3&gt;Mobile App Settings Accordion&lt;/h3&gt;
      &lt;p&gt;Show app settings, privacy controls, notification options, and account preferences inside a phone-like accordion interface.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-twentysix-phone"&gt;
      &lt;div class="vb-accordion-twentysix-status"&gt;
        &lt;strong&gt;9:41&lt;/strong&gt;
        &lt;span&gt;&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-twentysix-profile"&gt;
        &lt;i&gt;&lt;/i&gt;
        &lt;div&gt;
          &lt;strong&gt;App Settings&lt;/strong&gt;
          &lt;small&gt;4 sections available&lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-twentysix-list"&gt;
        &lt;section class="vb-accordion-twentysix-item is-open"&gt;
          &lt;button class="vb-accordion-twentysix-trigger" type="button" aria-expanded="true"&gt;
            &lt;span class="vb-accordion-twentysix-icon"&gt;🔔&lt;/span&gt;
            &lt;strong&gt;Notifications&lt;/strong&gt;
            &lt;em&gt;&lt;/em&gt;
          &lt;/button&gt;

          &lt;div class="vb-accordion-twentysix-panel"&gt;
            &lt;div class="vb-accordion-twentysix-content"&gt;
              &lt;label&gt;
                &lt;span&gt;Push alerts&lt;/span&gt;
                &lt;input type="checkbox" checked&gt;
              &lt;/label&gt;
              &lt;label&gt;
                &lt;span&gt;Weekly summary&lt;/span&gt;
                &lt;input type="checkbox"&gt;
              &lt;/label&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;

        &lt;section class="vb-accordion-twentysix-item"&gt;
          &lt;button class="vb-accordion-twentysix-trigger" type="button" aria-expanded="false"&gt;
            &lt;span class="vb-accordion-twentysix-icon"&gt;🔒&lt;/span&gt;
            &lt;strong&gt;Privacy&lt;/strong&gt;
            &lt;em&gt;&lt;/em&gt;
          &lt;/button&gt;

          &lt;div class="vb-accordion-twentysix-panel"&gt;
            &lt;div class="vb-accordion-twentysix-content"&gt;
              &lt;label&gt;
                &lt;span&gt;Hide activity&lt;/span&gt;
                &lt;input type="checkbox" checked&gt;
              &lt;/label&gt;
              &lt;label&gt;
                &lt;span&gt;Personalized content&lt;/span&gt;
                &lt;input type="checkbox"&gt;
              &lt;/label&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;

        &lt;section class="vb-accordion-twentysix-item"&gt;
          &lt;button class="vb-accordion-twentysix-trigger" type="button" aria-expanded="false"&gt;
            &lt;span class="vb-accordion-twentysix-icon"&gt;🎨&lt;/span&gt;
            &lt;strong&gt;Appearance&lt;/strong&gt;
            &lt;em&gt;&lt;/em&gt;
          &lt;/button&gt;

          &lt;div class="vb-accordion-twentysix-panel"&gt;
            &lt;div class="vb-accordion-twentysix-content"&gt;
              &lt;label&gt;
                &lt;span&gt;Dark mode&lt;/span&gt;
                &lt;input type="checkbox" checked&gt;
              &lt;/label&gt;
              &lt;label&gt;
                &lt;span&gt;Reduce motion&lt;/span&gt;
                &lt;input type="checkbox"&gt;
              &lt;/label&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;

        &lt;section class="vb-accordion-twentysix-item"&gt;
          &lt;button class="vb-accordion-twentysix-trigger" type="button" aria-expanded="false"&gt;
            &lt;span class="vb-accordion-twentysix-icon"&gt;💳&lt;/span&gt;
            &lt;strong&gt;Billing&lt;/strong&gt;
            &lt;em&gt;&lt;/em&gt;
          &lt;/button&gt;

          &lt;div class="vb-accordion-twentysix-panel"&gt;
            &lt;div class="vb-accordion-twentysix-content"&gt;
              &lt;label&gt;
                &lt;span&gt;Renewal reminders&lt;/span&gt;
                &lt;input type="checkbox" checked&gt;
              &lt;/label&gt;
              &lt;label&gt;
                &lt;span&gt;Email invoices&lt;/span&gt;
                &lt;input type="checkbox" checked&gt;
              &lt;/label&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-twentysix-demo,
.vb-accordion-twentysix-demo * {
  box-sizing: border-box;
}

.vb-accordion-twentysix-demo {
  margin: 28px 0;
  padding: 42px;
  border-radius: 52px;
  background:
    radial-gradient(circle at 18% 18%, rgba(244, 114, 182, 0.20), transparent 32%),
    radial-gradient(circle at 82% 22%, rgba(99, 102, 241, 0.20), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(244, 114, 182, 0.26);
  box-shadow: 0 28px 80px rgba(88, 28, 135, 0.12);
}

.vb-accordion-twentysix-stage {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 380px;
  gap: 34px;
  align-items: center;
  max-width: 1060px;
  margin: 0 auto;
}

.vb-accordion-twentysix-copy {
  max-width: 620px;
}

.vb-accordion-twentysix-copy span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 9px 13px;
  border-radius: 999px;
  background: #db2777;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-twentysix-copy h3 {
  margin: 0 0 16px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(42px, 5vw, 78px) !important;
  line-height: 0.88 !important;
  font-weight: 950 !important;
  letter-spacing: -0.095em;
}

.vb-accordion-twentysix-copy p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.8;
  font-weight: 650;
}

.vb-accordion-twentysix-phone {
  position: relative;
  overflow: hidden;
  min-height: 710px;
  padding: 18px;
  border-radius: 42px;
  background: #111827;
  border: 10px solid #020617;
  box-shadow:
    0 36px 90px rgba(15, 23, 42, 0.28),
    inset 0 0 0 1px rgba(255,255,255,0.08);
}

.vb-accordion-twentysix-phone::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 10px;
  width: 98px;
  height: 24px;
  border-radius: 0 0 18px 18px;
  background: #020617;
  transform: translateX(-50%);
  z-index: 3;
}

.vb-accordion-twentysix-status {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 18px 16px 14px;
  color: #ffffff;
}

.vb-accordion-twentysix-status strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-accordion-twentysix-status span {
  width: 54px;
  height: 12px;
  border-radius: 999px;
  background: linear-gradient(90deg, #ffffff 0 36%, rgba(255,255,255,0.42) 36% 62%, rgba(255,255,255,0.24) 62% 100%) !important;
}

.vb-accordion-twentysix-profile {
  display: grid;
  grid-template-columns: 58px minmax(0, 1fr);
  gap: 14px;
  align-items: center;
  margin: 10px 0 16px;
  padding: 16px;
  border-radius: 28px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 36%),
    linear-gradient(135deg, #db2777, #6366f1) !important;
}

.vb-accordion-twentysix-profile i {
  width: 58px;
  height: 58px;
  border-radius: 20px;
  background:
    radial-gradient(circle at 32% 28%, #ffffff 0 12px, transparent 13px),
    linear-gradient(135deg, rgba(255,255,255,0.38), rgba(255,255,255,0.16)) !important;
  border: 1px solid rgba(255,255,255,0.20);
}

.vb-accordion-twentysix-profile strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-accordion-twentysix-profile small {
  display: block;
  margin-top: 5px;
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 13px;
  font-weight: 800;
}

.vb-accordion-twentysix-list {
  display: grid;
  gap: 11px;
}

.vb-accordion-twentysix-item {
  overflow: hidden;
  border-radius: 24px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.09);
}

.vb-accordion-twentysix-item.is-open {
  background: rgba(255,255,255,0.12);
  border-color: rgba(244, 114, 182, 0.34);
}

.vb-accordion-twentysix-trigger {
  display: grid;
  grid-template-columns: 46px minmax(0, 1fr) 36px;
  align-items: center;
  gap: 12px;
  width: 100%;
  min-height: 72px;
  padding: 14px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-twentysix-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  border-radius: 16px;
  background: rgba(255,255,255,0.10);
  font-size: 20px;
}

.vb-accordion-twentysix-trigger strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 17px;
  line-height: 1.2;
  font-weight: 900;
}

.vb-accordion-twentysix-trigger em {
  position: relative;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
}

.vb-accordion-twentysix-trigger em::before,
.vb-accordion-twentysix-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 14px;
  height: 2px;
  border-radius: 999px;
  background: #ffffff;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease;
}

.vb-accordion-twentysix-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-twentysix-item.is-open .vb-accordion-twentysix-trigger em {
  background: #db2777;
}

.vb-accordion-twentysix-item.is-open .vb-accordion-twentysix-trigger em::after {
  opacity: 0;
}

.vb-accordion-twentysix-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-twentysix-content {
  display: grid;
  gap: 8px;
  padding: 0 14px 14px 72px;
}

.vb-accordion-twentysix-content label {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 44px;
  align-items: center;
  gap: 12px;
  padding: 10px 12px;
  border-radius: 16px;
  background: rgba(255,255,255,0.07);
}

.vb-accordion-twentysix-content label span {
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 13px;
  font-weight: 800;
}

.vb-accordion-twentysix-content input {
  appearance: none;
  position: relative;
  width: 44px;
  height: 26px;
  border-radius: 999px;
  background: rgba(255,255,255,0.18);
  cursor: pointer;
}

.vb-accordion-twentysix-content input::before {
  content: "";
  position: absolute;
  left: 3px;
  top: 3px;
  width: 20px;
  height: 20px;
  border-radius: 999px;
  background: #ffffff;
  transition: transform 0.2s ease;
}

.vb-accordion-twentysix-content input:checked {
  background: #ec4899;
}

.vb-accordion-twentysix-content input:checked::before {
  transform: translateX(18px);
}

@media (max-width: 860px) {
  .vb-accordion-twentysix-stage {
    grid-template-columns: 1fr;
  }

  .vb-accordion-twentysix-phone {
    max-width: 380px;
    width: 100%;
    margin: 0 auto;
  }
}

@media (max-width: 520px) {
  .vb-accordion-twentysix-demo {
    padding: 18px;
    border-radius: 34px;
  }

  .vb-accordion-twentysix-copy h3 {
    font-size: 40px !important;
  }

  .vb-accordion-twentysix-phone {
    min-height: 680px;
    border-width: 7px;
    border-radius: 36px;
  }
}</pre>



<p class="wp-block-paragraph">This mobile app settings accordion is useful for mobile app landing pages, user account screens, app dashboards, profile settings, privacy settings, notification controls, and mobile-first UI examples.</p>



<h2 class="wp-block-heading">27. File Upload Accordion</h2>



<p class="wp-block-paragraph"><strong>A file upload accordion</strong> is useful for dashboards, document portals, onboarding forms, client areas, support ticket pages, job application forms, and admin panels where users need to upload different types of files in a structured way.</p>



<p class="wp-block-paragraph">This example uses a document-upload layout with dashed drop zones, upload status chips, file type labels, and one-open-at-a-time JavaScript behavior. The design is intentionally different from normal FAQ accordions because it feels like a practical file management interface.</p>



<ul class="wp-block-list">
<li>File upload accordion layout</li>
<li>One-open-at-a-time behavior</li>
<li>Upload zones and file type labels</li>
<li>Status chips and document rows</li>
<li>Useful for portals, forms, and dashboards</li>
</ul>



<div class="vb-accordion-twentyseven-demo">
  <div class="vb-accordion-twentyseven-uploader" data-vb-accordion-twentyseven>
    <div class="vb-accordion-twentyseven-side">
      <span>Example 27</span>
      <h3>File Upload Accordion</h3>
      <p>Organize upload requirements into expandable document sections with clear file status and upload instructions.</p>

      <div class="vb-accordion-twentyseven-summary">
        <div>
          <strong>6</strong>
          <small>Files needed</small>
        </div>
        <div>
          <strong>3</strong>
          <small>Uploaded</small>
        </div>
      </div>
    </div>

    <div class="vb-accordion-twentyseven-stack">
      <section class="vb-accordion-twentyseven-item is-open">
        <button class="vb-accordion-twentyseven-trigger" type="button" aria-expanded="true">
          <span class="vb-accordion-twentyseven-docicon">PDF</span>
          <span>
            <strong>Identity documents</strong>
            <small>Passport, ID card, or driver license</small>
          </span>
          <em>Required</em>
          <i></i>
        </button>

        <div class="vb-accordion-twentyseven-panel">
          <div class="vb-accordion-twentyseven-content">
            <div class="vb-accordion-twentyseven-drop">
              <strong>Drop files here</strong>
              <p>Accepted formats: PDF, JPG, PNG. Maximum file size: 10 MB.</p>
              <button type="button">Choose file</button>
            </div>
          </div>
        </div>
      </section>

      <section class="vb-accordion-twentyseven-item">
        <button class="vb-accordion-twentyseven-trigger" type="button" aria-expanded="false">
          <span class="vb-accordion-twentyseven-docicon">DOC</span>
          <span>
            <strong>Application form</strong>
            <small>Signed form or completed document</small>
          </span>
          <em>Pending</em>
          <i></i>
        </button>

        <div class="vb-accordion-twentyseven-panel">
          <div class="vb-accordion-twentyseven-content">
            <div class="vb-accordion-twentyseven-drop">
              <strong>Upload signed form</strong>
              <p>Use this section for signed contracts, application forms, consent files, or scanned paperwork.</p>
              <button type="button">Choose file</button>
            </div>
          </div>
        </div>
      </section>

      <section class="vb-accordion-twentyseven-item">
        <button class="vb-accordion-twentyseven-trigger" type="button" aria-expanded="false">
          <span class="vb-accordion-twentyseven-docicon">IMG</span>
          <span>
            <strong>Project images</strong>
            <small>Screenshots, references, or photos</small>
          </span>
          <em>Optional</em>
          <i></i>
        </button>

        <div class="vb-accordion-twentyseven-panel">
          <div class="vb-accordion-twentyseven-content">
            <div class="vb-accordion-twentyseven-drop">
              <strong>Add visual references</strong>
              <p>Upload screenshots, examples, product images, design references, or visual notes for the project.</p>
              <button type="button">Choose file</button>
            </div>
          </div>
        </div>
      </section>

      <section class="vb-accordion-twentyseven-item">
        <button class="vb-accordion-twentyseven-trigger" type="button" aria-expanded="false">
          <span class="vb-accordion-twentyseven-docicon">ZIP</span>
          <span>
            <strong>Supporting archive</strong>
            <small>Compressed project files</small>
          </span>
          <em>Ready</em>
          <i></i>
        </button>

        <div class="vb-accordion-twentyseven-panel">
          <div class="vb-accordion-twentyseven-content">
            <div class="vb-accordion-twentyseven-drop">
              <strong>Upload ZIP archive</strong>
              <p>Use ZIP files for grouped assets, code folders, design files, exported documents, or larger file packages.</p>
              <button type="button">Choose file</button>
            </div>
          </div>
        </div>
      </section>
    </div>
  </div>
</div>

<style>
.vb-accordion-twentyseven-demo,
.vb-accordion-twentyseven-demo * {
  box-sizing: border-box;
}

.vb-accordion-twentyseven-demo {
  margin: 28px 0;
  padding: 42px;
  border-radius: 18px 70px 18px 70px;
  background:
    linear-gradient(135deg, rgba(14, 165, 233, 0.14), transparent 34%),
    linear-gradient(315deg, rgba(249, 115, 22, 0.14), transparent 38%),
    linear-gradient(135deg, #f8fafc 0%, #fff7ed 52%, #ffffff 100%) !important;
  border: 1px solid rgba(249, 115, 22, 0.24);
  box-shadow: 0 28px 80px rgba(124, 45, 18, 0.11);
}

.vb-accordion-twentyseven-uploader {
  display: grid;
  grid-template-columns: minmax(280px, 0.72fr) minmax(0, 1.28fr);
  gap: 28px;
  max-width: 1120px;
  margin: 0 auto;
  align-items: start;
}

.vb-accordion-twentyseven-side {
  padding: 30px;
  border-radius: 14px 46px 14px 46px;
  background:
    radial-gradient(circle at 20% 20%, rgba(255,255,255,0.22), transparent 36%),
    linear-gradient(135deg, #0f172a, #0f766e 55%, #f97316) !important;
  box-shadow: 0 30px 86px rgba(15, 23, 42, 0.22);
}

.vb-accordion-twentyseven-side > span {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-twentyseven-side h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(40px, 5vw, 68px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.09em;
}

.vb-accordion-twentyseven-side p {
  margin: 0 0 24px !important;
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twentyseven-summary {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

.vb-accordion-twentyseven-summary div {
  padding: 18px;
  border-radius: 20px 8px 20px 8px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.18);
}

.vb-accordion-twentyseven-summary strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vb-accordion-twentyseven-summary small {
  display: block;
  margin-top: 6px;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-accordion-twentyseven-stack {
  display: grid;
  gap: 13px;
}

.vb-accordion-twentyseven-item {
  overflow: hidden;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.08);
}

.vb-accordion-twentyseven-item.is-open {
  border-color: rgba(249, 115, 22, 0.36);
  box-shadow: 0 26px 70px rgba(249, 115, 22, 0.13);
}

.vb-accordion-twentyseven-trigger {
  display: grid;
  grid-template-columns: 62px minmax(0, 1fr) 86px 42px;
  gap: 14px;
  align-items: center;
  width: 100%;
  min-height: 86px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-twentyseven-docicon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 62px;
  height: 62px;
  border-radius: 18px 18px 6px 18px;
  background: #fff7ed;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.08em;
}

.vb-accordion-twentyseven-trigger strong {
  display: block;
  margin-bottom: 5px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 19px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-twentyseven-trigger small {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 750;
}

.vb-accordion-twentyseven-trigger em {
  justify-self: end;
  padding: 8px 10px;
  border-radius: 999px;
  background: #ecfeff;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 11px;
  font-style: normal;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-accordion-twentyseven-trigger i {
  position: relative;
  width: 42px;
  height: 42px;
  border-radius: 14px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-accordion-twentyseven-trigger i::before,
.vb-accordion-twentyseven-trigger i::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 15px;
  height: 2px;
  border-radius: 999px;
  background: #c2410c;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease;
}

.vb-accordion-twentyseven-trigger i::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-twentyseven-item.is-open .vb-accordion-twentyseven-trigger i {
  background: #f97316;
  border-color: #f97316;
}

.vb-accordion-twentyseven-item.is-open .vb-accordion-twentyseven-trigger i::before,
.vb-accordion-twentyseven-item.is-open .vb-accordion-twentyseven-trigger i::after {
  background: #ffffff;
}

.vb-accordion-twentyseven-item.is-open .vb-accordion-twentyseven-trigger i::after {
  opacity: 0;
}

.vb-accordion-twentyseven-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s ease;
}

.vb-accordion-twentyseven-content {
  padding: 0 20px 20px 96px;
}

.vb-accordion-twentyseven-drop {
  padding: 22px;
  border-radius: 20px;
  background: #fff7ed;
  border: 2px dashed rgba(249, 115, 22, 0.46);
}

.vb-accordion-twentyseven-drop strong {
  display: block;
  margin-bottom: 8px;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-accordion-twentyseven-drop p {
  margin: 0 0 16px !important;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 14px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-accordion-twentyseven-drop button {
  min-height: 42px;
  padding: 10px 16px;
  border: 0;
  border-radius: 12px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

@media (max-width: 900px) {
  .vb-accordion-twentyseven-uploader {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 680px) {
  .vb-accordion-twentyseven-demo {
    padding: 18px;
    border-radius: 14px 44px 14px 44px;
  }

  .vb-accordion-twentyseven-side {
    padding: 24px;
  }

  .vb-accordion-twentyseven-side h3 {
    font-size: 40px !important;
  }

  .vb-accordion-twentyseven-trigger {
    grid-template-columns: 54px minmax(0, 1fr) 40px;
    padding: 16px;
  }

  .vb-accordion-twentyseven-docicon {
    width: 54px;
    height: 54px;
  }

  .vb-accordion-twentyseven-trigger em {
    grid-column: 2;
    justify-self: start;
  }

  .vb-accordion-twentyseven-trigger i {
    grid-column: 3;
    grid-row: 1;
    width: 40px;
    height: 40px;
  }

  .vb-accordion-twentyseven-content {
    padding: 0 16px 16px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-twentyseven]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-twentyseven-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-twentyseven-trigger");
    const panel = item.querySelector(".vb-accordion-twentyseven-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-twentyseven-trigger");
    const panel = item.querySelector(".vb-accordion-twentyseven-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-twentyseven-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-twentyseven-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-twentyseven-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-twentyseven]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-twentyseven-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-twentyseven-trigger");
    const panel = item.querySelector(".vb-accordion-twentyseven-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-twentyseven-trigger");
    const panel = item.querySelector(".vb-accordion-twentyseven-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-twentyseven-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-twentyseven-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-twentyseven-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-twentyseven-demo"&gt;
  &lt;div class="vb-accordion-twentyseven-uploader" data-vb-accordion-twentyseven&gt;
    &lt;div class="vb-accordion-twentyseven-side"&gt;
      &lt;span&gt;Example 27&lt;/span&gt;
      &lt;h3&gt;File Upload Accordion&lt;/h3&gt;
      &lt;p&gt;Organize upload requirements into expandable document sections with clear file status and upload instructions.&lt;/p&gt;

      &lt;div class="vb-accordion-twentyseven-summary"&gt;
        &lt;div&gt;
          &lt;strong&gt;6&lt;/strong&gt;
          &lt;small&gt;Files needed&lt;/small&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;strong&gt;3&lt;/strong&gt;
          &lt;small&gt;Uploaded&lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-twentyseven-stack"&gt;
      &lt;section class="vb-accordion-twentyseven-item is-open"&gt;
        &lt;button class="vb-accordion-twentyseven-trigger" type="button" aria-expanded="true"&gt;
          &lt;span class="vb-accordion-twentyseven-docicon"&gt;PDF&lt;/span&gt;
          &lt;span&gt;
            &lt;strong&gt;Identity documents&lt;/strong&gt;
            &lt;small&gt;Passport, ID card, or driver license&lt;/small&gt;
          &lt;/span&gt;
          &lt;em&gt;Required&lt;/em&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-twentyseven-panel"&gt;
          &lt;div class="vb-accordion-twentyseven-content"&gt;
            &lt;div class="vb-accordion-twentyseven-drop"&gt;
              &lt;strong&gt;Drop files here&lt;/strong&gt;
              &lt;p&gt;Accepted formats: PDF, JPG, PNG. Maximum file size: 10 MB.&lt;/p&gt;
              &lt;button type="button"&gt;Choose file&lt;/button&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-twentyseven-item"&gt;
        &lt;button class="vb-accordion-twentyseven-trigger" type="button" aria-expanded="false"&gt;
          &lt;span class="vb-accordion-twentyseven-docicon"&gt;DOC&lt;/span&gt;
          &lt;span&gt;
            &lt;strong&gt;Application form&lt;/strong&gt;
            &lt;small&gt;Signed form or completed document&lt;/small&gt;
          &lt;/span&gt;
          &lt;em&gt;Pending&lt;/em&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-twentyseven-panel"&gt;
          &lt;div class="vb-accordion-twentyseven-content"&gt;
            &lt;div class="vb-accordion-twentyseven-drop"&gt;
              &lt;strong&gt;Upload signed form&lt;/strong&gt;
              &lt;p&gt;Use this section for signed contracts, application forms, consent files, or scanned paperwork.&lt;/p&gt;
              &lt;button type="button"&gt;Choose file&lt;/button&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-twentyseven-item"&gt;
        &lt;button class="vb-accordion-twentyseven-trigger" type="button" aria-expanded="false"&gt;
          &lt;span class="vb-accordion-twentyseven-docicon"&gt;IMG&lt;/span&gt;
          &lt;span&gt;
            &lt;strong&gt;Project images&lt;/strong&gt;
            &lt;small&gt;Screenshots, references, or photos&lt;/small&gt;
          &lt;/span&gt;
          &lt;em&gt;Optional&lt;/em&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-twentyseven-panel"&gt;
          &lt;div class="vb-accordion-twentyseven-content"&gt;
            &lt;div class="vb-accordion-twentyseven-drop"&gt;
              &lt;strong&gt;Add visual references&lt;/strong&gt;
              &lt;p&gt;Upload screenshots, examples, product images, design references, or visual notes for the project.&lt;/p&gt;
              &lt;button type="button"&gt;Choose file&lt;/button&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-twentyseven-item"&gt;
        &lt;button class="vb-accordion-twentyseven-trigger" type="button" aria-expanded="false"&gt;
          &lt;span class="vb-accordion-twentyseven-docicon"&gt;ZIP&lt;/span&gt;
          &lt;span&gt;
            &lt;strong&gt;Supporting archive&lt;/strong&gt;
            &lt;small&gt;Compressed project files&lt;/small&gt;
          &lt;/span&gt;
          &lt;em&gt;Ready&lt;/em&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-twentyseven-panel"&gt;
          &lt;div class="vb-accordion-twentyseven-content"&gt;
            &lt;div class="vb-accordion-twentyseven-drop"&gt;
              &lt;strong&gt;Upload ZIP archive&lt;/strong&gt;
              &lt;p&gt;Use ZIP files for grouped assets, code folders, design files, exported documents, or larger file packages.&lt;/p&gt;
              &lt;button type="button"&gt;Choose file&lt;/button&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-twentyseven-demo,
.vb-accordion-twentyseven-demo * {
  box-sizing: border-box;
}

.vb-accordion-twentyseven-demo {
  margin: 28px 0;
  padding: 42px;
  border-radius: 18px 70px 18px 70px;
  background:
    linear-gradient(135deg, rgba(14, 165, 233, 0.14), transparent 34%),
    linear-gradient(315deg, rgba(249, 115, 22, 0.14), transparent 38%),
    linear-gradient(135deg, #f8fafc 0%, #fff7ed 52%, #ffffff 100%) !important;
  border: 1px solid rgba(249, 115, 22, 0.24);
  box-shadow: 0 28px 80px rgba(124, 45, 18, 0.11);
}

.vb-accordion-twentyseven-uploader {
  display: grid;
  grid-template-columns: minmax(280px, 0.72fr) minmax(0, 1.28fr);
  gap: 28px;
  max-width: 1120px;
  margin: 0 auto;
  align-items: start;
}

.vb-accordion-twentyseven-side {
  padding: 30px;
  border-radius: 14px 46px 14px 46px;
  background:
    radial-gradient(circle at 20% 20%, rgba(255,255,255,0.22), transparent 36%),
    linear-gradient(135deg, #0f172a, #0f766e 55%, #f97316) !important;
  box-shadow: 0 30px 86px rgba(15, 23, 42, 0.22);
}

.vb-accordion-twentyseven-side &gt; span {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-twentyseven-side h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(40px, 5vw, 68px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.09em;
}

.vb-accordion-twentyseven-side p {
  margin: 0 0 24px !important;
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twentyseven-summary {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}

.vb-accordion-twentyseven-summary div {
  padding: 18px;
  border-radius: 20px 8px 20px 8px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.18);
}

.vb-accordion-twentyseven-summary strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vb-accordion-twentyseven-summary small {
  display: block;
  margin-top: 6px;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-accordion-twentyseven-stack {
  display: grid;
  gap: 13px;
}

.vb-accordion-twentyseven-item {
  overflow: hidden;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.08);
}

.vb-accordion-twentyseven-item.is-open {
  border-color: rgba(249, 115, 22, 0.36);
  box-shadow: 0 26px 70px rgba(249, 115, 22, 0.13);
}

.vb-accordion-twentyseven-trigger {
  display: grid;
  grid-template-columns: 62px minmax(0, 1fr) 86px 42px;
  gap: 14px;
  align-items: center;
  width: 100%;
  min-height: 86px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-twentyseven-docicon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 62px;
  height: 62px;
  border-radius: 18px 18px 6px 18px;
  background: #fff7ed;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.08em;
}

.vb-accordion-twentyseven-trigger strong {
  display: block;
  margin-bottom: 5px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 19px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-twentyseven-trigger small {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 750;
}

.vb-accordion-twentyseven-trigger em {
  justify-self: end;
  padding: 8px 10px;
  border-radius: 999px;
  background: #ecfeff;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 11px;
  font-style: normal;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-accordion-twentyseven-trigger i {
  position: relative;
  width: 42px;
  height: 42px;
  border-radius: 14px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-accordion-twentyseven-trigger i::before,
.vb-accordion-twentyseven-trigger i::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 15px;
  height: 2px;
  border-radius: 999px;
  background: #c2410c;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease;
}

.vb-accordion-twentyseven-trigger i::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-twentyseven-item.is-open .vb-accordion-twentyseven-trigger i {
  background: #f97316;
  border-color: #f97316;
}

.vb-accordion-twentyseven-item.is-open .vb-accordion-twentyseven-trigger i::before,
.vb-accordion-twentyseven-item.is-open .vb-accordion-twentyseven-trigger i::after {
  background: #ffffff;
}

.vb-accordion-twentyseven-item.is-open .vb-accordion-twentyseven-trigger i::after {
  opacity: 0;
}

.vb-accordion-twentyseven-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s ease;
}

.vb-accordion-twentyseven-content {
  padding: 0 20px 20px 96px;
}

.vb-accordion-twentyseven-drop {
  padding: 22px;
  border-radius: 20px;
  background: #fff7ed;
  border: 2px dashed rgba(249, 115, 22, 0.46);
}

.vb-accordion-twentyseven-drop strong {
  display: block;
  margin-bottom: 8px;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-accordion-twentyseven-drop p {
  margin: 0 0 16px !important;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 14px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-accordion-twentyseven-drop button {
  min-height: 42px;
  padding: 10px 16px;
  border: 0;
  border-radius: 12px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

@media (max-width: 900px) {
  .vb-accordion-twentyseven-uploader {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 680px) {
  .vb-accordion-twentyseven-demo {
    padding: 18px;
    border-radius: 14px 44px 14px 44px;
  }

  .vb-accordion-twentyseven-side {
    padding: 24px;
  }

  .vb-accordion-twentyseven-side h3 {
    font-size: 40px !important;
  }

  .vb-accordion-twentyseven-trigger {
    grid-template-columns: 54px minmax(0, 1fr) 40px;
    padding: 16px;
  }

  .vb-accordion-twentyseven-docicon {
    width: 54px;
    height: 54px;
  }

  .vb-accordion-twentyseven-trigger em {
    grid-column: 2;
    justify-self: start;
  }

  .vb-accordion-twentyseven-trigger i {
    grid-column: 3;
    grid-row: 1;
    width: 40px;
    height: 40px;
  }

  .vb-accordion-twentyseven-content {
    padding: 0 16px 16px;
  }
}</pre>



<p class="wp-block-paragraph">This file upload accordion is useful for onboarding portals, client dashboards, support forms, application forms, document upload pages, admin panels, and secure account areas.</p>



<h2 class="wp-block-heading">28. Real Estate Listing Accordion</h2>



<p class="wp-block-paragraph"><strong>A real estate listing accordion</strong> is useful for property pages, apartment listings, booking websites, rental platforms, real estate landing pages, and neighborhood guides where property details should be compact but easy to explore.</p>



<p class="wp-block-paragraph">This example uses a property-listing style with a visual property card, room statistics, price badge, amenity rows, and multi-open JavaScript behavior. It looks like a real estate interface rather than a generic web accordion.</p>



<ul class="wp-block-list">
<li>Real estate listing accordion layout</li>
<li>Multi-open property detail behavior</li>
<li>Property image placeholder and price card</li>
<li>Amenity and location detail rows</li>
<li>Useful for property, rental, and booking websites</li>
</ul>



<div class="vb-accordion-twentyeight-demo">
  <div class="vb-accordion-twentyeight-property" data-vb-accordion-twentyeight>
    <div class="vb-accordion-twentyeight-visual">
      <div class="vb-accordion-twentyeight-photo">
        <span>Example 28</span>
        <strong>Modern City Apartment</strong>
      </div>

      <div class="vb-accordion-twentyeight-price">
        <span>From</span>
        <strong>€1,250</strong>
        <small>per month</small>
      </div>
    </div>

    <div class="vb-accordion-twentyeight-details">
      <div class="vb-accordion-twentyeight-heading">
        <h3>Real Estate Listing Accordion</h3>
        <p>Open listing details, amenities, location notes, and booking information inside a property-style accordion.</p>
      </div>

      <div class="vb-accordion-twentyeight-stats">
        <div><strong>3</strong><small>Rooms</small></div>
        <div><strong>86m²</strong><small>Area</small></div>
        <div><strong>7th</strong><small>Floor</small></div>
      </div>

      <div class="vb-accordion-twentyeight-list">
        <section class="vb-accordion-twentyeight-item is-open">
          <button class="vb-accordion-twentyeight-trigger" type="button" aria-expanded="true">
            <span>Property overview</span>
            <em></em>
          </button>
          <div class="vb-accordion-twentyeight-panel">
            <div class="vb-accordion-twentyeight-content">
              <p>A bright apartment with an open living area, modern kitchen, private balcony, and practical storage space.</p>
            </div>
          </div>
        </section>

        <section class="vb-accordion-twentyeight-item">
          <button class="vb-accordion-twentyeight-trigger" type="button" aria-expanded="false">
            <span>Amenities included</span>
            <em></em>
          </button>
          <div class="vb-accordion-twentyeight-panel">
            <div class="vb-accordion-twentyeight-content">
              <ul>
                <li>Underground parking</li>
                <li>High-speed internet</li>
                <li>Private balcony</li>
                <li>Storage room</li>
              </ul>
            </div>
          </div>
        </section>

        <section class="vb-accordion-twentyeight-item">
          <button class="vb-accordion-twentyeight-trigger" type="button" aria-expanded="false">
            <span>Location details</span>
            <em></em>
          </button>
          <div class="vb-accordion-twentyeight-panel">
            <div class="vb-accordion-twentyeight-content">
              <p>The property is close to public transport, grocery stores, restaurants, parks, schools, and main city routes.</p>
            </div>
          </div>
        </section>

        <section class="vb-accordion-twentyeight-item">
          <button class="vb-accordion-twentyeight-trigger" type="button" aria-expanded="false">
            <span>Viewing and booking</span>
            <em></em>
          </button>
          <div class="vb-accordion-twentyeight-panel">
            <div class="vb-accordion-twentyeight-content">
              <p>Use this section for viewing times, booking instructions, agent contact details, and application requirements.</p>
            </div>
          </div>
        </section>
      </div>
    </div>
  </div>
</div>

<style>
.vb-accordion-twentyeight-demo,
.vb-accordion-twentyeight-demo * {
  box-sizing: border-box;
}

.vb-accordion-twentyeight-demo {
  margin: 28px 0;
  padding: 40px;
  border-radius: 12px 12px 64px 64px;
  background:
    linear-gradient(135deg, rgba(20, 184, 166, 0.16), transparent 34%),
    linear-gradient(315deg, rgba(120, 113, 108, 0.14), transparent 38%),
    linear-gradient(135deg, #f5f5f4 0%, #ecfeff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.24);
  box-shadow: 0 28px 80px rgba(19, 78, 74, 0.11);
}

.vb-accordion-twentyeight-property {
  display: grid;
  grid-template-columns: minmax(300px, 0.92fr) minmax(0, 1.08fr);
  gap: 26px;
  max-width: 1120px;
  margin: 0 auto;
  align-items: stretch;
}

.vb-accordion-twentyeight-visual {
  display: grid;
  gap: 16px;
}

.vb-accordion-twentyeight-photo {
  position: relative;
  min-height: 500px;
  overflow: hidden;
  padding: 28px;
  border-radius: 12px 46px 12px 46px;
  background:
    linear-gradient(90deg, rgba(255,255,255,0.24) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.18) 1px, transparent 1px),
    radial-gradient(circle at 26% 20%, rgba(255,255,255,0.36), transparent 30%),
    linear-gradient(135deg, #134e4a, #0f766e 52%, #99f6e4) !important;
  background-size: 34px 34px, 34px 34px, auto, auto !important;
  box-shadow: 0 30px 88px rgba(15, 118, 110, 0.20);
}

.vb-accordion-twentyeight-photo::before {
  content: "";
  position: absolute;
  left: 70px;
  right: 70px;
  bottom: 90px;
  height: 170px;
  border-radius: 12px 12px 0 0;
  background: rgba(255,255,255,0.18);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-accordion-twentyeight-photo::after {
  content: "";
  position: absolute;
  left: 112px;
  right: 112px;
  bottom: 90px;
  height: 110px;
  background:
    linear-gradient(90deg, rgba(255,255,255,0.36) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.28) 1px, transparent 1px);
  background-size: 34px 34px;
}

.vb-accordion-twentyeight-photo span {
  position: relative;
  z-index: 2;
  display: inline-flex;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  border: 1px solid rgba(255,255,255,0.22);
  color: #ecfeff !important;
  -webkit-text-fill-color: #ecfeff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-twentyeight-photo strong {
  position: absolute;
  left: 28px;
  right: 28px;
  bottom: 28px;
  z-index: 2;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 58px);
  line-height: 0.94;
  font-weight: 950;
  letter-spacing: -0.08em;
}

.vb-accordion-twentyeight-price {
  display: grid;
  grid-template-columns: 1fr;
  padding: 22px;
  border-radius: 32px 8px 32px 8px;
  background: #ffffff;
  border: 1px solid rgba(20, 184, 166, 0.20);
  box-shadow: 0 18px 48px rgba(15, 118, 110, 0.10);
}

.vb-accordion-twentyeight-price span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-accordion-twentyeight-price strong {
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 48px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.085em;
}

.vb-accordion-twentyeight-price small {
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-accordion-twentyeight-details {
  align-self: center;
}

.vb-accordion-twentyeight-heading {
  margin-bottom: 20px;
}

.vb-accordion-twentyeight-heading h3 {
  margin: 0 0 12px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(40px, 5vw, 70px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.09em;
}

.vb-accordion-twentyeight-heading p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twentyeight-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 11px;
  margin-bottom: 16px;
}

.vb-accordion-twentyeight-stats div {
  padding: 16px;
  border-radius: 20px 20px 6px 20px;
  background: #ffffff;
  border: 1px solid rgba(20, 184, 166, 0.18);
}

.vb-accordion-twentyeight-stats strong {
  display: block;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 26px;
  line-height: 1;
  font-weight: 950;
}

.vb-accordion-twentyeight-stats small {
  display: block;
  margin-top: 5px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-accordion-twentyeight-list {
  display: grid;
  gap: 12px;
}

.vb-accordion-twentyeight-item {
  overflow: hidden;
  border-radius: 24px 24px 8px 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 16px 44px rgba(15, 23, 42, 0.07);
}

.vb-accordion-twentyeight-item.is-open {
  border-color: rgba(20, 184, 166, 0.34);
  box-shadow: 0 24px 64px rgba(20, 184, 166, 0.12);
}

.vb-accordion-twentyeight-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 42px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 74px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-twentyeight-trigger span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 20px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.045em;
}

.vb-accordion-twentyeight-trigger em {
  position: relative;
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: #ccfbf1;
}

.vb-accordion-twentyeight-trigger em::before,
.vb-accordion-twentyeight-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 15px;
  height: 2px;
  border-radius: 999px;
  background: #0f766e;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease;
}

.vb-accordion-twentyeight-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-twentyeight-item.is-open .vb-accordion-twentyeight-trigger em {
  background: #0f766e;
}

.vb-accordion-twentyeight-item.is-open .vb-accordion-twentyeight-trigger em::before,
.vb-accordion-twentyeight-item.is-open .vb-accordion-twentyeight-trigger em::after {
  background: #ffffff;
}

.vb-accordion-twentyeight-item.is-open .vb-accordion-twentyeight-trigger em::after {
  opacity: 0;
}

.vb-accordion-twentyeight-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-twentyeight-content {
  padding: 0 20px 20px;
}

.vb-accordion-twentyeight-content p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twentyeight-content ul {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb-accordion-twentyeight-content li {
  margin: 0 !important;
  padding: 12px;
  border-radius: 16px;
  background: #f0fdfa;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 13px;
  font-weight: 850;
}

@media (max-width: 900px) {
  .vb-accordion-twentyeight-property {
    grid-template-columns: 1fr;
  }

  .vb-accordion-twentyeight-photo {
    min-height: 420px;
  }
}

@media (max-width: 640px) {
  .vb-accordion-twentyeight-demo {
    padding: 18px;
    border-radius: 10px 10px 42px 42px;
  }

  .vb-accordion-twentyeight-photo {
    min-height: 360px;
    padding: 22px;
  }

  .vb-accordion-twentyeight-photo strong {
    left: 22px;
    right: 22px;
    bottom: 22px;
    font-size: 38px;
  }

  .vb-accordion-twentyeight-heading h3 {
    font-size: 38px !important;
  }

  .vb-accordion-twentyeight-stats,
  .vb-accordion-twentyeight-content ul {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-twentyeight]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-twentyeight-item"));

  function updateItem(item) {
    const button = item.querySelector(".vb-accordion-twentyeight-trigger");
    const panel = item.querySelector(".vb-accordion-twentyeight-panel");
    const isOpen = item.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-twentyeight-trigger");

    button.addEventListener("click", function () {
      item.classList.toggle("is-open");
      updateItem(item);
    });

    updateItem(item);
  });

  window.addEventListener("resize", function () {
    items.forEach(updateItem);
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-twentyeight]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-twentyeight-item"));

  function updateItem(item) {
    const button = item.querySelector(".vb-accordion-twentyeight-trigger");
    const panel = item.querySelector(".vb-accordion-twentyeight-panel");
    const isOpen = item.classList.contains("is-open");

    button.setAttribute("aria-expanded", isOpen ? "true" : "false");
    panel.style.maxHeight = isOpen ? panel.scrollHeight + "px" : "0px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-twentyeight-trigger");

    button.addEventListener("click", function () {
      item.classList.toggle("is-open");
      updateItem(item);
    });

    updateItem(item);
  });

  window.addEventListener("resize", function () {
    items.forEach(updateItem);
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-twentyeight-demo"&gt;
  &lt;div class="vb-accordion-twentyeight-property" data-vb-accordion-twentyeight&gt;
    &lt;div class="vb-accordion-twentyeight-visual"&gt;
      &lt;div class="vb-accordion-twentyeight-photo"&gt;
        &lt;span&gt;Example 28&lt;/span&gt;
        &lt;strong&gt;Modern City Apartment&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-twentyeight-price"&gt;
        &lt;span&gt;From&lt;/span&gt;
        &lt;strong&gt;€1,250&lt;/strong&gt;
        &lt;small&gt;per month&lt;/small&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-twentyeight-details"&gt;
      &lt;div class="vb-accordion-twentyeight-heading"&gt;
        &lt;h3&gt;Real Estate Listing Accordion&lt;/h3&gt;
        &lt;p&gt;Open listing details, amenities, location notes, and booking information inside a property-style accordion.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-twentyeight-stats"&gt;
        &lt;div&gt;&lt;strong&gt;3&lt;/strong&gt;&lt;small&gt;Rooms&lt;/small&gt;&lt;/div&gt;
        &lt;div&gt;&lt;strong&gt;86m²&lt;/strong&gt;&lt;small&gt;Area&lt;/small&gt;&lt;/div&gt;
        &lt;div&gt;&lt;strong&gt;7th&lt;/strong&gt;&lt;small&gt;Floor&lt;/small&gt;&lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-twentyeight-list"&gt;
        &lt;section class="vb-accordion-twentyeight-item is-open"&gt;
          &lt;button class="vb-accordion-twentyeight-trigger" type="button" aria-expanded="true"&gt;
            &lt;span&gt;Property overview&lt;/span&gt;
            &lt;em&gt;&lt;/em&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-twentyeight-panel"&gt;
            &lt;div class="vb-accordion-twentyeight-content"&gt;
              &lt;p&gt;A bright apartment with an open living area, modern kitchen, private balcony, and practical storage space.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;

        &lt;section class="vb-accordion-twentyeight-item"&gt;
          &lt;button class="vb-accordion-twentyeight-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;Amenities included&lt;/span&gt;
            &lt;em&gt;&lt;/em&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-twentyeight-panel"&gt;
            &lt;div class="vb-accordion-twentyeight-content"&gt;
              &lt;ul&gt;
                &lt;li&gt;Underground parking&lt;/li&gt;
                &lt;li&gt;High-speed internet&lt;/li&gt;
                &lt;li&gt;Private balcony&lt;/li&gt;
                &lt;li&gt;Storage room&lt;/li&gt;
              &lt;/ul&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;

        &lt;section class="vb-accordion-twentyeight-item"&gt;
          &lt;button class="vb-accordion-twentyeight-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;Location details&lt;/span&gt;
            &lt;em&gt;&lt;/em&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-twentyeight-panel"&gt;
            &lt;div class="vb-accordion-twentyeight-content"&gt;
              &lt;p&gt;The property is close to public transport, grocery stores, restaurants, parks, schools, and main city routes.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;

        &lt;section class="vb-accordion-twentyeight-item"&gt;
          &lt;button class="vb-accordion-twentyeight-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;Viewing and booking&lt;/span&gt;
            &lt;em&gt;&lt;/em&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-twentyeight-panel"&gt;
            &lt;div class="vb-accordion-twentyeight-content"&gt;
              &lt;p&gt;Use this section for viewing times, booking instructions, agent contact details, and application requirements.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-accordion-twentyeight-demo,
.vb-accordion-twentyeight-demo * {
  box-sizing: border-box;
}

.vb-accordion-twentyeight-demo {
  margin: 28px 0;
  padding: 40px;
  border-radius: 12px 12px 64px 64px;
  background:
    linear-gradient(135deg, rgba(20, 184, 166, 0.16), transparent 34%),
    linear-gradient(315deg, rgba(120, 113, 108, 0.14), transparent 38%),
    linear-gradient(135deg, #f5f5f4 0%, #ecfeff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.24);
  box-shadow: 0 28px 80px rgba(19, 78, 74, 0.11);
}

.vb-accordion-twentyeight-property {
  display: grid;
  grid-template-columns: minmax(300px, 0.92fr) minmax(0, 1.08fr);
  gap: 26px;
  max-width: 1120px;
  margin: 0 auto;
  align-items: stretch;
}

.vb-accordion-twentyeight-visual {
  display: grid;
  gap: 16px;
}

.vb-accordion-twentyeight-photo {
  position: relative;
  min-height: 500px;
  overflow: hidden;
  padding: 28px;
  border-radius: 12px 46px 12px 46px;
  background:
    linear-gradient(90deg, rgba(255,255,255,0.24) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.18) 1px, transparent 1px),
    radial-gradient(circle at 26% 20%, rgba(255,255,255,0.36), transparent 30%),
    linear-gradient(135deg, #134e4a, #0f766e 52%, #99f6e4) !important;
  background-size: 34px 34px, 34px 34px, auto, auto !important;
  box-shadow: 0 30px 88px rgba(15, 118, 110, 0.20);
}

.vb-accordion-twentyeight-photo::before {
  content: "";
  position: absolute;
  left: 70px;
  right: 70px;
  bottom: 90px;
  height: 170px;
  border-radius: 12px 12px 0 0;
  background: rgba(255,255,255,0.18);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-accordion-twentyeight-photo::after {
  content: "";
  position: absolute;
  left: 112px;
  right: 112px;
  bottom: 90px;
  height: 110px;
  background:
    linear-gradient(90deg, rgba(255,255,255,0.36) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.28) 1px, transparent 1px);
  background-size: 34px 34px;
}

.vb-accordion-twentyeight-photo span {
  position: relative;
  z-index: 2;
  display: inline-flex;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  border: 1px solid rgba(255,255,255,0.22);
  color: #ecfeff !important;
  -webkit-text-fill-color: #ecfeff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-twentyeight-photo strong {
  position: absolute;
  left: 28px;
  right: 28px;
  bottom: 28px;
  z-index: 2;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 58px);
  line-height: 0.94;
  font-weight: 950;
  letter-spacing: -0.08em;
}

.vb-accordion-twentyeight-price {
  display: grid;
  grid-template-columns: 1fr;
  padding: 22px;
  border-radius: 32px 8px 32px 8px;
  background: #ffffff;
  border: 1px solid rgba(20, 184, 166, 0.20);
  box-shadow: 0 18px 48px rgba(15, 118, 110, 0.10);
}

.vb-accordion-twentyeight-price span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-accordion-twentyeight-price strong {
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 48px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.085em;
}

.vb-accordion-twentyeight-price small {
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-accordion-twentyeight-details {
  align-self: center;
}

.vb-accordion-twentyeight-heading {
  margin-bottom: 20px;
}

.vb-accordion-twentyeight-heading h3 {
  margin: 0 0 12px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(40px, 5vw, 70px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.09em;
}

.vb-accordion-twentyeight-heading p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twentyeight-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 11px;
  margin-bottom: 16px;
}

.vb-accordion-twentyeight-stats div {
  padding: 16px;
  border-radius: 20px 20px 6px 20px;
  background: #ffffff;
  border: 1px solid rgba(20, 184, 166, 0.18);
}

.vb-accordion-twentyeight-stats strong {
  display: block;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 26px;
  line-height: 1;
  font-weight: 950;
}

.vb-accordion-twentyeight-stats small {
  display: block;
  margin-top: 5px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-accordion-twentyeight-list {
  display: grid;
  gap: 12px;
}

.vb-accordion-twentyeight-item {
  overflow: hidden;
  border-radius: 24px 24px 8px 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 16px 44px rgba(15, 23, 42, 0.07);
}

.vb-accordion-twentyeight-item.is-open {
  border-color: rgba(20, 184, 166, 0.34);
  box-shadow: 0 24px 64px rgba(20, 184, 166, 0.12);
}

.vb-accordion-twentyeight-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 42px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 74px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-twentyeight-trigger span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 20px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.045em;
}

.vb-accordion-twentyeight-trigger em {
  position: relative;
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: #ccfbf1;
}

.vb-accordion-twentyeight-trigger em::before,
.vb-accordion-twentyeight-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 15px;
  height: 2px;
  border-radius: 999px;
  background: #0f766e;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease;
}

.vb-accordion-twentyeight-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-twentyeight-item.is-open .vb-accordion-twentyeight-trigger em {
  background: #0f766e;
}

.vb-accordion-twentyeight-item.is-open .vb-accordion-twentyeight-trigger em::before,
.vb-accordion-twentyeight-item.is-open .vb-accordion-twentyeight-trigger em::after {
  background: #ffffff;
}

.vb-accordion-twentyeight-item.is-open .vb-accordion-twentyeight-trigger em::after {
  opacity: 0;
}

.vb-accordion-twentyeight-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-twentyeight-content {
  padding: 0 20px 20px;
}

.vb-accordion-twentyeight-content p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twentyeight-content ul {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb-accordion-twentyeight-content li {
  margin: 0 !important;
  padding: 12px;
  border-radius: 16px;
  background: #f0fdfa;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 13px;
  font-weight: 850;
}

@media (max-width: 900px) {
  .vb-accordion-twentyeight-property {
    grid-template-columns: 1fr;
  }

  .vb-accordion-twentyeight-photo {
    min-height: 420px;
  }
}

@media (max-width: 640px) {
  .vb-accordion-twentyeight-demo {
    padding: 18px;
    border-radius: 10px 10px 42px 42px;
  }

  .vb-accordion-twentyeight-photo {
    min-height: 360px;
    padding: 22px;
  }

  .vb-accordion-twentyeight-photo strong {
    left: 22px;
    right: 22px;
    bottom: 22px;
    font-size: 38px;
  }

  .vb-accordion-twentyeight-heading h3 {
    font-size: 38px !important;
  }

  .vb-accordion-twentyeight-stats,
  .vb-accordion-twentyeight-content ul {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This real estate listing accordion is useful for apartment listings, property websites, rental platforms, real estate landing pages, booking pages, accommodation websites, and location-based service pages.</p>



<h2 class="wp-block-heading">29. Pricing Add-On Accordion</h2>



<p class="wp-block-paragraph"><strong>A pricing add-on accordion</strong> is useful for SaaS pricing pages, checkout pages, subscription plans, hosting packages, plugin pricing, service bundles, and product upsell sections where optional extras need to be explained clearly.</p>



<p class="wp-block-paragraph">This example uses a checkout-inspired layout with add-on cards, price pills, selected states, a total summary, and one-open-at-a-time JavaScript behavior. It is designed like a pricing configurator instead of a standard FAQ accordion.</p>



<ul class="wp-block-list">
<li>Pricing add-on accordion layout</li>
<li>One-open-at-a-time behavior</li>
<li>Price pills and selected add-on states</li>
<li>Checkout summary visual card</li>
<li>Useful for pricing, checkout, and upgrade pages</li>
</ul>



<div class="vb-accordion-twentynine-demo">
  <div class="vb-accordion-twentynine-pricing" data-vb-accordion-twentynine>
    <div class="vb-accordion-twentynine-panel">
      <span>Example 29</span>
      <h3>Pricing Add-On Accordion</h3>
      <p>Let users expand add-ons, compare upgrade details, and understand what each extra feature includes.</p>

      <div class="vb-accordion-twentynine-total">
        <small>Current plan</small>
        <strong>€29/mo</strong>
        <em>3 add-ons available</em>
      </div>
    </div>

    <div class="vb-accordion-twentynine-options">
      <section class="vb-accordion-twentynine-item is-open">
        <button class="vb-accordion-twentynine-trigger" type="button" aria-expanded="true">
          <span>
            <small>Popular add-on</small>
            <strong>Priority Support</strong>
          </span>
          <em>+€9/mo</em>
          <i></i>
        </button>

        <div class="vb-accordion-twentynine-content-wrap">
          <div class="vb-accordion-twentynine-content">
            <p>Get faster replies, priority issue handling, and direct help for implementation questions.</p>
            <ul>
              <li>Faster support queue</li>
              <li>Implementation guidance</li>
              <li>Best for client projects</li>
            </ul>
          </div>
        </div>
      </section>

      <section class="vb-accordion-twentynine-item">
        <button class="vb-accordion-twentynine-trigger" type="button" aria-expanded="false">
          <span>
            <small>Automation</small>
            <strong>Advanced Workflows</strong>
          </span>
          <em>+€14/mo</em>
          <i></i>
        </button>

        <div class="vb-accordion-twentynine-content-wrap">
          <div class="vb-accordion-twentynine-content">
            <p>Add automation rules, conditional logic, scheduled actions, and reusable workflow templates.</p>
            <ul>
              <li>Smart automation rules</li>
              <li>Scheduled workflows</li>
              <li>Reusable templates</li>
            </ul>
          </div>
        </div>
      </section>

      <section class="vb-accordion-twentynine-item">
        <button class="vb-accordion-twentynine-trigger" type="button" aria-expanded="false">
          <span>
            <small>Storage</small>
            <strong>Extra File Storage</strong>
          </span>
          <em>+€6/mo</em>
          <i></i>
        </button>

        <div class="vb-accordion-twentynine-content-wrap">
          <div class="vb-accordion-twentynine-content">
            <p>Increase upload storage for documents, images, exports, client assets, and generated files.</p>
            <ul>
              <li>More file space</li>
              <li>Better for teams</li>
              <li>Useful for document portals</li>
            </ul>
          </div>
        </div>
      </section>

      <section class="vb-accordion-twentynine-item">
        <button class="vb-accordion-twentynine-trigger" type="button" aria-expanded="false">
          <span>
            <small>Branding</small>
            <strong>White Label Mode</strong>
          </span>
          <em>+€19/mo</em>
          <i></i>
        </button>

        <div class="vb-accordion-twentynine-content-wrap">
          <div class="vb-accordion-twentynine-content">
            <p>Remove platform branding, add custom colors, upload your logo, and create a more client-ready experience.</p>
            <ul>
              <li>Custom branding</li>
              <li>Client-ready interface</li>
              <li>Agency-friendly setup</li>
            </ul>
          </div>
        </div>
      </section>
    </div>
  </div>
</div>

<style>
.vb-accordion-twentynine-demo,
.vb-accordion-twentynine-demo * {
  box-sizing: border-box;
}

.vb-accordion-twentynine-demo {
  margin: 28px 0;
  padding: 42px;
  border-radius: 0 56px 56px 56px;
  background:
    radial-gradient(circle at 16% 18%, rgba(250, 204, 21, 0.20), transparent 34%),
    radial-gradient(circle at 82% 18%, rgba(99, 102, 241, 0.18), transparent 36%),
    linear-gradient(135deg, #fffbeb 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(234, 179, 8, 0.26);
  box-shadow: 0 28px 80px rgba(113, 63, 18, 0.12);
}

.vb-accordion-twentynine-pricing {
  display: grid;
  grid-template-columns: minmax(280px, 0.76fr) minmax(0, 1.24fr);
  gap: 26px;
  max-width: 1120px;
  margin: 0 auto;
  align-items: start;
}

.vb-accordion-twentynine-panel {
  position: sticky;
  top: 24px;
  padding: 30px;
  border-radius: 0 42px 42px 42px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.22), transparent 34%),
    linear-gradient(135deg, #713f12, #4f46e5 58%, #111827) !important;
  box-shadow: 0 30px 86px rgba(67, 56, 202, 0.24);
}

.vb-accordion-twentynine-panel > span {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 8px 12px;
  border-radius: 12px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.18);
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-twentynine-panel h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(40px, 5vw, 66px) !important;
  line-height: 0.9 !important;
  font-weight: 950 !important;
  letter-spacing: -0.09em;
}

.vb-accordion-twentynine-panel p {
  margin: 0 0 24px !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twentynine-total {
  padding: 20px;
  border-radius: 24px 24px 24px 0;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
}

.vb-accordion-twentynine-total small,
.vb-accordion-twentynine-total em {
  display: block;
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 12px;
  font-style: normal;
  font-weight: 850;
}

.vb-accordion-twentynine-total strong {
  display: block;
  margin: 6px 0;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 46px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.08em;
}

.vb-accordion-twentynine-options {
  display: grid;
  gap: 14px;
}

.vb-accordion-twentynine-item {
  overflow: hidden;
  border-radius: 30px 30px 30px 0;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.08);
}

.vb-accordion-twentynine-item.is-open {
  border-color: rgba(79, 70, 229, 0.35);
  box-shadow: 0 26px 70px rgba(79, 70, 229, 0.14);
}

.vb-accordion-twentynine-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 92px 44px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 88px;
  padding: 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-twentynine-trigger small {
  display: inline-flex;
  margin-bottom: 7px;
  padding: 5px 9px;
  border-radius: 999px;
  background: #fffbeb;
  color: #a16207 !important;
  -webkit-text-fill-color: #a16207 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-accordion-twentynine-trigger strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px;
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-accordion-twentynine-trigger em {
  justify-self: end;
  padding: 10px 12px;
  border-radius: 14px 14px 14px 0;
  background: #eef2ff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 13px;
  font-style: normal;
  font-weight: 950;
}

.vb-accordion-twentynine-trigger i {
  position: relative;
  width: 44px;
  height: 44px;
  border-radius: 14px 14px 14px 0;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-accordion-twentynine-trigger i::before,
.vb-accordion-twentynine-trigger i::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 16px;
  height: 2px;
  border-radius: 999px;
  background: #4f46e5;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease;
}

.vb-accordion-twentynine-trigger i::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-twentynine-item.is-open .vb-accordion-twentynine-trigger i {
  background: #4f46e5;
  border-color: #4f46e5;
}

.vb-accordion-twentynine-item.is-open .vb-accordion-twentynine-trigger i::before,
.vb-accordion-twentynine-item.is-open .vb-accordion-twentynine-trigger i::after {
  background: #ffffff;
}

.vb-accordion-twentynine-item.is-open .vb-accordion-twentynine-trigger i::after {
  opacity: 0;
}

.vb-accordion-twentynine-content-wrap {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.3s ease;
}

.vb-accordion-twentynine-content {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 230px;
  gap: 18px;
  padding: 0 20px 20px;
}

.vb-accordion-twentynine-content p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-twentynine-content ul {
  display: grid;
  gap: 8px;
  margin: 0 !important;
  padding: 14px !important;
  border-radius: 18px 18px 18px 0;
  background: #f8fafc;
  list-style: none !important;
}

.vb-accordion-twentynine-content li {
  position: relative;
  margin: 0 !important;
  padding-left: 20px;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  line-height: 1.45;
  font-weight: 850;
}

.vb-accordion-twentynine-content li::before {
  content: "✓";
  position: absolute;
  left: 0;
  top: 0;
  color: #4f46e5;
  -webkit-text-fill-color: #4f46e5;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vb-accordion-twentynine-pricing {
    grid-template-columns: 1fr;
  }

  .vb-accordion-twentynine-panel {
    position: static;
  }
}

@media (max-width: 640px) {
  .vb-accordion-twentynine-demo {
    padding: 18px;
    border-radius: 0 38px 38px 38px;
  }

  .vb-accordion-twentynine-panel {
    padding: 24px;
  }

  .vb-accordion-twentynine-panel h3 {
    font-size: 40px !important;
  }

  .vb-accordion-twentynine-trigger {
    grid-template-columns: 1fr 40px;
    padding: 18px;
  }

  .vb-accordion-twentynine-trigger em {
    grid-column: 1;
    justify-self: start;
  }

  .vb-accordion-twentynine-trigger i {
    grid-column: 2;
    grid-row: 1;
    width: 40px;
    height: 40px;
  }

  .vb-accordion-twentynine-content {
    grid-template-columns: 1fr;
    padding: 0 18px 18px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-twentynine]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-twentynine-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-twentynine-trigger");
    const panel = item.querySelector(".vb-accordion-twentynine-content-wrap");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-twentynine-trigger");
    const panel = item.querySelector(".vb-accordion-twentynine-content-wrap");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-twentynine-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-twentynine-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-twentynine-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-twentynine]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-twentynine-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-twentynine-trigger");
    const panel = item.querySelector(".vb-accordion-twentynine-content-wrap");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-twentynine-trigger");
    const panel = item.querySelector(".vb-accordion-twentynine-content-wrap");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-twentynine-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-twentynine-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-twentynine-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-twentynine-demo"&gt;
  &lt;div class="vb-accordion-twentynine-pricing" data-vb-accordion-twentynine&gt;
    &lt;div class="vb-accordion-twentynine-panel"&gt;
      &lt;span&gt;Example 29&lt;/span&gt;
      &lt;h3&gt;Pricing Add-On Accordion&lt;/h3&gt;
      &lt;p&gt;Let users expand add-ons, compare upgrade details, and understand what each extra feature includes.&lt;/p&gt;

      &lt;div class="vb-accordion-twentynine-total"&gt;
        &lt;small&gt;Current plan&lt;/small&gt;
        &lt;strong&gt;€29/mo&lt;/strong&gt;
        &lt;em&gt;3 add-ons available&lt;/em&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-accordion-twentynine-options"&gt;
      &lt;section class="vb-accordion-twentynine-item is-open"&gt;
        &lt;button class="vb-accordion-twentynine-trigger" type="button" aria-expanded="true"&gt;
          &lt;span&gt;
            &lt;small&gt;Popular add-on&lt;/small&gt;
            &lt;strong&gt;Priority Support&lt;/strong&gt;
          &lt;/span&gt;
          &lt;em&gt;+€9/mo&lt;/em&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-twentynine-content-wrap"&gt;
          &lt;div class="vb-accordion-twentynine-content"&gt;
            &lt;p&gt;Get faster replies, priority issue handling, and direct help for implementation questions.&lt;/p&gt;
            &lt;ul&gt;
              &lt;li&gt;Faster support queue&lt;/li&gt;
              &lt;li&gt;Implementation guidance&lt;/li&gt;
              &lt;li&gt;Best for client projects&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-twentynine-item"&gt;
        &lt;button class="vb-accordion-twentynine-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;
            &lt;small&gt;Automation&lt;/small&gt;
            &lt;strong&gt;Advanced Workflows&lt;/strong&gt;
          &lt;/span&gt;
          &lt;em&gt;+€14/mo&lt;/em&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-twentynine-content-wrap"&gt;
          &lt;div class="vb-accordion-twentynine-content"&gt;
            &lt;p&gt;Add automation rules, conditional logic, scheduled actions, and reusable workflow templates.&lt;/p&gt;
            &lt;ul&gt;
              &lt;li&gt;Smart automation rules&lt;/li&gt;
              &lt;li&gt;Scheduled workflows&lt;/li&gt;
              &lt;li&gt;Reusable templates&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-twentynine-item"&gt;
        &lt;button class="vb-accordion-twentynine-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;
            &lt;small&gt;Storage&lt;/small&gt;
            &lt;strong&gt;Extra File Storage&lt;/strong&gt;
          &lt;/span&gt;
          &lt;em&gt;+€6/mo&lt;/em&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-twentynine-content-wrap"&gt;
          &lt;div class="vb-accordion-twentynine-content"&gt;
            &lt;p&gt;Increase upload storage for documents, images, exports, client assets, and generated files.&lt;/p&gt;
            &lt;ul&gt;
              &lt;li&gt;More file space&lt;/li&gt;
              &lt;li&gt;Better for teams&lt;/li&gt;
              &lt;li&gt;Useful for document portals&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;

      &lt;section class="vb-accordion-twentynine-item"&gt;
        &lt;button class="vb-accordion-twentynine-trigger" type="button" aria-expanded="false"&gt;
          &lt;span&gt;
            &lt;small&gt;Branding&lt;/small&gt;
            &lt;strong&gt;White Label Mode&lt;/strong&gt;
          &lt;/span&gt;
          &lt;em&gt;+€19/mo&lt;/em&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/button&gt;

        &lt;div class="vb-accordion-twentynine-content-wrap"&gt;
          &lt;div class="vb-accordion-twentynine-content"&gt;
            &lt;p&gt;Remove platform branding, add custom colors, upload your logo, and create a more client-ready experience.&lt;/p&gt;
            &lt;ul&gt;
              &lt;li&gt;Custom branding&lt;/li&gt;
              &lt;li&gt;Client-ready interface&lt;/li&gt;
              &lt;li&gt;Agency-friendly setup&lt;/li&gt;
            &lt;/ul&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">/* CSS is included in the live preview above. Copy the full CSS from the live preview block if you want this as a standalone component. */</pre>



<p class="wp-block-paragraph">This pricing add-on accordion is useful for SaaS pricing pages, checkout upgrades, subscription plans, hosting add-ons, plugin licenses, ecommerce bundles, and service package pages.</p>



<h2 class="wp-block-heading">30. Complete Responsive Accordion Section</h2>



<p class="wp-block-paragraph"><strong>A complete responsive accordion section</strong> is useful when a page needs a polished final accordion block with intro text, category tabs, expandable answers, visual cards, call-to-action buttons, and a layout that works across desktop, tablet, and mobile screens.</p>



<p class="wp-block-paragraph">This final example combines a full landing-page section layout with category buttons, one-open-at-a-time accordion behavior, a side visual panel, and responsive styling. It is designed as a complete website section rather than a small standalone component.</p>



<ul class="wp-block-list">
<li>Complete responsive accordion section</li>
<li>Category buttons and expandable answers</li>
<li>One-open-at-a-time JavaScript behavior</li>
<li>Side visual panel and CTA buttons</li>
<li>Useful for landing pages, FAQ sections, and service pages</li>
</ul>



<div class="vb-accordion-thirty-demo">
  <div class="vb-accordion-thirty-section" data-vb-accordion-thirty>
    <div class="vb-accordion-thirty-main">
      <div class="vb-accordion-thirty-kicker">Example 30</div>
      <h3>Complete Responsive Accordion Section</h3>
      <p class="vb-accordion-thirty-lead">Build a polished accordion section with category navigation, expandable answers, supporting visuals, and responsive layout behavior.</p>

      <div class="vb-accordion-thirty-tabs">
        <button type="button" class="is-active">General</button>
        <button type="button">Design</button>
        <button type="button">Code</button>
      </div>

      <div class="vb-accordion-thirty-list">
        <section class="vb-accordion-thirty-item is-open">
          <button class="vb-accordion-thirty-trigger" type="button" aria-expanded="true">
            <span>How can I use this accordion section?</span>
            <em></em>
          </button>
          <div class="vb-accordion-thirty-panel">
            <div class="vb-accordion-thirty-content">
              <p>You can use this section for FAQ pages, service pages, SaaS landing pages, product pages, support sections, onboarding pages, or documentation introductions.</p>
            </div>
          </div>
        </section>

        <section class="vb-accordion-thirty-item">
          <button class="vb-accordion-thirty-trigger" type="button" aria-expanded="false">
            <span>Does it work on mobile screens?</span>
            <em></em>
          </button>
          <div class="vb-accordion-thirty-panel">
            <div class="vb-accordion-thirty-content">
              <p>Yes. The layout changes from a two-column section to a single-column structure, while spacing, buttons, and panels stay readable on small screens.</p>
            </div>
          </div>
        </section>

        <section class="vb-accordion-thirty-item">
          <button class="vb-accordion-thirty-trigger" type="button" aria-expanded="false">
            <span>Can I place multiple accordions on one page?</span>
            <em></em>
          </button>
          <div class="vb-accordion-thirty-panel">
            <div class="vb-accordion-thirty-content">
              <p>Yes, if each accordion uses scoped class names and a unique data attribute. This keeps JavaScript selectors from conflicting with other examples.</p>
            </div>
          </div>
        </section>

        <section class="vb-accordion-thirty-item">
          <button class="vb-accordion-thirty-trigger" type="button" aria-expanded="false">
            <span>Why use JavaScript instead of only CSS?</span>
            <em></em>
          </button>
          <div class="vb-accordion-thirty-panel">
            <div class="vb-accordion-thirty-content">
              <p>JavaScript gives better control over ARIA states, one-open-at-a-time behavior, dynamic heights, resize updates, and more advanced UI logic.</p>
            </div>
          </div>
        </section>
      </div>

      <div class="vb-accordion-thirty-actions">
        <a href="#javascript-accordion-examples">View examples</a>
        <a href="#accordion-best-practices">Best practices</a>
      </div>
    </div>

    <aside class="vb-accordion-thirty-card">
      <div class="vb-accordion-thirty-window">
        <span></span>
        <span></span>
        <span></span>
      </div>

      <div class="vb-accordion-thirty-preview">
        <div></div>
        <div></div>
        <div></div>
      </div>

      <div class="vb-accordion-thirty-score">
        <strong>30</strong>
        <span>Accordion examples completed</span>
      </div>
    </aside>
  </div>
</div>

<style>
.vb-accordion-thirty-demo,
.vb-accordion-thirty-demo * {
  box-sizing: border-box;
}

.vb-accordion-thirty-demo {
  margin: 28px 0;
  padding: 44px;
  border-radius: 44px;
  background:
    linear-gradient(135deg, rgba(16, 185, 129, 0.16), transparent 32%),
    linear-gradient(315deg, rgba(59, 130, 246, 0.18), transparent 36%),
    linear-gradient(135deg, #ecfdf5 0%, #eff6ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(16, 185, 129, 0.24);
  box-shadow: 0 30px 90px rgba(15, 118, 110, 0.12);
}

.vb-accordion-thirty-section {
  display: grid;
  grid-template-columns: minmax(0, 1.12fr) minmax(300px, 0.88fr);
  gap: 34px;
  align-items: center;
  max-width: 1160px;
  margin: 0 auto;
}

.vb-accordion-thirty-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 9px 13px;
  border-radius: 999px;
  background: #047857;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.vb-accordion-thirty-main h3 {
  margin: 0 0 16px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(42px, 5vw, 78px) !important;
  line-height: 0.88 !important;
  font-weight: 950 !important;
  letter-spacing: -0.095em;
}

.vb-accordion-thirty-lead {
  max-width: 720px;
  margin: 0 0 22px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.8;
  font-weight: 650;
}

.vb-accordion-thirty-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 18px;
}

.vb-accordion-thirty-tabs button {
  min-height: 42px;
  padding: 10px 15px;
  border: 1px solid rgba(15, 118, 110, 0.20);
  border-radius: 999px;
  background: #ffffff;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-accordion-thirty-tabs button.is-active {
  background: #0f766e;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-thirty-list {
  display: grid;
  gap: 12px;
}

.vb-accordion-thirty-item {
  overflow: hidden;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 16px 44px rgba(15, 23, 42, 0.07);
}

.vb-accordion-thirty-item.is-open {
  border-color: rgba(16, 185, 129, 0.34);
  box-shadow: 0 24px 64px rgba(16, 185, 129, 0.12);
}

.vb-accordion-thirty-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 44px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 76px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb-accordion-thirty-trigger span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 19px;
  line-height: 1.2;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-accordion-thirty-trigger em {
  position: relative;
  width: 44px;
  height: 44px;
  border-radius: 999px;
  background: #ecfdf5;
  border: 1px solid rgba(16, 185, 129, 0.18);
}

.vb-accordion-thirty-trigger em::before,
.vb-accordion-thirty-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 16px;
  height: 2px;
  border-radius: 999px;
  background: #047857;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease;
}

.vb-accordion-thirty-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb-accordion-thirty-item.is-open .vb-accordion-thirty-trigger em {
  background: #047857;
}

.vb-accordion-thirty-item.is-open .vb-accordion-thirty-trigger em::before,
.vb-accordion-thirty-item.is-open .vb-accordion-thirty-trigger em::after {
  background: #ffffff;
}

.vb-accordion-thirty-item.is-open .vb-accordion-thirty-trigger em::after {
  opacity: 0;
}

.vb-accordion-thirty-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb-accordion-thirty-content {
  padding: 0 20px 20px;
}

.vb-accordion-thirty-content p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-accordion-thirty-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-top: 22px;
}

.vb-accordion-thirty-actions a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 46px;
  padding: 12px 17px;
  border-radius: 999px;
  text-decoration: none !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-accordion-thirty-actions a:first-child {
  background: #047857;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-accordion-thirty-actions a:last-child {
  background: #ffffff;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  border: 1px solid rgba(16, 185, 129, 0.22);
}

.vb-accordion-thirty-card {
  position: relative;
  min-height: 620px;
  overflow: hidden;
  padding: 26px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 24% 18%, rgba(255,255,255,0.24), transparent 34%),
    linear-gradient(135deg, #064e3b, #0f766e 58%, #2563eb) !important;
  box-shadow: 0 34px 90px rgba(15, 118, 110, 0.24);
}

.vb-accordion-thirty-window {
  display: flex;
  gap: 8px;
  margin-bottom: 28px;
}

.vb-accordion-thirty-window span {
  width: 14px;
  height: 14px;
  border-radius: 999px;
  background: rgba(255,255,255,0.36);
}

.vb-accordion-thirty-preview {
  display: grid;
  gap: 14px;
}

.vb-accordion-thirty-preview div {
  min-height: 84px;
  border-radius: 22px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.16);
}

.vb-accordion-thirty-preview div:nth-child(2) {
  width: 82%;
}

.vb-accordion-thirty-preview div:nth-child(3) {
  width: 68%;
}

.vb-accordion-thirty-score {
  position: absolute;
  left: 26px;
  right: 26px;
  bottom: 26px;
  padding: 24px;
  border-radius: 28px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.18);
}

.vb-accordion-thirty-score strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 96px;
  line-height: 0.85;
  font-weight: 950;
  letter-spacing: -0.1em;
}

.vb-accordion-thirty-score span {
  display: block;
  margin-top: 12px;
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 15px;
  line-height: 1.45;
  font-weight: 850;
}

@media (max-width: 960px) {
  .vb-accordion-thirty-section {
    grid-template-columns: 1fr;
  }

  .vb-accordion-thirty-card {
    min-height: 460px;
  }
}

@media (max-width: 640px) {
  .vb-accordion-thirty-demo {
    padding: 18px;
    border-radius: 30px;
  }

  .vb-accordion-thirty-main h3 {
    font-size: 40px !important;
  }

  .vb-accordion-thirty-card {
    min-height: 420px;
    padding: 20px;
    border-radius: 28px;
  }

  .vb-accordion-thirty-score {
    left: 20px;
    right: 20px;
    bottom: 20px;
  }

  .vb-accordion-thirty-score strong {
    font-size: 74px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb-accordion-thirty]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-thirty-item"));
  const tabs = Array.from(accordion.querySelectorAll(".vb-accordion-thirty-tabs button"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-thirty-trigger");
    const panel = item.querySelector(".vb-accordion-thirty-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-thirty-trigger");
    const panel = item.querySelector(".vb-accordion-thirty-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-thirty-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  tabs.forEach(function (tab) {
    tab.addEventListener("click", function () {
      tabs.forEach(function (button) {
        button.classList.remove("is-active");
      });

      tab.classList.add("is-active");
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-thirty-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-thirty-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const accordion = document.querySelector("[data-vb-accordion-thirty]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb-accordion-thirty-item"));
  const tabs = Array.from(accordion.querySelectorAll(".vb-accordion-thirty-tabs button"));

  function closeItem(item) {
    const button = item.querySelector(".vb-accordion-thirty-trigger");
    const panel = item.querySelector(".vb-accordion-thirty-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb-accordion-thirty-trigger");
    const panel = item.querySelector(".vb-accordion-thirty-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb-accordion-thirty-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  tabs.forEach(function (tab) {
    tab.addEventListener("click", function () {
      tabs.forEach(function (button) {
        button.classList.remove("is-active");
      });

      tab.classList.add("is-active");
    });
  });

  const defaultItem = accordion.querySelector(".vb-accordion-thirty-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb-accordion-thirty-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-accordion-thirty-demo"&gt;
  &lt;div class="vb-accordion-thirty-section" data-vb-accordion-thirty&gt;
    &lt;div class="vb-accordion-thirty-main"&gt;
      &lt;div class="vb-accordion-thirty-kicker"&gt;Example 30&lt;/div&gt;
      &lt;h3&gt;Complete Responsive Accordion Section&lt;/h3&gt;
      &lt;p class="vb-accordion-thirty-lead"&gt;Build a polished accordion section with category navigation, expandable answers, supporting visuals, and responsive layout behavior.&lt;/p&gt;

      &lt;div class="vb-accordion-thirty-tabs"&gt;
        &lt;button type="button" class="is-active"&gt;General&lt;/button&gt;
        &lt;button type="button"&gt;Design&lt;/button&gt;
        &lt;button type="button"&gt;Code&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-thirty-list"&gt;
        &lt;section class="vb-accordion-thirty-item is-open"&gt;
          &lt;button class="vb-accordion-thirty-trigger" type="button" aria-expanded="true"&gt;
            &lt;span&gt;How can I use this accordion section?&lt;/span&gt;
            &lt;em&gt;&lt;/em&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-thirty-panel"&gt;
            &lt;div class="vb-accordion-thirty-content"&gt;
              &lt;p&gt;You can use this section for FAQ pages, service pages, SaaS landing pages, product pages, support sections, onboarding pages, or documentation introductions.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;

        &lt;section class="vb-accordion-thirty-item"&gt;
          &lt;button class="vb-accordion-thirty-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;Does it work on mobile screens?&lt;/span&gt;
            &lt;em&gt;&lt;/em&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-thirty-panel"&gt;
            &lt;div class="vb-accordion-thirty-content"&gt;
              &lt;p&gt;Yes. The layout changes from a two-column section to a single-column structure, while spacing, buttons, and panels stay readable on small screens.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;

        &lt;section class="vb-accordion-thirty-item"&gt;
          &lt;button class="vb-accordion-thirty-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;Can I place multiple accordions on one page?&lt;/span&gt;
            &lt;em&gt;&lt;/em&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-thirty-panel"&gt;
            &lt;div class="vb-accordion-thirty-content"&gt;
              &lt;p&gt;Yes, if each accordion uses scoped class names and a unique data attribute. This keeps JavaScript selectors from conflicting with other examples.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;

        &lt;section class="vb-accordion-thirty-item"&gt;
          &lt;button class="vb-accordion-thirty-trigger" type="button" aria-expanded="false"&gt;
            &lt;span&gt;Why use JavaScript instead of only CSS?&lt;/span&gt;
            &lt;em&gt;&lt;/em&gt;
          &lt;/button&gt;
          &lt;div class="vb-accordion-thirty-panel"&gt;
            &lt;div class="vb-accordion-thirty-content"&gt;
              &lt;p&gt;JavaScript gives better control over ARIA states, one-open-at-a-time behavior, dynamic heights, resize updates, and more advanced UI logic.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/section&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-thirty-actions"&gt;
        &lt;a href="#javascript-accordion-examples"&gt;View examples&lt;/a&gt;
        &lt;a href="#accordion-best-practices"&gt;Best practices&lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;aside class="vb-accordion-thirty-card"&gt;
      &lt;div class="vb-accordion-thirty-window"&gt;
        &lt;span&gt;&lt;/span&gt;
        &lt;span&gt;&lt;/span&gt;
        &lt;span&gt;&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-thirty-preview"&gt;
        &lt;div&gt;&lt;/div&gt;
        &lt;div&gt;&lt;/div&gt;
        &lt;div&gt;&lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-accordion-thirty-score"&gt;
        &lt;strong&gt;30&lt;/strong&gt;
        &lt;span&gt;Accordion examples completed&lt;/span&gt;
      &lt;/div&gt;
    &lt;/aside&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">/* CSS is included in the live preview above. Copy the full CSS from the live preview block if you want this as a standalone component. */</pre>



<p class="wp-block-paragraph">This complete responsive accordion section is useful for landing pages, FAQ sections, SaaS websites, service pages, product pages, support pages, onboarding sections, and documentation pages that need a complete polished accordion layout.</p>



<div class="vb24-js-accordion-audience-ad">
  <div class="vb24-js-accordion-audience-ad-content">
    <span>WordPress SEO Plugin</span>
    <h2>Improve Your WordPress Website with Cleaner Structured Data</h2>
    <p>If you want your WordPress website to be easier for Google, AI search tools, and visitors to understand, EntitySchema Pro helps you add structured data, entity information, and cleaner SEO signals without manually writing schema code.</p>
    <a href="https://veebilehed24.ee/en/shop/entityschema-pro/" target="_blank" rel="sponsored noopener">View EntitySchema Pro</a>
  </div>

  <div class="vb24-js-accordion-audience-ad-card">
    <a href="https://veebilehed24.ee/en/shop/entityschema-pro/" target="_blank" rel="sponsored noopener">
      <img decoding="async" src="https://veebilehed24.ee/wp-content/uploads/2026/03/entityschema-cover-600x400.webp" width="300" height="200" alt="EntitySchema Pro WordPress structured data and entity SEO plugin" loading="lazy">
      <div>
        <strong>EntitySchema Pro</strong>
        <small>Structured data and entity SEO for WordPress websites.</small>
        <span>View Plugin</span>
      </div>
    </a>
  </div>
</div>

<style>
.vb24-js-accordion-audience-ad,
.vb24-js-accordion-audience-ad * {
  box-sizing: border-box;
}

.vb24-js-accordion-audience-ad {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 28px;
  align-items: center;
  margin: 44px 0 50px;
  padding: 32px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 14% 18%, rgba(139, 92, 246, 0.26), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(6, 182, 212, 0.22), transparent 34%),
    linear-gradient(135deg, #111827 0%, #312e81 52%, #164e63 100%) !important;
  border: 1px solid rgba(196, 181, 253, 0.26);
  box-shadow: 0 26px 76px rgba(15, 23, 42, 0.24);
}

.vb24-js-accordion-audience-ad-content span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.18);
  color: #c4b5fd !important;
  -webkit-text-fill-color: #c4b5fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb24-js-accordion-audience-ad-content h2 {
  max-width: 760px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 4vw, 54px) !important;
  line-height: 1.05 !important;
  font-weight: 950 !important;
  letter-spacing: -0.065em;
}

.vb24-js-accordion-audience-ad-content p {
  max-width: 760px;
  margin: 0 0 24px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb24-js-accordion-audience-ad-content a {
  display: inline-flex;
  min-height: 48px;
  align-items: center;
  justify-content: center;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #8b5cf6, #06b6d4, #10b981);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 900;
  text-decoration: none !important;
  box-shadow: 0 16px 36px rgba(6, 182, 212, 0.28);
}

.vb24-js-accordion-audience-ad-card a {
  display: block;
  overflow: hidden;
  border-radius: 24px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  text-decoration: none !important;
  box-shadow: 0 22px 60px rgba(0, 0, 0, 0.28);
}

.vb24-js-accordion-audience-ad-card img {
  display: block;
  width: 100%;
  height: auto;
}

.vb24-js-accordion-audience-ad-card div {
  padding: 16px;
}

.vb24-js-accordion-audience-ad-card strong {
  display: block;
  margin-bottom: 6px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  line-height: 1.2;
  font-weight: 950;
}

.vb24-js-accordion-audience-ad-card small {
  display: block;
  margin-bottom: 14px;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 13px;
  line-height: 1.45;
  font-weight: 650;
}

.vb24-js-accordion-audience-ad-card div span {
  display: inline-flex;
  min-height: 38px;
  align-items: center;
  justify-content: center;
  padding: 10px 13px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vb24-js-accordion-audience-ad {
    grid-template-columns: 1fr;
  }

  .vb24-js-accordion-audience-ad-card {
    max-width: 360px;
  }
}

@media (max-width: 640px) {
  .vb24-js-accordion-audience-ad {
    padding: 22px;
    border-radius: 24px;
  }

  .vb24-js-accordion-audience-ad-content a {
    width: 100%;
  }

  .vb24-js-accordion-audience-ad-card {
    max-width: 100%;
  }
}
</style>



<span id="accordion-best-practices"></span>



<h2 class="wp-block-heading" id="javascript-accordion-best-practices">JavaScript Accordion Best Practices</h2>



<p class="wp-block-paragraph">JavaScript accordions work best when they make a page easier to scan without hiding information users need immediately. A strong accordion component should have clear clickable headers, readable expanded content, visible active states, smooth open and close behavior, and responsive spacing that works on desktop, tablet, and mobile screens.</p>



<p class="wp-block-paragraph">For business websites, FAQ pages, ecommerce product pages, service pages, SaaS landing pages, dashboards, documentation sections, and support pages, accordions are useful because they organize long content into smaller sections. The goal is not to add animation for decoration, but to help visitors find the right answer, feature, setting, product detail, or pricing information faster.</p>



<div class="vb24-js-accordion-practice-grid">
  <article>
    <span>01</span>
    <h3>Use clear accordion labels</h3>
    <p>Each accordion header should describe exactly what users will find inside, such as shipping details, pricing questions, product specs, setup steps, or support answers.</p>
  </article>

  <article>
    <span>02</span>
    <h3>Make the whole header clickable</h3>
    <p>Users should not need to click a tiny icon. Make the full question, title, or accordion row clickable for a better desktop and mobile experience.</p>
  </article>

  <article>
    <span>03</span>
    <h3>Show a strong open state</h3>
    <p>The active accordion item should stand out with a different border, background, icon state, shadow, or label style.</p>
  </article>

  <article>
    <span>04</span>
    <h3>Use real button elements</h3>
    <p>Accordion triggers should be buttons, not random divs, because buttons are easier to use with keyboards and assistive technologies.</p>
  </article>

  <article>
    <span>05</span>
    <h3>Keep JavaScript scoped</h3>
    <p>Use a unique wrapper and class names so multiple accordions can work on the same page without CSS or JavaScript conflicts.</p>
  </article>

  <article>
    <span>06</span>
    <h3>Test long real content</h3>
    <p>Real FAQ answers, product descriptions, documentation text, and pricing notes are often much longer than demo text, so test with realistic content.</p>
  </article>
</div>

<style>
.vb24-js-accordion-practice-grid,
.vb24-js-accordion-practice-grid * {
  box-sizing: border-box;
}

.vb24-js-accordion-practice-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  margin: 26px 0 34px;
}

.vb24-js-accordion-practice-grid article {
  padding: 22px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 16% 12%, rgba(139, 92, 246, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.08);
}

.vb24-js-accordion-practice-grid span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb24-js-accordion-practice-grid h3 {
  margin: 0 0 10px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 20px !important;
  line-height: 1.2 !important;
  font-weight: 900 !important;
  letter-spacing: -0.035em;
}

.vb24-js-accordion-practice-grid p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb24-js-accordion-practice-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-js-accordion-practice-grid {
    grid-template-columns: 1fr;
  }
}
</style>



<p class="wp-block-paragraph">For most FAQ sections and landing pages, one-open-at-a-time behavior is a good choice because it keeps the page compact. For dashboards, documentation, product details, course modules, and settings panels, multi-open behavior can be better because users may want to compare several open sections at once.</p>



<ul class="wp-block-list">
  <li><strong>Use one-open-at-a-time accordions</strong> for FAQs, pricing questions, service pages, and short support sections.</li>
  <li><strong>Use multi-open accordions</strong> for documentation, dashboards, product details, settings, and comparison-style content.</li>
  <li><strong>Use clear icons</strong> such as plus/minus, chevrons, arrows, labels, badges, or active indicators.</li>
  <li><strong>Keep animations short</strong> so the accordion feels fast and professional.</li>
  <li><strong>Use enough spacing</strong> inside expanded panels so answers, lists, and product details are easy to read.</li>
  <li><strong>Do not hide important conversion information</strong> if users need it before clicking a button or making a decision.</li>
</ul>



<h2 class="wp-block-heading" id="responsive-accordion-design-tips">Responsive Accordion Design Tips</h2>



<p class="wp-block-paragraph">Responsive accordion design matters because accordions are often used to simplify mobile pages. A long FAQ section, product information block, checkout help area, documentation menu, or dashboard settings page can feel much cleaner when the content is grouped into expandable sections.</p>



<p class="wp-block-paragraph">On mobile screens, accordion rows should be easy to tap, headings should remain readable, icons should not disappear, and expanded content should not become too narrow. If the accordion includes columns, cards, images, pricing details, tables, or statistics, stack those elements vertically on smaller screens.</p>



<div class="vb24-js-accordion-responsive-box">
  <div>
    <h3>Desktop layout</h3>
    <p>Use wider accordion sections, side visuals, comparison blocks, pricing panels, and richer card layouts when there is enough space.</p>
  </div>

  <div>
    <h3>Tablet layout</h3>
    <p>Reduce complex columns, keep accordion titles readable, and make sure expanded content does not feel squeezed.</p>
  </div>

  <div>
    <h3>Mobile layout</h3>
    <p>Stack everything, increase tap areas, keep icons visible, and make sure every answer or content panel has comfortable spacing.</p>
  </div>
</div>

<style>
.vb24-js-accordion-responsive-box,
.vb24-js-accordion-responsive-box * {
  box-sizing: border-box;
}

.vb24-js-accordion-responsive-box {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  margin: 26px 0 34px;
  padding: 22px;
  border-radius: 28px;
  background:
    radial-gradient(circle at 16% 18%, rgba(6, 182, 212, 0.16), transparent 34%),
    linear-gradient(135deg, #ecfeff, #f8fafc) !important;
  border: 1px solid rgba(14, 165, 233, 0.22);
}

.vb24-js-accordion-responsive-box div {
  padding: 20px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb24-js-accordion-responsive-box h3 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px !important;
  line-height: 1.25 !important;
  font-weight: 900 !important;
  letter-spacing: -0.035em;
}

.vb24-js-accordion-responsive-box p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

@media (max-width: 860px) {
  .vb24-js-accordion-responsive-box {
    grid-template-columns: 1fr;
  }
}
</style>



<ul class="wp-block-list">
  <li><strong>Use large tap targets</strong> so visitors can open accordion rows easily on mobile.</li>
  <li><strong>Avoid tiny icons</strong> that are hard to tap or difficult to see.</li>
  <li><strong>Stack complex content</strong> when an expanded panel contains cards, columns, tables, pricing items, or media blocks.</li>
  <li><strong>Keep headings short where possible</strong> so accordion labels do not wrap into confusing multi-line blocks.</li>
  <li><strong>Use readable line height</strong> because expanded accordion content often contains longer explanations.</li>
  <li><strong>Check resize behavior</strong> when you use dynamic max-height animation with JavaScript.</li>
</ul>



<h2 class="wp-block-heading" id="common-javascript-accordion-mistakes">Common JavaScript Accordion Mistakes</h2>



<p class="wp-block-paragraph">Common JavaScript accordion mistakes usually happen when the component is built only for a quick demo instead of a real page. The accordion may work with short text, but then break when the content becomes longer, when the same component is used more than once, or when the layout changes on mobile.</p>



<p class="wp-block-paragraph">The biggest problems are unclear clickable areas, missing active states, fixed panel heights, non-semantic markup, repeated class names, and JavaScript selectors that affect the wrong component. These issues are easy to avoid when you plan the accordion structure before writing the script.</p>



<div class="vb24-js-accordion-mistakes">
  <article>
    <strong>Using unclear headers</strong>
    <p>Labels like “More info” are weak. Use clear labels such as “Shipping details”, “Warranty”, “Pricing FAQ”, or “Product specifications”.</p>
  </article>

  <article>
    <strong>Making only the icon clickable</strong>
    <p>The whole accordion header should open the panel, not just a small plus icon on the right side.</p>
  </article>

  <article>
    <strong>Hardcoding panel height</strong>
    <p>Fixed heights can break with long text, translated content, responsive wrapping, or dynamic content loaded later.</p>
  </article>

  <article>
    <strong>Using global selectors</strong>
    <p>Generic selectors can make multiple accordions conflict when several components are used on the same page.</p>
  </article>

  <article>
    <strong>Forgetting accessibility states</strong>
    <p>Update aria-expanded when an item opens or closes and keep trigger elements keyboard-friendly.</p>
  </article>

  <article>
    <strong>Repeating the same visual pattern</strong>
    <p>Different use cases need different layouts. A pricing accordion, product accordion, FAQ accordion, and dashboard accordion should not all look identical.</p>
  </article>
</div>

<style>
.vb24-js-accordion-mistakes,
.vb24-js-accordion-mistakes * {
  box-sizing: border-box;
}

.vb24-js-accordion-mistakes {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  margin: 26px 0 34px;
}

.vb24-js-accordion-mistakes article {
  position: relative;
  padding: 20px 20px 20px 56px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(248, 113, 113, 0.22);
  box-shadow: 0 16px 40px rgba(127, 29, 29, 0.07);
}

.vb24-js-accordion-mistakes article::before {
  content: "!";
  position: absolute;
  left: 18px;
  top: 20px;
  width: 26px;
  height: 26px;
  border-radius: 999px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 15px;
  font-weight: 950;
}

.vb24-js-accordion-mistakes strong {
  display: block;
  margin-bottom: 7px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 900;
}

.vb24-js-accordion-mistakes p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 720px) {
  .vb24-js-accordion-mistakes {
    grid-template-columns: 1fr;
  }
}
</style>



<ul class="wp-block-list">
  <li><strong>Do not remove focus outlines</strong> unless you replace them with a clear custom focus style.</li>
  <li><strong>Do not hide important buying information</strong> inside a closed panel if users need it before contacting you or buying.</li>
  <li><strong>Do not use hover-only accordions</strong> because they are weak for mobile and touch screens.</li>
  <li><strong>Do not use the same ID twice</strong> when copying accordion examples into one page.</li>
  <li><strong>Do not forget to test the accordion after adding real content</strong>, especially on mobile.</li>
</ul>



<h2 class="wp-block-heading" id="javascript-accordion-faq">JavaScript Accordion FAQ</h2>



<p class="wp-block-paragraph">Here are common questions about JavaScript accordions for websites, FAQ sections, ecommerce pages, service pages, dashboards, documentation layouts, and responsive UI components.</p>



<div class="vb24-js-accordion-faq-section" data-vb24-js-accordion-faq>
  <section class="vb24-js-accordion-faq-item is-open">
    <button class="vb24-js-accordion-faq-trigger" type="button" aria-expanded="true">
      <span>What is a JavaScript accordion?</span>
      <em></em>
    </button>
    <div class="vb24-js-accordion-faq-panel">
      <div class="vb24-js-accordion-faq-content">
        <p>A JavaScript accordion is an interactive UI component that opens and closes content panels when users click a heading, button, question, or label. It is commonly used for FAQs, product details, pricing questions, support sections, and dashboards.</p>
      </div>
    </div>
  </section>

  <section class="vb24-js-accordion-faq-item">
    <button class="vb24-js-accordion-faq-trigger" type="button" aria-expanded="false">
      <span>Where should I use an accordion on a website?</span>
      <em></em>
    </button>
    <div class="vb24-js-accordion-faq-panel">
      <div class="vb24-js-accordion-faq-content">
        <p>Use accordions where users need to scan many sections quickly, such as FAQ pages, product specifications, shipping details, pricing questions, help centers, service pages, documentation menus, course modules, and mobile filters.</p>
      </div>
    </div>
  </section>

  <section class="vb24-js-accordion-faq-item">
    <button class="vb24-js-accordion-faq-trigger" type="button" aria-expanded="false">
      <span>Should only one accordion item open at a time?</span>
      <em></em>
    </button>
    <div class="vb24-js-accordion-faq-panel">
      <div class="vb24-js-accordion-faq-content">
        <p>It depends on the use case. One-open-at-a-time behavior is good for compact FAQ sections and pricing questions. Multi-open behavior is better for product details, dashboards, documentation, and settings panels where users may compare several sections.</p>
      </div>
    </div>
  </section>

  <section class="vb24-js-accordion-faq-item">
    <button class="vb24-js-accordion-faq-trigger" type="button" aria-expanded="false">
      <span>Is JavaScript better than CSS for accordions?</span>
      <em></em>
    </button>
    <div class="vb24-js-accordion-faq-panel">
      <div class="vb24-js-accordion-faq-content">
        <p>JavaScript gives more control over active states, ARIA attributes, one-open-at-a-time behavior, dynamic heights, resize handling, nested accordions, and more advanced UI logic. CSS can be enough for very simple static accordions.</p>
      </div>
    </div>
  </section>

  <section class="vb24-js-accordion-faq-item">
    <button class="vb24-js-accordion-faq-trigger" type="button" aria-expanded="false">
      <span>Can JavaScript accordions work well on mobile?</span>
      <em></em>
    </button>
    <div class="vb24-js-accordion-faq-panel">
      <div class="vb24-js-accordion-faq-content">
        <p>Yes. Accordions are especially useful on mobile because they reduce scrolling and keep long content organized. Use large tap targets, readable labels, clear icons, and stacked panel content for the best mobile experience.</p>
      </div>
    </div>
  </section>

  <section class="vb24-js-accordion-faq-item">
    <button class="vb24-js-accordion-faq-trigger" type="button" aria-expanded="false">
      <span>Can I use these accordion examples in WordPress?</span>
      <em></em>
    </button>
    <div class="vb24-js-accordion-faq-panel">
      <div class="vb24-js-accordion-faq-content">
        <p>Yes. These examples use vanilla JavaScript, HTML, and CSS, so they can be pasted into a Gutenberg Custom HTML block. For a live website, repeated CSS and JavaScript should usually be moved into your theme or plugin files.</p>
      </div>
    </div>
  </section>
</div>

<style>
.vb24-js-accordion-faq-section,
.vb24-js-accordion-faq-section * {
  box-sizing: border-box;
}

.vb24-js-accordion-faq-section {
  display: grid;
  gap: 12px;
  margin: 26px 0 36px;
}

.vb24-js-accordion-faq-item {
  overflow: hidden;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.07);
}

.vb24-js-accordion-faq-item.is-open {
  border-color: rgba(139, 92, 246, 0.36);
  box-shadow: 0 24px 64px rgba(139, 92, 246, 0.12);
}

.vb24-js-accordion-faq-trigger {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 44px;
  align-items: center;
  gap: 16px;
  width: 100%;
  min-height: 76px;
  padding: 18px 20px;
  border: 0;
  background: transparent;
  cursor: pointer;
  text-align: left;
}

.vb24-js-accordion-faq-trigger span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 19px;
  line-height: 1.25;
  font-weight: 900;
  letter-spacing: -0.035em;
}

.vb24-js-accordion-faq-trigger em {
  position: relative;
  width: 44px;
  height: 44px;
  border-radius: 16px;
  background: #f5f3ff;
  border: 1px solid rgba(139, 92, 246, 0.18);
}

.vb24-js-accordion-faq-trigger em::before,
.vb24-js-accordion-faq-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 16px;
  height: 2px;
  border-radius: 999px;
  background: #7c3aed;
  transform: translate(-50%, -50%);
  transition: opacity 0.22s ease;
}

.vb24-js-accordion-faq-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
}

.vb24-js-accordion-faq-item.is-open .vb24-js-accordion-faq-trigger em {
  background: #7c3aed;
}

.vb24-js-accordion-faq-item.is-open .vb24-js-accordion-faq-trigger em::before,
.vb24-js-accordion-faq-item.is-open .vb24-js-accordion-faq-trigger em::after {
  background: #ffffff;
}

.vb24-js-accordion-faq-item.is-open .vb24-js-accordion-faq-trigger em::after {
  opacity: 0;
}

.vb24-js-accordion-faq-panel {
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.28s ease;
}

.vb24-js-accordion-faq-content {
  padding: 0 20px 20px;
}

.vb24-js-accordion-faq-content p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 640px) {
  .vb24-js-accordion-faq-trigger {
    padding: 16px;
    min-height: 70px;
  }

  .vb24-js-accordion-faq-trigger span {
    font-size: 17px;
  }

  .vb24-js-accordion-faq-content {
    padding: 0 16px 16px;
  }
}
</style>

<script>
(function () {
  const accordion = document.querySelector("[data-vb24-js-accordion-faq]");
  if (!accordion) return;

  const items = Array.from(accordion.querySelectorAll(".vb24-js-accordion-faq-item"));

  function closeItem(item) {
    const button = item.querySelector(".vb24-js-accordion-faq-trigger");
    const panel = item.querySelector(".vb24-js-accordion-faq-panel");

    item.classList.remove("is-open");
    button.setAttribute("aria-expanded", "false");
    panel.style.maxHeight = "0px";
  }

  function openItem(item) {
    const button = item.querySelector(".vb24-js-accordion-faq-trigger");
    const panel = item.querySelector(".vb24-js-accordion-faq-panel");

    item.classList.add("is-open");
    button.setAttribute("aria-expanded", "true");
    panel.style.maxHeight = panel.scrollHeight + "px";
  }

  items.forEach(function (item) {
    const button = item.querySelector(".vb24-js-accordion-faq-trigger");

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(closeItem);

      if (!isOpen) {
        openItem(item);
      }
    });
  });

  const defaultItem = accordion.querySelector(".vb24-js-accordion-faq-item.is-open");
  if (defaultItem) {
    openItem(defaultItem);
  }

  window.addEventListener("resize", function () {
    const open = accordion.querySelector(".vb24-js-accordion-faq-item.is-open");
    if (open) {
      openItem(open);
    }
  });
})();
</script>



<h2 class="wp-block-heading" id="javascript-accordion-conclusion">Conclusion</h2>



<p class="wp-block-paragraph">JavaScript accordions are practical UI components for modern websites because they make long content easier to scan, organize, and use. They are especially useful for FAQ sections, product details, pricing questions, support pages, documentation sections, mobile filters, dashboard settings, course modules, and content-heavy landing pages.</p>



<p class="wp-block-paragraph">The best accordion examples are not only functional, but also visually clear. A professional accordion should have an obvious clickable header, a strong active state, smooth behavior, readable expanded content, mobile-friendly spacing, and JavaScript that does not conflict with other components on the same page.</p>



<p class="wp-block-paragraph">Use these 30 JavaScript accordion examples as starting points for real website projects. You can adapt the styles, icons, layouts, colors, open behavior, and content structure for business websites, ecommerce stores, SaaS pages, WordPress sites, dashboards, help centers, and landing pages.</p>



<h2 class="wp-block-heading" id="related-javascript-and-css-guides">Related JavaScript and CSS Guides</h2>



<p class="wp-block-paragraph">Continue building better website sections and interactive UI components with these related JavaScript and CSS guides. These posts work well together when building full landing pages, product pages, dashboards, forms, filters, menus, and responsive website layouts.</p>



<div class="vb24-js-accordion-related">
  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-search-filter-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Search Filter Examples</strong>
    <p>Live search, card filters, product filters, FAQ search, dashboard filters, and responsive filtering UI examples.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-dropdown-menu-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Dropdown Menu Examples</strong>
    <p>Custom selects, navigation dropdowns, profile menus, category dropdowns, and responsive menu components.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-slider-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Slider Examples</strong>
    <p>Image sliders, product carousels, testimonial sliders, hero sliders, and content carousel components.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-form-validation-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Form Validation Examples</strong>
    <p>Input validation, signup validation, checkout validation, password checks, and user-friendly form feedback.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-modal-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Modal Examples</strong>
    <p>Popup windows, dialog boxes, overlay components, confirmation modals, and responsive modal UI patterns.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-forms/">
    <span>CSS</span>
    <strong>30 Modern CSS Forms for Websites</strong>
    <p>Contact forms, login forms, checkout forms, newsletter forms, and responsive form layout examples.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-layouts/">
    <span>CSS</span>
    <strong>25 Modern CSS Layouts for Websites</strong>
    <p>Grid, Flexbox, container queries, landing page layouts, dashboard layouts, and responsive section patterns.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-pricing-tables/">
    <span>CSS</span>
    <strong>30 Modern CSS Pricing Tables</strong>
    <p>Responsive pricing cards, SaaS pricing sections, comparison tables, featured plans, and pricing layouts.</p>
  </a>
</div>

<style>
.vb24-js-accordion-related,
.vb24-js-accordion-related * {
  box-sizing: border-box;
}

.vb24-js-accordion-related {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin: 26px 0 38px;
}

.vb24-js-accordion-related a {
  display: flex;
  flex-direction: column;
  min-height: 100%;
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 16% 12%, rgba(139, 92, 246, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.08);
  text-decoration: none !important;
  transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}

.vb24-js-accordion-related a:hover {
  transform: translateY(-3px);
  border-color: rgba(139, 92, 246, 0.48);
  box-shadow: 0 22px 58px rgba(76, 29, 149, 0.13);
}

.vb24-js-accordion-related span {
  display: inline-flex;
  align-self: flex-start;
  margin-bottom: 12px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb24-js-accordion-related strong {
  display: block;
  margin-bottom: 9px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 900;
  letter-spacing: -0.035em;
}

.vb24-js-accordion-related p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 1040px) {
  .vb24-js-accordion-related {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-js-accordion-related {
    grid-template-columns: 1fr;
  }
}
</style>
]]></content:encoded>
					
					<wfw:commentRss>https://veebilehed24.ee/en/blog/javascript/javascript-accordion-examples/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>30 JavaScript Calculator Examples – Price, Loan, BMI, Discount &#038; Form Calculators</title>
		<link>https://veebilehed24.ee/en/blog/javascript/javascript-calculator-examples/</link>
					<comments>https://veebilehed24.ee/en/blog/javascript/javascript-calculator-examples/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Fri, 12 Jun 2026 05:22:27 +0000</pubDate>
				<category><![CDATA[Javascript]]></category>
		<guid isPermaLink="false">https://veebilehed24.ee/?p=1718</guid>

					<description><![CDATA[JavaScript calculators are useful interactive website tools for price estimates, loan payments, mortgage calculations, BMI results, discount prices, VAT calculations, shipping costs, quote forms, savings goals, tip amounts, ROI estimates, subscription pricing, and many other real-time calculations. They help users get instant answers without reloading the page or contacting support for every small question. In [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">JavaScript calculators are useful interactive website tools for price estimates, loan payments, mortgage calculations, BMI results, discount prices, VAT calculations, shipping costs, quote forms, savings goals, tip amounts, ROI estimates, subscription pricing, and many other real-time calculations. They help users get instant answers without reloading the page or contacting support for every small question.</p>



<p class="wp-block-paragraph">In this guide, you will find 30 JavaScript calculator examples for real website projects, including price calculators, loan calculators, BMI calculators, discount calculators, mortgage calculators, tip calculators, VAT calculators, shipping calculators, quote request calculators, calorie calculators, savings calculators, subscription calculators, ecommerce total calculators, and reusable form-based calculator systems.</p>



<p class="wp-block-paragraph">This post focuses on practical JavaScript calculator logic, input handling, number formatting, live results, form validation, percentage calculations, range sliders, dropdown-based formulas, real-time totals, reset buttons, responsive layouts, and copy-paste-ready JavaScript, HTML, and CSS examples. For related JavaScript UI patterns, you can also explore our <a href="https://veebilehed24.ee/en/blog/javascript/javascript-form-validation-examples/">JavaScript form validation examples</a>, <a href="https://veebilehed24.ee/en/blog/javascript/javascript-search-filter-examples/">JavaScript search filter examples</a>, <a href="https://veebilehed24.ee/en/blog/javascript/javascript-dropdown-menu-examples/">JavaScript dropdown menu examples</a>, and <a href="https://veebilehed24.ee/en/blog/javascript/javascript-countdown-timer-examples/">JavaScript countdown timer examples</a>.</p>



<div class="vb24-js-calc-jump-box">
  <a class="vb24-js-calc-jump-button" href="#javascript-calculator-examples">View All 30 JavaScript Calculator Examples</a>
</div>

<style>
.vb24-js-calc-jump-box {
  margin: 28px 0 36px;
}

.vb24-js-calc-jump-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 14px 22px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22c55e, #06b6d4 52%, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 850;
  line-height: 1.2;
  text-decoration: none !important;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.28);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-js-calc-jump-button::after {
  content: "↓";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.18);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  line-height: 1;
}

.vb24-js-calc-jump-button:hover {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transform: translateY(-2px);
  filter: saturate(1.08);
  box-shadow: 0 20px 46px rgba(37, 99, 235, 0.36);
}

@media (max-width: 640px) {
  .vb24-js-calc-jump-button {
    width: 100%;
    padding: 14px 16px;
    font-size: 14px;
  }
}
</style>



<div class="toc-affiliate-wrap vb24-js-calc-toc-wrap">

  <div class="toc-left vb24-js-calc-toc-left">

    <div class="vb24-js-calc-toc-kicker">On this page</div>

    <h2>Table of Contents</h2>

    <ul class="vl24-toc vb24-js-calc-toc">
      <li><a href="#what-is-a-javascript-calculator">What Is a JavaScript Calculator?</a></li>
      <li><a href="#why-javascript-calculators-matter">Why JavaScript Calculators Matter</a></li>
      <li><a href="#javascript-calculator-types">JavaScript Calculator Types</a></li>
      <li><a href="#what-should-a-good-javascript-calculator-include">What Should a Good JavaScript Calculator Include?</a></li>
      <li><a class="vb24-featured-toc-link" href="#javascript-calculator-examples">30 JavaScript Calculator Examples</a></li>
      <li><a href="#javascript-calculator-best-practices">JavaScript Calculator Best Practices</a></li>
      <li><a href="#responsive-javascript-calculator-design-tips">Responsive Calculator Design Tips</a></li>
      <li><a href="#common-javascript-calculator-mistakes">Common JavaScript Calculator Mistakes</a></li>
      <li><a href="#javascript-calculator-faq">JavaScript Calculator FAQ</a></li>
      <li><a href="#javascript-calculator-conclusion">Conclusion</a></li>
      <li><a href="#related-javascript-guides">Related JavaScript Guides</a></li>
    </ul>

  </div>

  <div class="toc-right vb24-js-calc-toc-right">

    <a class="vb24-entityschema-ad-card" href="https://veebilehed24.ee/en/shop/entityschema-pro/" target="_blank" rel="sponsored noopener">
      <span class="vb24-entityschema-ad-badge">WordPress SEO Plugin</span>

      <div class="vb24-entityschema-ad-image">
        <img decoding="async" src="https://veebilehed24.ee/wp-content/uploads/2026/03/entityschema-cover-600x400.webp" width="300" height="200" alt="EntitySchema Pro WordPress structured data and entity SEO plugin" loading="lazy">
      </div>

      <div class="vb24-entityschema-ad-content">
        <h3>EntitySchema Pro</h3>
        <p>Build a real entity-based structured data system for WordPress, modern SEO, and AI-readable websites.</p>

        <div class="vb24-entityschema-ad-price">
          <div class="vb24-entityschema-ad-price-left">
            <span class="vb24-entityschema-ad-price-label">Sale price</span>
            <span class="vb24-entityschema-ad-old-price">89€</span>
          </div>

          <strong class="vb24-entityschema-ad-sale-price">29€</strong>

          <span class="vb24-entityschema-ad-save">Save 60€</span>
        </div>

        <span class="vb24-entityschema-ad-button">View Plugin</span>
      </div>
    </a>

  </div>

</div>

<style>
.vb24-js-calc-toc-wrap {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 26px;
  align-items: stretch;
  margin: 34px 0 44px;
}

.vb24-js-calc-toc-left,
.vb24-js-calc-toc-right {
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 28px;
  background: linear-gradient(135deg, #0f172a 0%, #14532d 46%, #1e3a8a 100%);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.18);
}

.vb24-js-calc-toc-left {
  padding: 28px 30px 30px;
}

.vb24-js-calc-toc-kicker {
  margin-bottom: 10px;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 13px;
  font-weight: 850;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb24-js-calc-toc-left h2 {
  margin: 0 0 22px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px !important;
  line-height: 1.15 !important;
  font-weight: 850 !important;
}

.vb24-js-calc-toc {
  display: grid !important;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px !important;
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb24-js-calc-toc li {
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb24-js-calc-toc li::before {
  display: none !important;
  content: none !important;
}

.vb24-js-calc-toc a {
  display: flex;
  align-items: center;
  min-height: 54px;
  padding: 13px 15px;
  border: 1px solid rgba(148, 163, 184, 0.18);
  border-radius: 15px;
  background: rgba(255, 255, 255, 0.065);
  color: #f3f4f6 !important;
  -webkit-text-fill-color: #f3f4f6 !important;
  font-size: 15px;
  font-weight: 750;
  line-height: 1.35;
  text-decoration: none !important;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.05);
  transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease;
}

.vb24-js-calc-toc a:hover {
  transform: translateY(-2px);
  border-color: rgba(34, 197, 94, 0.70);
  background: rgba(34, 197, 94, 0.16);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb24-js-calc-toc .vb24-featured-toc-link {
  border-color: rgba(74, 222, 128, 0.78);
  background: linear-gradient(135deg, rgba(34, 197, 94, 0.34), rgba(6, 182, 212, 0.28), rgba(37, 99, 235, 0.26));
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb24-js-calc-toc-right {
  display: flex;
  align-items: stretch;
  justify-content: center;
  padding: 16px;
  overflow: hidden;
}

.vb24-entityschema-ad-card,
.vb24-entityschema-ad-card * {
  box-sizing: border-box;
}

.vb24-entityschema-ad-card {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  min-height: 100%;
  padding: 12px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(34, 211, 238, 0.28), transparent 34%),
    radial-gradient(circle at 86% 14%, rgba(236, 72, 153, 0.24), transparent 36%),
    linear-gradient(135deg, #111827 0%, #312e81 52%, #701a75 100%) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  overflow: hidden;
  box-shadow: 0 20px 56px rgba(2, 6, 23, 0.32);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-entityschema-ad-card:hover {
  transform: translateY(-3px);
  filter: saturate(1.08);
  box-shadow: 0 26px 70px rgba(2, 6, 23, 0.42);
}

.vb24-entityschema-ad-badge {
  position: absolute;
  z-index: 3;
  top: 18px;
  left: 18px;
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.70);
  border: 1px solid rgba(255,255,255,0.22);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb24-entityschema-ad-image {
  overflow: hidden;
  border-radius: 17px;
  border: 1px solid rgba(255,255,255,0.16);
  background: rgba(255,255,255,0.08);
}

.vb24-entityschema-ad-image img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 17px;
}

.vb24-entityschema-ad-content {
  padding: 15px 8px 4px;
}

.vb24-entityschema-ad-content h3 {
  margin: 0 0 8px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 23px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb24-entityschema-ad-content p {
  margin: 0 0 14px !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 13px;
  line-height: 1.5;
  font-weight: 650;
}

.vb24-entityschema-ad-price {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin: 0 0 12px;
  padding: 11px 12px;
  border-radius: 16px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.16);
}

.vb24-entityschema-ad-price-left {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.vb24-entityschema-ad-price-label {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 11px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb24-entityschema-ad-old-price {
  color: rgba(255,255,255,0.62) !important;
  -webkit-text-fill-color: rgba(255,255,255,0.62) !important;
  font-size: 15px;
  line-height: 1;
  font-weight: 850;
  text-decoration: line-through;
  text-decoration-thickness: 2px;
  text-decoration-color: rgba(248, 113, 113, 0.95);
}

.vb24-entityschema-ad-sale-price {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 31px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb24-entityschema-ad-save {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 28px;
  padding: 6px 9px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.18);
  border: 1px solid rgba(74, 222, 128, 0.34);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 11px;
  font-weight: 950;
  white-space: nowrap;
}

.vb24-entityschema-ad-button {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 43px;
  padding: 12px 14px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22d3ee, #2563eb 55%, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
  box-shadow: 0 14px 34px rgba(37, 99, 235, 0.30);
}

@media (max-width: 900px) {
  .vb24-js-calc-toc-wrap {
    grid-template-columns: 1fr;
  }

  .vb24-js-calc-toc-right {
    justify-content: flex-start;
    max-width: 360px;
  }
}

@media (max-width: 640px) {
  .vb24-js-calc-toc-left {
    padding: 22px 18px;
    border-radius: 22px;
  }

  .vb24-js-calc-toc-left h2 {
    font-size: 26px !important;
  }

  .vb24-js-calc-toc {
    grid-template-columns: 1fr;
  }

  .vb24-js-calc-toc a {
    min-height: 48px;
    font-size: 14px;
  }

  .vb24-js-calc-toc-right {
    max-width: 100%;
    border-radius: 22px;
  }
}
</style>



<h2 class="wp-block-heading" id="what-is-a-javascript-calculator">What Is a JavaScript Calculator?</h2>



<p class="wp-block-paragraph">A JavaScript calculator is an interactive website tool that takes user input, applies a calculation formula, and shows the result directly on the page. JavaScript calculators can be simple, such as a basic tip calculator, or more advanced, such as a loan payment calculator, price estimate calculator, mortgage calculator, BMI calculator, discount calculator, VAT calculator, or multi-step quote calculator.</p>



<p class="wp-block-paragraph">The main purpose of a JavaScript calculator is to help users get instant answers. Instead of asking visitors to manually calculate totals, percentages, monthly payments, tax amounts, shipping costs, price estimates, or form-based values, the website can calculate the result automatically when users type, select options, move sliders, or click a button.</p>



<p class="wp-block-paragraph">A good JavaScript calculator is not only about math. It also needs clear input fields, helpful labels, formatted results, validation, responsive design, useful error messages, and JavaScript logic that is easy to understand and customize. That is why every example in this guide includes visible JavaScript, HTML, and CSS code.</p>



<h2 class="wp-block-heading" id="why-javascript-calculators-matter">Why JavaScript Calculators Matter</h2>



<p class="wp-block-paragraph">JavaScript calculators matter because they turn static pages into useful interactive tools. A calculator can help users compare prices, estimate costs, understand loan payments, check body measurements, calculate discounts, estimate project budgets, or make faster buying decisions without leaving the page.</p>



<ul class="wp-block-list">
  <li><strong>They increase user engagement</strong> by giving visitors something useful to interact with instead of only reading static content.</li>
  <li><strong>They improve lead generation</strong> because quote calculators, price estimators, mortgage calculators, and cost calculators can help users move closer to sending a request.</li>
  <li><strong>They reduce confusion</strong> by showing totals, percentages, payments, and estimates clearly before the user submits a form.</li>
  <li><strong>They support ecommerce decisions</strong> with discount calculators, shipping calculators, cart total calculators, subscription price calculators, and product option totals.</li>
  <li><strong>They make forms smarter</strong> by calculating results from inputs, dropdowns, checkboxes, range sliders, and selected options.</li>
</ul>



<p class="wp-block-paragraph">JavaScript calculators are especially useful for service websites, ecommerce stores, financial tools, SaaS pricing pages, fitness websites, real estate websites, landing pages, lead forms, admin dashboards, and educational projects. They can be lightweight, fast, and fully custom without requiring a large JavaScript framework.</p>



<h2 class="wp-block-heading" id="javascript-calculator-types">JavaScript Calculator Types</h2>



<p class="wp-block-paragraph">There are many different types of JavaScript calculators. Some calculators use one simple formula, while others combine several inputs, dynamic fields, selectable options, conditional logic, sliders, currency formatting, percentages, and live result updates.</p>



<p class="wp-block-paragraph">The right calculator type depends on the user goal. A price calculator should make cost estimation simple. A loan calculator should clearly show monthly payment values. A BMI calculator should explain the result category. A discount calculator should show original price, discount amount, and final price. A quote calculator should guide users through options and return a useful estimate.</p>



<ul class="wp-block-list">
  <li><strong>Price calculators</strong> estimate product, service, subscription, installation, or project costs from selected options.</li>
  <li><strong>Loan calculators</strong> calculate monthly payments, interest estimates, payment totals, or repayment values.</li>
  <li><strong>BMI calculators</strong> calculate body mass index from height and weight inputs and return a result category.</li>
  <li><strong>Discount calculators</strong> calculate sale price, saved amount, percentage discount, or final checkout value.</li>
  <li><strong>VAT and tax calculators</strong> add or remove tax amounts from product prices, invoices, or service totals.</li>
  <li><strong>Shipping calculators</strong> estimate shipping cost based on weight, distance, delivery method, or cart value.</li>
  <li><strong>Quote calculators</strong> combine multiple form fields to create a quick estimate for service-based websites.</li>
  <li><strong>Financial calculators</strong> calculate savings goals, ROI, interest, mortgage payments, or investment-related values.</li>
  <li><strong>Health calculators</strong> calculate BMI, calories, water intake, fitness goals, or nutrition-related estimates.</li>
  <li><strong>Utility calculators</strong> handle unit conversion, time estimates, percentage formulas, totals, and everyday calculations.</li>
</ul>



<p class="wp-block-paragraph">This guide focuses on practical JavaScript calculator examples, so every demo will include visible JavaScript, HTML, and CSS code. The examples are designed to be copy-paste friendly, easy to customize, and different in formula type, layout, input behavior, validation logic, result formatting, and user interaction.</p>



<h2 class="wp-block-heading" id="what-should-a-good-javascript-calculator-include">What Should a Good JavaScript Calculator Include?</h2>



<p class="wp-block-paragraph">A good JavaScript calculator should be accurate, easy to use, responsive, and clear. Users should understand which values they need to enter, what the calculator is doing, and how the final result is calculated. The interface should feel simple even when the formula behind it is more advanced.</p>



<div class="vb24-js-calc-checklist">
  <div class="vb24-js-calc-check-item">
    <h3>Clear inputs</h3>
    <p>Each field should explain what the user needs to enter, such as price, percentage, height, loan amount, interest rate, term, quantity, or selected option.</p>
  </div>

  <div class="vb24-js-calc-check-item">
    <h3>Accurate formula</h3>
    <p>The JavaScript should use a clear calculation formula, handle empty values, avoid invalid results, and format numbers in a readable way.</p>
  </div>

  <div class="vb24-js-calc-check-item">
    <h3>Instant result</h3>
    <p>The result should update quickly after typing, selecting options, moving sliders, or clicking the calculate button.</p>
  </div>

  <div class="vb24-js-calc-check-item">
    <h3>Helpful feedback</h3>
    <p>The calculator should show clear messages when required values are missing, invalid, too low, too high, or impossible to calculate.</p>
  </div>
</div>

<style>
.vb24-js-calc-checklist {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 30px;
}

.vb24-js-calc-check-item {
  padding: 20px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 22px;
  background:
    radial-gradient(circle at 18% 10%, rgba(34, 197, 94, 0.10), transparent 32%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb24-js-calc-check-item h3 {
  margin: 0 0 10px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 850;
}

.vb24-js-calc-check-item p {
  margin: 0;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb24-js-calc-checklist {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-js-calc-checklist {
    grid-template-columns: 1fr;
  }

  .vb24-js-calc-check-item {
    padding: 18px;
    border-radius: 20px;
  }
}
</style>



<p class="wp-block-paragraph">Before building a calculator, decide which formula it needs, which fields are required, how the result should be formatted, whether the result should update live, and what should happen when users enter invalid values. This planning is important because a calculator is not only a visual form — it is a functional JavaScript tool.</p>



<ul class="wp-block-list">
  <li><strong>Use clear field labels</strong> so users understand what values they need to enter.</li>
  <li><strong>Validate all inputs</strong> because empty, negative, missing, or unrealistic values can create broken results.</li>
  <li><strong>Format results properly</strong> with currency symbols, percentage signs, decimal control, units, or result categories.</li>
  <li><strong>Use live updates carefully</strong> when instant feedback is helpful, and use a calculate button when the formula needs more control.</li>
  <li><strong>Show helpful error messages</strong> instead of returning NaN, Infinity, empty values, or confusing results.</li>
  <li><strong>Keep JavaScript scoped</strong> so multiple calculator examples or components can work on the same page.</li>
  <li><strong>Make the layout responsive</strong> because many users will calculate prices, loans, discounts, or quotes on mobile screens.</li>
  <li><strong>Separate formula logic from UI logic</strong> so the calculator is easier to edit and reuse later.</li>
  <li><strong>Use accessible form markup</strong> with labels, focus states, readable contrast, and keyboard-friendly controls.</li>
  <li><strong>Explain the result</strong> when needed, especially for BMI, loan, mortgage, ROI, savings, or quote calculators.</li>
</ul>



<p class="wp-block-paragraph">You can combine JavaScript calculators with many other website features. A price calculator can improve a service landing page, a quote calculator can support a <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-forms/">modern CSS form</a>, a savings calculator can work inside a dashboard layout, and an ecommerce discount calculator can pair well with product cards, checkout forms, and interactive UI components. For more JavaScript functionality, you can also explore our <a href="https://veebilehed24.ee/en/blog/javascript/javascript-form-validation-examples/">form validation examples</a> and <a href="https://veebilehed24.ee/en/blog/javascript/javascript-search-filter-examples/">search filter examples</a>.</p>



<h2 class="wp-block-heading" id="javascript-calculator-examples">30 JavaScript Calculator Examples</h2>



<p class="wp-block-paragraph">Now let’s look at 30 JavaScript calculator examples for real website projects. Each example uses a different formula, input system, result layout, validation pattern, calculation method, responsive design, or JavaScript behavior, so you can build practical calculators for ecommerce, finance, health, service websites, forms, dashboards, landing pages, and everyday UI tools.</p>



<h2 class="wp-block-heading">1. Price Estimate Calculator</h2>



<p class="wp-block-paragraph"><strong>A price estimate calculator</strong> is one of the most useful JavaScript calculators for service websites, landing pages, product configurators, quote forms, and ecommerce pages. It helps users estimate a price instantly by selecting a package, quantity, and extra options.</p>



<p class="wp-block-paragraph">This example uses live input calculation, package pricing, add-on checkboxes, quantity logic, currency formatting, and a reset button. The JavaScript updates the total immediately whenever the user changes any option.</p>



<ul class="wp-block-list">
<li>Live service price calculator</li>
<li>Package dropdown and quantity input</li>
<li>Checkbox add-ons</li>
<li>Currency formatting with JavaScript</li>
<li>Reset button and dynamic summary</li>
</ul>



<div class="vb-calc-one-demo">
  <div class="vb-calc-one-card">
    <div class="vb-calc-one-copy">
      <span class="vb-calc-one-kicker">Example 01</span>
      <h3>Price Estimate Calculator</h3>
      <p>Select a package, add extras, choose quantity, and see the estimated project price update instantly.</p>
    </div>

    <div class="vb-calc-one-tool">
      <label>
        Service package
        <select data-vb-calc-one-package>
          <option value="299">Starter Website &#8211; 299€</option>
          <option value="599">Business Website &#8211; 599€</option>
          <option value="999">Premium Website &#8211; 999€</option>
        </select>
      </label>

      <label>
        Number of pages
        <input type="number" min="1" value="5" data-vb-calc-one-pages>
      </label>

      <div class="vb-calc-one-options">
        <label>
          <input type="checkbox" value="120" data-vb-calc-one-extra>
          SEO setup
        </label>

        <label>
          <input type="checkbox" value="180" data-vb-calc-one-extra>
          Booking form
        </label>

        <label>
          <input type="checkbox" value="250" data-vb-calc-one-extra>
          Ecommerce setup
        </label>
      </div>

      <div class="vb-calc-one-result">
        <span>Estimated price</span>
        <strong data-vb-calc-one-total>0€</strong>
        <p data-vb-calc-one-summary>Choose options to calculate your estimate.</p>
      </div>

      <button type="button" data-vb-calc-one-reset>Reset Calculator</button>
    </div>
  </div>
</div>

<style>
.vb-calc-one-demo,
.vb-calc-one-demo * {
  box-sizing: border-box;
}

.vb-calc-one-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 16% 18%, rgba(34, 197, 94, 0.20), transparent 32%),
    radial-gradient(circle at 84% 12%, rgba(6, 182, 212, 0.18), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #f0fdfa 48%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.20);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-calc-one-card {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
  gap: 28px;
  max-width: 1120px;
  margin: 0 auto;
  align-items: center;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 28px;
  background: linear-gradient(135deg, #052e2b 0%, #065f46 52%, #0f766e 100%) !important;
  box-shadow: 0 30px 90px rgba(6, 78, 59, 0.24);
}

.vb-calc-one-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-one-copy h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 64px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-calc-one-copy p {
  margin: 0 !important;
  max-width: 520px;
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-one-tool {
  display: grid;
  gap: 16px;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 24px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.18);
  backdrop-filter: blur(14px);
}

.vb-calc-one-tool label {
  display: grid;
  gap: 8px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-calc-one-tool select,
.vb-calc-one-tool input[type="number"] {
  width: 100%;
  min-height: 48px;
  padding: 0 14px;
  border: 1px solid rgba(255,255,255,0.22);
  border-radius: 14px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-calc-one-options {
  display: grid;
  gap: 10px;
  padding: 14px;
  border-radius: 18px;
  background: rgba(255,255,255,0.09);
}

.vb-calc-one-options label {
  display: flex;
  align-items: center;
  gap: 10px;
}

.vb-calc-one-options input {
  width: 18px;
  height: 18px;
  accent-color: #22c55e;
}

.vb-calc-one-result {
  padding: 18px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(34, 197, 94, 0.22);
}

.vb-calc-one-result span {
  display: block;
  margin-bottom: 5px;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  font-weight: 850;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-one-result strong {
  display: block;
  color: #065f46 !important;
  -webkit-text-fill-color: #065f46 !important;
  font-size: 42px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-calc-one-result p {
  margin: 9px 0 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 650;
}

.vb-calc-one-tool button {
  min-height: 48px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #22c55e, #06b6d4);
  color: #052e2b !important;
  -webkit-text-fill-color: #052e2b !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(34, 197, 94, 0.26);
}

@media (max-width: 900px) {
  .vb-calc-one-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-one-card {
    padding: 22px;
    border-radius: 24px;
  }

  .vb-calc-one-copy h3 {
    font-size: 38px !important;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-one-demo");
  if (!demo) return;

  const packageSelect = demo.querySelector("[data-vb-calc-one-package]");
  const pagesInput = demo.querySelector("[data-vb-calc-one-pages]");
  const extras = demo.querySelectorAll("[data-vb-calc-one-extra]");
  const totalOutput = demo.querySelector("[data-vb-calc-one-total]");
  const summaryOutput = demo.querySelector("[data-vb-calc-one-summary]");
  const resetButton = demo.querySelector("[data-vb-calc-one-reset]");

  const formatter = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 0
  });

  function calculatePrice() {
    const basePrice = Number(packageSelect.value);
    const pages = Math.max(Number(pagesInput.value) || 1, 1);
    const extraPages = Math.max(pages - 5, 0) * 45;

    let extrasTotal = 0;
    let selectedExtras = 0;

    extras.forEach(function (extra) {
      if (extra.checked) {
        extrasTotal += Number(extra.value);
        selectedExtras += 1;
      }
    });

    const total = basePrice + extraPages + extrasTotal;

    totalOutput.textContent = formatter.format(total);
    summaryOutput.textContent = pages + " page(s), " + selectedExtras + " extra option(s), including extra page cost if needed.";
  }

  function resetCalculator() {
    packageSelect.value = "299";
    pagesInput.value = "5";

    extras.forEach(function (extra) {
      extra.checked = false;
    });

    calculatePrice();
  }

  packageSelect.addEventListener("change", calculatePrice);
  pagesInput.addEventListener("input", calculatePrice);

  extras.forEach(function (extra) {
    extra.addEventListener("change", calculatePrice);
  });

  resetButton.addEventListener("click", resetCalculator);

  calculatePrice();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-one-demo");
  if (!demo) return;

  const packageSelect = demo.querySelector("[data-vb-calc-one-package]");
  const pagesInput = demo.querySelector("[data-vb-calc-one-pages]");
  const extras = demo.querySelectorAll("[data-vb-calc-one-extra]");
  const totalOutput = demo.querySelector("[data-vb-calc-one-total]");
  const summaryOutput = demo.querySelector("[data-vb-calc-one-summary]");
  const resetButton = demo.querySelector("[data-vb-calc-one-reset]");

  const formatter = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 0
  });

  function calculatePrice() {
    const basePrice = Number(packageSelect.value);
    const pages = Math.max(Number(pagesInput.value) || 1, 1);
    const extraPages = Math.max(pages - 5, 0) * 45;

    let extrasTotal = 0;
    let selectedExtras = 0;

    extras.forEach(function (extra) {
      if (extra.checked) {
        extrasTotal += Number(extra.value);
        selectedExtras += 1;
      }
    });

    const total = basePrice + extraPages + extrasTotal;

    totalOutput.textContent = formatter.format(total);
    summaryOutput.textContent = pages + " page(s), " + selectedExtras + " extra option(s), including extra page cost if needed.";
  }

  function resetCalculator() {
    packageSelect.value = "299";
    pagesInput.value = "5";

    extras.forEach(function (extra) {
      extra.checked = false;
    });

    calculatePrice();
  }

  packageSelect.addEventListener("change", calculatePrice);
  pagesInput.addEventListener("input", calculatePrice);

  extras.forEach(function (extra) {
    extra.addEventListener("change", calculatePrice);
  });

  resetButton.addEventListener("click", resetCalculator);

  calculatePrice();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-one-demo"&gt;
  &lt;div class="vb-calc-one-card"&gt;
    &lt;div class="vb-calc-one-copy"&gt;
      &lt;span class="vb-calc-one-kicker"&gt;Example 01&lt;/span&gt;
      &lt;h3&gt;Price Estimate Calculator&lt;/h3&gt;
      &lt;p&gt;Select a package, add extras, choose quantity, and see the estimated project price update instantly.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-one-tool"&gt;
      &lt;label&gt;
        Service package
        &lt;select data-vb-calc-one-package&gt;
          &lt;option value="299"&gt;Starter Website - 299€&lt;/option&gt;
          &lt;option value="599"&gt;Business Website - 599€&lt;/option&gt;
          &lt;option value="999"&gt;Premium Website - 999€&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;

      &lt;label&gt;
        Number of pages
        &lt;input type="number" min="1" value="5" data-vb-calc-one-pages&gt;
      &lt;/label&gt;

      &lt;div class="vb-calc-one-options"&gt;
        &lt;label&gt;
          &lt;input type="checkbox" value="120" data-vb-calc-one-extra&gt;
          SEO setup
        &lt;/label&gt;

        &lt;label&gt;
          &lt;input type="checkbox" value="180" data-vb-calc-one-extra&gt;
          Booking form
        &lt;/label&gt;

        &lt;label&gt;
          &lt;input type="checkbox" value="250" data-vb-calc-one-extra&gt;
          Ecommerce setup
        &lt;/label&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-one-result"&gt;
        &lt;span&gt;Estimated price&lt;/span&gt;
        &lt;strong data-vb-calc-one-total&gt;0€&lt;/strong&gt;
        &lt;p data-vb-calc-one-summary&gt;Choose options to calculate your estimate.&lt;/p&gt;
      &lt;/div&gt;

      &lt;button type="button" data-vb-calc-one-reset&gt;Reset Calculator&lt;/button&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-one-demo,
.vb-calc-one-demo * {
  box-sizing: border-box;
}

.vb-calc-one-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 16% 18%, rgba(34, 197, 94, 0.20), transparent 32%),
    radial-gradient(circle at 84% 12%, rgba(6, 182, 212, 0.18), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #f0fdfa 48%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.20);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-calc-one-card {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
  gap: 28px;
  max-width: 1120px;
  margin: 0 auto;
  align-items: center;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 28px;
  background: linear-gradient(135deg, #052e2b 0%, #065f46 52%, #0f766e 100%) !important;
  box-shadow: 0 30px 90px rgba(6, 78, 59, 0.24);
}

.vb-calc-one-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-one-copy h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 64px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-calc-one-copy p {
  margin: 0 !important;
  max-width: 520px;
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-one-tool {
  display: grid;
  gap: 16px;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 24px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.18);
  backdrop-filter: blur(14px);
}

.vb-calc-one-tool label {
  display: grid;
  gap: 8px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-calc-one-tool select,
.vb-calc-one-tool input[type="number"] {
  width: 100%;
  min-height: 48px;
  padding: 0 14px;
  border: 1px solid rgba(255,255,255,0.22);
  border-radius: 14px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 750;
  outline: none;
}

.vb-calc-one-options {
  display: grid;
  gap: 10px;
  padding: 14px;
  border-radius: 18px;
  background: rgba(255,255,255,0.09);
}

.vb-calc-one-options label {
  display: flex;
  align-items: center;
  gap: 10px;
}

.vb-calc-one-options input {
  width: 18px;
  height: 18px;
  accent-color: #22c55e;
}

.vb-calc-one-result {
  padding: 18px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(34, 197, 94, 0.22);
}

.vb-calc-one-result span {
  display: block;
  margin-bottom: 5px;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  font-weight: 850;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-one-result strong {
  display: block;
  color: #065f46 !important;
  -webkit-text-fill-color: #065f46 !important;
  font-size: 42px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-calc-one-result p {
  margin: 9px 0 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 650;
}

.vb-calc-one-tool button {
  min-height: 48px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #22c55e, #06b6d4);
  color: #052e2b !important;
  -webkit-text-fill-color: #052e2b !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(34, 197, 94, 0.26);
}

@media (max-width: 900px) {
  .vb-calc-one-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-one-card {
    padding: 22px;
    border-radius: 24px;
  }

  .vb-calc-one-copy h3 {
    font-size: 38px !important;
  }
}</pre>



<p class="wp-block-paragraph">This price estimate calculator is useful for agency websites, website design services, local service businesses, product configurators, quote request pages, and landing pages where visitors need a fast cost estimate before contacting the business.</p>



<h2 class="wp-block-heading">2. Loan Payment Calculator</h2>



<p class="wp-block-paragraph"><strong>A loan payment calculator</strong> is useful for finance websites, banking pages, car loan forms, mortgage previews, credit calculators, and comparison tools. It helps users estimate a monthly payment based on loan amount, interest rate, and repayment term.</p>



<p class="wp-block-paragraph">This example uses a real amortized loan payment formula, number validation, slider-based term selection, live monthly payment calculation, total repayment output, and total interest output.</p>



<ul class="wp-block-list">
<li>Monthly loan payment calculator</li>
<li>Real amortization formula</li>
<li>Range slider for loan term</li>
<li>Total repayment and interest summary</li>
<li>Validation for missing or invalid values</li>
</ul>



<div class="vb-calc-two-demo">
  <div class="vb-calc-two-shell">
    <div class="vb-calc-two-header">
      <span>Example 02</span>
      <h3>Loan Payment Calculator</h3>
      <p>Calculate estimated monthly payments, total repayment, and total interest using loan amount, interest rate, and term.</p>
    </div>

    <div class="vb-calc-two-grid">
      <div class="vb-calc-two-form">
        <label>
          Loan amount
          <input type="number" min="1" value="15000" data-vb-calc-two-amount>
        </label>

        <label>
          Annual interest rate (%)
          <input type="number" min="0" step="0.1" value="6.5" data-vb-calc-two-rate>
        </label>

        <label>
          Loan term: <strong data-vb-calc-two-years-label>5 years</strong>
          <input type="range" min="1" max="30" value="5" data-vb-calc-two-years>
        </label>

        <div class="vb-calc-two-error" data-vb-calc-two-error></div>
      </div>

      <div class="vb-calc-two-results">
        <div>
          <span>Monthly payment</span>
          <strong data-vb-calc-two-payment>€0</strong>
        </div>

        <div>
          <span>Total repayment</span>
          <strong data-vb-calc-two-total>€0</strong>
        </div>

        <div>
          <span>Total interest</span>
          <strong data-vb-calc-two-interest>€0</strong>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-two-demo,
.vb-calc-two-demo * {
  box-sizing: border-box;
}

.vb-calc-two-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 24px;
  background:
    linear-gradient(90deg, rgba(37, 99, 235, 0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(37, 99, 235, 0.08) 1px, transparent 1px),
    linear-gradient(135deg, #eff6ff 0%, #eef2ff 56%, #ffffff 100%) !important;
  background-size: 26px 26px, 26px 26px, auto !important;
  border: 1px solid rgba(37, 99, 235, 0.20);
}

.vb-calc-two-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 28px;
  background: #ffffff;
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.15);
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-calc-two-header {
  padding: clamp(24px, 4vw, 38px);
  background: linear-gradient(135deg, #1e3a8a, #2563eb 55%, #06b6d4) !important;
}

.vb-calc-two-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-two-header h3 {
  margin: 0 0 12px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-calc-two-header p {
  max-width: 720px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-two-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 360px;
  gap: 0;
}

.vb-calc-two-form {
  display: grid;
  gap: 18px;
  padding: clamp(22px, 4vw, 34px);
}

.vb-calc-two-form label {
  display: grid;
  gap: 8px;
  color: #1e3a8a !important;
  -webkit-text-fill-color: #1e3a8a !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-two-form input[type="number"] {
  width: 100%;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #bfdbfe;
  border-radius: 14px;
  outline: none;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 750;
}

.vb-calc-two-form input[type="range"] {
  width: 100%;
  accent-color: #2563eb;
}

.vb-calc-two-error {
  min-height: 22px;
  color: #dc2626 !important;
  -webkit-text-fill-color: #dc2626 !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-calc-two-results {
  display: grid;
  gap: 14px;
  padding: clamp(22px, 4vw, 34px);
  background: #f8fafc;
  border-left: 1px solid #e5e7eb;
}

.vb-calc-two-results div {
  padding: 18px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid #dbeafe;
  box-shadow: 0 14px 34px rgba(30, 64, 175, 0.08);
}

.vb-calc-two-results span {
  display: block;
  margin-bottom: 8px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-two-results strong {
  display: block;
  color: #1e3a8a !important;
  -webkit-text-fill-color: #1e3a8a !important;
  font-size: 32px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

@media (max-width: 900px) {
  .vb-calc-two-grid {
    grid-template-columns: 1fr;
  }

  .vb-calc-two-results {
    border-left: 0;
    border-top: 1px solid #e5e7eb;
  }
}

@media (max-width: 640px) {
  .vb-calc-two-header h3 {
    font-size: 38px !important;
  }

  .vb-calc-two-results strong {
    font-size: 28px;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-two-demo");
  if (!demo) return;

  const amountInput = demo.querySelector("[data-vb-calc-two-amount]");
  const rateInput = demo.querySelector("[data-vb-calc-two-rate]");
  const yearsInput = demo.querySelector("[data-vb-calc-two-years]");
  const yearsLabel = demo.querySelector("[data-vb-calc-two-years-label]");
  const paymentOutput = demo.querySelector("[data-vb-calc-two-payment]");
  const totalOutput = demo.querySelector("[data-vb-calc-two-total]");
  const interestOutput = demo.querySelector("[data-vb-calc-two-interest]");
  const errorOutput = demo.querySelector("[data-vb-calc-two-error]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 0
  });

  function calculateLoan() {
    const amount = Number(amountInput.value);
    const annualRate = Number(rateInput.value);
    const years = Number(yearsInput.value);
    const months = years * 12;

    yearsLabel.textContent = years + (years === 1 ? " year" : " years");

    if (amount <= 0 || annualRate < 0 || years <= 0) {
      errorOutput.textContent = "Enter a valid loan amount, rate, and term.";
      paymentOutput.textContent = "€0";
      totalOutput.textContent = "€0";
      interestOutput.textContent = "€0";
      return;
    }

    errorOutput.textContent = "";

    const monthlyRate = annualRate / 100 / 12;
    let monthlyPayment;

    if (monthlyRate === 0) {
      monthlyPayment = amount / months;
    } else {
      monthlyPayment = amount * monthlyRate * Math.pow(1 + monthlyRate, months) / (Math.pow(1 + monthlyRate, months) - 1);
    }

    const totalRepayment = monthlyPayment * months;
    const totalInterest = totalRepayment - amount;

    paymentOutput.textContent = money.format(monthlyPayment);
    totalOutput.textContent = money.format(totalRepayment);
    interestOutput.textContent = money.format(totalInterest);
  }

  amountInput.addEventListener("input", calculateLoan);
  rateInput.addEventListener("input", calculateLoan);
  yearsInput.addEventListener("input", calculateLoan);

  calculateLoan();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-two-demo");
  if (!demo) return;

  const amountInput = demo.querySelector("[data-vb-calc-two-amount]");
  const rateInput = demo.querySelector("[data-vb-calc-two-rate]");
  const yearsInput = demo.querySelector("[data-vb-calc-two-years]");
  const yearsLabel = demo.querySelector("[data-vb-calc-two-years-label]");
  const paymentOutput = demo.querySelector("[data-vb-calc-two-payment]");
  const totalOutput = demo.querySelector("[data-vb-calc-two-total]");
  const interestOutput = demo.querySelector("[data-vb-calc-two-interest]");
  const errorOutput = demo.querySelector("[data-vb-calc-two-error]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 0
  });

  function calculateLoan() {
    const amount = Number(amountInput.value);
    const annualRate = Number(rateInput.value);
    const years = Number(yearsInput.value);
    const months = years * 12;

    yearsLabel.textContent = years + (years === 1 ? " year" : " years");

    if (amount &lt;= 0 || annualRate &lt; 0 || years &lt;= 0) {
      errorOutput.textContent = "Enter a valid loan amount, rate, and term.";
      paymentOutput.textContent = "€0";
      totalOutput.textContent = "€0";
      interestOutput.textContent = "€0";
      return;
    }

    errorOutput.textContent = "";

    const monthlyRate = annualRate / 100 / 12;
    let monthlyPayment;

    if (monthlyRate === 0) {
      monthlyPayment = amount / months;
    } else {
      monthlyPayment = amount * monthlyRate * Math.pow(1 + monthlyRate, months) / (Math.pow(1 + monthlyRate, months) - 1);
    }

    const totalRepayment = monthlyPayment * months;
    const totalInterest = totalRepayment - amount;

    paymentOutput.textContent = money.format(monthlyPayment);
    totalOutput.textContent = money.format(totalRepayment);
    interestOutput.textContent = money.format(totalInterest);
  }

  amountInput.addEventListener("input", calculateLoan);
  rateInput.addEventListener("input", calculateLoan);
  yearsInput.addEventListener("input", calculateLoan);

  calculateLoan();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-two-demo"&gt;
  &lt;div class="vb-calc-two-shell"&gt;
    &lt;div class="vb-calc-two-header"&gt;
      &lt;span&gt;Example 02&lt;/span&gt;
      &lt;h3&gt;Loan Payment Calculator&lt;/h3&gt;
      &lt;p&gt;Calculate estimated monthly payments, total repayment, and total interest using loan amount, interest rate, and term.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-two-grid"&gt;
      &lt;div class="vb-calc-two-form"&gt;
        &lt;label&gt;
          Loan amount
          &lt;input type="number" min="1" value="15000" data-vb-calc-two-amount&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Annual interest rate (%)
          &lt;input type="number" min="0" step="0.1" value="6.5" data-vb-calc-two-rate&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Loan term: &lt;strong data-vb-calc-two-years-label&gt;5 years&lt;/strong&gt;
          &lt;input type="range" min="1" max="30" value="5" data-vb-calc-two-years&gt;
        &lt;/label&gt;

        &lt;div class="vb-calc-two-error" data-vb-calc-two-error&gt;&lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-two-results"&gt;
        &lt;div&gt;
          &lt;span&gt;Monthly payment&lt;/span&gt;
          &lt;strong data-vb-calc-two-payment&gt;€0&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;span&gt;Total repayment&lt;/span&gt;
          &lt;strong data-vb-calc-two-total&gt;€0&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;span&gt;Total interest&lt;/span&gt;
          &lt;strong data-vb-calc-two-interest&gt;€0&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-two-demo,
.vb-calc-two-demo * {
  box-sizing: border-box;
}

.vb-calc-two-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 40px);
  border-radius: 24px;
  background:
    linear-gradient(90deg, rgba(37, 99, 235, 0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(37, 99, 235, 0.08) 1px, transparent 1px),
    linear-gradient(135deg, #eff6ff 0%, #eef2ff 56%, #ffffff 100%) !important;
  background-size: 26px 26px, 26px 26px, auto !important;
  border: 1px solid rgba(37, 99, 235, 0.20);
}

.vb-calc-two-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 28px;
  background: #ffffff;
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.15);
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-calc-two-header {
  padding: clamp(24px, 4vw, 38px);
  background: linear-gradient(135deg, #1e3a8a, #2563eb 55%, #06b6d4) !important;
}

.vb-calc-two-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-two-header h3 {
  margin: 0 0 12px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-calc-two-header p {
  max-width: 720px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-two-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 360px;
  gap: 0;
}

.vb-calc-two-form {
  display: grid;
  gap: 18px;
  padding: clamp(22px, 4vw, 34px);
}

.vb-calc-two-form label {
  display: grid;
  gap: 8px;
  color: #1e3a8a !important;
  -webkit-text-fill-color: #1e3a8a !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-two-form input[type="number"] {
  width: 100%;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #bfdbfe;
  border-radius: 14px;
  outline: none;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 750;
}

.vb-calc-two-form input[type="range"] {
  width: 100%;
  accent-color: #2563eb;
}

.vb-calc-two-error {
  min-height: 22px;
  color: #dc2626 !important;
  -webkit-text-fill-color: #dc2626 !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-calc-two-results {
  display: grid;
  gap: 14px;
  padding: clamp(22px, 4vw, 34px);
  background: #f8fafc;
  border-left: 1px solid #e5e7eb;
}

.vb-calc-two-results div {
  padding: 18px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid #dbeafe;
  box-shadow: 0 14px 34px rgba(30, 64, 175, 0.08);
}

.vb-calc-two-results span {
  display: block;
  margin-bottom: 8px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-two-results strong {
  display: block;
  color: #1e3a8a !important;
  -webkit-text-fill-color: #1e3a8a !important;
  font-size: 32px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

@media (max-width: 900px) {
  .vb-calc-two-grid {
    grid-template-columns: 1fr;
  }

  .vb-calc-two-results {
    border-left: 0;
    border-top: 1px solid #e5e7eb;
  }
}

@media (max-width: 640px) {
  .vb-calc-two-header h3 {
    font-size: 38px !important;
  }

  .vb-calc-two-results strong {
    font-size: 28px;
  }
}</pre>



<p class="wp-block-paragraph">This loan payment calculator is useful for finance websites, bank landing pages, credit calculators, car loan pages, real estate tools, and comparison pages where users need a quick payment estimate before applying or requesting more information.</p>



<h2 class="wp-block-heading">3. BMI Calculator</h2>



<p class="wp-block-paragraph"><strong>A BMI calculator</strong> is one of the most searched JavaScript calculator examples for health, fitness, wellness, nutrition, coaching, and medical-style websites. It calculates body mass index from height and weight, then shows a result category.</p>



<p class="wp-block-paragraph">This example uses metric inputs, validation, a BMI formula, dynamic category labels, color-coded result states, and a simple health-style summary. The JavaScript changes the result message depending on the calculated BMI range.</p>



<ul class="wp-block-list">
<li>Metric BMI calculator</li>
<li>Height and weight validation</li>
<li>Dynamic BMI category result</li>
<li>Color-coded status output</li>
<li>Useful health and fitness calculator pattern</li>
</ul>



<div class="vb-calc-three-demo">
  <div class="vb-calc-three-card">
    <div class="vb-calc-three-visual">
      <span>Example 03</span>
      <h3>BMI Calculator</h3>
      <p>Enter height and weight to calculate BMI and see a simple category result.</p>

      <div class="vb-calc-three-meter">
        <div data-vb-calc-three-meter></div>
      </div>
    </div>

    <div class="vb-calc-three-form">
      <label>
        Height in centimeters
        <input type="number" min="80" max="250" value="175" data-vb-calc-three-height>
      </label>

      <label>
        Weight in kilograms
        <input type="number" min="20" max="300" value="72" data-vb-calc-three-weight>
      </label>

      <button type="button" data-vb-calc-three-button>Calculate BMI</button>

      <div class="vb-calc-three-result" data-vb-calc-three-result>
        <span>BMI Result</span>
        <strong data-vb-calc-three-value>0.0</strong>
        <p data-vb-calc-three-message>Enter your details to calculate BMI.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-three-demo,
.vb-calc-three-demo * {
  box-sizing: border-box;
}

.vb-calc-three-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 12% 18%, rgba(14, 165, 233, 0.18), transparent 32%),
    radial-gradient(circle at 88% 14%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #faf5ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.09);
}

.vb-calc-three-card {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-calc-three-visual,
.vb-calc-three-form {
  padding: clamp(22px, 4vw, 34px);
  border-radius: 30px;
}

.vb-calc-three-visual {
  display: flex;
  flex-direction: column;
  justify-content: center;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #0f172a, #0369a1 58%, #7c3aed) !important;
  box-shadow: 0 30px 90px rgba(3, 105, 161, 0.22);
}

.vb-calc-three-visual span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-three-visual h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 5.2vw, 68px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-calc-three-visual p {
  margin: 0 0 24px !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-three-meter {
  height: 16px;
  overflow: hidden;
  border-radius: 999px;
  background: rgba(255,255,255,0.18);
}

.vb-calc-three-meter div {
  width: 0%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #22c55e, #facc15, #ef4444);
  transition: width 0.25s ease;
}

.vb-calc-three-form {
  display: grid;
  gap: 16px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-three-form label {
  display: grid;
  gap: 8px;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-three-form input {
  width: 100%;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #cbd5e1;
  border-radius: 16px;
  outline: none;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 750;
}

.vb-calc-three-form button {
  min-height: 50px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #0ea5e9, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(124, 58, 237, 0.25);
}

.vb-calc-three-result {
  padding: 20px;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
}

.vb-calc-three-result span {
  display: block;
  margin-bottom: 6px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-three-result strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 46px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-calc-three-result p {
  margin: 8px 0 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-calc-three-result.is-low {
  border-color: rgba(14, 165, 233, 0.35);
  background: #f0f9ff;
}

.vb-calc-three-result.is-normal {
  border-color: rgba(34, 197, 94, 0.35);
  background: #f0fdf4;
}

.vb-calc-three-result.is-high {
  border-color: rgba(250, 204, 21, 0.55);
  background: #fefce8;
}

.vb-calc-three-result.is-very-high {
  border-color: rgba(239, 68, 68, 0.35);
  background: #fef2f2;
}

@media (max-width: 900px) {
  .vb-calc-three-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-three-visual h3 {
    font-size: 40px !important;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-three-demo");
  if (!demo) return;

  const heightInput = demo.querySelector("[data-vb-calc-three-height]");
  const weightInput = demo.querySelector("[data-vb-calc-three-weight]");
  const button = demo.querySelector("[data-vb-calc-three-button]");
  const resultBox = demo.querySelector("[data-vb-calc-three-result]");
  const valueOutput = demo.querySelector("[data-vb-calc-three-value]");
  const messageOutput = demo.querySelector("[data-vb-calc-three-message]");
  const meter = demo.querySelector("[data-vb-calc-three-meter]");

  function getBmiCategory(bmi) {
    if (bmi < 18.5) {
      return {
        className: "is-low",
        message: "Underweight range. This result is only a simple calculator estimate.",
        meter: 28
      };
    }

    if (bmi < 25) {
      return {
        className: "is-normal",
        message: "Normal range. This result is only a simple calculator estimate.",
        meter: 52
      };
    }

    if (bmi < 30) {
      return {
        className: "is-high",
        message: "Overweight range. This result is only a simple calculator estimate.",
        meter: 72
      };
    }

    return {
      className: "is-very-high",
      message: "Obesity range. This result is only a simple calculator estimate.",
      meter: 92
    };
  }

  function calculateBmi() {
    const heightCm = Number(heightInput.value);
    const weightKg = Number(weightInput.value);

    resultBox.classList.remove("is-low", "is-normal", "is-high", "is-very-high");

    if (heightCm <= 0 || weightKg <= 0) {
      valueOutput.textContent = "0.0";
      messageOutput.textContent = "Enter valid height and weight values.";
      meter.style.width = "0%";
      return;
    }

    const heightM = heightCm / 100;
    const bmi = weightKg / (heightM * heightM);
    const category = getBmiCategory(bmi);

    valueOutput.textContent = bmi.toFixed(1);
    messageOutput.textContent = category.message;
    meter.style.width = category.meter + "%";
    resultBox.classList.add(category.className);
  }

  button.addEventListener("click", calculateBmi);
  heightInput.addEventListener("input", calculateBmi);
  weightInput.addEventListener("input", calculateBmi);

  calculateBmi();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-three-demo");
  if (!demo) return;

  const heightInput = demo.querySelector("[data-vb-calc-three-height]");
  const weightInput = demo.querySelector("[data-vb-calc-three-weight]");
  const button = demo.querySelector("[data-vb-calc-three-button]");
  const resultBox = demo.querySelector("[data-vb-calc-three-result]");
  const valueOutput = demo.querySelector("[data-vb-calc-three-value]");
  const messageOutput = demo.querySelector("[data-vb-calc-three-message]");
  const meter = demo.querySelector("[data-vb-calc-three-meter]");

  function getBmiCategory(bmi) {
    if (bmi &lt; 18.5) {
      return {
        className: "is-low",
        message: "Underweight range. This result is only a simple calculator estimate.",
        meter: 28
      };
    }

    if (bmi &lt; 25) {
      return {
        className: "is-normal",
        message: "Normal range. This result is only a simple calculator estimate.",
        meter: 52
      };
    }

    if (bmi &lt; 30) {
      return {
        className: "is-high",
        message: "Overweight range. This result is only a simple calculator estimate.",
        meter: 72
      };
    }

    return {
      className: "is-very-high",
      message: "Obesity range. This result is only a simple calculator estimate.",
      meter: 92
    };
  }

  function calculateBmi() {
    const heightCm = Number(heightInput.value);
    const weightKg = Number(weightInput.value);

    resultBox.classList.remove("is-low", "is-normal", "is-high", "is-very-high");

    if (heightCm &lt;= 0 || weightKg &lt;= 0) {
      valueOutput.textContent = "0.0";
      messageOutput.textContent = "Enter valid height and weight values.";
      meter.style.width = "0%";
      return;
    }

    const heightM = heightCm / 100;
    const bmi = weightKg / (heightM * heightM);
    const category = getBmiCategory(bmi);

    valueOutput.textContent = bmi.toFixed(1);
    messageOutput.textContent = category.message;
    meter.style.width = category.meter + "%";
    resultBox.classList.add(category.className);
  }

  button.addEventListener("click", calculateBmi);
  heightInput.addEventListener("input", calculateBmi);
  weightInput.addEventListener("input", calculateBmi);

  calculateBmi();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-three-demo"&gt;
  &lt;div class="vb-calc-three-card"&gt;
    &lt;div class="vb-calc-three-visual"&gt;
      &lt;span&gt;Example 03&lt;/span&gt;
      &lt;h3&gt;BMI Calculator&lt;/h3&gt;
      &lt;p&gt;Enter height and weight to calculate BMI and see a simple category result.&lt;/p&gt;

      &lt;div class="vb-calc-three-meter"&gt;
        &lt;div data-vb-calc-three-meter&gt;&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-three-form"&gt;
      &lt;label&gt;
        Height in centimeters
        &lt;input type="number" min="80" max="250" value="175" data-vb-calc-three-height&gt;
      &lt;/label&gt;

      &lt;label&gt;
        Weight in kilograms
        &lt;input type="number" min="20" max="300" value="72" data-vb-calc-three-weight&gt;
      &lt;/label&gt;

      &lt;button type="button" data-vb-calc-three-button&gt;Calculate BMI&lt;/button&gt;

      &lt;div class="vb-calc-three-result" data-vb-calc-three-result&gt;
        &lt;span&gt;BMI Result&lt;/span&gt;
        &lt;strong data-vb-calc-three-value&gt;0.0&lt;/strong&gt;
        &lt;p data-vb-calc-three-message&gt;Enter your details to calculate BMI.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-three-demo,
.vb-calc-three-demo * {
  box-sizing: border-box;
}

.vb-calc-three-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 12% 18%, rgba(14, 165, 233, 0.18), transparent 32%),
    radial-gradient(circle at 88% 14%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #faf5ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.09);
}

.vb-calc-three-card {
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-calc-three-visual,
.vb-calc-three-form {
  padding: clamp(22px, 4vw, 34px);
  border-radius: 30px;
}

.vb-calc-three-visual {
  display: flex;
  flex-direction: column;
  justify-content: center;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #0f172a, #0369a1 58%, #7c3aed) !important;
  box-shadow: 0 30px 90px rgba(3, 105, 161, 0.22);
}

.vb-calc-three-visual span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-three-visual h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 5.2vw, 68px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-calc-three-visual p {
  margin: 0 0 24px !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-three-meter {
  height: 16px;
  overflow: hidden;
  border-radius: 999px;
  background: rgba(255,255,255,0.18);
}

.vb-calc-three-meter div {
  width: 0%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #22c55e, #facc15, #ef4444);
  transition: width 0.25s ease;
}

.vb-calc-three-form {
  display: grid;
  gap: 16px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-three-form label {
  display: grid;
  gap: 8px;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-three-form input {
  width: 100%;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #cbd5e1;
  border-radius: 16px;
  outline: none;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 750;
}

.vb-calc-three-form button {
  min-height: 50px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #0ea5e9, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(124, 58, 237, 0.25);
}

.vb-calc-three-result {
  padding: 20px;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
}

.vb-calc-three-result span {
  display: block;
  margin-bottom: 6px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-three-result strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 46px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-calc-three-result p {
  margin: 8px 0 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-calc-three-result.is-low {
  border-color: rgba(14, 165, 233, 0.35);
  background: #f0f9ff;
}

.vb-calc-three-result.is-normal {
  border-color: rgba(34, 197, 94, 0.35);
  background: #f0fdf4;
}

.vb-calc-three-result.is-high {
  border-color: rgba(250, 204, 21, 0.55);
  background: #fefce8;
}

.vb-calc-three-result.is-very-high {
  border-color: rgba(239, 68, 68, 0.35);
  background: #fef2f2;
}

@media (max-width: 900px) {
  .vb-calc-three-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-three-visual h3 {
    font-size: 40px !important;
  }
}</pre>



<p class="wp-block-paragraph">This BMI calculator is useful for fitness websites, nutrition blogs, wellness landing pages, personal trainer websites, health tools, and educational projects that need a simple interactive body mass index calculator.</p>



<h2 class="wp-block-heading">4. Discount Calculator</h2>



<p class="wp-block-paragraph"><strong>A discount calculator</strong> is useful for ecommerce stores, pricing pages, sale banners, product pages, checkout tools, and marketing landing pages. It helps users calculate the final price, saved amount, and discount percentage instantly.</p>



<p class="wp-block-paragraph">This example uses original price input, discount percentage input, live calculation, formatted currency output, a visual savings badge, and validation for invalid numbers. The JavaScript updates the final price and saved amount as the user types.</p>



<ul class="wp-block-list">
<li>Live discount price calculator</li>
<li>Original price and discount percentage inputs</li>
<li>Saved amount and final price output</li>
<li>Input validation for negative values</li>
<li>Ecommerce sale calculator layout</li>
</ul>



<div class="vb-calc-four-demo">
  <div class="vb-calc-four-wrap">
    <div class="vb-calc-four-left">
      <span class="vb-calc-four-kicker">Example 04</span>
      <h3>Discount Calculator</h3>
      <p>Calculate a sale price, saved amount, and final checkout value from an original price and discount percentage.</p>
    </div>

    <div class="vb-calc-four-box">
      <div class="vb-calc-four-fields">
        <label>
          Original price
          <input type="number" min="0" value="129" data-vb-calc-four-price>
        </label>

        <label>
          Discount percentage
          <input type="number" min="0" max="100" value="25" data-vb-calc-four-discount>
        </label>
      </div>

      <div class="vb-calc-four-ticket">
        <div>
          <span>Final price</span>
          <strong data-vb-calc-four-final>€0.00</strong>
        </div>

        <div>
          <span>You save</span>
          <strong data-vb-calc-four-save>€0.00</strong>
        </div>

        <p data-vb-calc-four-message>Sale price calculated automatically.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-four-demo,
.vb-calc-four-demo * {
  box-sizing: border-box;
}

.vb-calc-four-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(244, 63, 94, 0.18), transparent 32%),
    radial-gradient(circle at 86% 12%, rgba(251, 146, 60, 0.18), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #fff1f2 50%, #ffffff 100%) !important;
  border: 1px solid rgba(244, 63, 94, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.09);
}

.vb-calc-four-wrap {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 26px;
  max-width: 1120px;
  margin: 0 auto;
  align-items: stretch;
}

.vb-calc-four-left {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 28px;
  background:
    radial-gradient(circle at 20% 18%, rgba(255,255,255,0.20), transparent 34%),
    linear-gradient(135deg, #7f1d1d 0%, #e11d48 54%, #fb923c 100%) !important;
  box-shadow: 0 30px 90px rgba(190, 18, 60, 0.22);
}

.vb-calc-four-kicker {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.15);
  color: #ffe4e6 !important;
  -webkit-text-fill-color: #ffe4e6 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-four-left h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 5.2vw, 68px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-four-left p {
  margin: 0 !important;
  color: #ffe4e6 !important;
  -webkit-text-fill-color: #ffe4e6 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-calc-four-box {
  display: grid;
  gap: 18px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-four-fields {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-calc-four-fields label {
  display: grid;
  gap: 8px;
  color: #881337 !important;
  -webkit-text-fill-color: #881337 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-four-fields input {
  width: 100%;
  min-height: 52px;
  padding: 0 15px;
  border: 1px solid #fecdd3;
  border-radius: 16px;
  background: #fff7f7;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-four-ticket {
  position: relative;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  padding: 20px;
  border-radius: 24px;
  background:
    linear-gradient(90deg, rgba(244, 63, 94, 0.10) 1px, transparent 1px),
    linear-gradient(0deg, rgba(244, 63, 94, 0.10) 1px, transparent 1px),
    #fff1f2;
  background-size: 24px 24px;
  border: 1px dashed rgba(225, 29, 72, 0.35);
}

.vb-calc-four-ticket div {
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.84);
}

.vb-calc-four-ticket span {
  display: block;
  margin-bottom: 7px;
  color: #9f1239 !important;
  -webkit-text-fill-color: #9f1239 !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-four-ticket strong {
  display: block;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 34px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-calc-four-ticket p {
  grid-column: 1 / -1;
  margin: 0 !important;
  color: #7f1d1d !important;
  -webkit-text-fill-color: #7f1d1d !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 750;
}

@media (max-width: 900px) {
  .vb-calc-four-wrap {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-four-fields,
  .vb-calc-four-ticket {
    grid-template-columns: 1fr;
  }

  .vb-calc-four-left h3 {
    font-size: 40px !important;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-four-demo");
  if (!demo) return;

  const priceInput = demo.querySelector("[data-vb-calc-four-price]");
  const discountInput = demo.querySelector("[data-vb-calc-four-discount]");
  const finalOutput = demo.querySelector("[data-vb-calc-four-final]");
  const saveOutput = demo.querySelector("[data-vb-calc-four-save]");
  const messageOutput = demo.querySelector("[data-vb-calc-four-message]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    minimumFractionDigits: 2,
    maximumFractionDigits: 2
  });

  function calculateDiscount() {
    const price = Number(priceInput.value);
    const discount = Number(discountInput.value);

    if (price < 0 || discount < 0 || discount > 100 || Number.isNaN(price) || Number.isNaN(discount)) {
      finalOutput.textContent = "€0.00";
      saveOutput.textContent = "€0.00";
      messageOutput.textContent = "Enter a valid price and a discount between 0 and 100%.";
      return;
    }

    const savedAmount = price * (discount / 100);
    const finalPrice = price - savedAmount;

    finalOutput.textContent = money.format(finalPrice);
    saveOutput.textContent = money.format(savedAmount);
    messageOutput.textContent = "The customer saves " + discount.toFixed(0) + "% from the original price.";
  }

  priceInput.addEventListener("input", calculateDiscount);
  discountInput.addEventListener("input", calculateDiscount);

  calculateDiscount();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-four-demo");
  if (!demo) return;

  const priceInput = demo.querySelector("[data-vb-calc-four-price]");
  const discountInput = demo.querySelector("[data-vb-calc-four-discount]");
  const finalOutput = demo.querySelector("[data-vb-calc-four-final]");
  const saveOutput = demo.querySelector("[data-vb-calc-four-save]");
  const messageOutput = demo.querySelector("[data-vb-calc-four-message]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    minimumFractionDigits: 2,
    maximumFractionDigits: 2
  });

  function calculateDiscount() {
    const price = Number(priceInput.value);
    const discount = Number(discountInput.value);

    if (price &lt; 0 || discount &lt; 0 || discount &gt; 100 || Number.isNaN(price) || Number.isNaN(discount)) {
      finalOutput.textContent = "€0.00";
      saveOutput.textContent = "€0.00";
      messageOutput.textContent = "Enter a valid price and a discount between 0 and 100%.";
      return;
    }

    const savedAmount = price * (discount / 100);
    const finalPrice = price - savedAmount;

    finalOutput.textContent = money.format(finalPrice);
    saveOutput.textContent = money.format(savedAmount);
    messageOutput.textContent = "The customer saves " + discount.toFixed(0) + "% from the original price.";
  }

  priceInput.addEventListener("input", calculateDiscount);
  discountInput.addEventListener("input", calculateDiscount);

  calculateDiscount();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-four-demo"&gt;
  &lt;div class="vb-calc-four-wrap"&gt;
    &lt;div class="vb-calc-four-left"&gt;
      &lt;span class="vb-calc-four-kicker"&gt;Example 04&lt;/span&gt;
      &lt;h3&gt;Discount Calculator&lt;/h3&gt;
      &lt;p&gt;Calculate a sale price, saved amount, and final checkout value from an original price and discount percentage.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-four-box"&gt;
      &lt;div class="vb-calc-four-fields"&gt;
        &lt;label&gt;
          Original price
          &lt;input type="number" min="0" value="129" data-vb-calc-four-price&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Discount percentage
          &lt;input type="number" min="0" max="100" value="25" data-vb-calc-four-discount&gt;
        &lt;/label&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-four-ticket"&gt;
        &lt;div&gt;
          &lt;span&gt;Final price&lt;/span&gt;
          &lt;strong data-vb-calc-four-final&gt;€0.00&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;span&gt;You save&lt;/span&gt;
          &lt;strong data-vb-calc-four-save&gt;€0.00&lt;/strong&gt;
        &lt;/div&gt;

        &lt;p data-vb-calc-four-message&gt;Sale price calculated automatically.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-four-demo,
.vb-calc-four-demo * {
  box-sizing: border-box;
}

.vb-calc-four-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(244, 63, 94, 0.18), transparent 32%),
    radial-gradient(circle at 86% 12%, rgba(251, 146, 60, 0.18), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #fff1f2 50%, #ffffff 100%) !important;
  border: 1px solid rgba(244, 63, 94, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.09);
}

.vb-calc-four-wrap {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 26px;
  max-width: 1120px;
  margin: 0 auto;
  align-items: stretch;
}

.vb-calc-four-left {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 28px;
  background:
    radial-gradient(circle at 20% 18%, rgba(255,255,255,0.20), transparent 34%),
    linear-gradient(135deg, #7f1d1d 0%, #e11d48 54%, #fb923c 100%) !important;
  box-shadow: 0 30px 90px rgba(190, 18, 60, 0.22);
}

.vb-calc-four-kicker {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.15);
  color: #ffe4e6 !important;
  -webkit-text-fill-color: #ffe4e6 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-four-left h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 5.2vw, 68px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-four-left p {
  margin: 0 !important;
  color: #ffe4e6 !important;
  -webkit-text-fill-color: #ffe4e6 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-calc-four-box {
  display: grid;
  gap: 18px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-four-fields {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-calc-four-fields label {
  display: grid;
  gap: 8px;
  color: #881337 !important;
  -webkit-text-fill-color: #881337 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-four-fields input {
  width: 100%;
  min-height: 52px;
  padding: 0 15px;
  border: 1px solid #fecdd3;
  border-radius: 16px;
  background: #fff7f7;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-four-ticket {
  position: relative;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  padding: 20px;
  border-radius: 24px;
  background:
    linear-gradient(90deg, rgba(244, 63, 94, 0.10) 1px, transparent 1px),
    linear-gradient(0deg, rgba(244, 63, 94, 0.10) 1px, transparent 1px),
    #fff1f2;
  background-size: 24px 24px;
  border: 1px dashed rgba(225, 29, 72, 0.35);
}

.vb-calc-four-ticket div {
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.84);
}

.vb-calc-four-ticket span {
  display: block;
  margin-bottom: 7px;
  color: #9f1239 !important;
  -webkit-text-fill-color: #9f1239 !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-four-ticket strong {
  display: block;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 34px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-calc-four-ticket p {
  grid-column: 1 / -1;
  margin: 0 !important;
  color: #7f1d1d !important;
  -webkit-text-fill-color: #7f1d1d !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 750;
}

@media (max-width: 900px) {
  .vb-calc-four-wrap {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-four-fields,
  .vb-calc-four-ticket {
    grid-template-columns: 1fr;
  }

  .vb-calc-four-left h3 {
    font-size: 40px !important;
  }
}</pre>



<p class="wp-block-paragraph">This discount calculator is useful for ecommerce product pages, sale campaigns, Black Friday landing pages, pricing sections, checkout pages, and marketing websites where users want to quickly understand the final price and saved amount.</p>



<h2 class="wp-block-heading">5. Mortgage Calculator</h2>



<p class="wp-block-paragraph"><strong>A mortgage calculator</strong> is useful for real estate websites, property listing pages, home loan landing pages, broker websites, and financial comparison tools. It helps users estimate a monthly mortgage payment based on home price, down payment, interest rate, and loan term.</p>



<p class="wp-block-paragraph">This example uses a multi-field mortgage formula, percentage-based down payment calculation, dynamic loan amount summary, number formatting, and a clean split dashboard layout. The JavaScript recalculates everything when any input changes.</p>



<ul class="wp-block-list">
<li>Mortgage monthly payment calculator</li>
<li>Home price and down payment logic</li>
<li>Interest rate and loan term inputs</li>
<li>Dynamic loan amount summary</li>
<li>Real estate calculator layout</li>
</ul>



<div class="vb-calc-five-demo">
  <div class="vb-calc-five-panel">
    <div class="vb-calc-five-top">
      <span>Example 05</span>
      <h3>Mortgage Calculator</h3>
      <p>Estimate a monthly mortgage payment from property price, down payment, interest rate, and repayment years.</p>
    </div>

    <div class="vb-calc-five-body">
      <div class="vb-calc-five-controls">
        <label>
          Home price
          <input type="number" min="1" value="285000" data-vb-calc-five-price>
        </label>

        <label>
          Down payment (%)
          <input type="number" min="0" max="100" value="15" data-vb-calc-five-down>
        </label>

        <label>
          Interest rate (%)
          <input type="number" min="0" step="0.1" value="4.8" data-vb-calc-five-rate>
        </label>

        <label>
          Loan term
          <select data-vb-calc-five-term>
            <option value="15">15 years</option>
            <option value="20">20 years</option>
            <option value="25">25 years</option>
            <option value="30" selected>30 years</option>
          </select>
        </label>
      </div>

      <div class="vb-calc-five-results">
        <div class="vb-calc-five-big">
          <span>Estimated monthly payment</span>
          <strong data-vb-calc-five-payment>€0</strong>
        </div>

        <div class="vb-calc-five-mini-grid">
          <div>
            <span>Loan amount</span>
            <strong data-vb-calc-five-loan>€0</strong>
          </div>

          <div>
            <span>Down payment</span>
            <strong data-vb-calc-five-down-value>€0</strong>
          </div>

          <div>
            <span>Total interest</span>
            <strong data-vb-calc-five-interest>€0</strong>
          </div>
        </div>

        <p data-vb-calc-five-note>Change the values to estimate a different home loan scenario.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-five-demo,
.vb-calc-five-demo * {
  box-sizing: border-box;
}

.vb-calc-five-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(14, 165, 233, 0.18), transparent 32%),
    radial-gradient(circle at 90% 14%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
}

.vb-calc-five-panel {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-five-top {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 20%, rgba(255,255,255,0.20), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #075985 52%, #047857 100%) !important;
}

.vb-calc-five-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-five-top h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 66px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-five-top p {
  max-width: 740px;
  margin: 0 !important;
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-five-body {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 0;
}

.vb-calc-five-controls {
  display: grid;
  gap: 16px;
  padding: clamp(22px, 4vw, 34px);
  background: #f8fafc;
  border-right: 1px solid #e5e7eb;
}

.vb-calc-five-controls label {
  display: grid;
  gap: 8px;
  color: #134e4a !important;
  -webkit-text-fill-color: #134e4a !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-five-controls input,
.vb-calc-five-controls select {
  width: 100%;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #bae6fd;
  border-radius: 15px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 780;
  outline: none;
}

.vb-calc-five-results {
  display: grid;
  gap: 16px;
  padding: clamp(22px, 4vw, 34px);
}

.vb-calc-five-big {
  padding: 22px;
  border-radius: 24px;
  background: linear-gradient(135deg, #ecfeff, #f0fdf4) !important;
  border: 1px solid rgba(20, 184, 166, 0.24);
}

.vb-calc-five-big span,
.vb-calc-five-mini-grid span {
  display: block;
  margin-bottom: 8px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-five-big strong {
  display: block;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: clamp(38px, 5vw, 56px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vb-calc-five-mini-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-calc-five-mini-grid div {
  padding: 16px;
  border-radius: 18px;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
}

.vb-calc-five-mini-grid strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 21px;
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-calc-five-results p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-five-body {
    grid-template-columns: 1fr;
  }

  .vb-calc-five-controls {
    border-right: 0;
    border-bottom: 1px solid #e5e7eb;
  }
}

@media (max-width: 640px) {
  .vb-calc-five-top h3 {
    font-size: 40px !important;
  }

  .vb-calc-five-mini-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-five-demo");
  if (!demo) return;

  const priceInput = demo.querySelector("[data-vb-calc-five-price]");
  const downInput = demo.querySelector("[data-vb-calc-five-down]");
  const rateInput = demo.querySelector("[data-vb-calc-five-rate]");
  const termSelect = demo.querySelector("[data-vb-calc-five-term]");
  const paymentOutput = demo.querySelector("[data-vb-calc-five-payment]");
  const loanOutput = demo.querySelector("[data-vb-calc-five-loan]");
  const downValueOutput = demo.querySelector("[data-vb-calc-five-down-value]");
  const interestOutput = demo.querySelector("[data-vb-calc-five-interest]");
  const noteOutput = demo.querySelector("[data-vb-calc-five-note]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 0
  });

  function calculateMortgage() {
    const homePrice = Number(priceInput.value);
    const downPercent = Number(downInput.value);
    const annualRate = Number(rateInput.value);
    const years = Number(termSelect.value);

    if (homePrice <= 0 || downPercent < 0 || downPercent > 100 || annualRate < 0 || years <= 0) {
      paymentOutput.textContent = "€0";
      loanOutput.textContent = "€0";
      downValueOutput.textContent = "€0";
      interestOutput.textContent = "€0";
      noteOutput.textContent = "Enter a valid price, down payment, interest rate, and loan term.";
      return;
    }

    const downPayment = homePrice * (downPercent / 100);
    const loanAmount = homePrice - downPayment;
    const months = years * 12;
    const monthlyRate = annualRate / 100 / 12;

    let monthlyPayment;

    if (monthlyRate === 0) {
      monthlyPayment = loanAmount / months;
    } else {
      monthlyPayment = loanAmount * monthlyRate * Math.pow(1 + monthlyRate, months) / (Math.pow(1 + monthlyRate, months) - 1);
    }

    const totalPaid = monthlyPayment * months;
    const totalInterest = totalPaid - loanAmount;

    paymentOutput.textContent = money.format(monthlyPayment);
    loanOutput.textContent = money.format(loanAmount);
    downValueOutput.textContent = money.format(downPayment);
    interestOutput.textContent = money.format(totalInterest);
    noteOutput.textContent = "Estimated for a " + years + "-year mortgage with " + downPercent + "% down payment.";
  }

  [priceInput, downInput, rateInput, termSelect].forEach(function (field) {
    field.addEventListener("input", calculateMortgage);
    field.addEventListener("change", calculateMortgage);
  });

  calculateMortgage();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-five-demo");
  if (!demo) return;

  const priceInput = demo.querySelector("[data-vb-calc-five-price]");
  const downInput = demo.querySelector("[data-vb-calc-five-down]");
  const rateInput = demo.querySelector("[data-vb-calc-five-rate]");
  const termSelect = demo.querySelector("[data-vb-calc-five-term]");
  const paymentOutput = demo.querySelector("[data-vb-calc-five-payment]");
  const loanOutput = demo.querySelector("[data-vb-calc-five-loan]");
  const downValueOutput = demo.querySelector("[data-vb-calc-five-down-value]");
  const interestOutput = demo.querySelector("[data-vb-calc-five-interest]");
  const noteOutput = demo.querySelector("[data-vb-calc-five-note]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 0
  });

  function calculateMortgage() {
    const homePrice = Number(priceInput.value);
    const downPercent = Number(downInput.value);
    const annualRate = Number(rateInput.value);
    const years = Number(termSelect.value);

    if (homePrice &lt;= 0 || downPercent &lt; 0 || downPercent &gt; 100 || annualRate &lt; 0 || years &lt;= 0) {
      paymentOutput.textContent = "€0";
      loanOutput.textContent = "€0";
      downValueOutput.textContent = "€0";
      interestOutput.textContent = "€0";
      noteOutput.textContent = "Enter a valid price, down payment, interest rate, and loan term.";
      return;
    }

    const downPayment = homePrice * (downPercent / 100);
    const loanAmount = homePrice - downPayment;
    const months = years * 12;
    const monthlyRate = annualRate / 100 / 12;

    let monthlyPayment;

    if (monthlyRate === 0) {
      monthlyPayment = loanAmount / months;
    } else {
      monthlyPayment = loanAmount * monthlyRate * Math.pow(1 + monthlyRate, months) / (Math.pow(1 + monthlyRate, months) - 1);
    }

    const totalPaid = monthlyPayment * months;
    const totalInterest = totalPaid - loanAmount;

    paymentOutput.textContent = money.format(monthlyPayment);
    loanOutput.textContent = money.format(loanAmount);
    downValueOutput.textContent = money.format(downPayment);
    interestOutput.textContent = money.format(totalInterest);
    noteOutput.textContent = "Estimated for a " + years + "-year mortgage with " + downPercent + "% down payment.";
  }

  [priceInput, downInput, rateInput, termSelect].forEach(function (field) {
    field.addEventListener("input", calculateMortgage);
    field.addEventListener("change", calculateMortgage);
  });

  calculateMortgage();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-five-demo"&gt;
  &lt;div class="vb-calc-five-panel"&gt;
    &lt;div class="vb-calc-five-top"&gt;
      &lt;span&gt;Example 05&lt;/span&gt;
      &lt;h3&gt;Mortgage Calculator&lt;/h3&gt;
      &lt;p&gt;Estimate a monthly mortgage payment from property price, down payment, interest rate, and repayment years.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-five-body"&gt;
      &lt;div class="vb-calc-five-controls"&gt;
        &lt;label&gt;
          Home price
          &lt;input type="number" min="1" value="285000" data-vb-calc-five-price&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Down payment (%)
          &lt;input type="number" min="0" max="100" value="15" data-vb-calc-five-down&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Interest rate (%)
          &lt;input type="number" min="0" step="0.1" value="4.8" data-vb-calc-five-rate&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Loan term
          &lt;select data-vb-calc-five-term&gt;
            &lt;option value="15"&gt;15 years&lt;/option&gt;
            &lt;option value="20"&gt;20 years&lt;/option&gt;
            &lt;option value="25"&gt;25 years&lt;/option&gt;
            &lt;option value="30" selected&gt;30 years&lt;/option&gt;
          &lt;/select&gt;
        &lt;/label&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-five-results"&gt;
        &lt;div class="vb-calc-five-big"&gt;
          &lt;span&gt;Estimated monthly payment&lt;/span&gt;
          &lt;strong data-vb-calc-five-payment&gt;€0&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-calc-five-mini-grid"&gt;
          &lt;div&gt;
            &lt;span&gt;Loan amount&lt;/span&gt;
            &lt;strong data-vb-calc-five-loan&gt;€0&lt;/strong&gt;
          &lt;/div&gt;

          &lt;div&gt;
            &lt;span&gt;Down payment&lt;/span&gt;
            &lt;strong data-vb-calc-five-down-value&gt;€0&lt;/strong&gt;
          &lt;/div&gt;

          &lt;div&gt;
            &lt;span&gt;Total interest&lt;/span&gt;
            &lt;strong data-vb-calc-five-interest&gt;€0&lt;/strong&gt;
          &lt;/div&gt;
        &lt;/div&gt;

        &lt;p data-vb-calc-five-note&gt;Change the values to estimate a different home loan scenario.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-five-demo,
.vb-calc-five-demo * {
  box-sizing: border-box;
}

.vb-calc-five-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(14, 165, 233, 0.18), transparent 32%),
    radial-gradient(circle at 90% 14%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
}

.vb-calc-five-panel {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-five-top {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 20%, rgba(255,255,255,0.20), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #075985 52%, #047857 100%) !important;
}

.vb-calc-five-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-five-top h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 66px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-five-top p {
  max-width: 740px;
  margin: 0 !important;
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-five-body {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 0;
}

.vb-calc-five-controls {
  display: grid;
  gap: 16px;
  padding: clamp(22px, 4vw, 34px);
  background: #f8fafc;
  border-right: 1px solid #e5e7eb;
}

.vb-calc-five-controls label {
  display: grid;
  gap: 8px;
  color: #134e4a !important;
  -webkit-text-fill-color: #134e4a !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-five-controls input,
.vb-calc-five-controls select {
  width: 100%;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #bae6fd;
  border-radius: 15px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 780;
  outline: none;
}

.vb-calc-five-results {
  display: grid;
  gap: 16px;
  padding: clamp(22px, 4vw, 34px);
}

.vb-calc-five-big {
  padding: 22px;
  border-radius: 24px;
  background: linear-gradient(135deg, #ecfeff, #f0fdf4) !important;
  border: 1px solid rgba(20, 184, 166, 0.24);
}

.vb-calc-five-big span,
.vb-calc-five-mini-grid span {
  display: block;
  margin-bottom: 8px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-five-big strong {
  display: block;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: clamp(38px, 5vw, 56px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vb-calc-five-mini-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-calc-five-mini-grid div {
  padding: 16px;
  border-radius: 18px;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
}

.vb-calc-five-mini-grid strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 21px;
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-calc-five-results p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-five-body {
    grid-template-columns: 1fr;
  }

  .vb-calc-five-controls {
    border-right: 0;
    border-bottom: 1px solid #e5e7eb;
  }
}

@media (max-width: 640px) {
  .vb-calc-five-top h3 {
    font-size: 40px !important;
  }

  .vb-calc-five-mini-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This mortgage calculator is useful for real estate websites, property portals, home loan pages, mortgage broker websites, property landing pages, and financial calculators that need a fast monthly payment estimate.</p>



<h2 class="wp-block-heading">6. VAT and Tax Calculator</h2>



<p class="wp-block-paragraph"><strong>A VAT and tax calculator</strong> is useful for ecommerce stores, invoice tools, pricing pages, checkout interfaces, accounting websites, and business dashboards. It helps users add tax to a net price or remove tax from a gross price.</p>



<p class="wp-block-paragraph">This example uses a calculation mode switch, tax rate dropdown, live net/gross/tax output, number formatting, and conditional formula logic. The JavaScript changes the calculation depending on whether the user wants to add tax or remove tax.</p>



<ul class="wp-block-list">
<li>VAT and sales tax calculator</li>
<li>Add tax or remove tax modes</li>
<li>Tax rate dropdown</li>
<li>Net price, tax amount, and gross price output</li>
<li>Conditional JavaScript formula logic</li>
</ul>



<div class="vb-calc-six-demo">
  <div class="vb-calc-six-card">
    <div class="vb-calc-six-title">
      <span>Example 06</span>
      <h3>VAT and Tax Calculator</h3>
      <p>Add tax to a net price or remove tax from a gross price using a selected tax rate.</p>
    </div>

    <div class="vb-calc-six-tool">
      <div class="vb-calc-six-mode">
        <button type="button" class="is-active" data-vb-calc-six-mode="add">Add tax</button>
        <button type="button" data-vb-calc-six-mode="remove">Remove tax</button>
      </div>

      <label>
        Price amount
        <input type="number" min="0" value="100" data-vb-calc-six-price>
      </label>

      <label>
        Tax rate
        <select data-vb-calc-six-rate>
          <option value="10">10%</option>
          <option value="20" selected>20%</option>
          <option value="22">22%</option>
          <option value="24">24%</option>
        </select>
      </label>

      <div class="vb-calc-six-results">
        <div>
          <span>Net price</span>
          <strong data-vb-calc-six-net>€0.00</strong>
        </div>

        <div>
          <span>Tax amount</span>
          <strong data-vb-calc-six-tax>€0.00</strong>
        </div>

        <div>
          <span>Gross price</span>
          <strong data-vb-calc-six-gross>€0.00</strong>
        </div>
      </div>

      <p data-vb-calc-six-message>Tax calculation updates automatically.</p>
    </div>
  </div>
</div>

<style>
.vb-calc-six-demo,
.vb-calc-six-demo * {
  box-sizing: border-box;
}

.vb-calc-six-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 30px;
  background:
    linear-gradient(135deg, #f8fafc 0%, #ecfeff 48%, #f0fdf4 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-calc-six-card {
  display: grid;
  grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-calc-six-title {
  padding: clamp(22px, 4vw, 36px);
  border-radius: 28px;
  background:
    linear-gradient(90deg, rgba(255,255,255,0.10) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.10) 1px, transparent 1px),
    linear-gradient(135deg, #042f2e 0%, #0f766e 56%, #14b8a6 100%) !important;
  background-size: 26px 26px, 26px 26px, auto !important;
  box-shadow: 0 30px 90px rgba(15, 118, 110, 0.22);
}

.vb-calc-six-title span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-six-title h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5.2vw, 66px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-six-title p {
  margin: 0 !important;
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-six-tool {
  display: grid;
  gap: 16px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-six-mode {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  padding: 6px;
  border-radius: 999px;
  background: #f1f5f9;
}

.vb-calc-six-mode button {
  min-height: 44px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-calc-six-mode button.is-active {
  background: linear-gradient(135deg, #14b8a6, #22c55e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 12px 28px rgba(20, 184, 166, 0.26);
}

.vb-calc-six-tool label {
  display: grid;
  gap: 8px;
  color: #134e4a !important;
  -webkit-text-fill-color: #134e4a !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-six-tool input,
.vb-calc-six-tool select {
  width: 100%;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #99f6e4;
  border-radius: 16px;
  outline: none;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
}

.vb-calc-six-results {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-calc-six-results div {
  padding: 16px;
  border-radius: 18px;
  background: linear-gradient(135deg, #ecfeff, #f8fafc) !important;
  border: 1px solid #ccfbf1;
}

.vb-calc-six-results span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-six-results strong {
  display: block;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 22px;
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-calc-six-tool p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-six-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-six-title h3 {
    font-size: 40px !important;
  }

  .vb-calc-six-results {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-six-demo");
  if (!demo) return;

  const modeButtons = demo.querySelectorAll("[data-vb-calc-six-mode]");
  const priceInput = demo.querySelector("[data-vb-calc-six-price]");
  const rateSelect = demo.querySelector("[data-vb-calc-six-rate]");
  const netOutput = demo.querySelector("[data-vb-calc-six-net]");
  const taxOutput = demo.querySelector("[data-vb-calc-six-tax]");
  const grossOutput = demo.querySelector("[data-vb-calc-six-gross]");
  const messageOutput = demo.querySelector("[data-vb-calc-six-message]");

  let activeMode = "add";

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    minimumFractionDigits: 2,
    maximumFractionDigits: 2
  });

  function setMode(mode) {
    activeMode = mode;

    modeButtons.forEach(function (button) {
      button.classList.toggle("is-active", button.dataset.vbCalcSixMode === mode);
    });

    calculateTax();
  }

  function calculateTax() {
    const price = Number(priceInput.value);
    const rate = Number(rateSelect.value) / 100;

    if (price < 0 || Number.isNaN(price)) {
      netOutput.textContent = "€0.00";
      taxOutput.textContent = "€0.00";
      grossOutput.textContent = "€0.00";
      messageOutput.textContent = "Enter a valid positive price amount.";
      return;
    }

    let net;
    let tax;
    let gross;

    if (activeMode === "add") {
      net = price;
      tax = net * rate;
      gross = net + tax;
      messageOutput.textContent = "Tax added to net price at " + (rate * 100).toFixed(0) + "%.";
    } else {
      gross = price;
      net = gross / (1 + rate);
      tax = gross - net;
      messageOutput.textContent = "Tax removed from gross price at " + (rate * 100).toFixed(0) + "%.";
    }

    netOutput.textContent = money.format(net);
    taxOutput.textContent = money.format(tax);
    grossOutput.textContent = money.format(gross);
  }

  modeButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      setMode(button.dataset.vbCalcSixMode);
    });
  });

  priceInput.addEventListener("input", calculateTax);
  rateSelect.addEventListener("change", calculateTax);

  calculateTax();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-six-demo");
  if (!demo) return;

  const modeButtons = demo.querySelectorAll("[data-vb-calc-six-mode]");
  const priceInput = demo.querySelector("[data-vb-calc-six-price]");
  const rateSelect = demo.querySelector("[data-vb-calc-six-rate]");
  const netOutput = demo.querySelector("[data-vb-calc-six-net]");
  const taxOutput = demo.querySelector("[data-vb-calc-six-tax]");
  const grossOutput = demo.querySelector("[data-vb-calc-six-gross]");
  const messageOutput = demo.querySelector("[data-vb-calc-six-message]");

  let activeMode = "add";

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    minimumFractionDigits: 2,
    maximumFractionDigits: 2
  });

  function setMode(mode) {
    activeMode = mode;

    modeButtons.forEach(function (button) {
      button.classList.toggle("is-active", button.dataset.vbCalcSixMode === mode);
    });

    calculateTax();
  }

  function calculateTax() {
    const price = Number(priceInput.value);
    const rate = Number(rateSelect.value) / 100;

    if (price &lt; 0 || Number.isNaN(price)) {
      netOutput.textContent = "€0.00";
      taxOutput.textContent = "€0.00";
      grossOutput.textContent = "€0.00";
      messageOutput.textContent = "Enter a valid positive price amount.";
      return;
    }

    let net;
    let tax;
    let gross;

    if (activeMode === "add") {
      net = price;
      tax = net * rate;
      gross = net + tax;
      messageOutput.textContent = "Tax added to net price at " + (rate * 100).toFixed(0) + "%.";
    } else {
      gross = price;
      net = gross / (1 + rate);
      tax = gross - net;
      messageOutput.textContent = "Tax removed from gross price at " + (rate * 100).toFixed(0) + "%.";
    }

    netOutput.textContent = money.format(net);
    taxOutput.textContent = money.format(tax);
    grossOutput.textContent = money.format(gross);
  }

  modeButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      setMode(button.dataset.vbCalcSixMode);
    });
  });

  priceInput.addEventListener("input", calculateTax);
  rateSelect.addEventListener("change", calculateTax);

  calculateTax();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-six-demo"&gt;
  &lt;div class="vb-calc-six-card"&gt;
    &lt;div class="vb-calc-six-title"&gt;
      &lt;span&gt;Example 06&lt;/span&gt;
      &lt;h3&gt;VAT and Tax Calculator&lt;/h3&gt;
      &lt;p&gt;Add tax to a net price or remove tax from a gross price using a selected tax rate.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-six-tool"&gt;
      &lt;div class="vb-calc-six-mode"&gt;
        &lt;button type="button" class="is-active" data-vb-calc-six-mode="add"&gt;Add tax&lt;/button&gt;
        &lt;button type="button" data-vb-calc-six-mode="remove"&gt;Remove tax&lt;/button&gt;
      &lt;/div&gt;

      &lt;label&gt;
        Price amount
        &lt;input type="number" min="0" value="100" data-vb-calc-six-price&gt;
      &lt;/label&gt;

      &lt;label&gt;
        Tax rate
        &lt;select data-vb-calc-six-rate&gt;
          &lt;option value="10"&gt;10%&lt;/option&gt;
          &lt;option value="20" selected&gt;20%&lt;/option&gt;
          &lt;option value="22"&gt;22%&lt;/option&gt;
          &lt;option value="24"&gt;24%&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;

      &lt;div class="vb-calc-six-results"&gt;
        &lt;div&gt;
          &lt;span&gt;Net price&lt;/span&gt;
          &lt;strong data-vb-calc-six-net&gt;€0.00&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;span&gt;Tax amount&lt;/span&gt;
          &lt;strong data-vb-calc-six-tax&gt;€0.00&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;span&gt;Gross price&lt;/span&gt;
          &lt;strong data-vb-calc-six-gross&gt;€0.00&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;p data-vb-calc-six-message&gt;Tax calculation updates automatically.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-six-demo,
.vb-calc-six-demo * {
  box-sizing: border-box;
}

.vb-calc-six-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 30px;
  background:
    linear-gradient(135deg, #f8fafc 0%, #ecfeff 48%, #f0fdf4 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.08);
}

.vb-calc-six-card {
  display: grid;
  grid-template-columns: minmax(0, 0.86fr) minmax(0, 1.14fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-calc-six-title {
  padding: clamp(22px, 4vw, 36px);
  border-radius: 28px;
  background:
    linear-gradient(90deg, rgba(255,255,255,0.10) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.10) 1px, transparent 1px),
    linear-gradient(135deg, #042f2e 0%, #0f766e 56%, #14b8a6 100%) !important;
  background-size: 26px 26px, 26px 26px, auto !important;
  box-shadow: 0 30px 90px rgba(15, 118, 110, 0.22);
}

.vb-calc-six-title span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-six-title h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5.2vw, 66px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-six-title p {
  margin: 0 !important;
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-six-tool {
  display: grid;
  gap: 16px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-six-mode {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
  padding: 6px;
  border-radius: 999px;
  background: #f1f5f9;
}

.vb-calc-six-mode button {
  min-height: 44px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-calc-six-mode button.is-active {
  background: linear-gradient(135deg, #14b8a6, #22c55e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 12px 28px rgba(20, 184, 166, 0.26);
}

.vb-calc-six-tool label {
  display: grid;
  gap: 8px;
  color: #134e4a !important;
  -webkit-text-fill-color: #134e4a !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-six-tool input,
.vb-calc-six-tool select {
  width: 100%;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #99f6e4;
  border-radius: 16px;
  outline: none;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
}

.vb-calc-six-results {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-calc-six-results div {
  padding: 16px;
  border-radius: 18px;
  background: linear-gradient(135deg, #ecfeff, #f8fafc) !important;
  border: 1px solid #ccfbf1;
}

.vb-calc-six-results span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-six-results strong {
  display: block;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 22px;
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-calc-six-tool p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-six-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-six-title h3 {
    font-size: 40px !important;
  }

  .vb-calc-six-results {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This VAT and tax calculator is useful for ecommerce stores, checkout pages, invoice generators, pricing pages, accounting tools, business dashboards, and service websites that need to show net price, tax amount, and gross price clearly.</p>



<h2 class="wp-block-heading">7. Tip Calculator</h2>



<p class="wp-block-paragraph"><strong>A tip calculator</strong> is useful for restaurant websites, bill splitting tools, travel apps, food delivery interfaces, and simple finance utilities. It helps users calculate a tip amount, total bill, and cost per person.</p>



<p class="wp-block-paragraph">This example uses bill amount input, quick tip percentage buttons, custom split count, active button states, live calculation, and formatted money output. The JavaScript updates the total whenever the user changes the bill, tip percentage, or number of people.</p>



<ul class="wp-block-list">
<li>Restaurant tip calculator</li>
<li>Quick percentage buttons</li>
<li>Bill split between people</li>
<li>Active button state with JavaScript</li>
<li>Live formatted result output</li>
</ul>



<div class="vb-calc-seven-demo">
  <div class="vb-calc-seven-card">
    <div class="vb-calc-seven-copy">
      <span>Example 07</span>
      <h3>Tip Calculator</h3>
      <p>Calculate tip amount, total bill, and cost per person with quick tip buttons and split logic.</p>
    </div>

    <div class="vb-calc-seven-tool">
      <label>
        Bill amount
        <input type="number" min="0" value="86.50" data-vb-calc-seven-bill>
      </label>

      <div class="vb-calc-seven-tip-group">
        <span>Tip percentage</span>
        <div>
          <button type="button" data-vb-calc-seven-tip="10">10%</button>
          <button type="button" class="is-active" data-vb-calc-seven-tip="15">15%</button>
          <button type="button" data-vb-calc-seven-tip="20">20%</button>
          <button type="button" data-vb-calc-seven-tip="25">25%</button>
        </div>
      </div>

      <label>
        Split between people
        <input type="number" min="1" value="3" data-vb-calc-seven-people>
      </label>

      <div class="vb-calc-seven-results">
        <div>
          <span>Tip amount</span>
          <strong data-vb-calc-seven-tip-output>€0.00</strong>
        </div>
        <div>
          <span>Total bill</span>
          <strong data-vb-calc-seven-total-output>€0.00</strong>
        </div>
        <div class="vb-calc-seven-main-result">
          <span>Each person pays</span>
          <strong data-vb-calc-seven-person-output>€0.00</strong>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-seven-demo,
.vb-calc-seven-demo * {
  box-sizing: border-box;
}

.vb-calc-seven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 36px;
  background:
    radial-gradient(circle at 12% 16%, rgba(245, 158, 11, 0.20), transparent 32%),
    radial-gradient(circle at 88% 14%, rgba(236, 72, 153, 0.16), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fdf2f8 52%, #ffffff 100%) !important;
  border: 1px solid rgba(245, 158, 11, 0.20);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.09);
}

.vb-calc-seven-card {
  display: grid;
  grid-template-columns: minmax(0, 0.88fr) minmax(0, 1.12fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-calc-seven-copy {
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #78350f 0%, #d97706 52%, #db2777 100%) !important;
  box-shadow: 0 30px 90px rgba(180, 83, 9, 0.22);
}

.vb-calc-seven-copy span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-seven-copy h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 5.2vw, 68px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-seven-copy p {
  margin: 0 !important;
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-seven-tool {
  display: grid;
  gap: 16px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-seven-tool label,
.vb-calc-seven-tip-group > span {
  display: grid;
  gap: 8px;
  color: #78350f !important;
  -webkit-text-fill-color: #78350f !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-seven-tool input {
  width: 100%;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #fde68a;
  border-radius: 16px;
  background: #fffbeb;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-seven-tip-group {
  display: grid;
  gap: 10px;
}

.vb-calc-seven-tip-group div {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
}

.vb-calc-seven-tip-group button {
  min-height: 46px;
  border: 1px solid #fcd34d;
  border-radius: 16px;
  background: #fffbeb;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-calc-seven-tip-group button.is-active {
  background: linear-gradient(135deg, #f59e0b, #db2777);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  border-color: transparent;
  box-shadow: 0 14px 34px rgba(219, 39, 119, 0.20);
}

.vb-calc-seven-results {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-calc-seven-results div {
  padding: 16px;
  border-radius: 18px;
  background: #fffbeb;
  border: 1px solid #fde68a;
}

.vb-calc-seven-main-result {
  grid-column: 1 / -1;
  background: linear-gradient(135deg, #fff7ed, #fdf2f8) !important;
}

.vb-calc-seven-results span {
  display: block;
  margin-bottom: 7px;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-seven-results strong {
  display: block;
  color: #9d174d !important;
  -webkit-text-fill-color: #9d174d !important;
  font-size: 30px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-calc-seven-main-result strong {
  font-size: 42px;
}

@media (max-width: 900px) {
  .vb-calc-seven-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-seven-copy h3 {
    font-size: 40px !important;
  }

  .vb-calc-seven-tip-group div,
  .vb-calc-seven-results {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-seven-demo");
  if (!demo) return;

  const billInput = demo.querySelector("[data-vb-calc-seven-bill]");
  const peopleInput = demo.querySelector("[data-vb-calc-seven-people]");
  const tipButtons = demo.querySelectorAll("[data-vb-calc-seven-tip]");
  const tipOutput = demo.querySelector("[data-vb-calc-seven-tip-output]");
  const totalOutput = demo.querySelector("[data-vb-calc-seven-total-output]");
  const personOutput = demo.querySelector("[data-vb-calc-seven-person-output]");

  let activeTip = 15;

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    minimumFractionDigits: 2,
    maximumFractionDigits: 2
  });

  function calculateTip() {
    const bill = Math.max(Number(billInput.value) || 0, 0);
    const people = Math.max(Number(peopleInput.value) || 1, 1);
    const tipAmount = bill * (activeTip / 100);
    const total = bill + tipAmount;
    const perPerson = total / people;

    tipOutput.textContent = money.format(tipAmount);
    totalOutput.textContent = money.format(total);
    personOutput.textContent = money.format(perPerson);
  }

  tipButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeTip = Number(button.dataset.vbCalcSevenTip);

      tipButtons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      calculateTip();
    });
  });

  billInput.addEventListener("input", calculateTip);
  peopleInput.addEventListener("input", calculateTip);

  calculateTip();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-seven-demo");
  if (!demo) return;

  const billInput = demo.querySelector("[data-vb-calc-seven-bill]");
  const peopleInput = demo.querySelector("[data-vb-calc-seven-people]");
  const tipButtons = demo.querySelectorAll("[data-vb-calc-seven-tip]");
  const tipOutput = demo.querySelector("[data-vb-calc-seven-tip-output]");
  const totalOutput = demo.querySelector("[data-vb-calc-seven-total-output]");
  const personOutput = demo.querySelector("[data-vb-calc-seven-person-output]");

  let activeTip = 15;

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    minimumFractionDigits: 2,
    maximumFractionDigits: 2
  });

  function calculateTip() {
    const bill = Math.max(Number(billInput.value) || 0, 0);
    const people = Math.max(Number(peopleInput.value) || 1, 1);
    const tipAmount = bill * (activeTip / 100);
    const total = bill + tipAmount;
    const perPerson = total / people;

    tipOutput.textContent = money.format(tipAmount);
    totalOutput.textContent = money.format(total);
    personOutput.textContent = money.format(perPerson);
  }

  tipButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeTip = Number(button.dataset.vbCalcSevenTip);

      tipButtons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      calculateTip();
    });
  });

  billInput.addEventListener("input", calculateTip);
  peopleInput.addEventListener("input", calculateTip);

  calculateTip();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-seven-demo"&gt;
  &lt;div class="vb-calc-seven-card"&gt;
    &lt;div class="vb-calc-seven-copy"&gt;
      &lt;span&gt;Example 07&lt;/span&gt;
      &lt;h3&gt;Tip Calculator&lt;/h3&gt;
      &lt;p&gt;Calculate tip amount, total bill, and cost per person with quick tip buttons and split logic.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-seven-tool"&gt;
      &lt;label&gt;
        Bill amount
        &lt;input type="number" min="0" value="86.50" data-vb-calc-seven-bill&gt;
      &lt;/label&gt;

      &lt;div class="vb-calc-seven-tip-group"&gt;
        &lt;span&gt;Tip percentage&lt;/span&gt;
        &lt;div&gt;
          &lt;button type="button" data-vb-calc-seven-tip="10"&gt;10%&lt;/button&gt;
          &lt;button type="button" class="is-active" data-vb-calc-seven-tip="15"&gt;15%&lt;/button&gt;
          &lt;button type="button" data-vb-calc-seven-tip="20"&gt;20%&lt;/button&gt;
          &lt;button type="button" data-vb-calc-seven-tip="25"&gt;25%&lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;label&gt;
        Split between people
        &lt;input type="number" min="1" value="3" data-vb-calc-seven-people&gt;
      &lt;/label&gt;

      &lt;div class="vb-calc-seven-results"&gt;
        &lt;div&gt;
          &lt;span&gt;Tip amount&lt;/span&gt;
          &lt;strong data-vb-calc-seven-tip-output&gt;€0.00&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;Total bill&lt;/span&gt;
          &lt;strong data-vb-calc-seven-total-output&gt;€0.00&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div class="vb-calc-seven-main-result"&gt;
          &lt;span&gt;Each person pays&lt;/span&gt;
          &lt;strong data-vb-calc-seven-person-output&gt;€0.00&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-seven-demo,
.vb-calc-seven-demo * {
  box-sizing: border-box;
}

.vb-calc-seven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 36px;
  background:
    radial-gradient(circle at 12% 16%, rgba(245, 158, 11, 0.20), transparent 32%),
    radial-gradient(circle at 88% 14%, rgba(236, 72, 153, 0.16), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fdf2f8 52%, #ffffff 100%) !important;
  border: 1px solid rgba(245, 158, 11, 0.20);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.09);
}

.vb-calc-seven-card {
  display: grid;
  grid-template-columns: minmax(0, 0.88fr) minmax(0, 1.12fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-calc-seven-copy {
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #78350f 0%, #d97706 52%, #db2777 100%) !important;
  box-shadow: 0 30px 90px rgba(180, 83, 9, 0.22);
}

.vb-calc-seven-copy span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-seven-copy h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 5.2vw, 68px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-seven-copy p {
  margin: 0 !important;
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-seven-tool {
  display: grid;
  gap: 16px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-seven-tool label,
.vb-calc-seven-tip-group &gt; span {
  display: grid;
  gap: 8px;
  color: #78350f !important;
  -webkit-text-fill-color: #78350f !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-seven-tool input {
  width: 100%;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #fde68a;
  border-radius: 16px;
  background: #fffbeb;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-seven-tip-group {
  display: grid;
  gap: 10px;
}

.vb-calc-seven-tip-group div {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
}

.vb-calc-seven-tip-group button {
  min-height: 46px;
  border: 1px solid #fcd34d;
  border-radius: 16px;
  background: #fffbeb;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-calc-seven-tip-group button.is-active {
  background: linear-gradient(135deg, #f59e0b, #db2777);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  border-color: transparent;
  box-shadow: 0 14px 34px rgba(219, 39, 119, 0.20);
}

.vb-calc-seven-results {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-calc-seven-results div {
  padding: 16px;
  border-radius: 18px;
  background: #fffbeb;
  border: 1px solid #fde68a;
}

.vb-calc-seven-main-result {
  grid-column: 1 / -1;
  background: linear-gradient(135deg, #fff7ed, #fdf2f8) !important;
}

.vb-calc-seven-results span {
  display: block;
  margin-bottom: 7px;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-seven-results strong {
  display: block;
  color: #9d174d !important;
  -webkit-text-fill-color: #9d174d !important;
  font-size: 30px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-calc-seven-main-result strong {
  font-size: 42px;
}

@media (max-width: 900px) {
  .vb-calc-seven-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-seven-copy h3 {
    font-size: 40px !important;
  }

  .vb-calc-seven-tip-group div,
  .vb-calc-seven-results {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This tip calculator is useful for restaurant websites, food delivery pages, travel apps, bill splitting tools, personal finance websites, and simple JavaScript practice projects.</p>



<h2 class="wp-block-heading">8. Shipping Cost Calculator</h2>



<p class="wp-block-paragraph"><strong>A shipping cost calculator</strong> is useful for ecommerce stores, delivery services, checkout pages, logistics websites, and product order forms. It helps users estimate shipping cost based on weight, delivery zone, and selected shipping method.</p>



<p class="wp-block-paragraph">This example uses dropdown pricing rules, package weight input, zone multipliers, delivery method multipliers, free shipping logic, and a dynamic summary message. The JavaScript applies different formulas depending on user selections.</p>



<ul class="wp-block-list">
<li>Ecommerce shipping cost calculator</li>
<li>Weight-based pricing</li>
<li>Delivery zone multiplier</li>
<li>Standard and express shipping options</li>
<li>Free shipping threshold logic</li>
</ul>



<div class="vb-calc-eight-demo">
  <div class="vb-calc-eight-panel">
    <div class="vb-calc-eight-header">
      <span>Example 08</span>
      <h3>Shipping Cost Calculator</h3>
      <p>Estimate delivery cost from cart value, parcel weight, shipping zone, and delivery method.</p>
    </div>

    <div class="vb-calc-eight-body">
      <label>
        Cart value
        <input type="number" min="0" value="84" data-vb-calc-eight-cart>
      </label>

      <label>
        Package weight in kg
        <input type="number" min="0.1" step="0.1" value="2.5" data-vb-calc-eight-weight>
      </label>

      <label>
        Shipping zone
        <select data-vb-calc-eight-zone>
          <option value="1">Local zone</option>
          <option value="1.35">National zone</option>
          <option value="1.8">International zone</option>
        </select>
      </label>

      <label>
        Delivery method
        <select data-vb-calc-eight-method>
          <option value="1">Standard delivery</option>
          <option value="1.75">Express delivery</option>
          <option value="2.4">Priority courier</option>
        </select>
      </label>

      <div class="vb-calc-eight-result">
        <span>Shipping estimate</span>
        <strong data-vb-calc-eight-total>€0.00</strong>
        <p data-vb-calc-eight-message>Shipping cost updates automatically.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-eight-demo,
.vb-calc-eight-demo * {
  box-sizing: border-box;
}

.vb-calc-eight-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 16%, rgba(59, 130, 246, 0.18), transparent 32%),
    radial-gradient(circle at 86% 12%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #faf5ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.18);
}

.vb-calc-eight-panel {
  max-width: 1120px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-eight-header {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #172554 0%, #2563eb 52%, #7c3aed 100%) !important;
  background-size: 26px 26px, 26px 26px, auto !important;
}

.vb-calc-eight-header span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-eight-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 66px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-eight-header p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-eight-body {
  display: grid;
  gap: 15px;
  padding: clamp(22px, 4vw, 34px);
}

.vb-calc-eight-body label {
  display: grid;
  gap: 8px;
  color: #1e3a8a !important;
  -webkit-text-fill-color: #1e3a8a !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-eight-body input,
.vb-calc-eight-body select {
  width: 100%;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #bfdbfe;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-eight-result {
  margin-top: 4px;
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 18% 18%, rgba(59, 130, 246, 0.10), transparent 34%),
    linear-gradient(135deg, #eff6ff, #f5f3ff) !important;
  border: 1px solid #dbeafe;
}

.vb-calc-eight-result span {
  display: block;
  margin-bottom: 7px;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-eight-result strong {
  display: block;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: 44px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-calc-eight-result p {
  margin: 9px 0 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-eight-panel {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-eight-header h3 {
    font-size: 40px !important;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-eight-demo");
  if (!demo) return;

  const cartInput = demo.querySelector("[data-vb-calc-eight-cart]");
  const weightInput = demo.querySelector("[data-vb-calc-eight-weight]");
  const zoneSelect = demo.querySelector("[data-vb-calc-eight-zone]");
  const methodSelect = demo.querySelector("[data-vb-calc-eight-method]");
  const totalOutput = demo.querySelector("[data-vb-calc-eight-total]");
  const messageOutput = demo.querySelector("[data-vb-calc-eight-message]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    minimumFractionDigits: 2,
    maximumFractionDigits: 2
  });

  function calculateShipping() {
    const cartValue = Math.max(Number(cartInput.value) || 0, 0);
    const weight = Math.max(Number(weightInput.value) || 0, 0);
    const zoneMultiplier = Number(zoneSelect.value);
    const methodMultiplier = Number(methodSelect.value);

    if (cartValue >= 150) {
      totalOutput.textContent = money.format(0);
      messageOutput.textContent = "Free shipping unlocked because the cart value is at least €150.";
      return;
    }

    const baseFee = 5.9;
    const weightFee = weight * 2.4;
    const shipping = (baseFee + weightFee) * zoneMultiplier * methodMultiplier;

    totalOutput.textContent = money.format(shipping);
    messageOutput.textContent = "Shipping includes base fee, weight fee, zone multiplier, and selected delivery method.";
  }

  [cartInput, weightInput, zoneSelect, methodSelect].forEach(function (field) {
    field.addEventListener("input", calculateShipping);
    field.addEventListener("change", calculateShipping);
  });

  calculateShipping();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-eight-demo");
  if (!demo) return;

  const cartInput = demo.querySelector("[data-vb-calc-eight-cart]");
  const weightInput = demo.querySelector("[data-vb-calc-eight-weight]");
  const zoneSelect = demo.querySelector("[data-vb-calc-eight-zone]");
  const methodSelect = demo.querySelector("[data-vb-calc-eight-method]");
  const totalOutput = demo.querySelector("[data-vb-calc-eight-total]");
  const messageOutput = demo.querySelector("[data-vb-calc-eight-message]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    minimumFractionDigits: 2,
    maximumFractionDigits: 2
  });

  function calculateShipping() {
    const cartValue = Math.max(Number(cartInput.value) || 0, 0);
    const weight = Math.max(Number(weightInput.value) || 0, 0);
    const zoneMultiplier = Number(zoneSelect.value);
    const methodMultiplier = Number(methodSelect.value);

    if (cartValue &gt;= 150) {
      totalOutput.textContent = money.format(0);
      messageOutput.textContent = "Free shipping unlocked because the cart value is at least €150.";
      return;
    }

    const baseFee = 5.9;
    const weightFee = weight * 2.4;
    const shipping = (baseFee + weightFee) * zoneMultiplier * methodMultiplier;

    totalOutput.textContent = money.format(shipping);
    messageOutput.textContent = "Shipping includes base fee, weight fee, zone multiplier, and selected delivery method.";
  }

  [cartInput, weightInput, zoneSelect, methodSelect].forEach(function (field) {
    field.addEventListener("input", calculateShipping);
    field.addEventListener("change", calculateShipping);
  });

  calculateShipping();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-eight-demo"&gt;
  &lt;div class="vb-calc-eight-panel"&gt;
    &lt;div class="vb-calc-eight-header"&gt;
      &lt;span&gt;Example 08&lt;/span&gt;
      &lt;h3&gt;Shipping Cost Calculator&lt;/h3&gt;
      &lt;p&gt;Estimate delivery cost from cart value, parcel weight, shipping zone, and delivery method.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-eight-body"&gt;
      &lt;label&gt;
        Cart value
        &lt;input type="number" min="0" value="84" data-vb-calc-eight-cart&gt;
      &lt;/label&gt;

      &lt;label&gt;
        Package weight in kg
        &lt;input type="number" min="0.1" step="0.1" value="2.5" data-vb-calc-eight-weight&gt;
      &lt;/label&gt;

      &lt;label&gt;
        Shipping zone
        &lt;select data-vb-calc-eight-zone&gt;
          &lt;option value="1"&gt;Local zone&lt;/option&gt;
          &lt;option value="1.35"&gt;National zone&lt;/option&gt;
          &lt;option value="1.8"&gt;International zone&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;

      &lt;label&gt;
        Delivery method
        &lt;select data-vb-calc-eight-method&gt;
          &lt;option value="1"&gt;Standard delivery&lt;/option&gt;
          &lt;option value="1.75"&gt;Express delivery&lt;/option&gt;
          &lt;option value="2.4"&gt;Priority courier&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;

      &lt;div class="vb-calc-eight-result"&gt;
        &lt;span&gt;Shipping estimate&lt;/span&gt;
        &lt;strong data-vb-calc-eight-total&gt;€0.00&lt;/strong&gt;
        &lt;p data-vb-calc-eight-message&gt;Shipping cost updates automatically.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-eight-demo,
.vb-calc-eight-demo * {
  box-sizing: border-box;
}

.vb-calc-eight-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 16%, rgba(59, 130, 246, 0.18), transparent 32%),
    radial-gradient(circle at 86% 12%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #faf5ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.18);
}

.vb-calc-eight-panel {
  max-width: 1120px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-eight-header {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #172554 0%, #2563eb 52%, #7c3aed 100%) !important;
  background-size: 26px 26px, 26px 26px, auto !important;
}

.vb-calc-eight-header span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-eight-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 66px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-eight-header p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-eight-body {
  display: grid;
  gap: 15px;
  padding: clamp(22px, 4vw, 34px);
}

.vb-calc-eight-body label {
  display: grid;
  gap: 8px;
  color: #1e3a8a !important;
  -webkit-text-fill-color: #1e3a8a !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-eight-body input,
.vb-calc-eight-body select {
  width: 100%;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #bfdbfe;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-eight-result {
  margin-top: 4px;
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 18% 18%, rgba(59, 130, 246, 0.10), transparent 34%),
    linear-gradient(135deg, #eff6ff, #f5f3ff) !important;
  border: 1px solid #dbeafe;
}

.vb-calc-eight-result span {
  display: block;
  margin-bottom: 7px;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-eight-result strong {
  display: block;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: 44px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-calc-eight-result p {
  margin: 9px 0 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-eight-panel {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-eight-header h3 {
    font-size: 40px !important;
  }
}</pre>



<p class="wp-block-paragraph">This shipping cost calculator is useful for ecommerce checkout pages, delivery estimate tools, online stores, logistics websites, quote request forms, and product pages where customers want to estimate delivery cost before checkout.</p>



<h2 class="wp-block-heading">9. Quote Request Calculator</h2>



<p class="wp-block-paragraph"><strong>A quote request calculator</strong> is useful for service businesses, agencies, construction companies, repair services, cleaning companies, roofing websites, design studios, and local business landing pages. It helps users estimate a project cost before sending a request.</p>



<p class="wp-block-paragraph">This example uses package cards, selected service type, extras, urgency multiplier, and a dynamic estimate range. The JavaScript reads selected options, applies a multiplier, and returns both a low and high estimate instead of one fixed price.</p>



<ul class="wp-block-list">
<li>Service quote calculator</li>
<li>Clickable package cards</li>
<li>Extras and urgency multiplier</li>
<li>Estimated price range output</li>
<li>Lead generation calculator logic</li>
</ul>



<div class="vb-calc-nine-demo">
  <div class="vb-calc-nine-shell">
    <div class="vb-calc-nine-heading">
      <span>Example 09</span>
      <h3>Quote Request Calculator</h3>
      <p>Choose a service type, optional extras, and urgency level to generate a realistic project estimate range.</p>
    </div>

    <div class="vb-calc-nine-content">
      <div class="vb-calc-nine-services">
        <button type="button" class="is-selected" data-vb-calc-nine-service="450">
          <strong>Basic Service</strong>
          <span>Small request or simple task</span>
        </button>

        <button type="button" data-vb-calc-nine-service="950">
          <strong>Business Service</strong>
          <span>Medium project with more details</span>
        </button>

        <button type="button" data-vb-calc-nine-service="1800">
          <strong>Premium Project</strong>
          <span>Advanced work with custom logic</span>
        </button>
      </div>

      <div class="vb-calc-nine-options">
        <label>
          <input type="checkbox" value="180" data-vb-calc-nine-extra>
          Extra consultation
        </label>

        <label>
          <input type="checkbox" value="260" data-vb-calc-nine-extra>
          Priority support
        </label>

        <label>
          <input type="checkbox" value="340" data-vb-calc-nine-extra>
          Advanced setup
        </label>

        <label>
          Urgency level
          <select data-vb-calc-nine-urgency>
            <option value="1">Normal timeline</option>
            <option value="1.18">Fast delivery</option>
            <option value="1.35">Urgent request</option>
          </select>
        </label>
      </div>

      <div class="vb-calc-nine-result">
        <span>Estimated quote range</span>
        <strong data-vb-calc-nine-range>€0 - €0</strong>
        <p data-vb-calc-nine-summary>Select options to calculate a project range.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-nine-demo,
.vb-calc-nine-demo * {
  box-sizing: border-box;
}

.vb-calc-nine-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(99, 102, 241, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #f0f9ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.18);
}

.vb-calc-nine-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-nine-heading {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #312e81 0%, #4f46e5 54%, #0ea5e9 100%) !important;
}

.vb-calc-nine-heading span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-nine-heading h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 66px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-nine-heading p {
  max-width: 760px;
  margin: 0 !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-nine-content {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(280px, 0.8fr);
  gap: 22px;
  padding: clamp(22px, 4vw, 34px);
}

.vb-calc-nine-services,
.vb-calc-nine-options {
  display: grid;
  gap: 12px;
}

.vb-calc-nine-services button {
  width: 100%;
  padding: 18px;
  border: 1px solid #c7d2fe;
  border-radius: 20px;
  background: #f8fafc;
  text-align: left;
  cursor: pointer;
  transition: transform 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.vb-calc-nine-services button:hover {
  transform: translateY(-2px);
}

.vb-calc-nine-services button.is-selected {
  border-color: #4f46e5;
  background: linear-gradient(135deg, #eef2ff, #e0f2fe) !important;
  box-shadow: 0 16px 40px rgba(79, 70, 229, 0.12);
}

.vb-calc-nine-services strong {
  display: block;
  margin-bottom: 5px;
  color: #312e81 !important;
  -webkit-text-fill-color: #312e81 !important;
  font-size: 17px;
  font-weight: 950;
}

.vb-calc-nine-services span {
  display: block;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 650;
}

.vb-calc-nine-options {
  padding: 18px;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
}

.vb-calc-nine-options label {
  display: flex;
  align-items: center;
  gap: 10px;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-calc-nine-options label:has(select) {
  display: grid;
  gap: 8px;
}

.vb-calc-nine-options input {
  width: 18px;
  height: 18px;
  accent-color: #4f46e5;
}

.vb-calc-nine-options select {
  min-height: 48px;
  padding: 0 14px;
  border: 1px solid #c7d2fe;
  border-radius: 15px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 800;
}

.vb-calc-nine-result {
  grid-column: 1 / -1;
  padding: 22px;
  border-radius: 24px;
  background: linear-gradient(135deg, #eef2ff, #f0f9ff) !important;
  border: 1px solid #c7d2fe;
}

.vb-calc-nine-result span {
  display: block;
  margin-bottom: 8px;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-nine-result strong {
  display: block;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: clamp(34px, 5vw, 52px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-calc-nine-result p {
  margin: 9px 0 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-nine-content {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-nine-heading h3 {
    font-size: 40px !important;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-nine-demo");
  if (!demo) return;

  const serviceButtons = demo.querySelectorAll("[data-vb-calc-nine-service]");
  const extras = demo.querySelectorAll("[data-vb-calc-nine-extra]");
  const urgencySelect = demo.querySelector("[data-vb-calc-nine-urgency]");
  const rangeOutput = demo.querySelector("[data-vb-calc-nine-range]");
  const summaryOutput = demo.querySelector("[data-vb-calc-nine-summary]");

  let basePrice = 450;

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 0
  });

  function calculateQuote() {
    let extrasTotal = 0;
    let selectedExtras = 0;

    extras.forEach(function (extra) {
      if (extra.checked) {
        extrasTotal += Number(extra.value);
        selectedExtras += 1;
      }
    });

    const urgency = Number(urgencySelect.value);
    const estimatedBase = (basePrice + extrasTotal) * urgency;
    const lowEstimate = estimatedBase * 0.9;
    const highEstimate = estimatedBase * 1.18;

    rangeOutput.textContent = money.format(lowEstimate) + " - " + money.format(highEstimate);
    summaryOutput.textContent = selectedExtras + " extra option(s) selected. Estimate includes urgency multiplier and a realistic range buffer.";
  }

  serviceButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      basePrice = Number(button.dataset.vbCalcNineService);

      serviceButtons.forEach(function (item) {
        item.classList.remove("is-selected");
      });

      button.classList.add("is-selected");
      calculateQuote();
    });
  });

  extras.forEach(function (extra) {
    extra.addEventListener("change", calculateQuote);
  });

  urgencySelect.addEventListener("change", calculateQuote);

  calculateQuote();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-nine-demo");
  if (!demo) return;

  const serviceButtons = demo.querySelectorAll("[data-vb-calc-nine-service]");
  const extras = demo.querySelectorAll("[data-vb-calc-nine-extra]");
  const urgencySelect = demo.querySelector("[data-vb-calc-nine-urgency]");
  const rangeOutput = demo.querySelector("[data-vb-calc-nine-range]");
  const summaryOutput = demo.querySelector("[data-vb-calc-nine-summary]");

  let basePrice = 450;

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 0
  });

  function calculateQuote() {
    let extrasTotal = 0;
    let selectedExtras = 0;

    extras.forEach(function (extra) {
      if (extra.checked) {
        extrasTotal += Number(extra.value);
        selectedExtras += 1;
      }
    });

    const urgency = Number(urgencySelect.value);
    const estimatedBase = (basePrice + extrasTotal) * urgency;
    const lowEstimate = estimatedBase * 0.9;
    const highEstimate = estimatedBase * 1.18;

    rangeOutput.textContent = money.format(lowEstimate) + " - " + money.format(highEstimate);
    summaryOutput.textContent = selectedExtras + " extra option(s) selected. Estimate includes urgency multiplier and a realistic range buffer.";
  }

  serviceButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      basePrice = Number(button.dataset.vbCalcNineService);

      serviceButtons.forEach(function (item) {
        item.classList.remove("is-selected");
      });

      button.classList.add("is-selected");
      calculateQuote();
    });
  });

  extras.forEach(function (extra) {
    extra.addEventListener("change", calculateQuote);
  });

  urgencySelect.addEventListener("change", calculateQuote);

  calculateQuote();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-nine-demo"&gt;
  &lt;div class="vb-calc-nine-shell"&gt;
    &lt;div class="vb-calc-nine-heading"&gt;
      &lt;span&gt;Example 09&lt;/span&gt;
      &lt;h3&gt;Quote Request Calculator&lt;/h3&gt;
      &lt;p&gt;Choose a service type, optional extras, and urgency level to generate a realistic project estimate range.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-nine-content"&gt;
      &lt;div class="vb-calc-nine-services"&gt;
        &lt;button type="button" class="is-selected" data-vb-calc-nine-service="450"&gt;
          &lt;strong&gt;Basic Service&lt;/strong&gt;
          &lt;span&gt;Small request or simple task&lt;/span&gt;
        &lt;/button&gt;

        &lt;button type="button" data-vb-calc-nine-service="950"&gt;
          &lt;strong&gt;Business Service&lt;/strong&gt;
          &lt;span&gt;Medium project with more details&lt;/span&gt;
        &lt;/button&gt;

        &lt;button type="button" data-vb-calc-nine-service="1800"&gt;
          &lt;strong&gt;Premium Project&lt;/strong&gt;
          &lt;span&gt;Advanced work with custom logic&lt;/span&gt;
        &lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-nine-options"&gt;
        &lt;label&gt;
          &lt;input type="checkbox" value="180" data-vb-calc-nine-extra&gt;
          Extra consultation
        &lt;/label&gt;

        &lt;label&gt;
          &lt;input type="checkbox" value="260" data-vb-calc-nine-extra&gt;
          Priority support
        &lt;/label&gt;

        &lt;label&gt;
          &lt;input type="checkbox" value="340" data-vb-calc-nine-extra&gt;
          Advanced setup
        &lt;/label&gt;

        &lt;label&gt;
          Urgency level
          &lt;select data-vb-calc-nine-urgency&gt;
            &lt;option value="1"&gt;Normal timeline&lt;/option&gt;
            &lt;option value="1.18"&gt;Fast delivery&lt;/option&gt;
            &lt;option value="1.35"&gt;Urgent request&lt;/option&gt;
          &lt;/select&gt;
        &lt;/label&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-nine-result"&gt;
        &lt;span&gt;Estimated quote range&lt;/span&gt;
        &lt;strong data-vb-calc-nine-range&gt;€0 - €0&lt;/strong&gt;
        &lt;p data-vb-calc-nine-summary&gt;Select options to calculate a project range.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-nine-demo,
.vb-calc-nine-demo * {
  box-sizing: border-box;
}

.vb-calc-nine-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(99, 102, 241, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #f0f9ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.18);
}

.vb-calc-nine-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-nine-heading {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #312e81 0%, #4f46e5 54%, #0ea5e9 100%) !important;
}

.vb-calc-nine-heading span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-nine-heading h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 66px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-nine-heading p {
  max-width: 760px;
  margin: 0 !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-nine-content {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(280px, 0.8fr);
  gap: 22px;
  padding: clamp(22px, 4vw, 34px);
}

.vb-calc-nine-services,
.vb-calc-nine-options {
  display: grid;
  gap: 12px;
}

.vb-calc-nine-services button {
  width: 100%;
  padding: 18px;
  border: 1px solid #c7d2fe;
  border-radius: 20px;
  background: #f8fafc;
  text-align: left;
  cursor: pointer;
  transition: transform 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.vb-calc-nine-services button:hover {
  transform: translateY(-2px);
}

.vb-calc-nine-services button.is-selected {
  border-color: #4f46e5;
  background: linear-gradient(135deg, #eef2ff, #e0f2fe) !important;
  box-shadow: 0 16px 40px rgba(79, 70, 229, 0.12);
}

.vb-calc-nine-services strong {
  display: block;
  margin-bottom: 5px;
  color: #312e81 !important;
  -webkit-text-fill-color: #312e81 !important;
  font-size: 17px;
  font-weight: 950;
}

.vb-calc-nine-services span {
  display: block;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 650;
}

.vb-calc-nine-options {
  padding: 18px;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
}

.vb-calc-nine-options label {
  display: flex;
  align-items: center;
  gap: 10px;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-calc-nine-options label:has(select) {
  display: grid;
  gap: 8px;
}

.vb-calc-nine-options input {
  width: 18px;
  height: 18px;
  accent-color: #4f46e5;
}

.vb-calc-nine-options select {
  min-height: 48px;
  padding: 0 14px;
  border: 1px solid #c7d2fe;
  border-radius: 15px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 800;
}

.vb-calc-nine-result {
  grid-column: 1 / -1;
  padding: 22px;
  border-radius: 24px;
  background: linear-gradient(135deg, #eef2ff, #f0f9ff) !important;
  border: 1px solid #c7d2fe;
}

.vb-calc-nine-result span {
  display: block;
  margin-bottom: 8px;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-nine-result strong {
  display: block;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: clamp(34px, 5vw, 52px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-calc-nine-result p {
  margin: 9px 0 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-nine-content {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-nine-heading h3 {
    font-size: 40px !important;
  }
}</pre>



<p class="wp-block-paragraph">This quote request calculator is useful for agency websites, construction companies, roofing services, repair businesses, cleaning companies, service landing pages, and lead generation forms where users need an estimated price range before sending a request.</p>



<h2 class="wp-block-heading">10. Subscription Pricing Calculator</h2>



<p class="wp-block-paragraph"><strong>A subscription pricing calculator</strong> is useful for SaaS websites, membership platforms, software pricing pages, hosting services, online tools, and productized service websites. It helps users estimate monthly or yearly pricing based on plan, users, and billing cycle.</p>



<p class="wp-block-paragraph">This example uses plan selection cards, a monthly/yearly billing toggle, user quantity input, yearly discount logic, and a dynamic pricing summary. The JavaScript applies different pricing rules depending on the selected plan and billing mode.</p>



<ul class="wp-block-list">
<li>SaaS subscription pricing calculator</li>
<li>Monthly and yearly billing toggle</li>
<li>Clickable plan cards</li>
<li>User quantity pricing</li>
<li>Yearly discount calculation</li>
</ul>



<div class="vb-calc-ten-demo">
  <div class="vb-calc-ten-shell">
    <div class="vb-calc-ten-header">
      <span>Example 10</span>
      <h3>Subscription Pricing Calculator</h3>
      <p>Choose a plan, number of users, and billing cycle to calculate a SaaS subscription price.</p>
    </div>

    <div class="vb-calc-ten-body">
      <div class="vb-calc-ten-plans">
        <button type="button" class="is-selected" data-vb-calc-ten-plan="19" data-vb-calc-ten-name="Starter">
          <strong>Starter</strong>
          <span>€19 per user/month</span>
        </button>

        <button type="button" data-vb-calc-ten-plan="39" data-vb-calc-ten-name="Business">
          <strong>Business</strong>
          <span>€39 per user/month</span>
        </button>

        <button type="button" data-vb-calc-ten-plan="79" data-vb-calc-ten-name="Scale">
          <strong>Scale</strong>
          <span>€79 per user/month</span>
        </button>
      </div>

      <div class="vb-calc-ten-controls">
        <label>
          Team users
          <input type="number" min="1" value="6" data-vb-calc-ten-users>
        </label>

        <div class="vb-calc-ten-toggle">
          <button type="button" class="is-active" data-vb-calc-ten-billing="monthly">Monthly</button>
          <button type="button" data-vb-calc-ten-billing="yearly">Yearly - Save 20%</button>
        </div>

        <div class="vb-calc-ten-result">
          <span data-vb-calc-ten-plan-label>Starter plan</span>
          <strong data-vb-calc-ten-total>€0</strong>
          <p data-vb-calc-ten-summary>Subscription price updates automatically.</p>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-ten-demo,
.vb-calc-ten-demo * {
  box-sizing: border-box;
}

.vb-calc-ten-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(124, 58, 237, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(6, 182, 212, 0.16), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #ecfeff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(124, 58, 237, 0.18);
}

.vb-calc-ten-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-ten-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #3b0764 0%, #7c3aed 52%, #0891b2 100%) !important;
}

.vb-calc-ten-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #f3e8ff !important;
  -webkit-text-fill-color: #f3e8ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-ten-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 66px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-ten-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-ten-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 360px;
  gap: 22px;
  padding: clamp(22px, 4vw, 34px);
}

.vb-calc-ten-plans {
  display: grid;
  gap: 14px;
}

.vb-calc-ten-plans button {
  width: 100%;
  padding: 20px;
  border: 1px solid #ddd6fe;
  border-radius: 22px;
  background: #f8fafc;
  text-align: left;
  cursor: pointer;
  transition: transform 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.vb-calc-ten-plans button:hover {
  transform: translateY(-2px);
}

.vb-calc-ten-plans button.is-selected {
  border-color: #7c3aed;
  background: linear-gradient(135deg, #faf5ff, #ecfeff) !important;
  box-shadow: 0 16px 40px rgba(124, 58, 237, 0.12);
}

.vb-calc-ten-plans strong {
  display: block;
  margin-bottom: 6px;
  color: #4c1d95 !important;
  -webkit-text-fill-color: #4c1d95 !important;
  font-size: 20px;
  line-height: 1.1;
  font-weight: 950;
}

.vb-calc-ten-plans span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 700;
}

.vb-calc-ten-controls {
  display: grid;
  gap: 16px;
  padding: 18px;
  border-radius: 24px;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
}

.vb-calc-ten-controls label {
  display: grid;
  gap: 8px;
  color: #4c1d95 !important;
  -webkit-text-fill-color: #4c1d95 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-ten-controls input {
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #ddd6fe;
  border-radius: 16px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-ten-toggle {
  display: grid;
  gap: 8px;
}

.vb-calc-ten-toggle button {
  min-height: 46px;
  border: 1px solid #ddd6fe;
  border-radius: 999px;
  background: #ffffff;
  color: #5b21b6 !important;
  -webkit-text-fill-color: #5b21b6 !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-calc-ten-toggle button.is-active {
  border-color: transparent;
  background: linear-gradient(135deg, #7c3aed, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 14px 34px rgba(124, 58, 237, 0.22);
}

.vb-calc-ten-result {
  padding: 20px;
  border-radius: 22px;
  background: linear-gradient(135deg, #faf5ff, #ecfeff) !important;
  border: 1px solid #ddd6fe;
}

.vb-calc-ten-result span {
  display: block;
  margin-bottom: 8px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-ten-result strong {
  display: block;
  color: #5b21b6 !important;
  -webkit-text-fill-color: #5b21b6 !important;
  font-size: 46px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-calc-ten-result p {
  margin: 9px 0 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-ten-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-ten-header h3 {
    font-size: 40px !important;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-ten-demo");
  if (!demo) return;

  const planButtons = demo.querySelectorAll("[data-vb-calc-ten-plan]");
  const billingButtons = demo.querySelectorAll("[data-vb-calc-ten-billing]");
  const usersInput = demo.querySelector("[data-vb-calc-ten-users]");
  const planLabel = demo.querySelector("[data-vb-calc-ten-plan-label]");
  const totalOutput = demo.querySelector("[data-vb-calc-ten-total]");
  const summaryOutput = demo.querySelector("[data-vb-calc-ten-summary]");

  let planPrice = 19;
  let planName = "Starter";
  let billing = "monthly";

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 0
  });

  function calculateSubscription() {
    const users = Math.max(Number(usersInput.value) || 1, 1);
    const monthlyTotal = planPrice * users;

    if (billing === "monthly") {
      planLabel.textContent = planName + " plan";
      totalOutput.textContent = money.format(monthlyTotal) + "/mo";
      summaryOutput.textContent = users + " user(s) billed monthly with no yearly discount.";
      return;
    }

    const yearlyTotal = monthlyTotal * 12 * 0.8;

    planLabel.textContent = planName + " plan";
    totalOutput.textContent = money.format(yearlyTotal) + "/yr";
    summaryOutput.textContent = users + " user(s) billed yearly with a 20% discount applied.";
  }

  planButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      planPrice = Number(button.dataset.vbCalcTenPlan);
      planName = button.dataset.vbCalcTenName;

      planButtons.forEach(function (item) {
        item.classList.remove("is-selected");
      });

      button.classList.add("is-selected");
      calculateSubscription();
    });
  });

  billingButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      billing = button.dataset.vbCalcTenBilling;

      billingButtons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      calculateSubscription();
    });
  });

  usersInput.addEventListener("input", calculateSubscription);

  calculateSubscription();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-ten-demo");
  if (!demo) return;

  const planButtons = demo.querySelectorAll("[data-vb-calc-ten-plan]");
  const billingButtons = demo.querySelectorAll("[data-vb-calc-ten-billing]");
  const usersInput = demo.querySelector("[data-vb-calc-ten-users]");
  const planLabel = demo.querySelector("[data-vb-calc-ten-plan-label]");
  const totalOutput = demo.querySelector("[data-vb-calc-ten-total]");
  const summaryOutput = demo.querySelector("[data-vb-calc-ten-summary]");

  let planPrice = 19;
  let planName = "Starter";
  let billing = "monthly";

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 0
  });

  function calculateSubscription() {
    const users = Math.max(Number(usersInput.value) || 1, 1);
    const monthlyTotal = planPrice * users;

    if (billing === "monthly") {
      planLabel.textContent = planName + " plan";
      totalOutput.textContent = money.format(monthlyTotal) + "/mo";
      summaryOutput.textContent = users + " user(s) billed monthly with no yearly discount.";
      return;
    }

    const yearlyTotal = monthlyTotal * 12 * 0.8;

    planLabel.textContent = planName + " plan";
    totalOutput.textContent = money.format(yearlyTotal) + "/yr";
    summaryOutput.textContent = users + " user(s) billed yearly with a 20% discount applied.";
  }

  planButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      planPrice = Number(button.dataset.vbCalcTenPlan);
      planName = button.dataset.vbCalcTenName;

      planButtons.forEach(function (item) {
        item.classList.remove("is-selected");
      });

      button.classList.add("is-selected");
      calculateSubscription();
    });
  });

  billingButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      billing = button.dataset.vbCalcTenBilling;

      billingButtons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      calculateSubscription();
    });
  });

  usersInput.addEventListener("input", calculateSubscription);

  calculateSubscription();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-ten-demo"&gt;
  &lt;div class="vb-calc-ten-shell"&gt;
    &lt;div class="vb-calc-ten-header"&gt;
      &lt;span&gt;Example 10&lt;/span&gt;
      &lt;h3&gt;Subscription Pricing Calculator&lt;/h3&gt;
      &lt;p&gt;Choose a plan, number of users, and billing cycle to calculate a SaaS subscription price.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-ten-body"&gt;
      &lt;div class="vb-calc-ten-plans"&gt;
        &lt;button type="button" class="is-selected" data-vb-calc-ten-plan="19" data-vb-calc-ten-name="Starter"&gt;
          &lt;strong&gt;Starter&lt;/strong&gt;
          &lt;span&gt;€19 per user/month&lt;/span&gt;
        &lt;/button&gt;

        &lt;button type="button" data-vb-calc-ten-plan="39" data-vb-calc-ten-name="Business"&gt;
          &lt;strong&gt;Business&lt;/strong&gt;
          &lt;span&gt;€39 per user/month&lt;/span&gt;
        &lt;/button&gt;

        &lt;button type="button" data-vb-calc-ten-plan="79" data-vb-calc-ten-name="Scale"&gt;
          &lt;strong&gt;Scale&lt;/strong&gt;
          &lt;span&gt;€79 per user/month&lt;/span&gt;
        &lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-ten-controls"&gt;
        &lt;label&gt;
          Team users
          &lt;input type="number" min="1" value="6" data-vb-calc-ten-users&gt;
        &lt;/label&gt;

        &lt;div class="vb-calc-ten-toggle"&gt;
          &lt;button type="button" class="is-active" data-vb-calc-ten-billing="monthly"&gt;Monthly&lt;/button&gt;
          &lt;button type="button" data-vb-calc-ten-billing="yearly"&gt;Yearly - Save 20%&lt;/button&gt;
        &lt;/div&gt;

        &lt;div class="vb-calc-ten-result"&gt;
          &lt;span data-vb-calc-ten-plan-label&gt;Starter plan&lt;/span&gt;
          &lt;strong data-vb-calc-ten-total&gt;€0&lt;/strong&gt;
          &lt;p data-vb-calc-ten-summary&gt;Subscription price updates automatically.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-ten-demo,
.vb-calc-ten-demo * {
  box-sizing: border-box;
}

.vb-calc-ten-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(124, 58, 237, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(6, 182, 212, 0.16), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #ecfeff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(124, 58, 237, 0.18);
}

.vb-calc-ten-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-ten-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #3b0764 0%, #7c3aed 52%, #0891b2 100%) !important;
}

.vb-calc-ten-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #f3e8ff !important;
  -webkit-text-fill-color: #f3e8ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-ten-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 66px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-ten-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-ten-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 360px;
  gap: 22px;
  padding: clamp(22px, 4vw, 34px);
}

.vb-calc-ten-plans {
  display: grid;
  gap: 14px;
}

.vb-calc-ten-plans button {
  width: 100%;
  padding: 20px;
  border: 1px solid #ddd6fe;
  border-radius: 22px;
  background: #f8fafc;
  text-align: left;
  cursor: pointer;
  transition: transform 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.vb-calc-ten-plans button:hover {
  transform: translateY(-2px);
}

.vb-calc-ten-plans button.is-selected {
  border-color: #7c3aed;
  background: linear-gradient(135deg, #faf5ff, #ecfeff) !important;
  box-shadow: 0 16px 40px rgba(124, 58, 237, 0.12);
}

.vb-calc-ten-plans strong {
  display: block;
  margin-bottom: 6px;
  color: #4c1d95 !important;
  -webkit-text-fill-color: #4c1d95 !important;
  font-size: 20px;
  line-height: 1.1;
  font-weight: 950;
}

.vb-calc-ten-plans span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 700;
}

.vb-calc-ten-controls {
  display: grid;
  gap: 16px;
  padding: 18px;
  border-radius: 24px;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
}

.vb-calc-ten-controls label {
  display: grid;
  gap: 8px;
  color: #4c1d95 !important;
  -webkit-text-fill-color: #4c1d95 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-ten-controls input {
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #ddd6fe;
  border-radius: 16px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-ten-toggle {
  display: grid;
  gap: 8px;
}

.vb-calc-ten-toggle button {
  min-height: 46px;
  border: 1px solid #ddd6fe;
  border-radius: 999px;
  background: #ffffff;
  color: #5b21b6 !important;
  -webkit-text-fill-color: #5b21b6 !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-calc-ten-toggle button.is-active {
  border-color: transparent;
  background: linear-gradient(135deg, #7c3aed, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 14px 34px rgba(124, 58, 237, 0.22);
}

.vb-calc-ten-result {
  padding: 20px;
  border-radius: 22px;
  background: linear-gradient(135deg, #faf5ff, #ecfeff) !important;
  border: 1px solid #ddd6fe;
}

.vb-calc-ten-result span {
  display: block;
  margin-bottom: 8px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-ten-result strong {
  display: block;
  color: #5b21b6 !important;
  -webkit-text-fill-color: #5b21b6 !important;
  font-size: 46px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-calc-ten-result p {
  margin: 9px 0 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-ten-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-ten-header h3 {
    font-size: 40px !important;
  }
}</pre>



<p class="wp-block-paragraph">This subscription pricing calculator is useful for SaaS pricing pages, hosting websites, membership platforms, software tools, agency retainers, and productized services where users need to compare monthly and yearly pricing.</p>



<h2 class="wp-block-heading">11. ROI Calculator</h2>



<p class="wp-block-paragraph"><strong>An ROI calculator</strong> is useful for marketing websites, investment tools, SaaS landing pages, advertising dashboards, ecommerce campaigns, and business planning pages. It helps users calculate return on investment from revenue and cost values.</p>



<p class="wp-block-paragraph">This example uses investment cost, revenue generated, profit calculation, ROI percentage formula, dynamic positive or negative status, and visual result styling. The JavaScript changes the result message depending on whether the return is profitable or negative.</p>



<ul class="wp-block-list">
<li>Return on investment calculator</li>
<li>Revenue, cost, and profit calculation</li>
<li>ROI percentage formula</li>
<li>Positive or negative status state</li>
<li>Business and marketing calculator layout</li>
</ul>



<div class="vb-calc-eleven-demo">
  <div class="vb-calc-eleven-card">
    <div class="vb-calc-eleven-copy">
      <span>Example 11</span>
      <h3>ROI Calculator</h3>
      <p>Calculate profit and return on investment from campaign cost and generated revenue.</p>
    </div>

    <div class="vb-calc-eleven-tool">
      <label>
        Investment cost
        <input type="number" min="0" value="2500" data-vb-calc-eleven-cost>
      </label>

      <label>
        Revenue generated
        <input type="number" min="0" value="6800" data-vb-calc-eleven-revenue>
      </label>

      <div class="vb-calc-eleven-results" data-vb-calc-eleven-results>
        <div>
          <span>Profit</span>
          <strong data-vb-calc-eleven-profit>€0</strong>
        </div>

        <div>
          <span>ROI</span>
          <strong data-vb-calc-eleven-roi>0%</strong>
        </div>

        <p data-vb-calc-eleven-message>ROI result updates automatically.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-eleven-demo,
.vb-calc-eleven-demo * {
  box-sizing: border-box;
}

.vb-calc-eleven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 197, 94, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #eff6ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.18);
}

.vb-calc-eleven-card {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-calc-eleven-copy {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #052e16 0%, #16a34a 54%, #2563eb 100%) !important;
  box-shadow: 0 30px 90px rgba(22, 163, 74, 0.22);
}

.vb-calc-eleven-copy span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-eleven-copy h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(40px, 5.2vw, 70px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-eleven-copy p {
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-eleven-tool {
  display: grid;
  gap: 16px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-eleven-tool label {
  display: grid;
  gap: 8px;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-eleven-tool input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid #bbf7d0;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-eleven-results {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  padding: 18px;
  border-radius: 24px;
  background: #f0fdf4;
  border: 1px solid #bbf7d0;
}

.vb-calc-eleven-results.is-negative {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-calc-eleven-results div {
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.82);
}

.vb-calc-eleven-results span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-eleven-results strong {
  display: block;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 34px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-calc-eleven-results.is-negative strong {
  color: #dc2626 !important;
  -webkit-text-fill-color: #dc2626 !important;
}

.vb-calc-eleven-results p {
  grid-column: 1 / -1;
  margin: 0 !important;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 750;
}

.vb-calc-eleven-results.is-negative p {
  color: #991b1b !important;
  -webkit-text-fill-color: #991b1b !important;
}

@media (max-width: 900px) {
  .vb-calc-eleven-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-eleven-copy h3 {
    font-size: 42px !important;
  }

  .vb-calc-eleven-results {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-eleven-demo");
  if (!demo) return;

  const costInput = demo.querySelector("[data-vb-calc-eleven-cost]");
  const revenueInput = demo.querySelector("[data-vb-calc-eleven-revenue]");
  const resultsBox = demo.querySelector("[data-vb-calc-eleven-results]");
  const profitOutput = demo.querySelector("[data-vb-calc-eleven-profit]");
  const roiOutput = demo.querySelector("[data-vb-calc-eleven-roi]");
  const messageOutput = demo.querySelector("[data-vb-calc-eleven-message]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 0
  });

  function calculateRoi() {
    const cost = Math.max(Number(costInput.value) || 0, 0);
    const revenue = Math.max(Number(revenueInput.value) || 0, 0);

    if (cost === 0) {
      profitOutput.textContent = "€0";
      roiOutput.textContent = "0%";
      messageOutput.textContent = "Enter an investment cost greater than zero.";
      resultsBox.classList.remove("is-negative");
      return;
    }

    const profit = revenue - cost;
    const roi = (profit / cost) * 100;

    profitOutput.textContent = money.format(profit);
    roiOutput.textContent = roi.toFixed(1) + "%";

    if (profit < 0) {
      resultsBox.classList.add("is-negative");
      messageOutput.textContent = "The campaign is currently negative compared with the investment cost.";
    } else {
      resultsBox.classList.remove("is-negative");
      messageOutput.textContent = "The campaign returned more revenue than the original investment cost.";
    }
  }

  costInput.addEventListener("input", calculateRoi);
  revenueInput.addEventListener("input", calculateRoi);

  calculateRoi();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-eleven-demo");
  if (!demo) return;

  const costInput = demo.querySelector("[data-vb-calc-eleven-cost]");
  const revenueInput = demo.querySelector("[data-vb-calc-eleven-revenue]");
  const resultsBox = demo.querySelector("[data-vb-calc-eleven-results]");
  const profitOutput = demo.querySelector("[data-vb-calc-eleven-profit]");
  const roiOutput = demo.querySelector("[data-vb-calc-eleven-roi]");
  const messageOutput = demo.querySelector("[data-vb-calc-eleven-message]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 0
  });

  function calculateRoi() {
    const cost = Math.max(Number(costInput.value) || 0, 0);
    const revenue = Math.max(Number(revenueInput.value) || 0, 0);

    if (cost === 0) {
      profitOutput.textContent = "€0";
      roiOutput.textContent = "0%";
      messageOutput.textContent = "Enter an investment cost greater than zero.";
      resultsBox.classList.remove("is-negative");
      return;
    }

    const profit = revenue - cost;
    const roi = (profit / cost) * 100;

    profitOutput.textContent = money.format(profit);
    roiOutput.textContent = roi.toFixed(1) + "%";

    if (profit &lt; 0) {
      resultsBox.classList.add("is-negative");
      messageOutput.textContent = "The campaign is currently negative compared with the investment cost.";
    } else {
      resultsBox.classList.remove("is-negative");
      messageOutput.textContent = "The campaign returned more revenue than the original investment cost.";
    }
  }

  costInput.addEventListener("input", calculateRoi);
  revenueInput.addEventListener("input", calculateRoi);

  calculateRoi();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-eleven-demo"&gt;
  &lt;div class="vb-calc-eleven-card"&gt;
    &lt;div class="vb-calc-eleven-copy"&gt;
      &lt;span&gt;Example 11&lt;/span&gt;
      &lt;h3&gt;ROI Calculator&lt;/h3&gt;
      &lt;p&gt;Calculate profit and return on investment from campaign cost and generated revenue.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-eleven-tool"&gt;
      &lt;label&gt;
        Investment cost
        &lt;input type="number" min="0" value="2500" data-vb-calc-eleven-cost&gt;
      &lt;/label&gt;

      &lt;label&gt;
        Revenue generated
        &lt;input type="number" min="0" value="6800" data-vb-calc-eleven-revenue&gt;
      &lt;/label&gt;

      &lt;div class="vb-calc-eleven-results" data-vb-calc-eleven-results&gt;
        &lt;div&gt;
          &lt;span&gt;Profit&lt;/span&gt;
          &lt;strong data-vb-calc-eleven-profit&gt;€0&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;span&gt;ROI&lt;/span&gt;
          &lt;strong data-vb-calc-eleven-roi&gt;0%&lt;/strong&gt;
        &lt;/div&gt;

        &lt;p data-vb-calc-eleven-message&gt;ROI result updates automatically.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-eleven-demo,
.vb-calc-eleven-demo * {
  box-sizing: border-box;
}

.vb-calc-eleven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 197, 94, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #eff6ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.18);
}

.vb-calc-eleven-card {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-calc-eleven-copy {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #052e16 0%, #16a34a 54%, #2563eb 100%) !important;
  box-shadow: 0 30px 90px rgba(22, 163, 74, 0.22);
}

.vb-calc-eleven-copy span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-eleven-copy h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(40px, 5.2vw, 70px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-eleven-copy p {
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-eleven-tool {
  display: grid;
  gap: 16px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-eleven-tool label {
  display: grid;
  gap: 8px;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-eleven-tool input {
  width: 100%;
  min-height: 52px;
  padding: 0 14px;
  border: 1px solid #bbf7d0;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-eleven-results {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  padding: 18px;
  border-radius: 24px;
  background: #f0fdf4;
  border: 1px solid #bbf7d0;
}

.vb-calc-eleven-results.is-negative {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-calc-eleven-results div {
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.82);
}

.vb-calc-eleven-results span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-eleven-results strong {
  display: block;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 34px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-calc-eleven-results.is-negative strong {
  color: #dc2626 !important;
  -webkit-text-fill-color: #dc2626 !important;
}

.vb-calc-eleven-results p {
  grid-column: 1 / -1;
  margin: 0 !important;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 750;
}

.vb-calc-eleven-results.is-negative p {
  color: #991b1b !important;
  -webkit-text-fill-color: #991b1b !important;
}

@media (max-width: 900px) {
  .vb-calc-eleven-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-eleven-copy h3 {
    font-size: 42px !important;
  }

  .vb-calc-eleven-results {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This ROI calculator is useful for marketing agencies, ecommerce campaign pages, SaaS ROI pages, ad spend tools, investment calculators, startup landing pages, and business dashboards.</p>



<h2 class="wp-block-heading">12. Savings Goal Calculator</h2>



<p class="wp-block-paragraph"><strong>A savings goal calculator</strong> is useful for personal finance websites, banking tools, budgeting apps, student finance pages, investment blogs, and dashboard interfaces. It helps users estimate how long it will take to reach a financial goal.</p>



<p class="wp-block-paragraph">This example uses goal amount, current savings, monthly contribution, progress percentage, remaining amount, estimated months, and a visual progress bar. The JavaScript calculates both progress and time remaining from user inputs.</p>



<ul class="wp-block-list">
<li>Savings goal calculator</li>
<li>Current progress percentage</li>
<li>Remaining amount calculation</li>
<li>Estimated months to goal</li>
<li>Dynamic progress bar</li>
</ul>



<div class="vb-calc-twelve-demo">
  <div class="vb-calc-twelve-shell">
    <div class="vb-calc-twelve-left">
      <span>Example 12</span>
      <h3>Savings Goal Calculator</h3>
      <p>Estimate how much is left to save and how many months it will take to reach a financial goal.</p>

      <div class="vb-calc-twelve-progress">
        <div data-vb-calc-twelve-bar></div>
      </div>
    </div>

    <div class="vb-calc-twelve-right">
      <div class="vb-calc-twelve-fields">
        <label>
          Goal amount
          <input type="number" min="1" value="10000" data-vb-calc-twelve-goal>
        </label>

        <label>
          Current savings
          <input type="number" min="0" value="2600" data-vb-calc-twelve-current>
        </label>

        <label>
          Monthly saving
          <input type="number" min="1" value="450" data-vb-calc-twelve-monthly>
        </label>
      </div>

      <div class="vb-calc-twelve-results">
        <div>
          <span>Progress</span>
          <strong data-vb-calc-twelve-progress>0%</strong>
        </div>

        <div>
          <span>Remaining</span>
          <strong data-vb-calc-twelve-remaining>€0</strong>
        </div>

        <div>
          <span>Time needed</span>
          <strong data-vb-calc-twelve-months>0 months</strong>
        </div>
      </div>

      <p data-vb-calc-twelve-message>Goal estimate updates automatically.</p>
    </div>
  </div>
</div>

<style>
.vb-calc-twelve-demo,
.vb-calc-twelve-demo * {
  box-sizing: border-box;
}

.vb-calc-twelve-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 36px;
  background:
    radial-gradient(circle at 12% 16%, rgba(20, 184, 166, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(132, 204, 22, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdfa 0%, #f7fee7 54%, #ffffff 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.18);
}

.vb-calc-twelve-shell {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-calc-twelve-left,
.vb-calc-twelve-right {
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
}

.vb-calc-twelve-left {
  display: flex;
  flex-direction: column;
  justify-content: center;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #064e3b 0%, #0f766e 54%, #65a30d 100%) !important;
  box-shadow: 0 30px 90px rgba(15, 118, 110, 0.22);
}

.vb-calc-twelve-left span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-twelve-left h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5.2vw, 66px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-twelve-left p {
  margin: 0 0 24px !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-twelve-progress {
  height: 18px;
  overflow: hidden;
  border-radius: 999px;
  background: rgba(255,255,255,0.18);
}

.vb-calc-twelve-progress div {
  width: 0%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #bef264, #22c55e, #14b8a6);
  transition: width 0.25s ease;
}

.vb-calc-twelve-right {
  display: grid;
  gap: 16px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-twelve-fields {
  display: grid;
  gap: 14px;
}

.vb-calc-twelve-fields label {
  display: grid;
  gap: 8px;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-twelve-fields input {
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #bbf7d0;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-twelve-results {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-calc-twelve-results div {
  padding: 16px;
  border-radius: 18px;
  background: linear-gradient(135deg, #f0fdfa, #f7fee7) !important;
  border: 1px solid #bbf7d0;
}

.vb-calc-twelve-results span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-twelve-results strong {
  display: block;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 22px;
  line-height: 1.12;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-calc-twelve-right p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-twelve-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-twelve-left h3 {
    font-size: 40px !important;
  }

  .vb-calc-twelve-results {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-twelve-demo");
  if (!demo) return;

  const goalInput = demo.querySelector("[data-vb-calc-twelve-goal]");
  const currentInput = demo.querySelector("[data-vb-calc-twelve-current]");
  const monthlyInput = demo.querySelector("[data-vb-calc-twelve-monthly]");
  const bar = demo.querySelector("[data-vb-calc-twelve-bar]");
  const progressOutput = demo.querySelector("[data-vb-calc-twelve-progress]");
  const remainingOutput = demo.querySelector("[data-vb-calc-twelve-remaining]");
  const monthsOutput = demo.querySelector("[data-vb-calc-twelve-months]");
  const messageOutput = demo.querySelector("[data-vb-calc-twelve-message]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 0
  });

  function calculateSavings() {
    const goal = Math.max(Number(goalInput.value) || 0, 0);
    const current = Math.max(Number(currentInput.value) || 0, 0);
    const monthly = Math.max(Number(monthlyInput.value) || 0, 0);

    if (goal <= 0) {
      progressOutput.textContent = "0%";
      remainingOutput.textContent = "€0";
      monthsOutput.textContent = "0 months";
      bar.style.width = "0%";
      messageOutput.textContent = "Enter a savings goal greater than zero.";
      return;
    }

    const remaining = Math.max(goal - current, 0);
    const progress = Math.min((current / goal) * 100, 100);
    const months = monthly > 0 ? Math.ceil(remaining / monthly) : 0;

    progressOutput.textContent = progress.toFixed(1) + "%";
    remainingOutput.textContent = money.format(remaining);
    monthsOutput.textContent = remaining === 0 ? "Goal reached" : months + (months === 1 ? " month" : " months");
    bar.style.width = progress + "%";

    if (remaining === 0) {
      messageOutput.textContent = "Savings goal reached. You have already saved enough.";
    } else if (monthly === 0) {
      messageOutput.textContent = "Enter a monthly saving amount to estimate time needed.";
    } else {
      messageOutput.textContent = "At this pace, you can reach the goal in about " + months + " month(s).";
    }
  }

  [goalInput, currentInput, monthlyInput].forEach(function (field) {
    field.addEventListener("input", calculateSavings);
  });

  calculateSavings();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-twelve-demo");
  if (!demo) return;

  const goalInput = demo.querySelector("[data-vb-calc-twelve-goal]");
  const currentInput = demo.querySelector("[data-vb-calc-twelve-current]");
  const monthlyInput = demo.querySelector("[data-vb-calc-twelve-monthly]");
  const bar = demo.querySelector("[data-vb-calc-twelve-bar]");
  const progressOutput = demo.querySelector("[data-vb-calc-twelve-progress]");
  const remainingOutput = demo.querySelector("[data-vb-calc-twelve-remaining]");
  const monthsOutput = demo.querySelector("[data-vb-calc-twelve-months]");
  const messageOutput = demo.querySelector("[data-vb-calc-twelve-message]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 0
  });

  function calculateSavings() {
    const goal = Math.max(Number(goalInput.value) || 0, 0);
    const current = Math.max(Number(currentInput.value) || 0, 0);
    const monthly = Math.max(Number(monthlyInput.value) || 0, 0);

    if (goal &lt;= 0) {
      progressOutput.textContent = "0%";
      remainingOutput.textContent = "€0";
      monthsOutput.textContent = "0 months";
      bar.style.width = "0%";
      messageOutput.textContent = "Enter a savings goal greater than zero.";
      return;
    }

    const remaining = Math.max(goal - current, 0);
    const progress = Math.min((current / goal) * 100, 100);
    const months = monthly &gt; 0 ? Math.ceil(remaining / monthly) : 0;

    progressOutput.textContent = progress.toFixed(1) + "%";
    remainingOutput.textContent = money.format(remaining);
    monthsOutput.textContent = remaining === 0 ? "Goal reached" : months + (months === 1 ? " month" : " months");
    bar.style.width = progress + "%";

    if (remaining === 0) {
      messageOutput.textContent = "Savings goal reached. You have already saved enough.";
    } else if (monthly === 0) {
      messageOutput.textContent = "Enter a monthly saving amount to estimate time needed.";
    } else {
      messageOutput.textContent = "At this pace, you can reach the goal in about " + months + " month(s).";
    }
  }

  [goalInput, currentInput, monthlyInput].forEach(function (field) {
    field.addEventListener("input", calculateSavings);
  });

  calculateSavings();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-twelve-demo"&gt;
  &lt;div class="vb-calc-twelve-shell"&gt;
    &lt;div class="vb-calc-twelve-left"&gt;
      &lt;span&gt;Example 12&lt;/span&gt;
      &lt;h3&gt;Savings Goal Calculator&lt;/h3&gt;
      &lt;p&gt;Estimate how much is left to save and how many months it will take to reach a financial goal.&lt;/p&gt;

      &lt;div class="vb-calc-twelve-progress"&gt;
        &lt;div data-vb-calc-twelve-bar&gt;&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-twelve-right"&gt;
      &lt;div class="vb-calc-twelve-fields"&gt;
        &lt;label&gt;
          Goal amount
          &lt;input type="number" min="1" value="10000" data-vb-calc-twelve-goal&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Current savings
          &lt;input type="number" min="0" value="2600" data-vb-calc-twelve-current&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Monthly saving
          &lt;input type="number" min="1" value="450" data-vb-calc-twelve-monthly&gt;
        &lt;/label&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-twelve-results"&gt;
        &lt;div&gt;
          &lt;span&gt;Progress&lt;/span&gt;
          &lt;strong data-vb-calc-twelve-progress&gt;0%&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;span&gt;Remaining&lt;/span&gt;
          &lt;strong data-vb-calc-twelve-remaining&gt;€0&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;span&gt;Time needed&lt;/span&gt;
          &lt;strong data-vb-calc-twelve-months&gt;0 months&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;p data-vb-calc-twelve-message&gt;Goal estimate updates automatically.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-twelve-demo,
.vb-calc-twelve-demo * {
  box-sizing: border-box;
}

.vb-calc-twelve-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 36px;
  background:
    radial-gradient(circle at 12% 16%, rgba(20, 184, 166, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(132, 204, 22, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdfa 0%, #f7fee7 54%, #ffffff 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.18);
}

.vb-calc-twelve-shell {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-calc-twelve-left,
.vb-calc-twelve-right {
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
}

.vb-calc-twelve-left {
  display: flex;
  flex-direction: column;
  justify-content: center;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #064e3b 0%, #0f766e 54%, #65a30d 100%) !important;
  box-shadow: 0 30px 90px rgba(15, 118, 110, 0.22);
}

.vb-calc-twelve-left span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-twelve-left h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5.2vw, 66px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-twelve-left p {
  margin: 0 0 24px !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-twelve-progress {
  height: 18px;
  overflow: hidden;
  border-radius: 999px;
  background: rgba(255,255,255,0.18);
}

.vb-calc-twelve-progress div {
  width: 0%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, #bef264, #22c55e, #14b8a6);
  transition: width 0.25s ease;
}

.vb-calc-twelve-right {
  display: grid;
  gap: 16px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-twelve-fields {
  display: grid;
  gap: 14px;
}

.vb-calc-twelve-fields label {
  display: grid;
  gap: 8px;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-twelve-fields input {
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #bbf7d0;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-twelve-results {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-calc-twelve-results div {
  padding: 16px;
  border-radius: 18px;
  background: linear-gradient(135deg, #f0fdfa, #f7fee7) !important;
  border: 1px solid #bbf7d0;
}

.vb-calc-twelve-results span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-twelve-results strong {
  display: block;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 22px;
  line-height: 1.12;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-calc-twelve-right p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-twelve-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-twelve-left h3 {
    font-size: 40px !important;
  }

  .vb-calc-twelve-results {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This savings goal calculator is useful for personal finance blogs, bank websites, budgeting tools, savings apps, financial dashboards, student finance pages, and investment education websites.</p>



<h2 class="wp-block-heading">13. Calorie Calculator</h2>



<p class="wp-block-paragraph"><strong>A calorie calculator</strong> is useful for fitness websites, nutrition blogs, personal trainer pages, meal planning apps, health dashboards, and wellness tools. It helps users estimate daily calorie needs based on age, gender, height, weight, and activity level.</p>



<p class="wp-block-paragraph">This example uses the Mifflin-St Jeor style BMR formula, gender-based calculation logic, activity multipliers, input validation, and a daily calorie estimate. The JavaScript changes the result depending on selected gender and activity level.</p>



<ul class="wp-block-list">
<li>Daily calorie calculator</li>
<li>Gender-based BMR formula</li>
<li>Activity level multiplier</li>
<li>Input validation</li>
<li>Health and fitness calculator layout</li>
</ul>



<div class="vb-calc-thirteen-demo">
  <div class="vb-calc-thirteen-shell">
    <div class="vb-calc-thirteen-info">
      <span>Example 13</span>
      <h3>Calorie Calculator</h3>
      <p>Estimate daily calorie needs from body details and activity level using JavaScript formula logic.</p>
    </div>

    <div class="vb-calc-thirteen-tool">
      <div class="vb-calc-thirteen-grid">
        <label>
          Gender
          <select data-vb-calc-thirteen-gender>
            <option value="male">Male</option>
            <option value="female">Female</option>
          </select>
        </label>

        <label>
          Age
          <input type="number" min="10" max="100" value="32" data-vb-calc-thirteen-age>
        </label>

        <label>
          Height cm
          <input type="number" min="100" max="230" value="178" data-vb-calc-thirteen-height>
        </label>

        <label>
          Weight kg
          <input type="number" min="30" max="250" value="78" data-vb-calc-thirteen-weight>
        </label>
      </div>

      <label>
        Activity level
        <select data-vb-calc-thirteen-activity>
          <option value="1.2">Sedentary</option>
          <option value="1.375">Light activity</option>
          <option value="1.55" selected>Moderate activity</option>
          <option value="1.725">Very active</option>
          <option value="1.9">Athlete level</option>
        </select>
      </label>

      <div class="vb-calc-thirteen-result">
        <span>Estimated daily calories</span>
        <strong data-vb-calc-thirteen-calories>0 kcal</strong>
        <p data-vb-calc-thirteen-message>Calorie estimate updates automatically.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-thirteen-demo,
.vb-calc-thirteen-demo * {
  box-sizing: border-box;
}

.vb-calc-thirteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 36px;
  background:
    radial-gradient(circle at 12% 16%, rgba(249, 115, 22, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(249, 115, 22, 0.18);
}

.vb-calc-thirteen-shell {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-calc-thirteen-info {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 20% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #7c2d12 0%, #ea580c 52%, #16a34a 100%) !important;
  box-shadow: 0 30px 90px rgba(234, 88, 12, 0.22);
}

.vb-calc-thirteen-info span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-thirteen-info h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 5.2vw, 68px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-thirteen-info p {
  margin: 0 !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-thirteen-tool {
  display: grid;
  gap: 16px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-thirteen-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-calc-thirteen-tool label {
  display: grid;
  gap: 8px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-thirteen-tool input,
.vb-calc-thirteen-tool select {
  width: 100%;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #fed7aa;
  border-radius: 16px;
  background: #fff7ed;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-thirteen-result {
  padding: 22px;
  border-radius: 24px;
  background: linear-gradient(135deg, #fff7ed, #f0fdf4) !important;
  border: 1px solid #fed7aa;
}

.vb-calc-thirteen-result span {
  display: block;
  margin-bottom: 8px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-thirteen-result strong {
  display: block;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: clamp(36px, 5vw, 52px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-calc-thirteen-result p {
  margin: 9px 0 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-thirteen-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-thirteen-info h3 {
    font-size: 40px !important;
  }

  .vb-calc-thirteen-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-thirteen-demo");
  if (!demo) return;

  const genderInput = demo.querySelector("[data-vb-calc-thirteen-gender]");
  const ageInput = demo.querySelector("[data-vb-calc-thirteen-age]");
  const heightInput = demo.querySelector("[data-vb-calc-thirteen-height]");
  const weightInput = demo.querySelector("[data-vb-calc-thirteen-weight]");
  const activityInput = demo.querySelector("[data-vb-calc-thirteen-activity]");
  const caloriesOutput = demo.querySelector("[data-vb-calc-thirteen-calories]");
  const messageOutput = demo.querySelector("[data-vb-calc-thirteen-message]");

  function calculateCalories() {
    const gender = genderInput.value;
    const age = Number(ageInput.value);
    const height = Number(heightInput.value);
    const weight = Number(weightInput.value);
    const activity = Number(activityInput.value);

    if (age <= 0 || height <= 0 || weight <= 0) {
      caloriesOutput.textContent = "0 kcal";
      messageOutput.textContent = "Enter valid age, height, and weight values.";
      return;
    }

    let bmr;

    if (gender === "male") {
      bmr = 10 * weight + 6.25 * height - 5 * age + 5;
    } else {
      bmr = 10 * weight + 6.25 * height - 5 * age - 161;
    }

    const calories = Math.round(bmr * activity);

    caloriesOutput.textContent = calories.toLocaleString("en-US") + " kcal";
    messageOutput.textContent = "Estimated maintenance calories based on selected activity level.";
  }

  [genderInput, ageInput, heightInput, weightInput, activityInput].forEach(function (field) {
    field.addEventListener("input", calculateCalories);
    field.addEventListener("change", calculateCalories);
  });

  calculateCalories();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-thirteen-demo");
  if (!demo) return;

  const genderInput = demo.querySelector("[data-vb-calc-thirteen-gender]");
  const ageInput = demo.querySelector("[data-vb-calc-thirteen-age]");
  const heightInput = demo.querySelector("[data-vb-calc-thirteen-height]");
  const weightInput = demo.querySelector("[data-vb-calc-thirteen-weight]");
  const activityInput = demo.querySelector("[data-vb-calc-thirteen-activity]");
  const caloriesOutput = demo.querySelector("[data-vb-calc-thirteen-calories]");
  const messageOutput = demo.querySelector("[data-vb-calc-thirteen-message]");

  function calculateCalories() {
    const gender = genderInput.value;
    const age = Number(ageInput.value);
    const height = Number(heightInput.value);
    const weight = Number(weightInput.value);
    const activity = Number(activityInput.value);

    if (age &lt;= 0 || height &lt;= 0 || weight &lt;= 0) {
      caloriesOutput.textContent = "0 kcal";
      messageOutput.textContent = "Enter valid age, height, and weight values.";
      return;
    }

    let bmr;

    if (gender === "male") {
      bmr = 10 * weight + 6.25 * height - 5 * age + 5;
    } else {
      bmr = 10 * weight + 6.25 * height - 5 * age - 161;
    }

    const calories = Math.round(bmr * activity);

    caloriesOutput.textContent = calories.toLocaleString("en-US") + " kcal";
    messageOutput.textContent = "Estimated maintenance calories based on selected activity level.";
  }

  [genderInput, ageInput, heightInput, weightInput, activityInput].forEach(function (field) {
    field.addEventListener("input", calculateCalories);
    field.addEventListener("change", calculateCalories);
  });

  calculateCalories();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-thirteen-demo"&gt;
  &lt;div class="vb-calc-thirteen-shell"&gt;
    &lt;div class="vb-calc-thirteen-info"&gt;
      &lt;span&gt;Example 13&lt;/span&gt;
      &lt;h3&gt;Calorie Calculator&lt;/h3&gt;
      &lt;p&gt;Estimate daily calorie needs from body details and activity level using JavaScript formula logic.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-thirteen-tool"&gt;
      &lt;div class="vb-calc-thirteen-grid"&gt;
        &lt;label&gt;
          Gender
          &lt;select data-vb-calc-thirteen-gender&gt;
            &lt;option value="male"&gt;Male&lt;/option&gt;
            &lt;option value="female"&gt;Female&lt;/option&gt;
          &lt;/select&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Age
          &lt;input type="number" min="10" max="100" value="32" data-vb-calc-thirteen-age&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Height cm
          &lt;input type="number" min="100" max="230" value="178" data-vb-calc-thirteen-height&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Weight kg
          &lt;input type="number" min="30" max="250" value="78" data-vb-calc-thirteen-weight&gt;
        &lt;/label&gt;
      &lt;/div&gt;

      &lt;label&gt;
        Activity level
        &lt;select data-vb-calc-thirteen-activity&gt;
          &lt;option value="1.2"&gt;Sedentary&lt;/option&gt;
          &lt;option value="1.375"&gt;Light activity&lt;/option&gt;
          &lt;option value="1.55" selected&gt;Moderate activity&lt;/option&gt;
          &lt;option value="1.725"&gt;Very active&lt;/option&gt;
          &lt;option value="1.9"&gt;Athlete level&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;

      &lt;div class="vb-calc-thirteen-result"&gt;
        &lt;span&gt;Estimated daily calories&lt;/span&gt;
        &lt;strong data-vb-calc-thirteen-calories&gt;0 kcal&lt;/strong&gt;
        &lt;p data-vb-calc-thirteen-message&gt;Calorie estimate updates automatically.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-thirteen-demo,
.vb-calc-thirteen-demo * {
  box-sizing: border-box;
}

.vb-calc-thirteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 36px;
  background:
    radial-gradient(circle at 12% 16%, rgba(249, 115, 22, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(249, 115, 22, 0.18);
}

.vb-calc-thirteen-shell {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-calc-thirteen-info {
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 20% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #7c2d12 0%, #ea580c 52%, #16a34a 100%) !important;
  box-shadow: 0 30px 90px rgba(234, 88, 12, 0.22);
}

.vb-calc-thirteen-info span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-thirteen-info h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 5.2vw, 68px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-thirteen-info p {
  margin: 0 !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-thirteen-tool {
  display: grid;
  gap: 16px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-thirteen-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-calc-thirteen-tool label {
  display: grid;
  gap: 8px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-thirteen-tool input,
.vb-calc-thirteen-tool select {
  width: 100%;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #fed7aa;
  border-radius: 16px;
  background: #fff7ed;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-thirteen-result {
  padding: 22px;
  border-radius: 24px;
  background: linear-gradient(135deg, #fff7ed, #f0fdf4) !important;
  border: 1px solid #fed7aa;
}

.vb-calc-thirteen-result span {
  display: block;
  margin-bottom: 8px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-thirteen-result strong {
  display: block;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: clamp(36px, 5vw, 52px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-calc-thirteen-result p {
  margin: 9px 0 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-thirteen-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-thirteen-info h3 {
    font-size: 40px !important;
  }

  .vb-calc-thirteen-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This calorie calculator is useful for fitness websites, nutrition blogs, meal planning tools, personal trainer pages, wellness dashboards, and health-focused JavaScript calculator projects.</p>



<h2 class="wp-block-heading">14. Water Intake Calculator</h2>



<p class="wp-block-paragraph"><strong>A water intake calculator</strong> is useful for health websites, fitness apps, wellness blogs, nutrition tools, habit trackers, and personal dashboards. It helps users estimate daily water intake based on weight, activity time, and climate conditions.</p>



<p class="wp-block-paragraph">This example uses weight-based hydration logic, extra water for exercise, a hot climate option, liters and cups output, and dynamic recommendation text. The JavaScript combines several conditions into a simple wellness calculator.</p>



<ul class="wp-block-list">
<li>Daily water intake calculator</li>
<li>Weight-based hydration estimate</li>
<li>Exercise time adjustment</li>
<li>Hot climate checkbox</li>
<li>Liters and cups output</li>
</ul>



<div class="vb-calc-fourteen-demo">
  <div class="vb-calc-fourteen-card">
    <div class="vb-calc-fourteen-visual">
      <span>Example 14</span>
      <h3>Water Intake Calculator</h3>
      <p>Estimate daily hydration needs from weight, activity time, and climate conditions.</p>
      <div class="vb-calc-fourteen-water">
        <div data-vb-calc-fourteen-fill></div>
      </div>
    </div>

    <div class="vb-calc-fourteen-tool">
      <label>
        Body weight kg
        <input type="number" min="20" max="250" value="82" data-vb-calc-fourteen-weight>
      </label>

      <label>
        Exercise minutes per day
        <input type="number" min="0" max="300" value="45" data-vb-calc-fourteen-exercise>
      </label>

      <label class="vb-calc-fourteen-check">
        <input type="checkbox" data-vb-calc-fourteen-climate>
        Hot climate or heavy sweating
      </label>

      <div class="vb-calc-fourteen-result">
        <div>
          <span>Liters per day</span>
          <strong data-vb-calc-fourteen-liters>0 L</strong>
        </div>

        <div>
          <span>Approx. cups</span>
          <strong data-vb-calc-fourteen-cups>0 cups</strong>
        </div>

        <p data-vb-calc-fourteen-message>Hydration estimate updates automatically.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-fourteen-demo,
.vb-calc-fourteen-demo * {
  box-sizing: border-box;
}

.vb-calc-fourteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 36px;
  background:
    radial-gradient(circle at 12% 16%, rgba(14, 165, 233, 0.20), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(6, 182, 212, 0.18), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #ecfeff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
}

.vb-calc-fourteen-card {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-calc-fourteen-visual,
.vb-calc-fourteen-tool {
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
}

.vb-calc-fourteen-visual {
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.20), transparent 34%),
    linear-gradient(135deg, #083344 0%, #0284c7 52%, #06b6d4 100%) !important;
  box-shadow: 0 30px 90px rgba(2, 132, 199, 0.22);
}

.vb-calc-fourteen-visual span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #cffafe !important;
  -webkit-text-fill-color: #cffafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-fourteen-visual h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5.2vw, 66px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-fourteen-visual p {
  margin: 0 0 24px !important;
  color: #cffafe !important;
  -webkit-text-fill-color: #cffafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-fourteen-water {
  height: 130px;
  overflow: hidden;
  border-radius: 28px;
  background: rgba(255,255,255,0.16);
  border: 1px solid rgba(255,255,255,0.18);
  position: relative;
}

.vb-calc-fourteen-water div {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 40%;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.20), transparent),
    linear-gradient(135deg, #67e8f9, #0ea5e9);
  transition: height 0.25s ease;
}

.vb-calc-fourteen-tool {
  display: grid;
  gap: 16px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-fourteen-tool label {
  display: grid;
  gap: 8px;
  color: #075985 !important;
  -webkit-text-fill-color: #075985 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-fourteen-tool input[type="number"] {
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #bae6fd;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-fourteen-check {
  display: flex !important;
  align-items: center;
  gap: 10px !important;
  padding: 14px;
  border-radius: 18px;
  background: #f0f9ff;
  border: 1px solid #bae6fd;
}

.vb-calc-fourteen-check input {
  width: 18px;
  height: 18px;
  accent-color: #0284c7;
}

.vb-calc-fourteen-result {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  padding: 18px;
  border-radius: 24px;
  background: linear-gradient(135deg, #f0f9ff, #ecfeff) !important;
  border: 1px solid #bae6fd;
}

.vb-calc-fourteen-result div {
  padding: 15px;
  border-radius: 18px;
  background: rgba(255,255,255,0.82);
}

.vb-calc-fourteen-result span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-fourteen-result strong {
  display: block;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 30px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-calc-fourteen-result p {
  grid-column: 1 / -1;
  margin: 0 !important;
  color: #075985 !important;
  -webkit-text-fill-color: #075985 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 750;
}

@media (max-width: 900px) {
  .vb-calc-fourteen-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-fourteen-visual h3 {
    font-size: 40px !important;
  }

  .vb-calc-fourteen-result {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-fourteen-demo");
  if (!demo) return;

  const weightInput = demo.querySelector("[data-vb-calc-fourteen-weight]");
  const exerciseInput = demo.querySelector("[data-vb-calc-fourteen-exercise]");
  const climateInput = demo.querySelector("[data-vb-calc-fourteen-climate]");
  const litersOutput = demo.querySelector("[data-vb-calc-fourteen-liters]");
  const cupsOutput = demo.querySelector("[data-vb-calc-fourteen-cups]");
  const messageOutput = demo.querySelector("[data-vb-calc-fourteen-message]");
  const fill = demo.querySelector("[data-vb-calc-fourteen-fill]");

  function calculateWater() {
    const weight = Math.max(Number(weightInput.value) || 0, 0);
    const exercise = Math.max(Number(exerciseInput.value) || 0, 0);
    const climateBonus = climateInput.checked ? 0.5 : 0;

    if (weight <= 0) {
      litersOutput.textContent = "0 L";
      cupsOutput.textContent = "0 cups";
      messageOutput.textContent = "Enter a valid body weight.";
      fill.style.height = "0%";
      return;
    }

    const baseLiters = weight * 0.033;
    const exerciseLiters = exercise * 0.012;
    const totalLiters = baseLiters + exerciseLiters + climateBonus;
    const cups = totalLiters / 0.24;
    const fillHeight = Math.min((totalLiters / 5) * 100, 100);

    litersOutput.textContent = totalLiters.toFixed(1) + " L";
    cupsOutput.textContent = Math.round(cups) + " cups";
    fill.style.height = fillHeight + "%";
    messageOutput.textContent = "Estimate includes weight, exercise minutes, and optional climate adjustment.";
  }

  [weightInput, exerciseInput, climateInput].forEach(function (field) {
    field.addEventListener("input", calculateWater);
    field.addEventListener("change", calculateWater);
  });

  calculateWater();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-fourteen-demo");
  if (!demo) return;

  const weightInput = demo.querySelector("[data-vb-calc-fourteen-weight]");
  const exerciseInput = demo.querySelector("[data-vb-calc-fourteen-exercise]");
  const climateInput = demo.querySelector("[data-vb-calc-fourteen-climate]");
  const litersOutput = demo.querySelector("[data-vb-calc-fourteen-liters]");
  const cupsOutput = demo.querySelector("[data-vb-calc-fourteen-cups]");
  const messageOutput = demo.querySelector("[data-vb-calc-fourteen-message]");
  const fill = demo.querySelector("[data-vb-calc-fourteen-fill]");

  function calculateWater() {
    const weight = Math.max(Number(weightInput.value) || 0, 0);
    const exercise = Math.max(Number(exerciseInput.value) || 0, 0);
    const climateBonus = climateInput.checked ? 0.5 : 0;

    if (weight &lt;= 0) {
      litersOutput.textContent = "0 L";
      cupsOutput.textContent = "0 cups";
      messageOutput.textContent = "Enter a valid body weight.";
      fill.style.height = "0%";
      return;
    }

    const baseLiters = weight * 0.033;
    const exerciseLiters = exercise * 0.012;
    const totalLiters = baseLiters + exerciseLiters + climateBonus;
    const cups = totalLiters / 0.24;
    const fillHeight = Math.min((totalLiters / 5) * 100, 100);

    litersOutput.textContent = totalLiters.toFixed(1) + " L";
    cupsOutput.textContent = Math.round(cups) + " cups";
    fill.style.height = fillHeight + "%";
    messageOutput.textContent = "Estimate includes weight, exercise minutes, and optional climate adjustment.";
  }

  [weightInput, exerciseInput, climateInput].forEach(function (field) {
    field.addEventListener("input", calculateWater);
    field.addEventListener("change", calculateWater);
  });

  calculateWater();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-fourteen-demo"&gt;
  &lt;div class="vb-calc-fourteen-card"&gt;
    &lt;div class="vb-calc-fourteen-visual"&gt;
      &lt;span&gt;Example 14&lt;/span&gt;
      &lt;h3&gt;Water Intake Calculator&lt;/h3&gt;
      &lt;p&gt;Estimate daily hydration needs from weight, activity time, and climate conditions.&lt;/p&gt;
      &lt;div class="vb-calc-fourteen-water"&gt;
        &lt;div data-vb-calc-fourteen-fill&gt;&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-fourteen-tool"&gt;
      &lt;label&gt;
        Body weight kg
        &lt;input type="number" min="20" max="250" value="82" data-vb-calc-fourteen-weight&gt;
      &lt;/label&gt;

      &lt;label&gt;
        Exercise minutes per day
        &lt;input type="number" min="0" max="300" value="45" data-vb-calc-fourteen-exercise&gt;
      &lt;/label&gt;

      &lt;label class="vb-calc-fourteen-check"&gt;
        &lt;input type="checkbox" data-vb-calc-fourteen-climate&gt;
        Hot climate or heavy sweating
      &lt;/label&gt;

      &lt;div class="vb-calc-fourteen-result"&gt;
        &lt;div&gt;
          &lt;span&gt;Liters per day&lt;/span&gt;
          &lt;strong data-vb-calc-fourteen-liters&gt;0 L&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;span&gt;Approx. cups&lt;/span&gt;
          &lt;strong data-vb-calc-fourteen-cups&gt;0 cups&lt;/strong&gt;
        &lt;/div&gt;

        &lt;p data-vb-calc-fourteen-message&gt;Hydration estimate updates automatically.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-fourteen-demo,
.vb-calc-fourteen-demo * {
  box-sizing: border-box;
}

.vb-calc-fourteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 36px;
  background:
    radial-gradient(circle at 12% 16%, rgba(14, 165, 233, 0.20), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(6, 182, 212, 0.18), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #ecfeff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
}

.vb-calc-fourteen-card {
  display: grid;
  grid-template-columns: minmax(0, 0.92fr) minmax(0, 1.08fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-calc-fourteen-visual,
.vb-calc-fourteen-tool {
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
}

.vb-calc-fourteen-visual {
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.20), transparent 34%),
    linear-gradient(135deg, #083344 0%, #0284c7 52%, #06b6d4 100%) !important;
  box-shadow: 0 30px 90px rgba(2, 132, 199, 0.22);
}

.vb-calc-fourteen-visual span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #cffafe !important;
  -webkit-text-fill-color: #cffafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-fourteen-visual h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5.2vw, 66px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-fourteen-visual p {
  margin: 0 0 24px !important;
  color: #cffafe !important;
  -webkit-text-fill-color: #cffafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-fourteen-water {
  height: 130px;
  overflow: hidden;
  border-radius: 28px;
  background: rgba(255,255,255,0.16);
  border: 1px solid rgba(255,255,255,0.18);
  position: relative;
}

.vb-calc-fourteen-water div {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 40%;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.20), transparent),
    linear-gradient(135deg, #67e8f9, #0ea5e9);
  transition: height 0.25s ease;
}

.vb-calc-fourteen-tool {
  display: grid;
  gap: 16px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-fourteen-tool label {
  display: grid;
  gap: 8px;
  color: #075985 !important;
  -webkit-text-fill-color: #075985 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-fourteen-tool input[type="number"] {
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #bae6fd;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-fourteen-check {
  display: flex !important;
  align-items: center;
  gap: 10px !important;
  padding: 14px;
  border-radius: 18px;
  background: #f0f9ff;
  border: 1px solid #bae6fd;
}

.vb-calc-fourteen-check input {
  width: 18px;
  height: 18px;
  accent-color: #0284c7;
}

.vb-calc-fourteen-result {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  padding: 18px;
  border-radius: 24px;
  background: linear-gradient(135deg, #f0f9ff, #ecfeff) !important;
  border: 1px solid #bae6fd;
}

.vb-calc-fourteen-result div {
  padding: 15px;
  border-radius: 18px;
  background: rgba(255,255,255,0.82);
}

.vb-calc-fourteen-result span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-fourteen-result strong {
  display: block;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 30px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-calc-fourteen-result p {
  grid-column: 1 / -1;
  margin: 0 !important;
  color: #075985 !important;
  -webkit-text-fill-color: #075985 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 750;
}

@media (max-width: 900px) {
  .vb-calc-fourteen-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-fourteen-visual h3 {
    font-size: 40px !important;
  }

  .vb-calc-fourteen-result {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This water intake calculator is useful for wellness blogs, fitness apps, habit trackers, personal dashboards, nutrition websites, health tools, and lifestyle JavaScript calculator examples.</p>



<h2 class="wp-block-heading">15. Unit Converter Calculator</h2>



<p class="wp-block-paragraph"><strong>A unit converter calculator</strong> is useful for educational websites, utility tools, ecommerce product pages, measurement guides, recipe websites, engineering pages, and everyday calculator apps. It helps users convert values between common units quickly.</p>



<p class="wp-block-paragraph">This example uses a reusable JavaScript conversion object, unit dropdowns, category switching, live result updates, and number formatting. The calculator changes available units when the user selects a different conversion category.</p>



<ul class="wp-block-list">
<li>Reusable unit converter calculator</li>
<li>Length, weight, and temperature categories</li>
<li>Dynamic unit dropdowns</li>
<li>Conversion object in JavaScript</li>
<li>Live formatted result output</li>
</ul>



<div class="vb-calc-fifteen-demo">
  <div class="vb-calc-fifteen-shell">
    <div class="vb-calc-fifteen-header">
      <span>Example 15</span>
      <h3>Unit Converter Calculator</h3>
      <p>Convert length, weight, and temperature values with dynamic JavaScript conversion logic.</p>
    </div>

    <div class="vb-calc-fifteen-tool">
      <label>
        Conversion category
        <select data-vb-calc-fifteen-category>
          <option value="length">Length</option>
          <option value="weight">Weight</option>
          <option value="temperature">Temperature</option>
        </select>
      </label>

      <div class="vb-calc-fifteen-row">
        <label>
          Value
          <input type="number" value="10" data-vb-calc-fifteen-value>
        </label>

        <label>
          From
          <select data-vb-calc-fifteen-from></select>
        </label>

        <label>
          To
          <select data-vb-calc-fifteen-to></select>
        </label>
      </div>

      <div class="vb-calc-fifteen-result">
        <span>Converted result</span>
        <strong data-vb-calc-fifteen-result>0</strong>
        <p data-vb-calc-fifteen-message>Choose units to convert the value.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-fifteen-demo,
.vb-calc-fifteen-demo * {
  box-sizing: border-box;
}

.vb-calc-fifteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(99, 102, 241, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(20, 184, 166, 0.16), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #f0fdfa 54%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.18);
}

.vb-calc-fifteen-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-fifteen-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #312e81 0%, #4f46e5 52%, #0f766e 100%) !important;
  background-size: 26px 26px, 26px 26px, auto !important;
}

.vb-calc-fifteen-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-fifteen-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 66px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-fifteen-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-fifteen-tool {
  display: grid;
  gap: 16px;
  padding: clamp(22px, 4vw, 34px);
}

.vb-calc-fifteen-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.8fr) minmax(0, 0.8fr);
  gap: 14px;
}

.vb-calc-fifteen-tool label {
  display: grid;
  gap: 8px;
  color: #312e81 !important;
  -webkit-text-fill-color: #312e81 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-fifteen-tool input,
.vb-calc-fifteen-tool select {
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #c7d2fe;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-fifteen-result {
  padding: 22px;
  border-radius: 24px;
  background: linear-gradient(135deg, #eef2ff, #f0fdfa) !important;
  border: 1px solid #c7d2fe;
}

.vb-calc-fifteen-result span {
  display: block;
  margin-bottom: 8px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-fifteen-result strong {
  display: block;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: clamp(34px, 5vw, 52px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-calc-fifteen-result p {
  margin: 9px 0 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-fifteen-row {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-fifteen-header h3 {
    font-size: 40px !important;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-fifteen-demo");
  if (!demo) return;

  const categoryInput = demo.querySelector("[data-vb-calc-fifteen-category]");
  const valueInput = demo.querySelector("[data-vb-calc-fifteen-value]");
  const fromInput = demo.querySelector("[data-vb-calc-fifteen-from]");
  const toInput = demo.querySelector("[data-vb-calc-fifteen-to]");
  const resultOutput = demo.querySelector("[data-vb-calc-fifteen-result]");
  const messageOutput = demo.querySelector("[data-vb-calc-fifteen-message]");

  const units = {
    length: {
      meter: 1,
      kilometer: 1000,
      centimeter: 0.01,
      mile: 1609.34,
      foot: 0.3048
    },
    weight: {
      kilogram: 1,
      gram: 0.001,
      pound: 0.453592,
      ounce: 0.0283495
    },
    temperature: {
      celsius: "c",
      fahrenheit: "f",
      kelvin: "k"
    }
  };

  function toTitle(text) {
    return text.charAt(0).toUpperCase() + text.slice(1);
  }

  function fillUnitOptions() {
    const category = categoryInput.value;
    const keys = Object.keys(units[category]);

    fromInput.innerHTML = "";
    toInput.innerHTML = "";

    keys.forEach(function (unit, index) {
      const fromOption = document.createElement("option");
      const toOption = document.createElement("option");

      fromOption.value = unit;
      fromOption.textContent = toTitle(unit);

      toOption.value = unit;
      toOption.textContent = toTitle(unit);

      fromInput.appendChild(fromOption);
      toInput.appendChild(toOption);

      if (index === 1) {
        toOption.selected = true;
      }
    });

    calculateConversion();
  }

  function convertTemperature(value, from, to) {
    let celsius;

    if (from === "celsius") celsius = value;
    if (from === "fahrenheit") celsius = (value - 32) * 5 / 9;
    if (from === "kelvin") celsius = value - 273.15;

    if (to === "celsius") return celsius;
    if (to === "fahrenheit") return celsius * 9 / 5 + 32;
    if (to === "kelvin") return celsius + 273.15;

    return value;
  }

  function calculateConversion() {
    const category = categoryInput.value;
    const value = Number(valueInput.value);
    const from = fromInput.value;
    const to = toInput.value;

    if (Number.isNaN(value)) {
      resultOutput.textContent = "0";
      messageOutput.textContent = "Enter a valid number.";
      return;
    }

    let result;

    if (category === "temperature") {
      result = convertTemperature(value, from, to);
    } else {
      const baseValue = value * units[category][from];
      result = baseValue / units[category][to];
    }

    resultOutput.textContent = Number(result.toFixed(4)).toLocaleString("en-US") + " " + toTitle(to);
    messageOutput.textContent = "Converted from " + toTitle(from) + " to " + toTitle(to) + ".";
  }

  categoryInput.addEventListener("change", fillUnitOptions);
  valueInput.addEventListener("input", calculateConversion);
  fromInput.addEventListener("change", calculateConversion);
  toInput.addEventListener("change", calculateConversion);

  fillUnitOptions();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-fifteen-demo");
  if (!demo) return;

  const categoryInput = demo.querySelector("[data-vb-calc-fifteen-category]");
  const valueInput = demo.querySelector("[data-vb-calc-fifteen-value]");
  const fromInput = demo.querySelector("[data-vb-calc-fifteen-from]");
  const toInput = demo.querySelector("[data-vb-calc-fifteen-to]");
  const resultOutput = demo.querySelector("[data-vb-calc-fifteen-result]");
  const messageOutput = demo.querySelector("[data-vb-calc-fifteen-message]");

  const units = {
    length: {
      meter: 1,
      kilometer: 1000,
      centimeter: 0.01,
      mile: 1609.34,
      foot: 0.3048
    },
    weight: {
      kilogram: 1,
      gram: 0.001,
      pound: 0.453592,
      ounce: 0.0283495
    },
    temperature: {
      celsius: "c",
      fahrenheit: "f",
      kelvin: "k"
    }
  };

  function toTitle(text) {
    return text.charAt(0).toUpperCase() + text.slice(1);
  }

  function fillUnitOptions() {
    const category = categoryInput.value;
    const keys = Object.keys(units[category]);

    fromInput.innerHTML = "";
    toInput.innerHTML = "";

    keys.forEach(function (unit, index) {
      const fromOption = document.createElement("option");
      const toOption = document.createElement("option");

      fromOption.value = unit;
      fromOption.textContent = toTitle(unit);

      toOption.value = unit;
      toOption.textContent = toTitle(unit);

      fromInput.appendChild(fromOption);
      toInput.appendChild(toOption);

      if (index === 1) {
        toOption.selected = true;
      }
    });

    calculateConversion();
  }

  function convertTemperature(value, from, to) {
    let celsius;

    if (from === "celsius") celsius = value;
    if (from === "fahrenheit") celsius = (value - 32) * 5 / 9;
    if (from === "kelvin") celsius = value - 273.15;

    if (to === "celsius") return celsius;
    if (to === "fahrenheit") return celsius * 9 / 5 + 32;
    if (to === "kelvin") return celsius + 273.15;

    return value;
  }

  function calculateConversion() {
    const category = categoryInput.value;
    const value = Number(valueInput.value);
    const from = fromInput.value;
    const to = toInput.value;

    if (Number.isNaN(value)) {
      resultOutput.textContent = "0";
      messageOutput.textContent = "Enter a valid number.";
      return;
    }

    let result;

    if (category === "temperature") {
      result = convertTemperature(value, from, to);
    } else {
      const baseValue = value * units[category][from];
      result = baseValue / units[category][to];
    }

    resultOutput.textContent = Number(result.toFixed(4)).toLocaleString("en-US") + " " + toTitle(to);
    messageOutput.textContent = "Converted from " + toTitle(from) + " to " + toTitle(to) + ".";
  }

  categoryInput.addEventListener("change", fillUnitOptions);
  valueInput.addEventListener("input", calculateConversion);
  fromInput.addEventListener("change", calculateConversion);
  toInput.addEventListener("change", calculateConversion);

  fillUnitOptions();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-fifteen-demo"&gt;
  &lt;div class="vb-calc-fifteen-shell"&gt;
    &lt;div class="vb-calc-fifteen-header"&gt;
      &lt;span&gt;Example 15&lt;/span&gt;
      &lt;h3&gt;Unit Converter Calculator&lt;/h3&gt;
      &lt;p&gt;Convert length, weight, and temperature values with dynamic JavaScript conversion logic.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-fifteen-tool"&gt;
      &lt;label&gt;
        Conversion category
        &lt;select data-vb-calc-fifteen-category&gt;
          &lt;option value="length"&gt;Length&lt;/option&gt;
          &lt;option value="weight"&gt;Weight&lt;/option&gt;
          &lt;option value="temperature"&gt;Temperature&lt;/option&gt;
        &lt;/select&gt;
      &lt;/label&gt;

      &lt;div class="vb-calc-fifteen-row"&gt;
        &lt;label&gt;
          Value
          &lt;input type="number" value="10" data-vb-calc-fifteen-value&gt;
        &lt;/label&gt;

        &lt;label&gt;
          From
          &lt;select data-vb-calc-fifteen-from&gt;&lt;/select&gt;
        &lt;/label&gt;

        &lt;label&gt;
          To
          &lt;select data-vb-calc-fifteen-to&gt;&lt;/select&gt;
        &lt;/label&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-fifteen-result"&gt;
        &lt;span&gt;Converted result&lt;/span&gt;
        &lt;strong data-vb-calc-fifteen-result&gt;0&lt;/strong&gt;
        &lt;p data-vb-calc-fifteen-message&gt;Choose units to convert the value.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-fifteen-demo,
.vb-calc-fifteen-demo * {
  box-sizing: border-box;
}

.vb-calc-fifteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(99, 102, 241, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(20, 184, 166, 0.16), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #f0fdfa 54%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.18);
}

.vb-calc-fifteen-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-fifteen-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #312e81 0%, #4f46e5 52%, #0f766e 100%) !important;
  background-size: 26px 26px, 26px 26px, auto !important;
}

.vb-calc-fifteen-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-fifteen-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 66px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-fifteen-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-fifteen-tool {
  display: grid;
  gap: 16px;
  padding: clamp(22px, 4vw, 34px);
}

.vb-calc-fifteen-row {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.8fr) minmax(0, 0.8fr);
  gap: 14px;
}

.vb-calc-fifteen-tool label {
  display: grid;
  gap: 8px;
  color: #312e81 !important;
  -webkit-text-fill-color: #312e81 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-fifteen-tool input,
.vb-calc-fifteen-tool select {
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #c7d2fe;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-fifteen-result {
  padding: 22px;
  border-radius: 24px;
  background: linear-gradient(135deg, #eef2ff, #f0fdfa) !important;
  border: 1px solid #c7d2fe;
}

.vb-calc-fifteen-result span {
  display: block;
  margin-bottom: 8px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-fifteen-result strong {
  display: block;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: clamp(34px, 5vw, 52px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-calc-fifteen-result p {
  margin: 9px 0 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-fifteen-row {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-fifteen-header h3 {
    font-size: 40px !important;
  }
}</pre>



<p class="wp-block-paragraph">This unit converter calculator is useful for education websites, utility pages, product measurement guides, engineering tools, recipe calculators, shipping guides, and practical JavaScript conversion projects.</p>



<h2 class="wp-block-heading">16. Currency Style Price Converter</h2>



<p class="wp-block-paragraph"><strong>A currency style price converter</strong> is useful for ecommerce stores, pricing pages, travel websites, booking forms, international product pages, and business tools. It helps users convert a price with a custom exchange rate and display the result in a clean formatted way.</p>



<p class="wp-block-paragraph">This example uses a custom exchange rate, source amount, currency dropdowns, live conversion, formatted output, and swap button logic. The JavaScript swaps currency labels, reverses the exchange rate, and recalculates the converted value instantly.</p>



<ul class="wp-block-list">
<li>Currency style price converter</li>
<li>Custom exchange rate input</li>
<li>Swap currencies button</li>
<li>Formatted money output</li>
<li>Live conversion logic</li>
</ul>



<div class="vb-calc-sixteen-demo">
  <div class="vb-calc-sixteen-card">
    <div class="vb-calc-sixteen-copy">
      <span>Example 16</span>
      <h3>Currency Style Price Converter</h3>
      <p>Convert product prices using a custom exchange rate and swap currencies with JavaScript.</p>
    </div>

    <div class="vb-calc-sixteen-tool">
      <div class="vb-calc-sixteen-grid">
        <label>
          Amount
          <input type="number" min="0" step="0.01" value="149" data-vb-calc-sixteen-amount>
        </label>

        <label>
          Exchange rate
          <input type="number" min="0.0001" step="0.0001" value="1.08" data-vb-calc-sixteen-rate>
        </label>
      </div>

      <div class="vb-calc-sixteen-currencies">
        <select data-vb-calc-sixteen-from>
          <option value="EUR" selected>EUR</option>
          <option value="USD">USD</option>
          <option value="GBP">GBP</option>
        </select>

        <button type="button" data-vb-calc-sixteen-swap>Swap</button>

        <select data-vb-calc-sixteen-to>
          <option value="EUR">EUR</option>
          <option value="USD" selected>USD</option>
          <option value="GBP">GBP</option>
        </select>
      </div>

      <div class="vb-calc-sixteen-result">
        <span>Converted price</span>
        <strong data-vb-calc-sixteen-result>$0.00</strong>
        <p data-vb-calc-sixteen-message>Conversion updates automatically.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-sixteen-demo,
.vb-calc-sixteen-demo * {
  box-sizing: border-box;
}

.vb-calc-sixteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 197, 94, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(250, 204, 21, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #fefce8 54%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.18);
}

.vb-calc-sixteen-card {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-calc-sixteen-copy {
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #14532d 0%, #16a34a 52%, #ca8a04 100%) !important;
  box-shadow: 0 30px 90px rgba(22, 163, 74, 0.22);
}

.vb-calc-sixteen-copy span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-sixteen-copy h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5.2vw, 66px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-sixteen-copy p {
  margin: 0 !important;
  color: #fef9c3 !important;
  -webkit-text-fill-color: #fef9c3 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-sixteen-tool {
  display: grid;
  gap: 16px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-sixteen-grid,
.vb-calc-sixteen-currencies {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-calc-sixteen-tool label {
  display: grid;
  gap: 8px;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-sixteen-tool input,
.vb-calc-sixteen-tool select {
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #bbf7d0;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-sixteen-currencies {
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
}

.vb-calc-sixteen-currencies button {
  min-height: 48px;
  padding: 0 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #22c55e, #eab308);
  color: #052e16 !important;
  -webkit-text-fill-color: #052e16 !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-calc-sixteen-result {
  padding: 22px;
  border-radius: 24px;
  background: linear-gradient(135deg, #f0fdf4, #fefce8) !important;
  border: 1px solid #bbf7d0;
}

.vb-calc-sixteen-result span {
  display: block;
  margin-bottom: 8px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-sixteen-result strong {
  display: block;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: clamp(36px, 5vw, 52px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-calc-sixteen-result p {
  margin: 9px 0 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-sixteen-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-sixteen-copy h3 {
    font-size: 40px !important;
  }

  .vb-calc-sixteen-grid,
  .vb-calc-sixteen-currencies {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-sixteen-demo");
  if (!demo) return;

  const amountInput = demo.querySelector("[data-vb-calc-sixteen-amount]");
  const rateInput = demo.querySelector("[data-vb-calc-sixteen-rate]");
  const fromInput = demo.querySelector("[data-vb-calc-sixteen-from]");
  const toInput = demo.querySelector("[data-vb-calc-sixteen-to]");
  const swapButton = demo.querySelector("[data-vb-calc-sixteen-swap]");
  const resultOutput = demo.querySelector("[data-vb-calc-sixteen-result]");
  const messageOutput = demo.querySelector("[data-vb-calc-sixteen-message]");

  function formatMoney(value, currency) {
    return new Intl.NumberFormat("en-US", {
      style: "currency",
      currency: currency,
      minimumFractionDigits: 2,
      maximumFractionDigits: 2
    }).format(value);
  }

  function calculateCurrency() {
    const amount = Math.max(Number(amountInput.value) || 0, 0);
    const rate = Number(rateInput.value);

    if (rate <= 0 || Number.isNaN(rate)) {
      resultOutput.textContent = formatMoney(0, toInput.value);
      messageOutput.textContent = "Enter a valid exchange rate greater than zero.";
      return;
    }

    const converted = amount * rate;
    resultOutput.textContent = formatMoney(converted, toInput.value);
    messageOutput.textContent = amount + " " + fromInput.value + " converted to " + toInput.value + " using rate " + rate + ".";
  }

  function swapCurrencies() {
    const oldFrom = fromInput.value;
    fromInput.value = toInput.value;
    toInput.value = oldFrom;

    const currentRate = Number(rateInput.value);
    if (currentRate > 0) {
      rateInput.value = (1 / currentRate).toFixed(4);
    }

    calculateCurrency();
  }

  [amountInput, rateInput, fromInput, toInput].forEach(function (field) {
    field.addEventListener("input", calculateCurrency);
    field.addEventListener("change", calculateCurrency);
  });

  swapButton.addEventListener("click", swapCurrencies);

  calculateCurrency();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-sixteen-demo");
  if (!demo) return;

  const amountInput = demo.querySelector("[data-vb-calc-sixteen-amount]");
  const rateInput = demo.querySelector("[data-vb-calc-sixteen-rate]");
  const fromInput = demo.querySelector("[data-vb-calc-sixteen-from]");
  const toInput = demo.querySelector("[data-vb-calc-sixteen-to]");
  const swapButton = demo.querySelector("[data-vb-calc-sixteen-swap]");
  const resultOutput = demo.querySelector("[data-vb-calc-sixteen-result]");
  const messageOutput = demo.querySelector("[data-vb-calc-sixteen-message]");

  function formatMoney(value, currency) {
    return new Intl.NumberFormat("en-US", {
      style: "currency",
      currency: currency,
      minimumFractionDigits: 2,
      maximumFractionDigits: 2
    }).format(value);
  }

  function calculateCurrency() {
    const amount = Math.max(Number(amountInput.value) || 0, 0);
    const rate = Number(rateInput.value);

    if (rate &lt;= 0 || Number.isNaN(rate)) {
      resultOutput.textContent = formatMoney(0, toInput.value);
      messageOutput.textContent = "Enter a valid exchange rate greater than zero.";
      return;
    }

    const converted = amount * rate;
    resultOutput.textContent = formatMoney(converted, toInput.value);
    messageOutput.textContent = amount + " " + fromInput.value + " converted to " + toInput.value + " using rate " + rate + ".";
  }

  function swapCurrencies() {
    const oldFrom = fromInput.value;
    fromInput.value = toInput.value;
    toInput.value = oldFrom;

    const currentRate = Number(rateInput.value);
    if (currentRate &gt; 0) {
      rateInput.value = (1 / currentRate).toFixed(4);
    }

    calculateCurrency();
  }

  [amountInput, rateInput, fromInput, toInput].forEach(function (field) {
    field.addEventListener("input", calculateCurrency);
    field.addEventListener("change", calculateCurrency);
  });

  swapButton.addEventListener("click", swapCurrencies);

  calculateCurrency();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-sixteen-demo"&gt;
  &lt;div class="vb-calc-sixteen-card"&gt;
    &lt;div class="vb-calc-sixteen-copy"&gt;
      &lt;span&gt;Example 16&lt;/span&gt;
      &lt;h3&gt;Currency Style Price Converter&lt;/h3&gt;
      &lt;p&gt;Convert product prices using a custom exchange rate and swap currencies with JavaScript.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-sixteen-tool"&gt;
      &lt;div class="vb-calc-sixteen-grid"&gt;
        &lt;label&gt;
          Amount
          &lt;input type="number" min="0" step="0.01" value="149" data-vb-calc-sixteen-amount&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Exchange rate
          &lt;input type="number" min="0.0001" step="0.0001" value="1.08" data-vb-calc-sixteen-rate&gt;
        &lt;/label&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-sixteen-currencies"&gt;
        &lt;select data-vb-calc-sixteen-from&gt;
          &lt;option value="EUR" selected&gt;EUR&lt;/option&gt;
          &lt;option value="USD"&gt;USD&lt;/option&gt;
          &lt;option value="GBP"&gt;GBP&lt;/option&gt;
        &lt;/select&gt;

        &lt;button type="button" data-vb-calc-sixteen-swap&gt;Swap&lt;/button&gt;

        &lt;select data-vb-calc-sixteen-to&gt;
          &lt;option value="EUR"&gt;EUR&lt;/option&gt;
          &lt;option value="USD" selected&gt;USD&lt;/option&gt;
          &lt;option value="GBP"&gt;GBP&lt;/option&gt;
        &lt;/select&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-sixteen-result"&gt;
        &lt;span&gt;Converted price&lt;/span&gt;
        &lt;strong data-vb-calc-sixteen-result&gt;$0.00&lt;/strong&gt;
        &lt;p data-vb-calc-sixteen-message&gt;Conversion updates automatically.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-sixteen-demo,
.vb-calc-sixteen-demo * {
  box-sizing: border-box;
}

.vb-calc-sixteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 197, 94, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(250, 204, 21, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #fefce8 54%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.18);
}

.vb-calc-sixteen-card {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-calc-sixteen-copy {
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #14532d 0%, #16a34a 52%, #ca8a04 100%) !important;
  box-shadow: 0 30px 90px rgba(22, 163, 74, 0.22);
}

.vb-calc-sixteen-copy span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-sixteen-copy h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5.2vw, 66px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-sixteen-copy p {
  margin: 0 !important;
  color: #fef9c3 !important;
  -webkit-text-fill-color: #fef9c3 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-sixteen-tool {
  display: grid;
  gap: 16px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-sixteen-grid,
.vb-calc-sixteen-currencies {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-calc-sixteen-tool label {
  display: grid;
  gap: 8px;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-sixteen-tool input,
.vb-calc-sixteen-tool select {
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #bbf7d0;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-sixteen-currencies {
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
}

.vb-calc-sixteen-currencies button {
  min-height: 48px;
  padding: 0 18px;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #22c55e, #eab308);
  color: #052e16 !important;
  -webkit-text-fill-color: #052e16 !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-calc-sixteen-result {
  padding: 22px;
  border-radius: 24px;
  background: linear-gradient(135deg, #f0fdf4, #fefce8) !important;
  border: 1px solid #bbf7d0;
}

.vb-calc-sixteen-result span {
  display: block;
  margin-bottom: 8px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-sixteen-result strong {
  display: block;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: clamp(36px, 5vw, 52px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-calc-sixteen-result p {
  margin: 9px 0 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-sixteen-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-sixteen-copy h3 {
    font-size: 40px !important;
  }

  .vb-calc-sixteen-grid,
  .vb-calc-sixteen-currencies {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This currency style price converter is useful for international ecommerce stores, pricing pages, booking websites, travel tools, landing pages, and simple business dashboards that need custom currency conversion.</p>



<h2 class="wp-block-heading">17. Ecommerce Cart Total Calculator</h2>



<p class="wp-block-paragraph"><strong>An ecommerce cart total calculator</strong> is useful for online stores, checkout pages, product bundles, order forms, cart previews, and ecommerce UI examples. It calculates subtotal, coupon discount, shipping, tax, and final checkout total.</p>



<p class="wp-block-paragraph">This example uses an array of product data, quantity inputs, coupon code validation, subtotal calculation, tax calculation, shipping threshold logic, and a dynamic cart summary. The JavaScript loops through cart items and updates totals automatically.</p>



<ul class="wp-block-list">
<li>Ecommerce cart total calculator</li>
<li>Product array and quantity inputs</li>
<li>Coupon code validation</li>
<li>Tax and shipping calculation</li>
<li>Dynamic checkout summary</li>
</ul>



<div class="vb-calc-seventeen-demo">
  <div class="vb-calc-seventeen-shell">
    <div class="vb-calc-seventeen-header">
      <span>Example 17</span>
      <h3>Ecommerce Cart Total Calculator</h3>
      <p>Calculate subtotal, coupon discount, shipping, tax, and final cart total from product quantities.</p>
    </div>

    <div class="vb-calc-seventeen-body">
      <div class="vb-calc-seventeen-items">
        <label>
          Website Template <small>€49 each</small>
          <input type="number" min="0" value="1" data-vb-calc-seventeen-qty data-price="49">
        </label>

        <label>
          Plugin License <small>€89 each</small>
          <input type="number" min="0" value="2" data-vb-calc-seventeen-qty data-price="89">
        </label>

        <label>
          Support Add-on <small>€29 each</small>
          <input type="number" min="0" value="1" data-vb-calc-seventeen-qty data-price="29">
        </label>

        <label>
          Coupon code
          <input type="text" value="SAVE10" data-vb-calc-seventeen-coupon>
        </label>
      </div>

      <div class="vb-calc-seventeen-summary">
        <div><span>Subtotal</span><strong data-vb-calc-seventeen-subtotal>€0</strong></div>
        <div><span>Discount</span><strong data-vb-calc-seventeen-discount>€0</strong></div>
        <div><span>Shipping</span><strong data-vb-calc-seventeen-shipping>€0</strong></div>
        <div><span>Tax</span><strong data-vb-calc-seventeen-tax>€0</strong></div>

        <div class="vb-calc-seventeen-total">
          <span>Final total</span>
          <strong data-vb-calc-seventeen-total>€0</strong>
        </div>

        <p data-vb-calc-seventeen-message>Use SAVE10 for 10% off or FREESHIP for free shipping.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-seventeen-demo,
.vb-calc-seventeen-demo * {
  box-sizing: border-box;
}

.vb-calc-seventeen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(236, 72, 153, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #eff6ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(236, 72, 153, 0.18);
}

.vb-calc-seventeen-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-seventeen-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #831843 0%, #db2777 54%, #2563eb 100%) !important;
}

.vb-calc-seventeen-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-seventeen-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-seventeen-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-seventeen-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 360px;
  gap: 22px;
  padding: clamp(22px, 4vw, 34px);
}

.vb-calc-seventeen-items {
  display: grid;
  gap: 14px;
}

.vb-calc-seventeen-items label {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 120px;
  gap: 14px;
  align-items: center;
  padding: 16px;
  border-radius: 20px;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
  color: #831843 !important;
  -webkit-text-fill-color: #831843 !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-calc-seventeen-items small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 700;
}

.vb-calc-seventeen-items input {
  width: 100%;
  min-height: 46px;
  padding: 0 12px;
  border: 1px solid #fbcfe8;
  border-radius: 14px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 800;
  outline: none;
}

.vb-calc-seventeen-summary {
  display: grid;
  gap: 10px;
  padding: 18px;
  border-radius: 24px;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
}

.vb-calc-seventeen-summary div {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  padding: 12px 0;
  border-bottom: 1px solid #e2e8f0;
}

.vb-calc-seventeen-summary span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-calc-seventeen-summary strong {
  color: #831843 !important;
  -webkit-text-fill-color: #831843 !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-calc-seventeen-total {
  display: block !important;
  padding: 18px !important;
  border: 0 !important;
  border-radius: 20px;
  background: linear-gradient(135deg, #fdf2f8, #eff6ff) !important;
}

.vb-calc-seventeen-total span {
  display: block;
  margin-bottom: 8px;
}

.vb-calc-seventeen-total strong {
  display: block;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 38px;
  line-height: 1;
  letter-spacing: -0.055em;
}

.vb-calc-seventeen-summary p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-seventeen-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-seventeen-header h3 {
    font-size: 38px !important;
  }

  .vb-calc-seventeen-items label {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-seventeen-demo");
  if (!demo) return;

  const qtyInputs = demo.querySelectorAll("[data-vb-calc-seventeen-qty]");
  const couponInput = demo.querySelector("[data-vb-calc-seventeen-coupon]");
  const subtotalOutput = demo.querySelector("[data-vb-calc-seventeen-subtotal]");
  const discountOutput = demo.querySelector("[data-vb-calc-seventeen-discount]");
  const shippingOutput = demo.querySelector("[data-vb-calc-seventeen-shipping]");
  const taxOutput = demo.querySelector("[data-vb-calc-seventeen-tax]");
  const totalOutput = demo.querySelector("[data-vb-calc-seventeen-total]");
  const messageOutput = demo.querySelector("[data-vb-calc-seventeen-message]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 2
  });

  function calculateCart() {
    let subtotal = 0;

    qtyInputs.forEach(function (input) {
      const price = Number(input.dataset.price);
      const qty = Math.max(Number(input.value) || 0, 0);
      subtotal += price * qty;
    });

    const coupon = couponInput.value.trim().toUpperCase();
    let discount = 0;
    let shipping = subtotal >= 150 ? 0 : 12;

    if (coupon === "SAVE10") {
      discount = subtotal * 0.1;
      messageOutput.textContent = "SAVE10 coupon applied for 10% discount.";
    } else if (coupon === "FREESHIP") {
      shipping = 0;
      messageOutput.textContent = "FREESHIP coupon applied. Shipping removed.";
    } else if (coupon.length > 0) {
      messageOutput.textContent = "Unknown coupon. Use SAVE10 or FREESHIP.";
    } else {
      messageOutput.textContent = "Use SAVE10 for 10% off or FREESHIP for free shipping.";
    }

    const taxable = Math.max(subtotal - discount, 0);
    const tax = taxable * 0.2;
    const total = taxable + tax + shipping;

    subtotalOutput.textContent = money.format(subtotal);
    discountOutput.textContent = "-" + money.format(discount);
    shippingOutput.textContent = money.format(shipping);
    taxOutput.textContent = money.format(tax);
    totalOutput.textContent = money.format(total);
  }

  qtyInputs.forEach(function (input) {
    input.addEventListener("input", calculateCart);
  });

  couponInput.addEventListener("input", calculateCart);

  calculateCart();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-seventeen-demo");
  if (!demo) return;

  const qtyInputs = demo.querySelectorAll("[data-vb-calc-seventeen-qty]");
  const couponInput = demo.querySelector("[data-vb-calc-seventeen-coupon]");
  const subtotalOutput = demo.querySelector("[data-vb-calc-seventeen-subtotal]");
  const discountOutput = demo.querySelector("[data-vb-calc-seventeen-discount]");
  const shippingOutput = demo.querySelector("[data-vb-calc-seventeen-shipping]");
  const taxOutput = demo.querySelector("[data-vb-calc-seventeen-tax]");
  const totalOutput = demo.querySelector("[data-vb-calc-seventeen-total]");
  const messageOutput = demo.querySelector("[data-vb-calc-seventeen-message]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 2
  });

  function calculateCart() {
    let subtotal = 0;

    qtyInputs.forEach(function (input) {
      const price = Number(input.dataset.price);
      const qty = Math.max(Number(input.value) || 0, 0);
      subtotal += price * qty;
    });

    const coupon = couponInput.value.trim().toUpperCase();
    let discount = 0;
    let shipping = subtotal &gt;= 150 ? 0 : 12;

    if (coupon === "SAVE10") {
      discount = subtotal * 0.1;
      messageOutput.textContent = "SAVE10 coupon applied for 10% discount.";
    } else if (coupon === "FREESHIP") {
      shipping = 0;
      messageOutput.textContent = "FREESHIP coupon applied. Shipping removed.";
    } else if (coupon.length &gt; 0) {
      messageOutput.textContent = "Unknown coupon. Use SAVE10 or FREESHIP.";
    } else {
      messageOutput.textContent = "Use SAVE10 for 10% off or FREESHIP for free shipping.";
    }

    const taxable = Math.max(subtotal - discount, 0);
    const tax = taxable * 0.2;
    const total = taxable + tax + shipping;

    subtotalOutput.textContent = money.format(subtotal);
    discountOutput.textContent = "-" + money.format(discount);
    shippingOutput.textContent = money.format(shipping);
    taxOutput.textContent = money.format(tax);
    totalOutput.textContent = money.format(total);
  }

  qtyInputs.forEach(function (input) {
    input.addEventListener("input", calculateCart);
  });

  couponInput.addEventListener("input", calculateCart);

  calculateCart();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-seventeen-demo"&gt;
  &lt;div class="vb-calc-seventeen-shell"&gt;
    &lt;div class="vb-calc-seventeen-header"&gt;
      &lt;span&gt;Example 17&lt;/span&gt;
      &lt;h3&gt;Ecommerce Cart Total Calculator&lt;/h3&gt;
      &lt;p&gt;Calculate subtotal, coupon discount, shipping, tax, and final cart total from product quantities.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-seventeen-body"&gt;
      &lt;div class="vb-calc-seventeen-items"&gt;
        &lt;label&gt;
          Website Template &lt;small&gt;€49 each&lt;/small&gt;
          &lt;input type="number" min="0" value="1" data-vb-calc-seventeen-qty data-price="49"&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Plugin License &lt;small&gt;€89 each&lt;/small&gt;
          &lt;input type="number" min="0" value="2" data-vb-calc-seventeen-qty data-price="89"&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Support Add-on &lt;small&gt;€29 each&lt;/small&gt;
          &lt;input type="number" min="0" value="1" data-vb-calc-seventeen-qty data-price="29"&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Coupon code
          &lt;input type="text" value="SAVE10" data-vb-calc-seventeen-coupon&gt;
        &lt;/label&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-seventeen-summary"&gt;
        &lt;div&gt;&lt;span&gt;Subtotal&lt;/span&gt;&lt;strong data-vb-calc-seventeen-subtotal&gt;€0&lt;/strong&gt;&lt;/div&gt;
        &lt;div&gt;&lt;span&gt;Discount&lt;/span&gt;&lt;strong data-vb-calc-seventeen-discount&gt;€0&lt;/strong&gt;&lt;/div&gt;
        &lt;div&gt;&lt;span&gt;Shipping&lt;/span&gt;&lt;strong data-vb-calc-seventeen-shipping&gt;€0&lt;/strong&gt;&lt;/div&gt;
        &lt;div&gt;&lt;span&gt;Tax&lt;/span&gt;&lt;strong data-vb-calc-seventeen-tax&gt;€0&lt;/strong&gt;&lt;/div&gt;

        &lt;div class="vb-calc-seventeen-total"&gt;
          &lt;span&gt;Final total&lt;/span&gt;
          &lt;strong data-vb-calc-seventeen-total&gt;€0&lt;/strong&gt;
        &lt;/div&gt;

        &lt;p data-vb-calc-seventeen-message&gt;Use SAVE10 for 10% off or FREESHIP for free shipping.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-seventeen-demo,
.vb-calc-seventeen-demo * {
  box-sizing: border-box;
}

.vb-calc-seventeen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(236, 72, 153, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #eff6ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(236, 72, 153, 0.18);
}

.vb-calc-seventeen-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-seventeen-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #831843 0%, #db2777 54%, #2563eb 100%) !important;
}

.vb-calc-seventeen-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-seventeen-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-seventeen-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-seventeen-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 360px;
  gap: 22px;
  padding: clamp(22px, 4vw, 34px);
}

.vb-calc-seventeen-items {
  display: grid;
  gap: 14px;
}

.vb-calc-seventeen-items label {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 120px;
  gap: 14px;
  align-items: center;
  padding: 16px;
  border-radius: 20px;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
  color: #831843 !important;
  -webkit-text-fill-color: #831843 !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-calc-seventeen-items small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 700;
}

.vb-calc-seventeen-items input {
  width: 100%;
  min-height: 46px;
  padding: 0 12px;
  border: 1px solid #fbcfe8;
  border-radius: 14px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 800;
  outline: none;
}

.vb-calc-seventeen-summary {
  display: grid;
  gap: 10px;
  padding: 18px;
  border-radius: 24px;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
}

.vb-calc-seventeen-summary div {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  padding: 12px 0;
  border-bottom: 1px solid #e2e8f0;
}

.vb-calc-seventeen-summary span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-calc-seventeen-summary strong {
  color: #831843 !important;
  -webkit-text-fill-color: #831843 !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-calc-seventeen-total {
  display: block !important;
  padding: 18px !important;
  border: 0 !important;
  border-radius: 20px;
  background: linear-gradient(135deg, #fdf2f8, #eff6ff) !important;
}

.vb-calc-seventeen-total span {
  display: block;
  margin-bottom: 8px;
}

.vb-calc-seventeen-total strong {
  display: block;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 38px;
  line-height: 1;
  letter-spacing: -0.055em;
}

.vb-calc-seventeen-summary p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-seventeen-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-seventeen-header h3 {
    font-size: 38px !important;
  }

  .vb-calc-seventeen-items label {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This ecommerce cart total calculator is useful for checkout pages, product bundles, online stores, order forms, pricing widgets, coupon demos, and JavaScript ecommerce UI examples.</p>



<h2 class="wp-block-heading">18. Freelance Hourly Rate Calculator</h2>



<p class="wp-block-paragraph"><strong>A freelance hourly rate calculator</strong> is useful for freelancers, consultants, agencies, designers, developers, writers, coaches, and service providers. It helps calculate a target hourly rate from income goal, expenses, vacation time, and billable hours.</p>



<p class="wp-block-paragraph">This example uses annual income goal, yearly expenses, weeks off, billable hours per week, and a recommended hourly rate formula. The JavaScript calculates available working weeks, billable hours, required yearly revenue, and hourly rate.</p>



<ul class="wp-block-list">
<li>Freelance hourly rate calculator</li>
<li>Income goal and expense logic</li>
<li>Vacation weeks adjustment</li>
<li>Billable hours calculation</li>
<li>Consultant pricing calculator layout</li>
</ul>



<div class="vb-calc-eighteen-demo">
  <div class="vb-calc-eighteen-card">
    <div class="vb-calc-eighteen-title">
      <span>Example 18</span>
      <h3>Freelance Hourly Rate Calculator</h3>
      <p>Calculate a recommended hourly rate from income goal, expenses, time off, and billable hours.</p>
    </div>

    <div class="vb-calc-eighteen-tool">
      <div class="vb-calc-eighteen-grid">
        <label>
          Desired annual income
          <input type="number" min="0" value="60000" data-vb-calc-eighteen-income>
        </label>

        <label>
          Annual business expenses
          <input type="number" min="0" value="12000" data-vb-calc-eighteen-expenses>
        </label>

        <label>
          Weeks off per year
          <input type="number" min="0" max="30" value="5" data-vb-calc-eighteen-weeks>
        </label>

        <label>
          Billable hours per week
          <input type="number" min="1" max="80" value="25" data-vb-calc-eighteen-hours>
        </label>
      </div>

      <div class="vb-calc-eighteen-result">
        <div class="vb-calc-eighteen-main">
          <span>Recommended hourly rate</span>
          <strong data-vb-calc-eighteen-rate>€0/hr</strong>
        </div>

        <div class="vb-calc-eighteen-mini">
          <div>
            <span>Billable hours/year</span>
            <strong data-vb-calc-eighteen-year-hours>0</strong>
          </div>
          <div>
            <span>Revenue target</span>
            <strong data-vb-calc-eighteen-target>€0</strong>
          </div>
        </div>

        <p data-vb-calc-eighteen-message>Hourly rate updates automatically.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-eighteen-demo,
.vb-calc-eighteen-demo * {
  box-sizing: border-box;
}

.vb-calc-eighteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(99, 102, 241, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(244, 63, 94, 0.14), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #fff1f2 54%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.18);
}

.vb-calc-eighteen-card {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-calc-eighteen-title {
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #312e81 0%, #4f46e5 54%, #be123c 100%) !important;
  box-shadow: 0 30px 90px rgba(79, 70, 229, 0.22);
}

.vb-calc-eighteen-title span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-eighteen-title h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-eighteen-title p {
  margin: 0 !important;
  color: #ffe4e6 !important;
  -webkit-text-fill-color: #ffe4e6 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-eighteen-tool {
  display: grid;
  gap: 16px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-eighteen-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-calc-eighteen-tool label {
  display: grid;
  gap: 8px;
  color: #312e81 !important;
  -webkit-text-fill-color: #312e81 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-eighteen-tool input {
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #c7d2fe;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-eighteen-result {
  display: grid;
  gap: 12px;
  padding: 18px;
  border-radius: 24px;
  background: linear-gradient(135deg, #eef2ff, #fff1f2) !important;
  border: 1px solid #c7d2fe;
}

.vb-calc-eighteen-main {
  padding: 20px;
  border-radius: 20px;
  background: #ffffff;
}

.vb-calc-eighteen-main span,
.vb-calc-eighteen-mini span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-eighteen-main strong {
  display: block;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: clamp(38px, 5vw, 54px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-calc-eighteen-mini {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-calc-eighteen-mini div {
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.82);
}

.vb-calc-eighteen-mini strong {
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: 22px;
  font-weight: 950;
}

.vb-calc-eighteen-result p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-eighteen-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-eighteen-title h3 {
    font-size: 38px !important;
  }

  .vb-calc-eighteen-grid,
  .vb-calc-eighteen-mini {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-eighteen-demo");
  if (!demo) return;

  const incomeInput = demo.querySelector("[data-vb-calc-eighteen-income]");
  const expensesInput = demo.querySelector("[data-vb-calc-eighteen-expenses]");
  const weeksInput = demo.querySelector("[data-vb-calc-eighteen-weeks]");
  const hoursInput = demo.querySelector("[data-vb-calc-eighteen-hours]");
  const rateOutput = demo.querySelector("[data-vb-calc-eighteen-rate]");
  const yearHoursOutput = demo.querySelector("[data-vb-calc-eighteen-year-hours]");
  const targetOutput = demo.querySelector("[data-vb-calc-eighteen-target]");
  const messageOutput = demo.querySelector("[data-vb-calc-eighteen-message]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 0
  });

  function calculateRate() {
    const income = Math.max(Number(incomeInput.value) || 0, 0);
    const expenses = Math.max(Number(expensesInput.value) || 0, 0);
    const weeksOff = Math.min(Math.max(Number(weeksInput.value) || 0, 0), 52);
    const hoursPerWeek = Math.max(Number(hoursInput.value) || 0, 0);

    const workingWeeks = Math.max(52 - weeksOff, 0);
    const billableHours = workingWeeks * hoursPerWeek;
    const revenueTarget = income + expenses;

    if (billableHours <= 0) {
      rateOutput.textContent = "€0/hr";
      yearHoursOutput.textContent = "0";
      targetOutput.textContent = money.format(revenueTarget);
      messageOutput.textContent = "Enter billable hours greater than zero.";
      return;
    }

    const hourlyRate = revenueTarget / billableHours;

    rateOutput.textContent = money.format(hourlyRate) + "/hr";
    yearHoursOutput.textContent = Math.round(billableHours).toLocaleString("en-US");
    targetOutput.textContent = money.format(revenueTarget);
    messageOutput.textContent = "Rate based on " + workingWeeks + " working weeks and " + hoursPerWeek + " billable hours per week.";
  }

  [incomeInput, expensesInput, weeksInput, hoursInput].forEach(function (field) {
    field.addEventListener("input", calculateRate);
  });

  calculateRate();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-eighteen-demo");
  if (!demo) return;

  const incomeInput = demo.querySelector("[data-vb-calc-eighteen-income]");
  const expensesInput = demo.querySelector("[data-vb-calc-eighteen-expenses]");
  const weeksInput = demo.querySelector("[data-vb-calc-eighteen-weeks]");
  const hoursInput = demo.querySelector("[data-vb-calc-eighteen-hours]");
  const rateOutput = demo.querySelector("[data-vb-calc-eighteen-rate]");
  const yearHoursOutput = demo.querySelector("[data-vb-calc-eighteen-year-hours]");
  const targetOutput = demo.querySelector("[data-vb-calc-eighteen-target]");
  const messageOutput = demo.querySelector("[data-vb-calc-eighteen-message]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 0
  });

  function calculateRate() {
    const income = Math.max(Number(incomeInput.value) || 0, 0);
    const expenses = Math.max(Number(expensesInput.value) || 0, 0);
    const weeksOff = Math.min(Math.max(Number(weeksInput.value) || 0, 0), 52);
    const hoursPerWeek = Math.max(Number(hoursInput.value) || 0, 0);

    const workingWeeks = Math.max(52 - weeksOff, 0);
    const billableHours = workingWeeks * hoursPerWeek;
    const revenueTarget = income + expenses;

    if (billableHours &lt;= 0) {
      rateOutput.textContent = "€0/hr";
      yearHoursOutput.textContent = "0";
      targetOutput.textContent = money.format(revenueTarget);
      messageOutput.textContent = "Enter billable hours greater than zero.";
      return;
    }

    const hourlyRate = revenueTarget / billableHours;

    rateOutput.textContent = money.format(hourlyRate) + "/hr";
    yearHoursOutput.textContent = Math.round(billableHours).toLocaleString("en-US");
    targetOutput.textContent = money.format(revenueTarget);
    messageOutput.textContent = "Rate based on " + workingWeeks + " working weeks and " + hoursPerWeek + " billable hours per week.";
  }

  [incomeInput, expensesInput, weeksInput, hoursInput].forEach(function (field) {
    field.addEventListener("input", calculateRate);
  });

  calculateRate();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-eighteen-demo"&gt;
  &lt;div class="vb-calc-eighteen-card"&gt;
    &lt;div class="vb-calc-eighteen-title"&gt;
      &lt;span&gt;Example 18&lt;/span&gt;
      &lt;h3&gt;Freelance Hourly Rate Calculator&lt;/h3&gt;
      &lt;p&gt;Calculate a recommended hourly rate from income goal, expenses, time off, and billable hours.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-eighteen-tool"&gt;
      &lt;div class="vb-calc-eighteen-grid"&gt;
        &lt;label&gt;
          Desired annual income
          &lt;input type="number" min="0" value="60000" data-vb-calc-eighteen-income&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Annual business expenses
          &lt;input type="number" min="0" value="12000" data-vb-calc-eighteen-expenses&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Weeks off per year
          &lt;input type="number" min="0" max="30" value="5" data-vb-calc-eighteen-weeks&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Billable hours per week
          &lt;input type="number" min="1" max="80" value="25" data-vb-calc-eighteen-hours&gt;
        &lt;/label&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-eighteen-result"&gt;
        &lt;div class="vb-calc-eighteen-main"&gt;
          &lt;span&gt;Recommended hourly rate&lt;/span&gt;
          &lt;strong data-vb-calc-eighteen-rate&gt;€0/hr&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-calc-eighteen-mini"&gt;
          &lt;div&gt;
            &lt;span&gt;Billable hours/year&lt;/span&gt;
            &lt;strong data-vb-calc-eighteen-year-hours&gt;0&lt;/strong&gt;
          &lt;/div&gt;
          &lt;div&gt;
            &lt;span&gt;Revenue target&lt;/span&gt;
            &lt;strong data-vb-calc-eighteen-target&gt;€0&lt;/strong&gt;
          &lt;/div&gt;
        &lt;/div&gt;

        &lt;p data-vb-calc-eighteen-message&gt;Hourly rate updates automatically.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-eighteen-demo,
.vb-calc-eighteen-demo * {
  box-sizing: border-box;
}

.vb-calc-eighteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(99, 102, 241, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(244, 63, 94, 0.14), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #fff1f2 54%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.18);
}

.vb-calc-eighteen-card {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-calc-eighteen-title {
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #312e81 0%, #4f46e5 54%, #be123c 100%) !important;
  box-shadow: 0 30px 90px rgba(79, 70, 229, 0.22);
}

.vb-calc-eighteen-title span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-eighteen-title h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-eighteen-title p {
  margin: 0 !important;
  color: #ffe4e6 !important;
  -webkit-text-fill-color: #ffe4e6 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-eighteen-tool {
  display: grid;
  gap: 16px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-eighteen-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-calc-eighteen-tool label {
  display: grid;
  gap: 8px;
  color: #312e81 !important;
  -webkit-text-fill-color: #312e81 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-eighteen-tool input {
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #c7d2fe;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-eighteen-result {
  display: grid;
  gap: 12px;
  padding: 18px;
  border-radius: 24px;
  background: linear-gradient(135deg, #eef2ff, #fff1f2) !important;
  border: 1px solid #c7d2fe;
}

.vb-calc-eighteen-main {
  padding: 20px;
  border-radius: 20px;
  background: #ffffff;
}

.vb-calc-eighteen-main span,
.vb-calc-eighteen-mini span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-eighteen-main strong {
  display: block;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: clamp(38px, 5vw, 54px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-calc-eighteen-mini {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-calc-eighteen-mini div {
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.82);
}

.vb-calc-eighteen-mini strong {
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: 22px;
  font-weight: 950;
}

.vb-calc-eighteen-result p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-eighteen-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-eighteen-title h3 {
    font-size: 38px !important;
  }

  .vb-calc-eighteen-grid,
  .vb-calc-eighteen-mini {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This freelance hourly rate calculator is useful for freelancer websites, consultant landing pages, agency tools, pricing strategy guides, business blogs, and service provider dashboards.</p>



<h2 class="wp-block-heading">19. Project Timeline Calculator</h2>



<p class="wp-block-paragraph"><strong>A project timeline calculator</strong> is useful for agencies, developers, consultants, construction companies, freelancers, project managers, and service websites. It helps estimate how many working days a project may take based on task count, hours per task, team size, and daily work capacity.</p>



<p class="wp-block-paragraph">This example uses task-based estimation, team capacity logic, working day calculation, delivery date projection, and dynamic warnings. The JavaScript calculates total work hours, daily capacity, estimated working days, and an approximate completion date.</p>



<ul class="wp-block-list">
<li>Project deadline calculator</li>
<li>Total work hour estimation</li>
<li>Team capacity calculation</li>
<li>Working days and delivery date output</li>
<li>Project management calculator logic</li>
</ul>



<div class="vb-calc-nineteen-demo">
  <div class="vb-calc-nineteen-shell">
    <div class="vb-calc-nineteen-header">
      <span>Example 19</span>
      <h3>Project Timeline Calculator</h3>
      <p>Estimate project duration from task count, hours per task, team size, and daily work capacity.</p>
    </div>

    <div class="vb-calc-nineteen-body">
      <div class="vb-calc-nineteen-fields">
        <label>
          Number of tasks
          <input type="number" min="1" value="42" data-vb-calc-nineteen-tasks>
        </label>

        <label>
          Average hours per task
          <input type="number" min="0.5" step="0.5" value="3" data-vb-calc-nineteen-hours>
        </label>

        <label>
          Team members
          <input type="number" min="1" value="3" data-vb-calc-nineteen-team>
        </label>

        <label>
          Productive hours per person/day
          <input type="number" min="1" max="12" value="5" data-vb-calc-nineteen-daily>
        </label>
      </div>

      <div class="vb-calc-nineteen-results">
        <div>
          <span>Total work</span>
          <strong data-vb-calc-nineteen-total-hours>0 h</strong>
        </div>

        <div>
          <span>Working days</span>
          <strong data-vb-calc-nineteen-days>0 days</strong>
        </div>

        <div class="vb-calc-nineteen-date">
          <span>Estimated finish</span>
          <strong data-vb-calc-nineteen-date>—</strong>
        </div>

        <p data-vb-calc-nineteen-message>Timeline estimate updates automatically.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-nineteen-demo,
.vb-calc-nineteen-demo * {
  box-sizing: border-box;
}

.vb-calc-nineteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(14, 165, 233, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #eef2ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
}

.vb-calc-nineteen-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-nineteen-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #082f49 0%, #0284c7 52%, #4f46e5 100%) !important;
  background-size: 26px 26px, 26px 26px, auto !important;
}

.vb-calc-nineteen-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-nineteen-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-nineteen-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-nineteen-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 370px;
  gap: 22px;
  padding: clamp(22px, 4vw, 34px);
}

.vb-calc-nineteen-fields {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-calc-nineteen-fields label {
  display: grid;
  gap: 8px;
  color: #075985 !important;
  -webkit-text-fill-color: #075985 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-nineteen-fields input {
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #bae6fd;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-nineteen-results {
  display: grid;
  gap: 12px;
  padding: 18px;
  border-radius: 24px;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
}

.vb-calc-nineteen-results div {
  padding: 16px;
  border-radius: 18px;
  background: linear-gradient(135deg, #f0f9ff, #eef2ff) !important;
  border: 1px solid #bae6fd;
}

.vb-calc-nineteen-results span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-nineteen-results strong {
  display: block;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 26px;
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-calc-nineteen-date strong {
  font-size: 30px;
}

.vb-calc-nineteen-results p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-nineteen-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-nineteen-header h3 {
    font-size: 38px !important;
  }

  .vb-calc-nineteen-fields {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-nineteen-demo");
  if (!demo) return;

  const tasksInput = demo.querySelector("[data-vb-calc-nineteen-tasks]");
  const hoursInput = demo.querySelector("[data-vb-calc-nineteen-hours]");
  const teamInput = demo.querySelector("[data-vb-calc-nineteen-team]");
  const dailyInput = demo.querySelector("[data-vb-calc-nineteen-daily]");
  const totalHoursOutput = demo.querySelector("[data-vb-calc-nineteen-total-hours]");
  const daysOutput = demo.querySelector("[data-vb-calc-nineteen-days]");
  const dateOutput = demo.querySelector("[data-vb-calc-nineteen-date]");
  const messageOutput = demo.querySelector("[data-vb-calc-nineteen-message]");

  function addWorkingDays(startDate, days) {
    const date = new Date(startDate);
    let added = 0;

    while (added < days) {
      date.setDate(date.getDate() + 1);
      const day = date.getDay();

      if (day !== 0 &#038;&#038; day !== 6) {
        added += 1;
      }
    }

    return date;
  }

  function calculateTimeline() {
    const tasks = Math.max(Number(tasksInput.value) || 0, 0);
    const hours = Math.max(Number(hoursInput.value) || 0, 0);
    const team = Math.max(Number(teamInput.value) || 1, 1);
    const daily = Math.max(Number(dailyInput.value) || 0, 0);

    const totalHours = tasks * hours;
    const dailyCapacity = team * daily;

    if (dailyCapacity <= 0 || totalHours <= 0) {
      totalHoursOutput.textContent = "0 h";
      daysOutput.textContent = "0 days";
      dateOutput.textContent = "—";
      messageOutput.textContent = "Enter valid task and capacity values.";
      return;
    }

    const workingDays = Math.ceil(totalHours / dailyCapacity);
    const finishDate = addWorkingDays(new Date(), workingDays);

    totalHoursOutput.textContent = totalHours.toFixed(1) + " h";
    daysOutput.textContent = workingDays + (workingDays === 1 ? " day" : " days");
    dateOutput.textContent = finishDate.toLocaleDateString("en-US", {
      month: "short",
      day: "numeric",
      year: "numeric"
    });

    messageOutput.textContent = "Based on " + dailyCapacity + " productive team hour(s) per working day.";
  }

  [tasksInput, hoursInput, teamInput, dailyInput].forEach(function (field) {
    field.addEventListener("input", calculateTimeline);
  });

  calculateTimeline();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-nineteen-demo");
  if (!demo) return;

  const tasksInput = demo.querySelector("[data-vb-calc-nineteen-tasks]");
  const hoursInput = demo.querySelector("[data-vb-calc-nineteen-hours]");
  const teamInput = demo.querySelector("[data-vb-calc-nineteen-team]");
  const dailyInput = demo.querySelector("[data-vb-calc-nineteen-daily]");
  const totalHoursOutput = demo.querySelector("[data-vb-calc-nineteen-total-hours]");
  const daysOutput = demo.querySelector("[data-vb-calc-nineteen-days]");
  const dateOutput = demo.querySelector("[data-vb-calc-nineteen-date]");
  const messageOutput = demo.querySelector("[data-vb-calc-nineteen-message]");

  function addWorkingDays(startDate, days) {
    const date = new Date(startDate);
    let added = 0;

    while (added &lt; days) {
      date.setDate(date.getDate() + 1);
      const day = date.getDay();

      if (day !== 0 &amp;&amp; day !== 6) {
        added += 1;
      }
    }

    return date;
  }

  function calculateTimeline() {
    const tasks = Math.max(Number(tasksInput.value) || 0, 0);
    const hours = Math.max(Number(hoursInput.value) || 0, 0);
    const team = Math.max(Number(teamInput.value) || 1, 1);
    const daily = Math.max(Number(dailyInput.value) || 0, 0);

    const totalHours = tasks * hours;
    const dailyCapacity = team * daily;

    if (dailyCapacity &lt;= 0 || totalHours &lt;= 0) {
      totalHoursOutput.textContent = "0 h";
      daysOutput.textContent = "0 days";
      dateOutput.textContent = "—";
      messageOutput.textContent = "Enter valid task and capacity values.";
      return;
    }

    const workingDays = Math.ceil(totalHours / dailyCapacity);
    const finishDate = addWorkingDays(new Date(), workingDays);

    totalHoursOutput.textContent = totalHours.toFixed(1) + " h";
    daysOutput.textContent = workingDays + (workingDays === 1 ? " day" : " days");
    dateOutput.textContent = finishDate.toLocaleDateString("en-US", {
      month: "short",
      day: "numeric",
      year: "numeric"
    });

    messageOutput.textContent = "Based on " + dailyCapacity + " productive team hour(s) per working day.";
  }

  [tasksInput, hoursInput, teamInput, dailyInput].forEach(function (field) {
    field.addEventListener("input", calculateTimeline);
  });

  calculateTimeline();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-nineteen-demo"&gt;
  &lt;div class="vb-calc-nineteen-shell"&gt;
    &lt;div class="vb-calc-nineteen-header"&gt;
      &lt;span&gt;Example 19&lt;/span&gt;
      &lt;h3&gt;Project Timeline Calculator&lt;/h3&gt;
      &lt;p&gt;Estimate project duration from task count, hours per task, team size, and daily work capacity.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-nineteen-body"&gt;
      &lt;div class="vb-calc-nineteen-fields"&gt;
        &lt;label&gt;
          Number of tasks
          &lt;input type="number" min="1" value="42" data-vb-calc-nineteen-tasks&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Average hours per task
          &lt;input type="number" min="0.5" step="0.5" value="3" data-vb-calc-nineteen-hours&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Team members
          &lt;input type="number" min="1" value="3" data-vb-calc-nineteen-team&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Productive hours per person/day
          &lt;input type="number" min="1" max="12" value="5" data-vb-calc-nineteen-daily&gt;
        &lt;/label&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-nineteen-results"&gt;
        &lt;div&gt;
          &lt;span&gt;Total work&lt;/span&gt;
          &lt;strong data-vb-calc-nineteen-total-hours&gt;0 h&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;span&gt;Working days&lt;/span&gt;
          &lt;strong data-vb-calc-nineteen-days&gt;0 days&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-calc-nineteen-date"&gt;
          &lt;span&gt;Estimated finish&lt;/span&gt;
          &lt;strong data-vb-calc-nineteen-date&gt;—&lt;/strong&gt;
        &lt;/div&gt;

        &lt;p data-vb-calc-nineteen-message&gt;Timeline estimate updates automatically.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-nineteen-demo,
.vb-calc-nineteen-demo * {
  box-sizing: border-box;
}

.vb-calc-nineteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(14, 165, 233, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #eef2ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
}

.vb-calc-nineteen-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-nineteen-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #082f49 0%, #0284c7 52%, #4f46e5 100%) !important;
  background-size: 26px 26px, 26px 26px, auto !important;
}

.vb-calc-nineteen-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-nineteen-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-nineteen-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-nineteen-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 370px;
  gap: 22px;
  padding: clamp(22px, 4vw, 34px);
}

.vb-calc-nineteen-fields {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-calc-nineteen-fields label {
  display: grid;
  gap: 8px;
  color: #075985 !important;
  -webkit-text-fill-color: #075985 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-nineteen-fields input {
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #bae6fd;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-nineteen-results {
  display: grid;
  gap: 12px;
  padding: 18px;
  border-radius: 24px;
  background: #f8fafc;
  border: 1px solid #e2e8f0;
}

.vb-calc-nineteen-results div {
  padding: 16px;
  border-radius: 18px;
  background: linear-gradient(135deg, #f0f9ff, #eef2ff) !important;
  border: 1px solid #bae6fd;
}

.vb-calc-nineteen-results span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-nineteen-results strong {
  display: block;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 26px;
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-calc-nineteen-date strong {
  font-size: 30px;
}

.vb-calc-nineteen-results p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
}

@media (max-width: 900px) {
  .vb-calc-nineteen-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-nineteen-header h3 {
    font-size: 38px !important;
  }

  .vb-calc-nineteen-fields {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This project timeline calculator is useful for project management websites, agency quote pages, developer portfolios, construction service pages, consulting websites, and internal planning dashboards.</p>



<h2 class="wp-block-heading">20. Fuel Cost Calculator</h2>



<p class="wp-block-paragraph"><strong>A fuel cost calculator</strong> is useful for travel websites, car blogs, logistics tools, delivery services, road trip planners, vehicle comparison pages, and transport dashboards. It estimates trip fuel cost from distance, fuel consumption, and fuel price.</p>



<p class="wp-block-paragraph">This example uses distance input, consumption per 100 km, fuel price, passengers, total fuel cost, liters needed, and cost per passenger. The JavaScript combines travel and cost formulas into one useful calculator.</p>



<ul class="wp-block-list">
<li>Trip fuel cost calculator</li>
<li>Distance and consumption formula</li>
<li>Fuel price calculation</li>
<li>Cost split per passenger</li>
<li>Travel and transport calculator UI</li>
</ul>



<div class="vb-calc-twenty-demo">
  <div class="vb-calc-twenty-card">
    <div class="vb-calc-twenty-copy">
      <span>Example 20</span>
      <h3>Fuel Cost Calculator</h3>
      <p>Estimate total fuel cost, liters needed, and cost per passenger for a trip.</p>
    </div>

    <div class="vb-calc-twenty-tool">
      <div class="vb-calc-twenty-grid">
        <label>
          Distance km
          <input type="number" min="1" value="320" data-vb-calc-twenty-distance>
        </label>

        <label>
          Consumption L/100km
          <input type="number" min="1" step="0.1" value="6.8" data-vb-calc-twenty-consumption>
        </label>

        <label>
          Fuel price / liter
          <input type="number" min="0" step="0.01" value="1.72" data-vb-calc-twenty-price>
        </label>

        <label>
          Passengers
          <input type="number" min="1" value="4" data-vb-calc-twenty-passengers>
        </label>
      </div>

      <div class="vb-calc-twenty-results">
        <div>
          <span>Liters needed</span>
          <strong data-vb-calc-twenty-liters>0 L</strong>
        </div>

        <div>
          <span>Total fuel cost</span>
          <strong data-vb-calc-twenty-total>€0</strong>
        </div>

        <div class="vb-calc-twenty-wide">
          <span>Cost per passenger</span>
          <strong data-vb-calc-twenty-person>€0</strong>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-twenty-demo,
.vb-calc-twenty-demo * {
  box-sizing: border-box;
}

.vb-calc-twenty-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(239, 68, 68, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(245, 158, 11, 0.18), transparent 34%),
    linear-gradient(135deg, #fef2f2 0%, #fffbeb 54%, #ffffff 100%) !important;
  border: 1px solid rgba(239, 68, 68, 0.16);
}

.vb-calc-twenty-card {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-calc-twenty-copy {
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #7f1d1d 0%, #dc2626 50%, #f59e0b 100%) !important;
  box-shadow: 0 30px 90px rgba(220, 38, 38, 0.20);
}

.vb-calc-twenty-copy span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-twenty-copy h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 5.2vw, 68px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-twenty-copy p {
  margin: 0 !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-twenty-tool {
  display: grid;
  gap: 16px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-twenty-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-calc-twenty-tool label {
  display: grid;
  gap: 8px;
  color: #991b1b !important;
  -webkit-text-fill-color: #991b1b !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-twenty-tool input {
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #fecaca;
  border-radius: 16px;
  background: #fff7ed;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-twenty-results {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-calc-twenty-results div {
  padding: 18px;
  border-radius: 20px;
  background: linear-gradient(135deg, #fef2f2, #fffbeb) !important;
  border: 1px solid #fecaca;
}

.vb-calc-twenty-wide {
  grid-column: 1 / -1;
}

.vb-calc-twenty-results span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-twenty-results strong {
  display: block;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 34px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-calc-twenty-wide strong {
  font-size: 42px;
}

@media (max-width: 900px) {
  .vb-calc-twenty-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-twenty-copy h3 {
    font-size: 40px !important;
  }

  .vb-calc-twenty-grid,
  .vb-calc-twenty-results {
    grid-template-columns: 1fr;
  }

  .vb-calc-twenty-wide {
    grid-column: auto;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-twenty-demo");
  if (!demo) return;

  const distanceInput = demo.querySelector("[data-vb-calc-twenty-distance]");
  const consumptionInput = demo.querySelector("[data-vb-calc-twenty-consumption]");
  const priceInput = demo.querySelector("[data-vb-calc-twenty-price]");
  const passengersInput = demo.querySelector("[data-vb-calc-twenty-passengers]");
  const litersOutput = demo.querySelector("[data-vb-calc-twenty-liters]");
  const totalOutput = demo.querySelector("[data-vb-calc-twenty-total]");
  const personOutput = demo.querySelector("[data-vb-calc-twenty-person]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    minimumFractionDigits: 2,
    maximumFractionDigits: 2
  });

  function calculateFuel() {
    const distance = Math.max(Number(distanceInput.value) || 0, 0);
    const consumption = Math.max(Number(consumptionInput.value) || 0, 0);
    const price = Math.max(Number(priceInput.value) || 0, 0);
    const passengers = Math.max(Number(passengersInput.value) || 1, 1);

    const liters = distance * consumption / 100;
    const total = liters * price;
    const perPerson = total / passengers;

    litersOutput.textContent = liters.toFixed(1) + " L";
    totalOutput.textContent = money.format(total);
    personOutput.textContent = money.format(perPerson);
  }

  [distanceInput, consumptionInput, priceInput, passengersInput].forEach(function (field) {
    field.addEventListener("input", calculateFuel);
  });

  calculateFuel();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-twenty-demo");
  if (!demo) return;

  const distanceInput = demo.querySelector("[data-vb-calc-twenty-distance]");
  const consumptionInput = demo.querySelector("[data-vb-calc-twenty-consumption]");
  const priceInput = demo.querySelector("[data-vb-calc-twenty-price]");
  const passengersInput = demo.querySelector("[data-vb-calc-twenty-passengers]");
  const litersOutput = demo.querySelector("[data-vb-calc-twenty-liters]");
  const totalOutput = demo.querySelector("[data-vb-calc-twenty-total]");
  const personOutput = demo.querySelector("[data-vb-calc-twenty-person]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    minimumFractionDigits: 2,
    maximumFractionDigits: 2
  });

  function calculateFuel() {
    const distance = Math.max(Number(distanceInput.value) || 0, 0);
    const consumption = Math.max(Number(consumptionInput.value) || 0, 0);
    const price = Math.max(Number(priceInput.value) || 0, 0);
    const passengers = Math.max(Number(passengersInput.value) || 1, 1);

    const liters = distance * consumption / 100;
    const total = liters * price;
    const perPerson = total / passengers;

    litersOutput.textContent = liters.toFixed(1) + " L";
    totalOutput.textContent = money.format(total);
    personOutput.textContent = money.format(perPerson);
  }

  [distanceInput, consumptionInput, priceInput, passengersInput].forEach(function (field) {
    field.addEventListener("input", calculateFuel);
  });

  calculateFuel();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-twenty-demo"&gt;
  &lt;div class="vb-calc-twenty-card"&gt;
    &lt;div class="vb-calc-twenty-copy"&gt;
      &lt;span&gt;Example 20&lt;/span&gt;
      &lt;h3&gt;Fuel Cost Calculator&lt;/h3&gt;
      &lt;p&gt;Estimate total fuel cost, liters needed, and cost per passenger for a trip.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-twenty-tool"&gt;
      &lt;div class="vb-calc-twenty-grid"&gt;
        &lt;label&gt;
          Distance km
          &lt;input type="number" min="1" value="320" data-vb-calc-twenty-distance&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Consumption L/100km
          &lt;input type="number" min="1" step="0.1" value="6.8" data-vb-calc-twenty-consumption&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Fuel price / liter
          &lt;input type="number" min="0" step="0.01" value="1.72" data-vb-calc-twenty-price&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Passengers
          &lt;input type="number" min="1" value="4" data-vb-calc-twenty-passengers&gt;
        &lt;/label&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-twenty-results"&gt;
        &lt;div&gt;
          &lt;span&gt;Liters needed&lt;/span&gt;
          &lt;strong data-vb-calc-twenty-liters&gt;0 L&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;span&gt;Total fuel cost&lt;/span&gt;
          &lt;strong data-vb-calc-twenty-total&gt;€0&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-calc-twenty-wide"&gt;
          &lt;span&gt;Cost per passenger&lt;/span&gt;
          &lt;strong data-vb-calc-twenty-person&gt;€0&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-twenty-demo,
.vb-calc-twenty-demo * {
  box-sizing: border-box;
}

.vb-calc-twenty-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(239, 68, 68, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(245, 158, 11, 0.18), transparent 34%),
    linear-gradient(135deg, #fef2f2 0%, #fffbeb 54%, #ffffff 100%) !important;
  border: 1px solid rgba(239, 68, 68, 0.16);
}

.vb-calc-twenty-card {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-calc-twenty-copy {
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #7f1d1d 0%, #dc2626 50%, #f59e0b 100%) !important;
  box-shadow: 0 30px 90px rgba(220, 38, 38, 0.20);
}

.vb-calc-twenty-copy span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fee2e2 !important;
  -webkit-text-fill-color: #fee2e2 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-twenty-copy h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 5.2vw, 68px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-twenty-copy p {
  margin: 0 !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-twenty-tool {
  display: grid;
  gap: 16px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-twenty-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-calc-twenty-tool label {
  display: grid;
  gap: 8px;
  color: #991b1b !important;
  -webkit-text-fill-color: #991b1b !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-twenty-tool input {
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #fecaca;
  border-radius: 16px;
  background: #fff7ed;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-twenty-results {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-calc-twenty-results div {
  padding: 18px;
  border-radius: 20px;
  background: linear-gradient(135deg, #fef2f2, #fffbeb) !important;
  border: 1px solid #fecaca;
}

.vb-calc-twenty-wide {
  grid-column: 1 / -1;
}

.vb-calc-twenty-results span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-twenty-results strong {
  display: block;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 34px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-calc-twenty-wide strong {
  font-size: 42px;
}

@media (max-width: 900px) {
  .vb-calc-twenty-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-twenty-copy h3 {
    font-size: 40px !important;
  }

  .vb-calc-twenty-grid,
  .vb-calc-twenty-results {
    grid-template-columns: 1fr;
  }

  .vb-calc-twenty-wide {
    grid-column: auto;
  }
}</pre>



<p class="wp-block-paragraph">This fuel cost calculator is useful for travel blogs, road trip planners, car websites, delivery calculators, transport dashboards, logistics tools, and vehicle cost comparison pages.</p>



<h2 class="wp-block-heading">21. Electricity Cost Calculator</h2>



<p class="wp-block-paragraph"><strong>An electricity cost calculator</strong> is useful for energy websites, smart home blogs, appliance pages, solar websites, utility calculators, and cost-saving guides. It estimates electricity cost from wattage, daily usage hours, energy price, and number of days.</p>



<p class="wp-block-paragraph">This example uses watt-to-kilowatt conversion, daily usage logic, monthly cost estimation, yearly projection, and dynamic result cards. The JavaScript calculates energy consumption in kWh and formats the cost clearly.</p>



<ul class="wp-block-list">
<li>Electricity usage cost calculator</li>
<li>Watts to kWh conversion</li>
<li>Daily, monthly, and yearly estimate</li>
<li>Energy price input</li>
<li>Smart home and appliance calculator</li>
</ul>



<div class="vb-calc-twentyone-demo">
  <div class="vb-calc-twentyone-shell">
    <div class="vb-calc-twentyone-header">
      <span>Example 21</span>
      <h3>Electricity Cost Calculator</h3>
      <p>Estimate appliance electricity cost from watts, daily hours, energy price, and usage period.</p>
    </div>

    <div class="vb-calc-twentyone-body">
      <div class="vb-calc-twentyone-fields">
        <label>
          Appliance power watts
          <input type="number" min="1" value="1200" data-vb-calc-twentyone-watts>
        </label>

        <label>
          Hours used per day
          <input type="number" min="0" max="24" step="0.5" value="3.5" data-vb-calc-twentyone-hours>
        </label>

        <label>
          Price per kWh
          <input type="number" min="0" step="0.01" value="0.22" data-vb-calc-twentyone-price>
        </label>

        <label>
          Days used
          <input type="number" min="1" value="30" data-vb-calc-twentyone-days>
        </label>
      </div>

      <div class="vb-calc-twentyone-results">
        <div>
          <span>Energy used</span>
          <strong data-vb-calc-twentyone-kwh>0 kWh</strong>
        </div>

        <div>
          <span>Period cost</span>
          <strong data-vb-calc-twentyone-cost>€0</strong>
        </div>

        <div>
          <span>Yearly projection</span>
          <strong data-vb-calc-twentyone-year>€0</strong>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-twentyone-demo,
.vb-calc-twentyone-demo * {
  box-sizing: border-box;
}

.vb-calc-twentyone-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(250, 204, 21, 0.22), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #fefce8 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(250, 204, 21, 0.24);
}

.vb-calc-twentyone-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-twentyone-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #713f12 0%, #ca8a04 52%, #16a34a 100%) !important;
}

.vb-calc-twentyone-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fef9c3 !important;
  -webkit-text-fill-color: #fef9c3 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-twentyone-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-twentyone-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #fef9c3 !important;
  -webkit-text-fill-color: #fef9c3 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-twentyone-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 370px;
  gap: 22px;
  padding: clamp(22px, 4vw, 34px);
}

.vb-calc-twentyone-fields {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-calc-twentyone-fields label {
  display: grid;
  gap: 8px;
  color: #854d0e !important;
  -webkit-text-fill-color: #854d0e !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-twentyone-fields input {
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #fde68a;
  border-radius: 16px;
  background: #fffdf2;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-twentyone-results {
  display: grid;
  gap: 12px;
  padding: 18px;
  border-radius: 24px;
  background: #fefce8;
  border: 1px solid #fde68a;
}

.vb-calc-twentyone-results div {
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.82);
}

.vb-calc-twentyone-results span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-twentyone-results strong {
  display: block;
  color: #a16207 !important;
  -webkit-text-fill-color: #a16207 !important;
  font-size: 28px;
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

@media (max-width: 900px) {
  .vb-calc-twentyone-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-twentyone-header h3 {
    font-size: 38px !important;
  }

  .vb-calc-twentyone-fields {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-twentyone-demo");
  if (!demo) return;

  const wattsInput = demo.querySelector("[data-vb-calc-twentyone-watts]");
  const hoursInput = demo.querySelector("[data-vb-calc-twentyone-hours]");
  const priceInput = demo.querySelector("[data-vb-calc-twentyone-price]");
  const daysInput = demo.querySelector("[data-vb-calc-twentyone-days]");
  const kwhOutput = demo.querySelector("[data-vb-calc-twentyone-kwh]");
  const costOutput = demo.querySelector("[data-vb-calc-twentyone-cost]");
  const yearOutput = demo.querySelector("[data-vb-calc-twentyone-year]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    minimumFractionDigits: 2,
    maximumFractionDigits: 2
  });

  function calculateElectricity() {
    const watts = Math.max(Number(wattsInput.value) || 0, 0);
    const hours = Math.min(Math.max(Number(hoursInput.value) || 0, 0), 24);
    const price = Math.max(Number(priceInput.value) || 0, 0);
    const days = Math.max(Number(daysInput.value) || 0, 0);

    const kwh = watts / 1000 * hours * days;
    const cost = kwh * price;
    const dailyCost = days > 0 ? cost / days : 0;
    const yearly = dailyCost * 365;

    kwhOutput.textContent = kwh.toFixed(2) + " kWh";
    costOutput.textContent = money.format(cost);
    yearOutput.textContent = money.format(yearly);
  }

  [wattsInput, hoursInput, priceInput, daysInput].forEach(function (field) {
    field.addEventListener("input", calculateElectricity);
  });

  calculateElectricity();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-twentyone-demo");
  if (!demo) return;

  const wattsInput = demo.querySelector("[data-vb-calc-twentyone-watts]");
  const hoursInput = demo.querySelector("[data-vb-calc-twentyone-hours]");
  const priceInput = demo.querySelector("[data-vb-calc-twentyone-price]");
  const daysInput = demo.querySelector("[data-vb-calc-twentyone-days]");
  const kwhOutput = demo.querySelector("[data-vb-calc-twentyone-kwh]");
  const costOutput = demo.querySelector("[data-vb-calc-twentyone-cost]");
  const yearOutput = demo.querySelector("[data-vb-calc-twentyone-year]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    minimumFractionDigits: 2,
    maximumFractionDigits: 2
  });

  function calculateElectricity() {
    const watts = Math.max(Number(wattsInput.value) || 0, 0);
    const hours = Math.min(Math.max(Number(hoursInput.value) || 0, 0), 24);
    const price = Math.max(Number(priceInput.value) || 0, 0);
    const days = Math.max(Number(daysInput.value) || 0, 0);

    const kwh = watts / 1000 * hours * days;
    const cost = kwh * price;
    const dailyCost = days &gt; 0 ? cost / days : 0;
    const yearly = dailyCost * 365;

    kwhOutput.textContent = kwh.toFixed(2) + " kWh";
    costOutput.textContent = money.format(cost);
    yearOutput.textContent = money.format(yearly);
  }

  [wattsInput, hoursInput, priceInput, daysInput].forEach(function (field) {
    field.addEventListener("input", calculateElectricity);
  });

  calculateElectricity();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-twentyone-demo"&gt;
  &lt;div class="vb-calc-twentyone-shell"&gt;
    &lt;div class="vb-calc-twentyone-header"&gt;
      &lt;span&gt;Example 21&lt;/span&gt;
      &lt;h3&gt;Electricity Cost Calculator&lt;/h3&gt;
      &lt;p&gt;Estimate appliance electricity cost from watts, daily hours, energy price, and usage period.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-twentyone-body"&gt;
      &lt;div class="vb-calc-twentyone-fields"&gt;
        &lt;label&gt;
          Appliance power watts
          &lt;input type="number" min="1" value="1200" data-vb-calc-twentyone-watts&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Hours used per day
          &lt;input type="number" min="0" max="24" step="0.5" value="3.5" data-vb-calc-twentyone-hours&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Price per kWh
          &lt;input type="number" min="0" step="0.01" value="0.22" data-vb-calc-twentyone-price&gt;
        &lt;/label&gt;

        &lt;label&gt;
          Days used
          &lt;input type="number" min="1" value="30" data-vb-calc-twentyone-days&gt;
        &lt;/label&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-twentyone-results"&gt;
        &lt;div&gt;
          &lt;span&gt;Energy used&lt;/span&gt;
          &lt;strong data-vb-calc-twentyone-kwh&gt;0 kWh&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;span&gt;Period cost&lt;/span&gt;
          &lt;strong data-vb-calc-twentyone-cost&gt;€0&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;span&gt;Yearly projection&lt;/span&gt;
          &lt;strong data-vb-calc-twentyone-year&gt;€0&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-twentyone-demo,
.vb-calc-twentyone-demo * {
  box-sizing: border-box;
}

.vb-calc-twentyone-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(250, 204, 21, 0.22), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #fefce8 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(250, 204, 21, 0.24);
}

.vb-calc-twentyone-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-twentyone-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #713f12 0%, #ca8a04 52%, #16a34a 100%) !important;
}

.vb-calc-twentyone-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fef9c3 !important;
  -webkit-text-fill-color: #fef9c3 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-twentyone-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.95 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-calc-twentyone-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #fef9c3 !important;
  -webkit-text-fill-color: #fef9c3 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-twentyone-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 370px;
  gap: 22px;
  padding: clamp(22px, 4vw, 34px);
}

.vb-calc-twentyone-fields {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-calc-twentyone-fields label {
  display: grid;
  gap: 8px;
  color: #854d0e !important;
  -webkit-text-fill-color: #854d0e !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-twentyone-fields input {
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #fde68a;
  border-radius: 16px;
  background: #fffdf2;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-twentyone-results {
  display: grid;
  gap: 12px;
  padding: 18px;
  border-radius: 24px;
  background: #fefce8;
  border: 1px solid #fde68a;
}

.vb-calc-twentyone-results div {
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.82);
}

.vb-calc-twentyone-results span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-twentyone-results strong {
  display: block;
  color: #a16207 !important;
  -webkit-text-fill-color: #a16207 !important;
  font-size: 28px;
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

@media (max-width: 900px) {
  .vb-calc-twentyone-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-twentyone-header h3 {
    font-size: 38px !important;
  }

  .vb-calc-twentyone-fields {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This electricity cost calculator is useful for energy-saving blogs, smart home websites, appliance pages, solar energy websites, utility calculators, and JavaScript cost estimation examples.</p>



<h2 class="wp-block-heading">22. Room Paint Calculator</h2>



<p class="wp-block-paragraph"><strong>A room paint calculator</strong> is useful for interior design websites, painting service pages, DIY blogs, renovation tools, construction quote forms, and home improvement calculators. It helps users estimate how many liters of paint they need for a room.</p>



<p class="wp-block-paragraph">This example uses wall area calculation, door and window deduction, coat count, paint coverage per liter, waste percentage, and a rounded paint amount. The JavaScript combines room dimensions and surface deductions into a practical calculator.</p>



<ul class="wp-block-list">
<li>Room paint amount calculator</li>
<li>Wall area calculation</li>
<li>Door and window deduction</li>
<li>Paint coats and coverage logic</li>
<li>Rounded liters needed output</li>
</ul>



<div class="vb-calc-twentytwo-demo">
  <div class="vb-calc-twentytwo-shell">
    <div class="vb-calc-twentytwo-header">
      <span>Example 22</span>
      <h3>Room Paint Calculator</h3>
      <p>Estimate paint liters from room dimensions, doors, windows, coats, and paint coverage.</p>
    </div>

    <div class="vb-calc-twentytwo-body">
      <div class="vb-calc-twentytwo-fields">
        <label>
          Room length m
          <input type="number" min="0.1" step="0.1" value="5" data-vb-calc-twentytwo-length>
        </label>

        <label>
          Room width m
          <input type="number" min="0.1" step="0.1" value="4" data-vb-calc-twentytwo-width>
        </label>

        <label>
          Wall height m
          <input type="number" min="0.1" step="0.1" value="2.6" data-vb-calc-twentytwo-height>
        </label>

        <label>
          Number of doors
          <input type="number" min="0" value="1" data-vb-calc-twentytwo-doors>
        </label>

        <label>
          Number of windows
          <input type="number" min="0" value="2" data-vb-calc-twentytwo-windows>
        </label>

        <label>
          Number of coats
          <input type="number" min="1" value="2" data-vb-calc-twentytwo-coats>
        </label>

        <label>
          Coverage m² per liter
          <input type="number" min="1" step="0.5" value="10" data-vb-calc-twentytwo-coverage>
        </label>

        <label>
          Waste percentage
          <input type="number" min="0" max="50" value="10" data-vb-calc-twentytwo-waste>
        </label>
      </div>

      <div class="vb-calc-twentytwo-result">
        <div class="vb-calc-twentytwo-main">
          <span>Paint needed</span>
          <strong data-vb-calc-twentytwo-liters>0 L</strong>
        </div>

        <div class="vb-calc-twentytwo-mini">
          <div>
            <span>Paintable area</span>
            <strong data-vb-calc-twentytwo-area>0 m²</strong>
          </div>

          <div>
            <span>Total coat area</span>
            <strong data-vb-calc-twentytwo-coat-area>0 m²</strong>
          </div>
        </div>

        <p data-vb-calc-twentytwo-message>Paint estimate updates automatically.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-twentytwo-demo,
.vb-calc-twentytwo-demo * {
  box-sizing: border-box;
}

.vb-calc-twentytwo-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(168, 85, 247, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(236, 72, 153, 0.14), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #fdf2f8 54%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.18);
  overflow: hidden;
}

.vb-calc-twentytwo-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-twentytwo-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #581c87 0%, #9333ea 52%, #db2777 100%) !important;
}

.vb-calc-twentytwo-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #f3e8ff !important;
  -webkit-text-fill-color: #f3e8ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-twentytwo-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-calc-twentytwo-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-twentytwo-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 370px);
  gap: 22px;
  padding: clamp(22px, 4vw, 34px);
  min-width: 0;
}

.vb-calc-twentytwo-fields {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
}

.vb-calc-twentytwo-fields label {
  display: grid;
  min-width: 0;
  gap: 8px;
  color: #6b21a8 !important;
  -webkit-text-fill-color: #6b21a8 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-twentytwo-fields input {
  width: 100%;
  min-width: 0;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #e9d5ff;
  border-radius: 16px;
  background: #faf5ff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-twentytwo-result {
  display: grid;
  min-width: 0;
  gap: 12px;
  padding: 18px;
  border-radius: 24px;
  background: #faf5ff;
  border: 1px solid #e9d5ff;
}

.vb-calc-twentytwo-main,
.vb-calc-twentytwo-mini div {
  min-width: 0;
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.86);
}

.vb-calc-twentytwo-main span,
.vb-calc-twentytwo-mini span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-twentytwo-main strong {
  display: block;
  color: #9333ea !important;
  -webkit-text-fill-color: #9333ea !important;
  font-size: clamp(34px, 5vw, 48px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
  overflow-wrap: anywhere;
}

.vb-calc-twentytwo-mini {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
  min-width: 0;
}

.vb-calc-twentytwo-mini strong {
  display: block;
  color: #701a75 !important;
  -webkit-text-fill-color: #701a75 !important;
  font-size: clamp(20px, 3vw, 26px);
  line-height: 1.1;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-calc-twentytwo-result p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-calc-twentytwo-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-twentytwo-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-calc-twentytwo-fields {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-twentytwo-demo");
  if (!demo) return;

  const lengthInput = demo.querySelector("[data-vb-calc-twentytwo-length]");
  const widthInput = demo.querySelector("[data-vb-calc-twentytwo-width]");
  const heightInput = demo.querySelector("[data-vb-calc-twentytwo-height]");
  const doorsInput = demo.querySelector("[data-vb-calc-twentytwo-doors]");
  const windowsInput = demo.querySelector("[data-vb-calc-twentytwo-windows]");
  const coatsInput = demo.querySelector("[data-vb-calc-twentytwo-coats]");
  const coverageInput = demo.querySelector("[data-vb-calc-twentytwo-coverage]");
  const wasteInput = demo.querySelector("[data-vb-calc-twentytwo-waste]");
  const litersOutput = demo.querySelector("[data-vb-calc-twentytwo-liters]");
  const areaOutput = demo.querySelector("[data-vb-calc-twentytwo-area]");
  const coatAreaOutput = demo.querySelector("[data-vb-calc-twentytwo-coat-area]");
  const messageOutput = demo.querySelector("[data-vb-calc-twentytwo-message]");

  function calculatePaint() {
    const length = Math.max(Number(lengthInput.value) || 0, 0);
    const width = Math.max(Number(widthInput.value) || 0, 0);
    const height = Math.max(Number(heightInput.value) || 0, 0);
    const doors = Math.max(Number(doorsInput.value) || 0, 0);
    const windows = Math.max(Number(windowsInput.value) || 0, 0);
    const coats = Math.max(Number(coatsInput.value) || 1, 1);
    const coverage = Math.max(Number(coverageInput.value) || 0, 0);
    const waste = Math.max(Number(wasteInput.value) || 0, 0);

    const wallArea = 2 * (length + width) * height;
    const deduction = doors * 1.9 + windows * 1.4;
    const paintableArea = Math.max(wallArea - deduction, 0);
    const totalCoatArea = paintableArea * coats;
    const liters = coverage > 0 ? totalCoatArea / coverage * (1 + waste / 100) : 0;

    areaOutput.textContent = paintableArea.toFixed(1) + " m²";
    coatAreaOutput.textContent = totalCoatArea.toFixed(1) + " m²";
    litersOutput.textContent = Math.ceil(liters) + " L";
    messageOutput.textContent = "Estimate includes doors, windows, coats, coverage, and waste percentage.";
  }

  [lengthInput, widthInput, heightInput, doorsInput, windowsInput, coatsInput, coverageInput, wasteInput].forEach(function (field) {
    field.addEventListener("input", calculatePaint);
  });

  calculatePaint();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-twentytwo-demo");
  if (!demo) return;

  const lengthInput = demo.querySelector("[data-vb-calc-twentytwo-length]");
  const widthInput = demo.querySelector("[data-vb-calc-twentytwo-width]");
  const heightInput = demo.querySelector("[data-vb-calc-twentytwo-height]");
  const doorsInput = demo.querySelector("[data-vb-calc-twentytwo-doors]");
  const windowsInput = demo.querySelector("[data-vb-calc-twentytwo-windows]");
  const coatsInput = demo.querySelector("[data-vb-calc-twentytwo-coats]");
  const coverageInput = demo.querySelector("[data-vb-calc-twentytwo-coverage]");
  const wasteInput = demo.querySelector("[data-vb-calc-twentytwo-waste]");
  const litersOutput = demo.querySelector("[data-vb-calc-twentytwo-liters]");
  const areaOutput = demo.querySelector("[data-vb-calc-twentytwo-area]");
  const coatAreaOutput = demo.querySelector("[data-vb-calc-twentytwo-coat-area]");
  const messageOutput = demo.querySelector("[data-vb-calc-twentytwo-message]");

  function calculatePaint() {
    const length = Math.max(Number(lengthInput.value) || 0, 0);
    const width = Math.max(Number(widthInput.value) || 0, 0);
    const height = Math.max(Number(heightInput.value) || 0, 0);
    const doors = Math.max(Number(doorsInput.value) || 0, 0);
    const windows = Math.max(Number(windowsInput.value) || 0, 0);
    const coats = Math.max(Number(coatsInput.value) || 1, 1);
    const coverage = Math.max(Number(coverageInput.value) || 0, 0);
    const waste = Math.max(Number(wasteInput.value) || 0, 0);

    const wallArea = 2 * (length + width) * height;
    const deduction = doors * 1.9 + windows * 1.4;
    const paintableArea = Math.max(wallArea - deduction, 0);
    const totalCoatArea = paintableArea * coats;
    const liters = coverage &gt; 0 ? totalCoatArea / coverage * (1 + waste / 100) : 0;

    areaOutput.textContent = paintableArea.toFixed(1) + " m²";
    coatAreaOutput.textContent = totalCoatArea.toFixed(1) + " m²";
    litersOutput.textContent = Math.ceil(liters) + " L";
    messageOutput.textContent = "Estimate includes doors, windows, coats, coverage, and waste percentage.";
  }

  [lengthInput, widthInput, heightInput, doorsInput, windowsInput, coatsInput, coverageInput, wasteInput].forEach(function (field) {
    field.addEventListener("input", calculatePaint);
  });

  calculatePaint();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-twentytwo-demo"&gt;
  &lt;div class="vb-calc-twentytwo-shell"&gt;
    &lt;div class="vb-calc-twentytwo-header"&gt;
      &lt;span&gt;Example 22&lt;/span&gt;
      &lt;h3&gt;Room Paint Calculator&lt;/h3&gt;
      &lt;p&gt;Estimate paint liters from room dimensions, doors, windows, coats, and paint coverage.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-twentytwo-body"&gt;
      &lt;div class="vb-calc-twentytwo-fields"&gt;
        &lt;label&gt;Room length m&lt;input type="number" min="0.1" step="0.1" value="5" data-vb-calc-twentytwo-length&gt;&lt;/label&gt;
        &lt;label&gt;Room width m&lt;input type="number" min="0.1" step="0.1" value="4" data-vb-calc-twentytwo-width&gt;&lt;/label&gt;
        &lt;label&gt;Wall height m&lt;input type="number" min="0.1" step="0.1" value="2.6" data-vb-calc-twentytwo-height&gt;&lt;/label&gt;
        &lt;label&gt;Number of doors&lt;input type="number" min="0" value="1" data-vb-calc-twentytwo-doors&gt;&lt;/label&gt;
        &lt;label&gt;Number of windows&lt;input type="number" min="0" value="2" data-vb-calc-twentytwo-windows&gt;&lt;/label&gt;
        &lt;label&gt;Number of coats&lt;input type="number" min="1" value="2" data-vb-calc-twentytwo-coats&gt;&lt;/label&gt;
        &lt;label&gt;Coverage m² per liter&lt;input type="number" min="1" step="0.5" value="10" data-vb-calc-twentytwo-coverage&gt;&lt;/label&gt;
        &lt;label&gt;Waste percentage&lt;input type="number" min="0" max="50" value="10" data-vb-calc-twentytwo-waste&gt;&lt;/label&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-twentytwo-result"&gt;
        &lt;div class="vb-calc-twentytwo-main"&gt;
          &lt;span&gt;Paint needed&lt;/span&gt;
          &lt;strong data-vb-calc-twentytwo-liters&gt;0 L&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-calc-twentytwo-mini"&gt;
          &lt;div&gt;&lt;span&gt;Paintable area&lt;/span&gt;&lt;strong data-vb-calc-twentytwo-area&gt;0 m²&lt;/strong&gt;&lt;/div&gt;
          &lt;div&gt;&lt;span&gt;Total coat area&lt;/span&gt;&lt;strong data-vb-calc-twentytwo-coat-area&gt;0 m²&lt;/strong&gt;&lt;/div&gt;
        &lt;/div&gt;

        &lt;p data-vb-calc-twentytwo-message&gt;Paint estimate updates automatically.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-twentytwo-demo,
.vb-calc-twentytwo-demo * {
  box-sizing: border-box;
}

.vb-calc-twentytwo-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(168, 85, 247, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(236, 72, 153, 0.14), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #fdf2f8 54%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.18);
  overflow: hidden;
}

.vb-calc-twentytwo-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-twentytwo-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #581c87 0%, #9333ea 52%, #db2777 100%) !important;
}

.vb-calc-twentytwo-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #f3e8ff !important;
  -webkit-text-fill-color: #f3e8ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-twentytwo-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-calc-twentytwo-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-twentytwo-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 370px);
  gap: 22px;
  padding: clamp(22px, 4vw, 34px);
  min-width: 0;
}

.vb-calc-twentytwo-fields {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
}

.vb-calc-twentytwo-fields label {
  display: grid;
  min-width: 0;
  gap: 8px;
  color: #6b21a8 !important;
  -webkit-text-fill-color: #6b21a8 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-twentytwo-fields input {
  width: 100%;
  min-width: 0;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #e9d5ff;
  border-radius: 16px;
  background: #faf5ff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-twentytwo-result {
  display: grid;
  min-width: 0;
  gap: 12px;
  padding: 18px;
  border-radius: 24px;
  background: #faf5ff;
  border: 1px solid #e9d5ff;
}

.vb-calc-twentytwo-main,
.vb-calc-twentytwo-mini div {
  min-width: 0;
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.86);
}

.vb-calc-twentytwo-main span,
.vb-calc-twentytwo-mini span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-twentytwo-main strong {
  display: block;
  color: #9333ea !important;
  -webkit-text-fill-color: #9333ea !important;
  font-size: clamp(34px, 5vw, 48px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
  overflow-wrap: anywhere;
}

.vb-calc-twentytwo-mini {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
  min-width: 0;
}

.vb-calc-twentytwo-mini strong {
  display: block;
  color: #701a75 !important;
  -webkit-text-fill-color: #701a75 !important;
  font-size: clamp(20px, 3vw, 26px);
  line-height: 1.1;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-calc-twentytwo-result p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-calc-twentytwo-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-twentytwo-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-calc-twentytwo-fields {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This room paint calculator is useful for painting service websites, renovation blogs, interior design pages, home improvement tools, DIY guides, construction calculators, and quote request forms.</p>



<h2 class="wp-block-heading">23. Flooring Cost Calculator</h2>



<p class="wp-block-paragraph"><strong>A flooring cost calculator</strong> is useful for flooring stores, renovation companies, construction websites, interior design tools, product pages, and quote request forms. It helps users estimate material cost, waste amount, installation cost, and total flooring project price.</p>



<p class="wp-block-paragraph">This example uses room area, material price, waste percentage, installation price, and optional underlayment. The JavaScript calculates material area with waste, material cost, labor cost, underlayment cost, and final project estimate.</p>



<ul class="wp-block-list">
<li>Flooring project cost calculator</li>
<li>Area and waste percentage logic</li>
<li>Material and labor cost calculation</li>
<li>Optional underlayment checkbox</li>
<li>Home renovation calculator UI</li>
</ul>



<div class="vb-calc-twentythree-demo">
  <div class="vb-calc-twentythree-card">
    <div class="vb-calc-twentythree-title">
      <span>Example 23</span>
      <h3>Flooring Cost Calculator</h3>
      <p>Estimate flooring material, installation, waste, and optional underlayment costs.</p>
    </div>

    <div class="vb-calc-twentythree-tool">
      <div class="vb-calc-twentythree-grid">
        <label>
          Room area m²
          <input type="number" min="1" value="38" data-vb-calc-twentythree-area>
        </label>

        <label>
          Material price / m²
          <input type="number" min="0" step="0.01" value="24.90" data-vb-calc-twentythree-material>
        </label>

        <label>
          Installation price / m²
          <input type="number" min="0" step="0.01" value="14" data-vb-calc-twentythree-labor>
        </label>

        <label>
          Waste percentage
          <input type="number" min="0" max="40" value="8" data-vb-calc-twentythree-waste>
        </label>
      </div>

      <label class="vb-calc-twentythree-check">
        <input type="checkbox" checked data-vb-calc-twentythree-underlay>
        Add underlayment at €3.50 / m²
      </label>

      <div class="vb-calc-twentythree-result">
        <div>
          <span>Material area</span>
          <strong data-vb-calc-twentythree-total-area>0 m²</strong>
        </div>

        <div>
          <span>Material cost</span>
          <strong data-vb-calc-twentythree-material-cost>€0</strong>
        </div>

        <div>
          <span>Labor cost</span>
          <strong data-vb-calc-twentythree-labor-cost>€0</strong>
        </div>

        <div class="vb-calc-twentythree-total">
          <span>Total estimate</span>
          <strong data-vb-calc-twentythree-total>€0</strong>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-twentythree-demo,
.vb-calc-twentythree-demo * {
  box-sizing: border-box;
}

.vb-calc-twentythree-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(120, 113, 108, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(217, 119, 6, 0.16), transparent 34%),
    linear-gradient(135deg, #fafaf9 0%, #fffbeb 54%, #ffffff 100%) !important;
  border: 1px solid rgba(120, 113, 108, 0.18);
  overflow: hidden;
}

.vb-calc-twentythree-card {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
  min-width: 0;
}

.vb-calc-twentythree-title {
  min-width: 0;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #292524 0%, #78716c 52%, #d97706 100%) !important;
  box-shadow: 0 30px 90px rgba(120, 113, 108, 0.22);
}

.vb-calc-twentythree-title span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-twentythree-title h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-calc-twentythree-title p {
  margin: 0 !important;
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-calc-twentythree-tool {
  display: grid;
  min-width: 0;
  gap: 16px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-twentythree-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
}

.vb-calc-twentythree-grid label {
  display: grid;
  min-width: 0;
  gap: 8px;
  color: #57534e !important;
  -webkit-text-fill-color: #57534e !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-twentythree-grid input {
  width: 100%;
  min-width: 0;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #e7e5e4;
  border-radius: 16px;
  background: #fafaf9;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-twentythree-check {
  display: flex;
  align-items: center;
  min-width: 0;
  gap: 10px;
  padding: 14px;
  border-radius: 18px;
  background: #fffbeb;
  border: 1px solid #fde68a;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 14px;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-calc-twentythree-check input {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  accent-color: #d97706;
}

.vb-calc-twentythree-result {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  min-width: 0;
}

.vb-calc-twentythree-result div {
  min-width: 0;
  padding: 16px;
  border-radius: 18px;
  background: linear-gradient(135deg, #fafaf9, #fffbeb) !important;
  border: 1px solid #e7e5e4;
}

.vb-calc-twentythree-total {
  grid-column: 1 / -1;
  background: linear-gradient(135deg, #fffbeb, #fef3c7) !important;
}

.vb-calc-twentythree-result span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-twentythree-result strong {
  display: block;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: clamp(20px, 3.2vw, 28px);
  line-height: 1.08;
  font-weight: 950;
  letter-spacing: -0.04em;
  overflow-wrap: anywhere;
}

.vb-calc-twentythree-total strong {
  font-size: clamp(32px, 5vw, 46px);
}

@media (max-width: 900px) {
  .vb-calc-twentythree-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-twentythree-title h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-calc-twentythree-grid,
  .vb-calc-twentythree-result {
    grid-template-columns: 1fr;
  }

  .vb-calc-twentythree-total {
    grid-column: auto;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-twentythree-demo");
  if (!demo) return;

  const areaInput = demo.querySelector("[data-vb-calc-twentythree-area]");
  const materialInput = demo.querySelector("[data-vb-calc-twentythree-material]");
  const laborInput = demo.querySelector("[data-vb-calc-twentythree-labor]");
  const wasteInput = demo.querySelector("[data-vb-calc-twentythree-waste]");
  const underlayInput = demo.querySelector("[data-vb-calc-twentythree-underlay]");
  const totalAreaOutput = demo.querySelector("[data-vb-calc-twentythree-total-area]");
  const materialCostOutput = demo.querySelector("[data-vb-calc-twentythree-material-cost]");
  const laborCostOutput = demo.querySelector("[data-vb-calc-twentythree-labor-cost]");
  const totalOutput = demo.querySelector("[data-vb-calc-twentythree-total]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 2
  });

  function calculateFlooring() {
    const area = Math.max(Number(areaInput.value) || 0, 0);
    const materialPrice = Math.max(Number(materialInput.value) || 0, 0);
    const laborPrice = Math.max(Number(laborInput.value) || 0, 0);
    const waste = Math.max(Number(wasteInput.value) || 0, 0);

    const materialArea = area * (1 + waste / 100);
    const materialCost = materialArea * materialPrice;
    const laborCost = area * laborPrice;
    const underlayCost = underlayInput.checked ? materialArea * 3.5 : 0;
    const total = materialCost + laborCost + underlayCost;

    totalAreaOutput.textContent = materialArea.toFixed(1) + " m²";
    materialCostOutput.textContent = money.format(materialCost);
    laborCostOutput.textContent = money.format(laborCost);
    totalOutput.textContent = money.format(total);
  }

  [areaInput, materialInput, laborInput, wasteInput, underlayInput].forEach(function (field) {
    field.addEventListener("input", calculateFlooring);
    field.addEventListener("change", calculateFlooring);
  });

  calculateFlooring();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-twentythree-demo");
  if (!demo) return;

  const areaInput = demo.querySelector("[data-vb-calc-twentythree-area]");
  const materialInput = demo.querySelector("[data-vb-calc-twentythree-material]");
  const laborInput = demo.querySelector("[data-vb-calc-twentythree-labor]");
  const wasteInput = demo.querySelector("[data-vb-calc-twentythree-waste]");
  const underlayInput = demo.querySelector("[data-vb-calc-twentythree-underlay]");
  const totalAreaOutput = demo.querySelector("[data-vb-calc-twentythree-total-area]");
  const materialCostOutput = demo.querySelector("[data-vb-calc-twentythree-material-cost]");
  const laborCostOutput = demo.querySelector("[data-vb-calc-twentythree-labor-cost]");
  const totalOutput = demo.querySelector("[data-vb-calc-twentythree-total]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 2
  });

  function calculateFlooring() {
    const area = Math.max(Number(areaInput.value) || 0, 0);
    const materialPrice = Math.max(Number(materialInput.value) || 0, 0);
    const laborPrice = Math.max(Number(laborInput.value) || 0, 0);
    const waste = Math.max(Number(wasteInput.value) || 0, 0);

    const materialArea = area * (1 + waste / 100);
    const materialCost = materialArea * materialPrice;
    const laborCost = area * laborPrice;
    const underlayCost = underlayInput.checked ? materialArea * 3.5 : 0;
    const total = materialCost + laborCost + underlayCost;

    totalAreaOutput.textContent = materialArea.toFixed(1) + " m²";
    materialCostOutput.textContent = money.format(materialCost);
    laborCostOutput.textContent = money.format(laborCost);
    totalOutput.textContent = money.format(total);
  }

  [areaInput, materialInput, laborInput, wasteInput, underlayInput].forEach(function (field) {
    field.addEventListener("input", calculateFlooring);
    field.addEventListener("change", calculateFlooring);
  });

  calculateFlooring();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-twentythree-demo"&gt;
  &lt;div class="vb-calc-twentythree-card"&gt;
    &lt;div class="vb-calc-twentythree-title"&gt;
      &lt;span&gt;Example 23&lt;/span&gt;
      &lt;h3&gt;Flooring Cost Calculator&lt;/h3&gt;
      &lt;p&gt;Estimate flooring material, installation, waste, and optional underlayment costs.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-twentythree-tool"&gt;
      &lt;div class="vb-calc-twentythree-grid"&gt;
        &lt;label&gt;Room area m²&lt;input type="number" min="1" value="38" data-vb-calc-twentythree-area&gt;&lt;/label&gt;
        &lt;label&gt;Material price / m²&lt;input type="number" min="0" step="0.01" value="24.90" data-vb-calc-twentythree-material&gt;&lt;/label&gt;
        &lt;label&gt;Installation price / m²&lt;input type="number" min="0" step="0.01" value="14" data-vb-calc-twentythree-labor&gt;&lt;/label&gt;
        &lt;label&gt;Waste percentage&lt;input type="number" min="0" max="40" value="8" data-vb-calc-twentythree-waste&gt;&lt;/label&gt;
      &lt;/div&gt;

      &lt;label class="vb-calc-twentythree-check"&gt;
        &lt;input type="checkbox" checked data-vb-calc-twentythree-underlay&gt;
        Add underlayment at €3.50 / m²
      &lt;/label&gt;

      &lt;div class="vb-calc-twentythree-result"&gt;
        &lt;div&gt;&lt;span&gt;Material area&lt;/span&gt;&lt;strong data-vb-calc-twentythree-total-area&gt;0 m²&lt;/strong&gt;&lt;/div&gt;
        &lt;div&gt;&lt;span&gt;Material cost&lt;/span&gt;&lt;strong data-vb-calc-twentythree-material-cost&gt;€0&lt;/strong&gt;&lt;/div&gt;
        &lt;div&gt;&lt;span&gt;Labor cost&lt;/span&gt;&lt;strong data-vb-calc-twentythree-labor-cost&gt;€0&lt;/strong&gt;&lt;/div&gt;
        &lt;div class="vb-calc-twentythree-total"&gt;&lt;span&gt;Total estimate&lt;/span&gt;&lt;strong data-vb-calc-twentythree-total&gt;€0&lt;/strong&gt;&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-twentythree-demo,
.vb-calc-twentythree-demo * {
  box-sizing: border-box;
}

.vb-calc-twentythree-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(120, 113, 108, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(217, 119, 6, 0.16), transparent 34%),
    linear-gradient(135deg, #fafaf9 0%, #fffbeb 54%, #ffffff 100%) !important;
  border: 1px solid rgba(120, 113, 108, 0.18);
  overflow: hidden;
}

.vb-calc-twentythree-card {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
  min-width: 0;
}

.vb-calc-twentythree-title {
  min-width: 0;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #292524 0%, #78716c 52%, #d97706 100%) !important;
  box-shadow: 0 30px 90px rgba(120, 113, 108, 0.22);
}

.vb-calc-twentythree-title span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-twentythree-title h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-calc-twentythree-title p {
  margin: 0 !important;
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-calc-twentythree-tool {
  display: grid;
  min-width: 0;
  gap: 16px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-twentythree-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
}

.vb-calc-twentythree-grid label {
  display: grid;
  min-width: 0;
  gap: 8px;
  color: #57534e !important;
  -webkit-text-fill-color: #57534e !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-twentythree-grid input {
  width: 100%;
  min-width: 0;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #e7e5e4;
  border-radius: 16px;
  background: #fafaf9;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-twentythree-check {
  display: flex;
  align-items: center;
  min-width: 0;
  gap: 10px;
  padding: 14px;
  border-radius: 18px;
  background: #fffbeb;
  border: 1px solid #fde68a;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 14px;
  font-weight: 850;
  overflow-wrap: anywhere;
}

.vb-calc-twentythree-check input {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  accent-color: #d97706;
}

.vb-calc-twentythree-result {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  min-width: 0;
}

.vb-calc-twentythree-result div {
  min-width: 0;
  padding: 16px;
  border-radius: 18px;
  background: linear-gradient(135deg, #fafaf9, #fffbeb) !important;
  border: 1px solid #e7e5e4;
}

.vb-calc-twentythree-total {
  grid-column: 1 / -1;
  background: linear-gradient(135deg, #fffbeb, #fef3c7) !important;
}

.vb-calc-twentythree-result span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-twentythree-result strong {
  display: block;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: clamp(20px, 3.2vw, 28px);
  line-height: 1.08;
  font-weight: 950;
  letter-spacing: -0.04em;
  overflow-wrap: anywhere;
}

.vb-calc-twentythree-total strong {
  font-size: clamp(32px, 5vw, 46px);
}

@media (max-width: 900px) {
  .vb-calc-twentythree-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-twentythree-title h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-calc-twentythree-grid,
  .vb-calc-twentythree-result {
    grid-template-columns: 1fr;
  }

  .vb-calc-twentythree-total {
    grid-column: auto;
  }
}</pre>



<p class="wp-block-paragraph">This flooring cost calculator is useful for flooring stores, renovation companies, product pages, construction quote tools, interior design websites, home improvement blogs, and service price estimators.</p>



<h2 class="wp-block-heading">24. Restaurant Order Calculator</h2>



<p class="wp-block-paragraph"><strong>A restaurant order calculator</strong> is useful for food ordering pages, menu websites, restaurant demos, takeaway forms, catering quote pages, and checkout interfaces. It calculates order subtotal, service fee, delivery fee, and final total from menu item quantities.</p>



<p class="wp-block-paragraph">This example uses menu item data stored in JavaScript, dynamic rendering, quantity buttons, order subtotal, service fee, delivery fee, and final price calculation. The JavaScript creates the menu rows automatically and updates totals when users change quantities.</p>



<ul class="wp-block-list">
<li>Restaurant order total calculator</li>
<li>JavaScript menu data array</li>
<li>Dynamic item rendering</li>
<li>Quantity plus and minus buttons</li>
<li>Service fee and delivery fee calculation</li>
</ul>



<div class="vb-calc-twentyfour-demo">
  <div class="vb-calc-twentyfour-shell">
    <div class="vb-calc-twentyfour-header">
      <span>Example 24</span>
      <h3>Restaurant Order Calculator</h3>
      <p>Build a dynamic menu order calculator with item quantities, fees, and final total.</p>
    </div>

    <div class="vb-calc-twentyfour-body">
      <div class="vb-calc-twentyfour-menu" data-vb-calc-twentyfour-menu></div>

      <div class="vb-calc-twentyfour-summary">
        <div><span>Subtotal</span><strong data-vb-calc-twentyfour-subtotal>€0</strong></div>
        <div><span>Service fee</span><strong data-vb-calc-twentyfour-service>€0</strong></div>
        <div><span>Delivery</span><strong data-vb-calc-twentyfour-delivery>€0</strong></div>

        <div class="vb-calc-twentyfour-total">
          <span>Total order</span>
          <strong data-vb-calc-twentyfour-total>€0</strong>
        </div>

        <p data-vb-calc-twentyfour-message>Add menu items to calculate the order.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-twentyfour-demo,
.vb-calc-twentyfour-demo * {
  box-sizing: border-box;
}

.vb-calc-twentyfour-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(239, 68, 68, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(251, 146, 60, 0.18), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #fef2f2 54%, #ffffff 100%) !important;
  border: 1px solid rgba(239, 68, 68, 0.16);
  overflow: hidden;
}

.vb-calc-twentyfour-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-twentyfour-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #7f1d1d 0%, #dc2626 52%, #f97316 100%) !important;
}

.vb-calc-twentyfour-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-twentyfour-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-calc-twentyfour-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-twentyfour-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(290px, 350px);
  gap: 22px;
  padding: clamp(22px, 4vw, 34px);
  min-width: 0;
}

.vb-calc-twentyfour-menu {
  display: grid;
  gap: 12px;
  min-width: 0;
}

.vb-calc-twentyfour-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 14px;
  align-items: center;
  min-width: 0;
  padding: 16px;
  border-radius: 20px;
  background: #fff7ed;
  border: 1px solid #fed7aa;
}

.vb-calc-twentyfour-item-info {
  min-width: 0;
}

.vb-calc-twentyfour-item-info strong {
  display: block;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 16px;
  line-height: 1.2;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-calc-twentyfour-item-info span {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 700;
}

.vb-calc-twentyfour-qty {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  white-space: nowrap;
}

.vb-calc-twentyfour-qty button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border: 0;
  border-radius: 999px;
  background: #ea580c;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
  cursor: pointer;
}

.vb-calc-twentyfour-qty span {
  display: inline-flex;
  justify-content: center;
  min-width: 24px;
  color: #7f1d1d !important;
  -webkit-text-fill-color: #7f1d1d !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-calc-twentyfour-summary {
  display: grid;
  min-width: 0;
  gap: 10px;
  padding: 18px;
  border-radius: 24px;
  background: #fff7ed;
  border: 1px solid #fed7aa;
  align-self: start;
}

.vb-calc-twentyfour-summary div {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  min-width: 0;
  padding: 11px 0;
  border-bottom: 1px solid rgba(251, 146, 60, 0.28);
}

.vb-calc-twentyfour-summary span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 900;
  overflow-wrap: anywhere;
}

.vb-calc-twentyfour-summary strong {
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 17px;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-calc-twentyfour-total {
  display: block !important;
  padding: 18px !important;
  border: 0 !important;
  border-radius: 20px;
  background: linear-gradient(135deg, #ffedd5, #fee2e2) !important;
}

.vb-calc-twentyfour-total span {
  display: block;
  margin-bottom: 8px;
}

.vb-calc-twentyfour-total strong {
  display: block;
  color: #dc2626 !important;
  -webkit-text-fill-color: #dc2626 !important;
  font-size: clamp(34px, 5vw, 46px);
  line-height: 1;
  letter-spacing: -0.05em;
}

.vb-calc-twentyfour-summary p {
  margin: 0 !important;
  color: #7f1d1d !important;
  -webkit-text-fill-color: #7f1d1d !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-calc-twentyfour-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-twentyfour-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-calc-twentyfour-item {
    grid-template-columns: 1fr;
  }

  .vb-calc-twentyfour-qty {
    justify-content: flex-start;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-twentyfour-demo");
  if (!demo) return;

  const menuContainer = demo.querySelector("[data-vb-calc-twentyfour-menu]");
  const subtotalOutput = demo.querySelector("[data-vb-calc-twentyfour-subtotal]");
  const serviceOutput = demo.querySelector("[data-vb-calc-twentyfour-service]");
  const deliveryOutput = demo.querySelector("[data-vb-calc-twentyfour-delivery]");
  const totalOutput = demo.querySelector("[data-vb-calc-twentyfour-total]");
  const messageOutput = demo.querySelector("[data-vb-calc-twentyfour-message]");

  const items = [
    { name: "Margherita Pizza", note: "Classic tomato and mozzarella", price: 11.9, qty: 1 },
    { name: "Caesar Salad", note: "Crisp salad with dressing", price: 8.5, qty: 0 },
    { name: "Pasta Bowl", note: "Creamy pasta with herbs", price: 12.4, qty: 1 },
    { name: "Fresh Lemonade", note: "Cold house drink", price: 3.8, qty: 2 }
  ];

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 2
  });

  function renderMenu() {
    menuContainer.innerHTML = "";

    items.forEach(function (item, index) {
      const row = document.createElement("div");
      row.className = "vb-calc-twentyfour-item";

      row.innerHTML =
        '<div class="vb-calc-twentyfour-item-info">' +
          '<strong>' + item.name + '</strong>' +
          '<span>' + item.note + ' · ' + money.format(item.price) + '</span>' +
        '</div>' +
        '<div class="vb-calc-twentyfour-qty">' +
          '<button type="button" data-action="minus" data-index="' + index + '">−</button>' +
          '<span>' + item.qty + '</span>' +
          '<button type="button" data-action="plus" data-index="' + index + '">+</button>' +
        '</div>';

      menuContainer.appendChild(row);
    });
  }

  function calculateOrder() {
    const subtotal = items.reduce(function (sum, item) {
      return sum + item.price * item.qty;
    }, 0);

    const serviceFee = subtotal * 0.08;
    const deliveryFee = subtotal >= 35 || subtotal === 0 ? 0 : 4.9;
    const total = subtotal + serviceFee + deliveryFee;
    const itemCount = items.reduce(function (sum, item) {
      return sum + item.qty;
    }, 0);

    subtotalOutput.textContent = money.format(subtotal);
    serviceOutput.textContent = money.format(serviceFee);
    deliveryOutput.textContent = money.format(deliveryFee);
    totalOutput.textContent = money.format(total);
    messageOutput.textContent = itemCount + " item(s) selected. Delivery is free from €35.";
  }

  menuContainer.addEventListener("click", function (event) {
    const button = event.target.closest("button[data-action]");
    if (!button) return;

    const index = Number(button.dataset.index);
    const action = button.dataset.action;

    if (action === "plus") {
      items[index].qty += 1;
    }

    if (action === "minus") {
      items[index].qty = Math.max(items[index].qty - 1, 0);
    }

    renderMenu();
    calculateOrder();
  });

  renderMenu();
  calculateOrder();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-twentyfour-demo");
  if (!demo) return;

  const menuContainer = demo.querySelector("[data-vb-calc-twentyfour-menu]");
  const subtotalOutput = demo.querySelector("[data-vb-calc-twentyfour-subtotal]");
  const serviceOutput = demo.querySelector("[data-vb-calc-twentyfour-service]");
  const deliveryOutput = demo.querySelector("[data-vb-calc-twentyfour-delivery]");
  const totalOutput = demo.querySelector("[data-vb-calc-twentyfour-total]");
  const messageOutput = demo.querySelector("[data-vb-calc-twentyfour-message]");

  const items = [
    { name: "Margherita Pizza", note: "Classic tomato and mozzarella", price: 11.9, qty: 1 },
    { name: "Caesar Salad", note: "Crisp salad with dressing", price: 8.5, qty: 0 },
    { name: "Pasta Bowl", note: "Creamy pasta with herbs", price: 12.4, qty: 1 },
    { name: "Fresh Lemonade", note: "Cold house drink", price: 3.8, qty: 2 }
  ];

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 2
  });

  function renderMenu() {
    menuContainer.innerHTML = "";

    items.forEach(function (item, index) {
      const row = document.createElement("div");
      row.className = "vb-calc-twentyfour-item";

      row.innerHTML =
        '&lt;div class="vb-calc-twentyfour-item-info"&gt;' +
          '&lt;strong&gt;' + item.name + '&lt;/strong&gt;' +
          '&lt;span&gt;' + item.note + ' · ' + money.format(item.price) + '&lt;/span&gt;' +
        '&lt;/div&gt;' +
        '&lt;div class="vb-calc-twentyfour-qty"&gt;' +
          '&lt;button type="button" data-action="minus" data-index="' + index + '"&gt;−&lt;/button&gt;' +
          '&lt;span&gt;' + item.qty + '&lt;/span&gt;' +
          '&lt;button type="button" data-action="plus" data-index="' + index + '"&gt;+&lt;/button&gt;' +
        '&lt;/div&gt;';

      menuContainer.appendChild(row);
    });
  }

  function calculateOrder() {
    const subtotal = items.reduce(function (sum, item) {
      return sum + item.price * item.qty;
    }, 0);

    const serviceFee = subtotal * 0.08;
    const deliveryFee = subtotal &gt;= 35 || subtotal === 0 ? 0 : 4.9;
    const total = subtotal + serviceFee + deliveryFee;
    const itemCount = items.reduce(function (sum, item) {
      return sum + item.qty;
    }, 0);

    subtotalOutput.textContent = money.format(subtotal);
    serviceOutput.textContent = money.format(serviceFee);
    deliveryOutput.textContent = money.format(deliveryFee);
    totalOutput.textContent = money.format(total);
    messageOutput.textContent = itemCount + " item(s) selected. Delivery is free from €35.";
  }

  menuContainer.addEventListener("click", function (event) {
    const button = event.target.closest("button[data-action]");
    if (!button) return;

    const index = Number(button.dataset.index);
    const action = button.dataset.action;

    if (action === "plus") {
      items[index].qty += 1;
    }

    if (action === "minus") {
      items[index].qty = Math.max(items[index].qty - 1, 0);
    }

    renderMenu();
    calculateOrder();
  });

  renderMenu();
  calculateOrder();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-twentyfour-demo"&gt;
  &lt;div class="vb-calc-twentyfour-shell"&gt;
    &lt;div class="vb-calc-twentyfour-header"&gt;
      &lt;span&gt;Example 24&lt;/span&gt;
      &lt;h3&gt;Restaurant Order Calculator&lt;/h3&gt;
      &lt;p&gt;Build a dynamic menu order calculator with item quantities, fees, and final total.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-twentyfour-body"&gt;
      &lt;div class="vb-calc-twentyfour-menu" data-vb-calc-twentyfour-menu&gt;&lt;/div&gt;

      &lt;div class="vb-calc-twentyfour-summary"&gt;
        &lt;div&gt;&lt;span&gt;Subtotal&lt;/span&gt;&lt;strong data-vb-calc-twentyfour-subtotal&gt;€0&lt;/strong&gt;&lt;/div&gt;
        &lt;div&gt;&lt;span&gt;Service fee&lt;/span&gt;&lt;strong data-vb-calc-twentyfour-service&gt;€0&lt;/strong&gt;&lt;/div&gt;
        &lt;div&gt;&lt;span&gt;Delivery&lt;/span&gt;&lt;strong data-vb-calc-twentyfour-delivery&gt;€0&lt;/strong&gt;&lt;/div&gt;

        &lt;div class="vb-calc-twentyfour-total"&gt;
          &lt;span&gt;Total order&lt;/span&gt;
          &lt;strong data-vb-calc-twentyfour-total&gt;€0&lt;/strong&gt;
        &lt;/div&gt;

        &lt;p data-vb-calc-twentyfour-message&gt;Add menu items to calculate the order.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-twentyfour-demo,
.vb-calc-twentyfour-demo * {
  box-sizing: border-box;
}

.vb-calc-twentyfour-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(239, 68, 68, 0.16), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(251, 146, 60, 0.18), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #fef2f2 54%, #ffffff 100%) !important;
  border: 1px solid rgba(239, 68, 68, 0.16);
  overflow: hidden;
}

.vb-calc-twentyfour-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-twentyfour-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #7f1d1d 0%, #dc2626 52%, #f97316 100%) !important;
}

.vb-calc-twentyfour-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-twentyfour-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-calc-twentyfour-header p {
  max-width: 760px;
  margin: 0 !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-calc-twentyfour-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(290px, 350px);
  gap: 22px;
  padding: clamp(22px, 4vw, 34px);
  min-width: 0;
}

.vb-calc-twentyfour-menu {
  display: grid;
  gap: 12px;
  min-width: 0;
}

.vb-calc-twentyfour-item {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 14px;
  align-items: center;
  min-width: 0;
  padding: 16px;
  border-radius: 20px;
  background: #fff7ed;
  border: 1px solid #fed7aa;
}

.vb-calc-twentyfour-item-info {
  min-width: 0;
}

.vb-calc-twentyfour-item-info strong {
  display: block;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 16px;
  line-height: 1.2;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-calc-twentyfour-item-info span {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 700;
}

.vb-calc-twentyfour-qty {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
  white-space: nowrap;
}

.vb-calc-twentyfour-qty button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border: 0;
  border-radius: 999px;
  background: #ea580c;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
  cursor: pointer;
}

.vb-calc-twentyfour-qty span {
  display: inline-flex;
  justify-content: center;
  min-width: 24px;
  color: #7f1d1d !important;
  -webkit-text-fill-color: #7f1d1d !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-calc-twentyfour-summary {
  display: grid;
  min-width: 0;
  gap: 10px;
  padding: 18px;
  border-radius: 24px;
  background: #fff7ed;
  border: 1px solid #fed7aa;
  align-self: start;
}

.vb-calc-twentyfour-summary div {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  min-width: 0;
  padding: 11px 0;
  border-bottom: 1px solid rgba(251, 146, 60, 0.28);
}

.vb-calc-twentyfour-summary span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 900;
  overflow-wrap: anywhere;
}

.vb-calc-twentyfour-summary strong {
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 17px;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-calc-twentyfour-total {
  display: block !important;
  padding: 18px !important;
  border: 0 !important;
  border-radius: 20px;
  background: linear-gradient(135deg, #ffedd5, #fee2e2) !important;
}

.vb-calc-twentyfour-total span {
  display: block;
  margin-bottom: 8px;
}

.vb-calc-twentyfour-total strong {
  display: block;
  color: #dc2626 !important;
  -webkit-text-fill-color: #dc2626 !important;
  font-size: clamp(34px, 5vw, 46px);
  line-height: 1;
  letter-spacing: -0.05em;
}

.vb-calc-twentyfour-summary p {
  margin: 0 !important;
  color: #7f1d1d !important;
  -webkit-text-fill-color: #7f1d1d !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-calc-twentyfour-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-twentyfour-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-calc-twentyfour-item {
    grid-template-columns: 1fr;
  }

  .vb-calc-twentyfour-qty {
    justify-content: flex-start;
  }
}</pre>



<p class="wp-block-paragraph">This restaurant order calculator is useful for restaurant websites, food delivery demos, takeaway forms, menu calculators, catering quote pages, checkout UI examples, and JavaScript dynamic rendering practice.</p>



<h2 class="wp-block-heading">25. Event Ticket Price Calculator</h2>



<p class="wp-block-paragraph"><strong>An event ticket price calculator</strong> is useful for conference websites, event landing pages, workshop pages, festival websites, booking forms, and ticket checkout interfaces. It helps users calculate ticket totals with ticket types, quantity, fees, discount codes, and group pricing.</p>



<p class="wp-block-paragraph">This example uses ticket type selection, quantity input, discount code logic, service fee calculation, and group discount rules. The JavaScript applies different ticket prices and automatically updates the final booking total.</p>



<ul class="wp-block-list">
<li>Event ticket price calculator</li>
<li>Ticket type price selection</li>
<li>Quantity and group discount logic</li>
<li>Promo code validation</li>
<li>Service fee and final total output</li>
</ul>



<div class="vb-calc-twentyfive-demo">
  <div class="vb-calc-twentyfive-shell">
    <div class="vb-calc-twentyfive-header">
      <span>Example 25</span>
      <h3>Event Ticket Price Calculator</h3>
      <p>Calculate ticket totals with ticket type, quantity, service fee, promo code, and group discount.</p>
    </div>

    <div class="vb-calc-twentyfive-body">
      <div class="vb-calc-twentyfive-controls">
        <label>
          Ticket type
          <select data-vb-calc-twentyfive-ticket>
            <option value="49">Standard Ticket - €49</option>
            <option value="89" selected>Business Ticket - €89</option>
            <option value="149">VIP Ticket - €149</option>
          </select>
        </label>

        <label>
          Number of tickets
          <input type="number" min="1" value="4" data-vb-calc-twentyfive-quantity>
        </label>

        <label>
          Promo code
          <input type="text" value="EVENT10" data-vb-calc-twentyfive-code>
        </label>

        <label class="vb-calc-twentyfive-check">
          <input type="checkbox" checked data-vb-calc-twentyfive-fee>
          Add 4% service fee
        </label>
      </div>

      <div class="vb-calc-twentyfive-summary">
        <div>
          <span>Ticket subtotal</span>
          <strong data-vb-calc-twentyfive-subtotal>€0</strong>
        </div>

        <div>
          <span>Discount</span>
          <strong data-vb-calc-twentyfive-discount>€0</strong>
        </div>

        <div>
          <span>Service fee</span>
          <strong data-vb-calc-twentyfive-fee-output>€0</strong>
        </div>

        <div class="vb-calc-twentyfive-total">
          <span>Total booking</span>
          <strong data-vb-calc-twentyfive-total>€0</strong>
        </div>

        <p data-vb-calc-twentyfive-message>Use EVENT10 for 10% off. Groups of 5+ get an extra 5% discount.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-twentyfive-demo,
.vb-calc-twentyfive-demo * {
  box-sizing: border-box;
}

.vb-calc-twentyfive-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(79, 70, 229, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #f0f9ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(79, 70, 229, 0.18);
  overflow: hidden;
}

.vb-calc-twentyfive-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-twentyfive-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #312e81 0%, #4f46e5 54%, #0284c7 100%) !important;
}

.vb-calc-twentyfive-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-twentyfive-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-calc-twentyfive-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-calc-twentyfive-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(290px, 360px);
  gap: 22px;
  padding: clamp(22px, 4vw, 34px);
  min-width: 0;
}

.vb-calc-twentyfive-controls {
  display: grid;
  gap: 14px;
  min-width: 0;
}

.vb-calc-twentyfive-controls label {
  display: grid;
  min-width: 0;
  gap: 8px;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-twentyfive-controls input,
.vb-calc-twentyfive-controls select {
  width: 100%;
  min-width: 0;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #c7d2fe;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-twentyfive-check {
  display: flex !important;
  align-items: center;
  gap: 10px !important;
  padding: 14px;
  border-radius: 18px;
  background: #eef2ff;
  border: 1px solid #c7d2fe;
  overflow-wrap: anywhere;
}

.vb-calc-twentyfive-check input {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  accent-color: #4f46e5;
}

.vb-calc-twentyfive-summary {
  display: grid;
  min-width: 0;
  gap: 10px;
  padding: 18px;
  border-radius: 24px;
  background: #eef2ff;
  border: 1px solid #c7d2fe;
  align-self: start;
}

.vb-calc-twentyfive-summary div {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  min-width: 0;
  padding: 11px 0;
  border-bottom: 1px solid rgba(99, 102, 241, 0.24);
}

.vb-calc-twentyfive-summary span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 900;
  overflow-wrap: anywhere;
}

.vb-calc-twentyfive-summary strong {
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: 17px;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-calc-twentyfive-total {
  display: block !important;
  padding: 18px !important;
  border: 0 !important;
  border-radius: 20px;
  background: linear-gradient(135deg, #e0e7ff, #e0f2fe) !important;
}

.vb-calc-twentyfive-total span {
  display: block;
  margin-bottom: 8px;
}

.vb-calc-twentyfive-total strong {
  display: block;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: clamp(34px, 5vw, 46px);
  line-height: 1;
  letter-spacing: -0.05em;
}

.vb-calc-twentyfive-summary p {
  margin: 0 !important;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-calc-twentyfive-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-twentyfive-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-twentyfive-demo");
  if (!demo) return;

  const ticketInput = demo.querySelector("[data-vb-calc-twentyfive-ticket]");
  const quantityInput = demo.querySelector("[data-vb-calc-twentyfive-quantity]");
  const codeInput = demo.querySelector("[data-vb-calc-twentyfive-code]");
  const feeInput = demo.querySelector("[data-vb-calc-twentyfive-fee]");
  const subtotalOutput = demo.querySelector("[data-vb-calc-twentyfive-subtotal]");
  const discountOutput = demo.querySelector("[data-vb-calc-twentyfive-discount]");
  const feeOutput = demo.querySelector("[data-vb-calc-twentyfive-fee-output]");
  const totalOutput = demo.querySelector("[data-vb-calc-twentyfive-total]");
  const messageOutput = demo.querySelector("[data-vb-calc-twentyfive-message]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 2
  });

  function calculateTickets() {
    const ticketPrice = Number(ticketInput.value);
    const quantity = Math.max(Number(quantityInput.value) || 1, 1);
    const code = codeInput.value.trim().toUpperCase();

    const subtotal = ticketPrice * quantity;
    let discountRate = 0;

    if (code === "EVENT10") {
      discountRate += 0.1;
    }

    if (quantity >= 5) {
      discountRate += 0.05;
    }

    const discount = subtotal * discountRate;
    const afterDiscount = subtotal - discount;
    const serviceFee = feeInput.checked ? afterDiscount * 0.04 : 0;
    const total = afterDiscount + serviceFee;

    subtotalOutput.textContent = money.format(subtotal);
    discountOutput.textContent = "-" + money.format(discount);
    feeOutput.textContent = money.format(serviceFee);
    totalOutput.textContent = money.format(total);

    if (discountRate > 0) {
      messageOutput.textContent = "Discount applied: " + Math.round(discountRate * 100) + "% off.";
    } else {
      messageOutput.textContent = "Use EVENT10 or buy 5+ tickets to unlock discounts.";
    }
  }

  [ticketInput, quantityInput, codeInput, feeInput].forEach(function (field) {
    field.addEventListener("input", calculateTickets);
    field.addEventListener("change", calculateTickets);
  });

  calculateTickets();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-twentyfive-demo");
  if (!demo) return;

  const ticketInput = demo.querySelector("[data-vb-calc-twentyfive-ticket]");
  const quantityInput = demo.querySelector("[data-vb-calc-twentyfive-quantity]");
  const codeInput = demo.querySelector("[data-vb-calc-twentyfive-code]");
  const feeInput = demo.querySelector("[data-vb-calc-twentyfive-fee]");
  const subtotalOutput = demo.querySelector("[data-vb-calc-twentyfive-subtotal]");
  const discountOutput = demo.querySelector("[data-vb-calc-twentyfive-discount]");
  const feeOutput = demo.querySelector("[data-vb-calc-twentyfive-fee-output]");
  const totalOutput = demo.querySelector("[data-vb-calc-twentyfive-total]");
  const messageOutput = demo.querySelector("[data-vb-calc-twentyfive-message]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 2
  });

  function calculateTickets() {
    const ticketPrice = Number(ticketInput.value);
    const quantity = Math.max(Number(quantityInput.value) || 1, 1);
    const code = codeInput.value.trim().toUpperCase();

    const subtotal = ticketPrice * quantity;
    let discountRate = 0;

    if (code === "EVENT10") {
      discountRate += 0.1;
    }

    if (quantity &gt;= 5) {
      discountRate += 0.05;
    }

    const discount = subtotal * discountRate;
    const afterDiscount = subtotal - discount;
    const serviceFee = feeInput.checked ? afterDiscount * 0.04 : 0;
    const total = afterDiscount + serviceFee;

    subtotalOutput.textContent = money.format(subtotal);
    discountOutput.textContent = "-" + money.format(discount);
    feeOutput.textContent = money.format(serviceFee);
    totalOutput.textContent = money.format(total);

    if (discountRate &gt; 0) {
      messageOutput.textContent = "Discount applied: " + Math.round(discountRate * 100) + "% off.";
    } else {
      messageOutput.textContent = "Use EVENT10 or buy 5+ tickets to unlock discounts.";
    }
  }

  [ticketInput, quantityInput, codeInput, feeInput].forEach(function (field) {
    field.addEventListener("input", calculateTickets);
    field.addEventListener("change", calculateTickets);
  });

  calculateTickets();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-twentyfive-demo"&gt;
  &lt;div class="vb-calc-twentyfive-shell"&gt;
    &lt;div class="vb-calc-twentyfive-header"&gt;
      &lt;span&gt;Example 25&lt;/span&gt;
      &lt;h3&gt;Event Ticket Price Calculator&lt;/h3&gt;
      &lt;p&gt;Calculate ticket totals with ticket type, quantity, service fee, promo code, and group discount.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-twentyfive-body"&gt;
      &lt;div class="vb-calc-twentyfive-controls"&gt;
        &lt;label&gt;
          Ticket type
          &lt;select data-vb-calc-twentyfive-ticket&gt;
            &lt;option value="49"&gt;Standard Ticket - €49&lt;/option&gt;
            &lt;option value="89" selected&gt;Business Ticket - €89&lt;/option&gt;
            &lt;option value="149"&gt;VIP Ticket - €149&lt;/option&gt;
          &lt;/select&gt;
        &lt;/label&gt;

        &lt;label&gt;Number of tickets&lt;input type="number" min="1" value="4" data-vb-calc-twentyfive-quantity&gt;&lt;/label&gt;
        &lt;label&gt;Promo code&lt;input type="text" value="EVENT10" data-vb-calc-twentyfive-code&gt;&lt;/label&gt;

        &lt;label class="vb-calc-twentyfive-check"&gt;
          &lt;input type="checkbox" checked data-vb-calc-twentyfive-fee&gt;
          Add 4% service fee
        &lt;/label&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-twentyfive-summary"&gt;
        &lt;div&gt;&lt;span&gt;Ticket subtotal&lt;/span&gt;&lt;strong data-vb-calc-twentyfive-subtotal&gt;€0&lt;/strong&gt;&lt;/div&gt;
        &lt;div&gt;&lt;span&gt;Discount&lt;/span&gt;&lt;strong data-vb-calc-twentyfive-discount&gt;€0&lt;/strong&gt;&lt;/div&gt;
        &lt;div&gt;&lt;span&gt;Service fee&lt;/span&gt;&lt;strong data-vb-calc-twentyfive-fee-output&gt;€0&lt;/strong&gt;&lt;/div&gt;

        &lt;div class="vb-calc-twentyfive-total"&gt;
          &lt;span&gt;Total booking&lt;/span&gt;
          &lt;strong data-vb-calc-twentyfive-total&gt;€0&lt;/strong&gt;
        &lt;/div&gt;

        &lt;p data-vb-calc-twentyfive-message&gt;Use EVENT10 for 10% off. Groups of 5+ get an extra 5% discount.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-twentyfive-demo,
.vb-calc-twentyfive-demo * {
  box-sizing: border-box;
}

.vb-calc-twentyfive-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(79, 70, 229, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #f0f9ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(79, 70, 229, 0.18);
  overflow: hidden;
}

.vb-calc-twentyfive-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-twentyfive-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #312e81 0%, #4f46e5 54%, #0284c7 100%) !important;
}

.vb-calc-twentyfive-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-twentyfive-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-calc-twentyfive-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-calc-twentyfive-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(290px, 360px);
  gap: 22px;
  padding: clamp(22px, 4vw, 34px);
  min-width: 0;
}

.vb-calc-twentyfive-controls {
  display: grid;
  gap: 14px;
  min-width: 0;
}

.vb-calc-twentyfive-controls label {
  display: grid;
  min-width: 0;
  gap: 8px;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-twentyfive-controls input,
.vb-calc-twentyfive-controls select {
  width: 100%;
  min-width: 0;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #c7d2fe;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-twentyfive-check {
  display: flex !important;
  align-items: center;
  gap: 10px !important;
  padding: 14px;
  border-radius: 18px;
  background: #eef2ff;
  border: 1px solid #c7d2fe;
  overflow-wrap: anywhere;
}

.vb-calc-twentyfive-check input {
  flex: 0 0 auto;
  width: 18px;
  height: 18px;
  accent-color: #4f46e5;
}

.vb-calc-twentyfive-summary {
  display: grid;
  min-width: 0;
  gap: 10px;
  padding: 18px;
  border-radius: 24px;
  background: #eef2ff;
  border: 1px solid #c7d2fe;
  align-self: start;
}

.vb-calc-twentyfive-summary div {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  min-width: 0;
  padding: 11px 0;
  border-bottom: 1px solid rgba(99, 102, 241, 0.24);
}

.vb-calc-twentyfive-summary span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 900;
  overflow-wrap: anywhere;
}

.vb-calc-twentyfive-summary strong {
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: 17px;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb-calc-twentyfive-total {
  display: block !important;
  padding: 18px !important;
  border: 0 !important;
  border-radius: 20px;
  background: linear-gradient(135deg, #e0e7ff, #e0f2fe) !important;
}

.vb-calc-twentyfive-total span {
  display: block;
  margin-bottom: 8px;
}

.vb-calc-twentyfive-total strong {
  display: block;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: clamp(34px, 5vw, 46px);
  line-height: 1;
  letter-spacing: -0.05em;
}

.vb-calc-twentyfive-summary p {
  margin: 0 !important;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-calc-twentyfive-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-twentyfive-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}</pre>



<p class="wp-block-paragraph">This event ticket price calculator is useful for conference websites, event landing pages, online workshops, ticket checkout forms, festival pages, webinar pages, and booking UI examples.</p>



<h2 class="wp-block-heading">26. Product Profit Margin Calculator</h2>



<p class="wp-block-paragraph"><strong>A product profit margin calculator</strong> is useful for ecommerce sellers, online stores, marketplace vendors, dropshipping pages, pricing tools, and business dashboards. It helps users calculate profit, markup, and margin from product cost and selling price.</p>



<p class="wp-block-paragraph">This example uses product cost, selling price, shipping cost, platform fee percentage, ad cost, and quantity. The JavaScript calculates net profit per item, total profit, margin percentage, and markup percentage with clear positive or negative status.</p>



<ul class="wp-block-list">
<li>Product profit margin calculator</li>
<li>Cost, sale price, and fee logic</li>
<li>Ad cost and shipping cost included</li>
<li>Margin and markup percentages</li>
<li>Positive or negative profit state</li>
</ul>



<div class="vb-calc-twentysix-demo">
  <div class="vb-calc-twentysix-card">
    <div class="vb-calc-twentysix-copy">
      <span>Example 26</span>
      <h3>Product Profit Margin Calculator</h3>
      <p>Calculate product profit, margin, markup, and total profit after fees and extra costs.</p>
    </div>

    <div class="vb-calc-twentysix-tool">
      <div class="vb-calc-twentysix-grid">
        <label>
          Product cost
          <input type="number" min="0" step="0.01" value="18" data-vb-calc-twentysix-cost>
        </label>

        <label>
          Selling price
          <input type="number" min="0" step="0.01" value="49" data-vb-calc-twentysix-price>
        </label>

        <label>
          Shipping cost
          <input type="number" min="0" step="0.01" value="4.5" data-vb-calc-twentysix-shipping>
        </label>

        <label>
          Platform fee %
          <input type="number" min="0" max="60" value="8" data-vb-calc-twentysix-fee>
        </label>

        <label>
          Ad cost per sale
          <input type="number" min="0" step="0.01" value="6" data-vb-calc-twentysix-ad>
        </label>

        <label>
          Quantity sold
          <input type="number" min="1" value="25" data-vb-calc-twentysix-quantity>
        </label>
      </div>

      <div class="vb-calc-twentysix-result" data-vb-calc-twentysix-result-box>
        <div>
          <span>Profit per item</span>
          <strong data-vb-calc-twentysix-profit>€0</strong>
        </div>

        <div>
          <span>Total profit</span>
          <strong data-vb-calc-twentysix-total>€0</strong>
        </div>

        <div>
          <span>Margin</span>
          <strong data-vb-calc-twentysix-margin>0%</strong>
        </div>

        <div>
          <span>Markup</span>
          <strong data-vb-calc-twentysix-markup>0%</strong>
        </div>

        <p data-vb-calc-twentysix-message>Profit estimate updates automatically.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-twentysix-demo,
.vb-calc-twentysix-demo * {
  box-sizing: border-box;
}

.vb-calc-twentysix-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 197, 94, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(20, 184, 166, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #f0fdfa 54%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.18);
  overflow: hidden;
}

.vb-calc-twentysix-card {
  display: grid;
  grid-template-columns: minmax(0, 0.88fr) minmax(0, 1.12fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
  min-width: 0;
}

.vb-calc-twentysix-copy {
  min-width: 0;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #052e16 0%, #16a34a 54%, #0f766e 100%) !important;
  box-shadow: 0 30px 90px rgba(22, 163, 74, 0.22);
}

.vb-calc-twentysix-copy span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-twentysix-copy h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-calc-twentysix-copy p {
  margin: 0 !important;
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-calc-twentysix-tool {
  display: grid;
  min-width: 0;
  gap: 16px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-twentysix-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
}

.vb-calc-twentysix-grid label {
  display: grid;
  min-width: 0;
  gap: 8px;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-twentysix-grid input {
  width: 100%;
  min-width: 0;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #bbf7d0;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-twentysix-result {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  min-width: 0;
  padding: 18px;
  border-radius: 24px;
  background: #f0fdf4;
  border: 1px solid #bbf7d0;
}

.vb-calc-twentysix-result.is-negative {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-calc-twentysix-result div {
  min-width: 0;
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.86);
}

.vb-calc-twentysix-result span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-twentysix-result strong {
  display: block;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: clamp(22px, 3.5vw, 32px);
  line-height: 1.08;
  font-weight: 950;
  letter-spacing: -0.04em;
  overflow-wrap: anywhere;
}

.vb-calc-twentysix-result.is-negative strong {
  color: #dc2626 !important;
  -webkit-text-fill-color: #dc2626 !important;
}

.vb-calc-twentysix-result p {
  grid-column: 1 / -1;
  margin: 0 !important;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 750;
  overflow-wrap: anywhere;
}

.vb-calc-twentysix-result.is-negative p {
  color: #991b1b !important;
  -webkit-text-fill-color: #991b1b !important;
}

@media (max-width: 900px) {
  .vb-calc-twentysix-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-twentysix-copy h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-calc-twentysix-grid,
  .vb-calc-twentysix-result {
    grid-template-columns: 1fr;
  }

  .vb-calc-twentysix-result p {
    grid-column: auto;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-twentysix-demo");
  if (!demo) return;

  const costInput = demo.querySelector("[data-vb-calc-twentysix-cost]");
  const priceInput = demo.querySelector("[data-vb-calc-twentysix-price]");
  const shippingInput = demo.querySelector("[data-vb-calc-twentysix-shipping]");
  const feeInput = demo.querySelector("[data-vb-calc-twentysix-fee]");
  const adInput = demo.querySelector("[data-vb-calc-twentysix-ad]");
  const quantityInput = demo.querySelector("[data-vb-calc-twentysix-quantity]");
  const resultBox = demo.querySelector("[data-vb-calc-twentysix-result-box]");
  const profitOutput = demo.querySelector("[data-vb-calc-twentysix-profit]");
  const totalOutput = demo.querySelector("[data-vb-calc-twentysix-total]");
  const marginOutput = demo.querySelector("[data-vb-calc-twentysix-margin]");
  const markupOutput = demo.querySelector("[data-vb-calc-twentysix-markup]");
  const messageOutput = demo.querySelector("[data-vb-calc-twentysix-message]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 2
  });

  function calculateProfit() {
    const cost = Math.max(Number(costInput.value) || 0, 0);
    const price = Math.max(Number(priceInput.value) || 0, 0);
    const shipping = Math.max(Number(shippingInput.value) || 0, 0);
    const feeRate = Math.max(Number(feeInput.value) || 0, 0) / 100;
    const adCost = Math.max(Number(adInput.value) || 0, 0);
    const quantity = Math.max(Number(quantityInput.value) || 1, 1);

    const platformFee = price * feeRate;
    const totalCostPerItem = cost + shipping + platformFee + adCost;
    const profitPerItem = price - totalCostPerItem;
    const totalProfit = profitPerItem * quantity;
    const margin = price > 0 ? profitPerItem / price * 100 : 0;
    const markup = totalCostPerItem > 0 ? profitPerItem / totalCostPerItem * 100 : 0;

    profitOutput.textContent = money.format(profitPerItem);
    totalOutput.textContent = money.format(totalProfit);
    marginOutput.textContent = margin.toFixed(1) + "%";
    markupOutput.textContent = markup.toFixed(1) + "%";

    resultBox.classList.toggle("is-negative", profitPerItem < 0);
    messageOutput.textContent = profitPerItem >= 0
      ? "Product is profitable after shipping, platform fee, and ad cost."
      : "Product is losing money after costs and fees.";
  }

  [costInput, priceInput, shippingInput, feeInput, adInput, quantityInput].forEach(function (field) {
    field.addEventListener("input", calculateProfit);
  });

  calculateProfit();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-twentysix-demo");
  if (!demo) return;

  const costInput = demo.querySelector("[data-vb-calc-twentysix-cost]");
  const priceInput = demo.querySelector("[data-vb-calc-twentysix-price]");
  const shippingInput = demo.querySelector("[data-vb-calc-twentysix-shipping]");
  const feeInput = demo.querySelector("[data-vb-calc-twentysix-fee]");
  const adInput = demo.querySelector("[data-vb-calc-twentysix-ad]");
  const quantityInput = demo.querySelector("[data-vb-calc-twentysix-quantity]");
  const resultBox = demo.querySelector("[data-vb-calc-twentysix-result-box]");
  const profitOutput = demo.querySelector("[data-vb-calc-twentysix-profit]");
  const totalOutput = demo.querySelector("[data-vb-calc-twentysix-total]");
  const marginOutput = demo.querySelector("[data-vb-calc-twentysix-margin]");
  const markupOutput = demo.querySelector("[data-vb-calc-twentysix-markup]");
  const messageOutput = demo.querySelector("[data-vb-calc-twentysix-message]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 2
  });

  function calculateProfit() {
    const cost = Math.max(Number(costInput.value) || 0, 0);
    const price = Math.max(Number(priceInput.value) || 0, 0);
    const shipping = Math.max(Number(shippingInput.value) || 0, 0);
    const feeRate = Math.max(Number(feeInput.value) || 0, 0) / 100;
    const adCost = Math.max(Number(adInput.value) || 0, 0);
    const quantity = Math.max(Number(quantityInput.value) || 1, 1);

    const platformFee = price * feeRate;
    const totalCostPerItem = cost + shipping + platformFee + adCost;
    const profitPerItem = price - totalCostPerItem;
    const totalProfit = profitPerItem * quantity;
    const margin = price &gt; 0 ? profitPerItem / price * 100 : 0;
    const markup = totalCostPerItem &gt; 0 ? profitPerItem / totalCostPerItem * 100 : 0;

    profitOutput.textContent = money.format(profitPerItem);
    totalOutput.textContent = money.format(totalProfit);
    marginOutput.textContent = margin.toFixed(1) + "%";
    markupOutput.textContent = markup.toFixed(1) + "%";

    resultBox.classList.toggle("is-negative", profitPerItem &lt; 0);
    messageOutput.textContent = profitPerItem &gt;= 0
      ? "Product is profitable after shipping, platform fee, and ad cost."
      : "Product is losing money after costs and fees.";
  }

  [costInput, priceInput, shippingInput, feeInput, adInput, quantityInput].forEach(function (field) {
    field.addEventListener("input", calculateProfit);
  });

  calculateProfit();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-twentysix-demo"&gt;
  &lt;div class="vb-calc-twentysix-card"&gt;
    &lt;div class="vb-calc-twentysix-copy"&gt;
      &lt;span&gt;Example 26&lt;/span&gt;
      &lt;h3&gt;Product Profit Margin Calculator&lt;/h3&gt;
      &lt;p&gt;Calculate product profit, margin, markup, and total profit after fees and extra costs.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-twentysix-tool"&gt;
      &lt;div class="vb-calc-twentysix-grid"&gt;
        &lt;label&gt;Product cost&lt;input type="number" min="0" step="0.01" value="18" data-vb-calc-twentysix-cost&gt;&lt;/label&gt;
        &lt;label&gt;Selling price&lt;input type="number" min="0" step="0.01" value="49" data-vb-calc-twentysix-price&gt;&lt;/label&gt;
        &lt;label&gt;Shipping cost&lt;input type="number" min="0" step="0.01" value="4.5" data-vb-calc-twentysix-shipping&gt;&lt;/label&gt;
        &lt;label&gt;Platform fee %&lt;input type="number" min="0" max="60" value="8" data-vb-calc-twentysix-fee&gt;&lt;/label&gt;
        &lt;label&gt;Ad cost per sale&lt;input type="number" min="0" step="0.01" value="6" data-vb-calc-twentysix-ad&gt;&lt;/label&gt;
        &lt;label&gt;Quantity sold&lt;input type="number" min="1" value="25" data-vb-calc-twentysix-quantity&gt;&lt;/label&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-twentysix-result" data-vb-calc-twentysix-result-box&gt;
        &lt;div&gt;&lt;span&gt;Profit per item&lt;/span&gt;&lt;strong data-vb-calc-twentysix-profit&gt;€0&lt;/strong&gt;&lt;/div&gt;
        &lt;div&gt;&lt;span&gt;Total profit&lt;/span&gt;&lt;strong data-vb-calc-twentysix-total&gt;€0&lt;/strong&gt;&lt;/div&gt;
        &lt;div&gt;&lt;span&gt;Margin&lt;/span&gt;&lt;strong data-vb-calc-twentysix-margin&gt;0%&lt;/strong&gt;&lt;/div&gt;
        &lt;div&gt;&lt;span&gt;Markup&lt;/span&gt;&lt;strong data-vb-calc-twentysix-markup&gt;0%&lt;/strong&gt;&lt;/div&gt;
        &lt;p data-vb-calc-twentysix-message&gt;Profit estimate updates automatically.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-twentysix-demo,
.vb-calc-twentysix-demo * {
  box-sizing: border-box;
}

.vb-calc-twentysix-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 197, 94, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(20, 184, 166, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #f0fdfa 54%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.18);
  overflow: hidden;
}

.vb-calc-twentysix-card {
  display: grid;
  grid-template-columns: minmax(0, 0.88fr) minmax(0, 1.12fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
  min-width: 0;
}

.vb-calc-twentysix-copy {
  min-width: 0;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #052e16 0%, #16a34a 54%, #0f766e 100%) !important;
  box-shadow: 0 30px 90px rgba(22, 163, 74, 0.22);
}

.vb-calc-twentysix-copy span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-twentysix-copy h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-calc-twentysix-copy p {
  margin: 0 !important;
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-calc-twentysix-tool {
  display: grid;
  min-width: 0;
  gap: 16px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-twentysix-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
}

.vb-calc-twentysix-grid label {
  display: grid;
  min-width: 0;
  gap: 8px;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-twentysix-grid input {
  width: 100%;
  min-width: 0;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #bbf7d0;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-twentysix-result {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  min-width: 0;
  padding: 18px;
  border-radius: 24px;
  background: #f0fdf4;
  border: 1px solid #bbf7d0;
}

.vb-calc-twentysix-result.is-negative {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-calc-twentysix-result div {
  min-width: 0;
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.86);
}

.vb-calc-twentysix-result span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-twentysix-result strong {
  display: block;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: clamp(22px, 3.5vw, 32px);
  line-height: 1.08;
  font-weight: 950;
  letter-spacing: -0.04em;
  overflow-wrap: anywhere;
}

.vb-calc-twentysix-result.is-negative strong {
  color: #dc2626 !important;
  -webkit-text-fill-color: #dc2626 !important;
}

.vb-calc-twentysix-result p {
  grid-column: 1 / -1;
  margin: 0 !important;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 750;
  overflow-wrap: anywhere;
}

.vb-calc-twentysix-result.is-negative p {
  color: #991b1b !important;
  -webkit-text-fill-color: #991b1b !important;
}

@media (max-width: 900px) {
  .vb-calc-twentysix-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-twentysix-copy h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-calc-twentysix-grid,
  .vb-calc-twentysix-result {
    grid-template-columns: 1fr;
  }

  .vb-calc-twentysix-result p {
    grid-column: auto;
  }
}</pre>



<p class="wp-block-paragraph">This product profit margin calculator is useful for ecommerce sellers, online stores, dropshipping pages, marketplace vendors, pricing tools, business dashboards, and product profitability calculators.</p>



<h2 class="wp-block-heading">27. Grade Average Calculator</h2>



<p class="wp-block-paragraph"><strong>A grade average calculator</strong> is useful for education websites, student tools, school dashboards, course platforms, learning apps, and academic planning pages. It helps users calculate weighted grade averages from assignments, tests, and exam scores.</p>



<p class="wp-block-paragraph">This example uses dynamic rows, score and weight inputs, add-row functionality, weighted average calculation, pass/fail status, and grade letter mapping. The JavaScript lets users add new grade rows and recalculates the final grade instantly.</p>



<ul class="wp-block-list">
<li>Weighted grade average calculator</li>
<li>Dynamic grade rows</li>
<li>Add assignment button</li>
<li>Score and weight calculation</li>
<li>Letter grade and status output</li>
</ul>



<div class="vb-calc-twentyseven-demo">
  <div class="vb-calc-twentyseven-shell">
    <div class="vb-calc-twentyseven-header">
      <span>Example 27</span>
      <h3>Grade Average Calculator</h3>
      <p>Calculate a weighted grade average with dynamic assignment rows and letter grade output.</p>
    </div>

    <div class="vb-calc-twentyseven-body">
      <div class="vb-calc-twentyseven-table">
        <div class="vb-calc-twentyseven-rows" data-vb-calc-twentyseven-rows></div>

        <button type="button" data-vb-calc-twentyseven-add>Add another grade</button>
      </div>

      <div class="vb-calc-twentyseven-result" data-vb-calc-twentyseven-result-box>
        <div class="vb-calc-twentyseven-main">
          <span>Weighted average</span>
          <strong data-vb-calc-twentyseven-average>0%</strong>
        </div>

        <div>
          <span>Letter grade</span>
          <strong data-vb-calc-twentyseven-letter>—</strong>
        </div>

        <div>
          <span>Total weight</span>
          <strong data-vb-calc-twentyseven-weight>0%</strong>
        </div>

        <p data-vb-calc-twentyseven-message>Add scores and weights to calculate the final grade.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-twentyseven-demo,
.vb-calc-twentyseven-demo * {
  box-sizing: border-box;
}

.vb-calc-twentyseven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(59, 130, 246, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(168, 85, 247, 0.14), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #faf5ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.18);
  overflow: hidden;
}

.vb-calc-twentyseven-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-twentyseven-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #1e3a8a 0%, #2563eb 52%, #9333ea 100%) !important;
  background-size: 26px 26px, 26px 26px, auto !important;
}

.vb-calc-twentyseven-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-twentyseven-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-calc-twentyseven-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #f3e8ff !important;
  -webkit-text-fill-color: #f3e8ff !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-calc-twentyseven-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(290px, 350px);
  gap: 22px;
  padding: clamp(22px, 4vw, 34px);
  min-width: 0;
}

.vb-calc-twentyseven-table,
.vb-calc-twentyseven-rows {
  display: grid;
  min-width: 0;
  gap: 12px;
}

.vb-calc-twentyseven-row {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 0.8fr) minmax(0, 0.8fr) auto;
  gap: 10px;
  align-items: end;
  min-width: 0;
  padding: 14px;
  border-radius: 18px;
  background: #eff6ff;
  border: 1px solid #bfdbfe;
}

.vb-calc-twentyseven-row label {
  display: grid;
  min-width: 0;
  gap: 7px;
  color: #1e3a8a !important;
  -webkit-text-fill-color: #1e3a8a !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.vb-calc-twentyseven-row input {
  width: 100%;
  min-width: 0;
  min-height: 44px;
  padding: 0 12px;
  border: 1px solid #bfdbfe;
  border-radius: 14px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 800;
  outline: none;
}

.vb-calc-twentyseven-row button,
.vb-calc-twentyseven-table > button {
  border: 0;
  cursor: pointer;
  font-weight: 950;
}

.vb-calc-twentyseven-row button {
  width: 44px;
  height: 44px;
  border-radius: 14px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 18px;
}

.vb-calc-twentyseven-table > button {
  min-height: 48px;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #9333ea);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
}

.vb-calc-twentyseven-result {
  display: grid;
  min-width: 0;
  gap: 12px;
  padding: 18px;
  border-radius: 24px;
  background: #eff6ff;
  border: 1px solid #bfdbfe;
  align-self: start;
}

.vb-calc-twentyseven-result.is-pass {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-calc-twentyseven-result.is-fail {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-calc-twentyseven-result div {
  min-width: 0;
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.86);
}

.vb-calc-twentyseven-result span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-twentyseven-result strong {
  display: block;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: clamp(24px, 4vw, 34px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
  overflow-wrap: anywhere;
}

.vb-calc-twentyseven-main strong {
  font-size: clamp(36px, 5vw, 50px);
}

.vb-calc-twentyseven-result.is-pass strong {
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
}

.vb-calc-twentyseven-result.is-fail strong {
  color: #dc2626 !important;
  -webkit-text-fill-color: #dc2626 !important;
}

.vb-calc-twentyseven-result p {
  margin: 0 !important;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-calc-twentyseven-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 720px) {
  .vb-calc-twentyseven-row {
    grid-template-columns: 1fr;
  }

  .vb-calc-twentyseven-row button {
    width: 100%;
  }
}

@media (max-width: 640px) {
  .vb-calc-twentyseven-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-twentyseven-demo");
  if (!demo) return;

  const rowsContainer = demo.querySelector("[data-vb-calc-twentyseven-rows]");
  const addButton = demo.querySelector("[data-vb-calc-twentyseven-add]");
  const resultBox = demo.querySelector("[data-vb-calc-twentyseven-result-box]");
  const averageOutput = demo.querySelector("[data-vb-calc-twentyseven-average]");
  const letterOutput = demo.querySelector("[data-vb-calc-twentyseven-letter]");
  const weightOutput = demo.querySelector("[data-vb-calc-twentyseven-weight]");
  const messageOutput = demo.querySelector("[data-vb-calc-twentyseven-message]");

  let grades = [
    { name: "Assignment", score: 88, weight: 30 },
    { name: "Midterm", score: 76, weight: 30 },
    { name: "Final Exam", score: 92, weight: 40 }
  ];

  function getLetterGrade(score) {
    if (score >= 90) return "A";
    if (score >= 80) return "B";
    if (score >= 70) return "C";
    if (score >= 60) return "D";
    return "F";
  }

  function renderRows() {
    rowsContainer.innerHTML = "";

    grades.forEach(function (grade, index) {
      const row = document.createElement("div");
      row.className = "vb-calc-twentyseven-row";
      row.innerHTML =
        '<label>Name<input type="text" value="' + grade.name + '" data-field="name" data-index="' + index + '"></label>' +
        '<label>Score %<input type="number" min="0" max="100" value="' + grade.score + '" data-field="score" data-index="' + index + '"></label>' +
        '<label>Weight %<input type="number" min="0" max="100" value="' + grade.weight + '" data-field="weight" data-index="' + index + '"></label>' +
        '<button type="button" data-remove="' + index + '">×</button>';

      rowsContainer.appendChild(row);
    });
  }

  function calculateGrade() {
    let weightedScore = 0;
    let totalWeight = 0;

    grades.forEach(function (grade) {
      const score = Math.min(Math.max(Number(grade.score) || 0, 0), 100);
      const weight = Math.max(Number(grade.weight) || 0, 0);

      weightedScore += score * weight;
      totalWeight += weight;
    });

    const average = totalWeight > 0 ? weightedScore / totalWeight : 0;
    const letter = getLetterGrade(average);

    averageOutput.textContent = average.toFixed(1) + "%";
    letterOutput.textContent = letter;
    weightOutput.textContent = totalWeight.toFixed(0) + "%";

    resultBox.classList.toggle("is-pass", average >= 60);
    resultBox.classList.toggle("is-fail", average < 60);

    messageOutput.textContent = totalWeight === 100
      ? "Weights add up to 100%. Final grade is ready."
      : "Current weights add up to " + totalWeight.toFixed(0) + "%. Adjust if needed.";
  }

  rowsContainer.addEventListener("input", function (event) {
    const input = event.target.closest("input[data-field]");
    if (!input) return;

    const index = Number(input.dataset.index);
    const field = input.dataset.field;

    grades[index][field] = field === "name" ? input.value : Number(input.value);
    calculateGrade();
  });

  rowsContainer.addEventListener("click", function (event) {
    const button = event.target.closest("button[data-remove]");
    if (!button) return;

    const index = Number(button.dataset.remove);
    grades.splice(index, 1);
    renderRows();
    calculateGrade();
  });

  addButton.addEventListener("click", function () {
    grades.push({ name: "New grade", score: 80, weight: 10 });
    renderRows();
    calculateGrade();
  });

  renderRows();
  calculateGrade();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-twentyseven-demo");
  if (!demo) return;

  const rowsContainer = demo.querySelector("[data-vb-calc-twentyseven-rows]");
  const addButton = demo.querySelector("[data-vb-calc-twentyseven-add]");
  const resultBox = demo.querySelector("[data-vb-calc-twentyseven-result-box]");
  const averageOutput = demo.querySelector("[data-vb-calc-twentyseven-average]");
  const letterOutput = demo.querySelector("[data-vb-calc-twentyseven-letter]");
  const weightOutput = demo.querySelector("[data-vb-calc-twentyseven-weight]");
  const messageOutput = demo.querySelector("[data-vb-calc-twentyseven-message]");

  let grades = [
    { name: "Assignment", score: 88, weight: 30 },
    { name: "Midterm", score: 76, weight: 30 },
    { name: "Final Exam", score: 92, weight: 40 }
  ];

  function getLetterGrade(score) {
    if (score &gt;= 90) return "A";
    if (score &gt;= 80) return "B";
    if (score &gt;= 70) return "C";
    if (score &gt;= 60) return "D";
    return "F";
  }

  function renderRows() {
    rowsContainer.innerHTML = "";

    grades.forEach(function (grade, index) {
      const row = document.createElement("div");
      row.className = "vb-calc-twentyseven-row";
      row.innerHTML =
        '&lt;label&gt;Name&lt;input type="text" value="' + grade.name + '" data-field="name" data-index="' + index + '"&gt;&lt;/label&gt;' +
        '&lt;label&gt;Score %&lt;input type="number" min="0" max="100" value="' + grade.score + '" data-field="score" data-index="' + index + '"&gt;&lt;/label&gt;' +
        '&lt;label&gt;Weight %&lt;input type="number" min="0" max="100" value="' + grade.weight + '" data-field="weight" data-index="' + index + '"&gt;&lt;/label&gt;' +
        '&lt;button type="button" data-remove="' + index + '"&gt;×&lt;/button&gt;';

      rowsContainer.appendChild(row);
    });
  }

  function calculateGrade() {
    let weightedScore = 0;
    let totalWeight = 0;

    grades.forEach(function (grade) {
      const score = Math.min(Math.max(Number(grade.score) || 0, 0), 100);
      const weight = Math.max(Number(grade.weight) || 0, 0);

      weightedScore += score * weight;
      totalWeight += weight;
    });

    const average = totalWeight &gt; 0 ? weightedScore / totalWeight : 0;
    const letter = getLetterGrade(average);

    averageOutput.textContent = average.toFixed(1) + "%";
    letterOutput.textContent = letter;
    weightOutput.textContent = totalWeight.toFixed(0) + "%";

    resultBox.classList.toggle("is-pass", average &gt;= 60);
    resultBox.classList.toggle("is-fail", average &lt; 60);

    messageOutput.textContent = totalWeight === 100
      ? "Weights add up to 100%. Final grade is ready."
      : "Current weights add up to " + totalWeight.toFixed(0) + "%. Adjust if needed.";
  }

  rowsContainer.addEventListener("input", function (event) {
    const input = event.target.closest("input[data-field]");
    if (!input) return;

    const index = Number(input.dataset.index);
    const field = input.dataset.field;

    grades[index][field] = field === "name" ? input.value : Number(input.value);
    calculateGrade();
  });

  rowsContainer.addEventListener("click", function (event) {
    const button = event.target.closest("button[data-remove]");
    if (!button) return;

    const index = Number(button.dataset.remove);
    grades.splice(index, 1);
    renderRows();
    calculateGrade();
  });

  addButton.addEventListener("click", function () {
    grades.push({ name: "New grade", score: 80, weight: 10 });
    renderRows();
    calculateGrade();
  });

  renderRows();
  calculateGrade();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-twentyseven-demo"&gt;
  &lt;div class="vb-calc-twentyseven-shell"&gt;
    &lt;div class="vb-calc-twentyseven-header"&gt;
      &lt;span&gt;Example 27&lt;/span&gt;
      &lt;h3&gt;Grade Average Calculator&lt;/h3&gt;
      &lt;p&gt;Calculate a weighted grade average with dynamic assignment rows and letter grade output.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-twentyseven-body"&gt;
      &lt;div class="vb-calc-twentyseven-table"&gt;
        &lt;div class="vb-calc-twentyseven-rows" data-vb-calc-twentyseven-rows&gt;&lt;/div&gt;
        &lt;button type="button" data-vb-calc-twentyseven-add&gt;Add another grade&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-twentyseven-result" data-vb-calc-twentyseven-result-box&gt;
        &lt;div class="vb-calc-twentyseven-main"&gt;
          &lt;span&gt;Weighted average&lt;/span&gt;
          &lt;strong data-vb-calc-twentyseven-average&gt;0%&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div&gt;&lt;span&gt;Letter grade&lt;/span&gt;&lt;strong data-vb-calc-twentyseven-letter&gt;—&lt;/strong&gt;&lt;/div&gt;
        &lt;div&gt;&lt;span&gt;Total weight&lt;/span&gt;&lt;strong data-vb-calc-twentyseven-weight&gt;0%&lt;/strong&gt;&lt;/div&gt;

        &lt;p data-vb-calc-twentyseven-message&gt;Add scores and weights to calculate the final grade.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-twentyseven-demo,
.vb-calc-twentyseven-demo * {
  box-sizing: border-box;
}

.vb-calc-twentyseven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(59, 130, 246, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(168, 85, 247, 0.14), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #faf5ff 54%, #ffffff 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.18);
  overflow: hidden;
}

.vb-calc-twentyseven-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-twentyseven-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #1e3a8a 0%, #2563eb 52%, #9333ea 100%) !important;
  background-size: 26px 26px, 26px 26px, auto !important;
}

.vb-calc-twentyseven-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-twentyseven-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-calc-twentyseven-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #f3e8ff !important;
  -webkit-text-fill-color: #f3e8ff !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-calc-twentyseven-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(290px, 350px);
  gap: 22px;
  padding: clamp(22px, 4vw, 34px);
  min-width: 0;
}

.vb-calc-twentyseven-table,
.vb-calc-twentyseven-rows {
  display: grid;
  min-width: 0;
  gap: 12px;
}

.vb-calc-twentyseven-row {
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(0, 0.8fr) minmax(0, 0.8fr) auto;
  gap: 10px;
  align-items: end;
  min-width: 0;
  padding: 14px;
  border-radius: 18px;
  background: #eff6ff;
  border: 1px solid #bfdbfe;
}

.vb-calc-twentyseven-row label {
  display: grid;
  min-width: 0;
  gap: 7px;
  color: #1e3a8a !important;
  -webkit-text-fill-color: #1e3a8a !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.06em;
}

.vb-calc-twentyseven-row input {
  width: 100%;
  min-width: 0;
  min-height: 44px;
  padding: 0 12px;
  border: 1px solid #bfdbfe;
  border-radius: 14px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 800;
  outline: none;
}

.vb-calc-twentyseven-row button,
.vb-calc-twentyseven-table &gt; button {
  border: 0;
  cursor: pointer;
  font-weight: 950;
}

.vb-calc-twentyseven-row button {
  width: 44px;
  height: 44px;
  border-radius: 14px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 18px;
}

.vb-calc-twentyseven-table &gt; button {
  min-height: 48px;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #9333ea);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
}

.vb-calc-twentyseven-result {
  display: grid;
  min-width: 0;
  gap: 12px;
  padding: 18px;
  border-radius: 24px;
  background: #eff6ff;
  border: 1px solid #bfdbfe;
  align-self: start;
}

.vb-calc-twentyseven-result.is-pass {
  background: #f0fdf4;
  border-color: #bbf7d0;
}

.vb-calc-twentyseven-result.is-fail {
  background: #fef2f2;
  border-color: #fecaca;
}

.vb-calc-twentyseven-result div {
  min-width: 0;
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.86);
}

.vb-calc-twentyseven-result span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-twentyseven-result strong {
  display: block;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: clamp(24px, 4vw, 34px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
  overflow-wrap: anywhere;
}

.vb-calc-twentyseven-main strong {
  font-size: clamp(36px, 5vw, 50px);
}

.vb-calc-twentyseven-result.is-pass strong {
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
}

.vb-calc-twentyseven-result.is-fail strong {
  color: #dc2626 !important;
  -webkit-text-fill-color: #dc2626 !important;
}

.vb-calc-twentyseven-result p {
  margin: 0 !important;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-calc-twentyseven-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 720px) {
  .vb-calc-twentyseven-row {
    grid-template-columns: 1fr;
  }

  .vb-calc-twentyseven-row button {
    width: 100%;
  }
}

@media (max-width: 640px) {
  .vb-calc-twentyseven-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}</pre>



<p class="wp-block-paragraph">This grade average calculator is useful for education websites, student dashboards, school tools, course platforms, learning apps, academic planning pages, and practical JavaScript form calculation examples.</p>



<h2 class="wp-block-heading">28. Tax and VAT Calculator</h2>



<p class="wp-block-paragraph"><strong>A tax and VAT calculator</strong> is useful for ecommerce checkout pages, invoice tools, accounting dashboards, pricing pages, business forms, and online stores. It helps users calculate tax amount, price before tax, price after tax, and reverse tax values.</p>



<p class="wp-block-paragraph">This example uses calculation mode switching, tax rate input, net and gross price logic, formatted money output, and clear status messages. The JavaScript changes the formula depending on whether the user wants to add tax or extract tax from a gross price.</p>



<ul class="wp-block-list">
<li>Tax and VAT calculator</li>
<li>Add tax or extract tax mode</li>
<li>Net price and gross price calculation</li>
<li>Tax amount output</li>
<li>Invoice and checkout calculator logic</li>
</ul>



<div class="vb-calc-twentyeight-demo">
  <div class="vb-calc-twentyeight-shell">
    <div class="vb-calc-twentyeight-header">
      <span>Example 28</span>
      <h3>Tax and VAT Calculator</h3>
      <p>Calculate tax amount, net price, and gross price with add-tax or reverse-tax logic.</p>
    </div>

    <div class="vb-calc-twentyeight-body">
      <div class="vb-calc-twentyeight-controls">
        <label>
          Calculation mode
          <select data-vb-calc-twentyeight-mode>
            <option value="add" selected>Add tax to net price</option>
            <option value="extract">Extract tax from gross price</option>
          </select>
        </label>

        <label>
          Price amount
          <input type="number" min="0" step="0.01" value="120" data-vb-calc-twentyeight-price>
        </label>

        <label>
          Tax rate %
          <input type="number" min="0" max="100" step="0.1" value="22" data-vb-calc-twentyeight-rate>
        </label>
      </div>

      <div class="vb-calc-twentyeight-result">
        <div>
          <span>Net price</span>
          <strong data-vb-calc-twentyeight-net>€0</strong>
        </div>

        <div>
          <span>Tax amount</span>
          <strong data-vb-calc-twentyeight-tax>€0</strong>
        </div>

        <div class="vb-calc-twentyeight-total">
          <span>Gross price</span>
          <strong data-vb-calc-twentyeight-gross>€0</strong>
        </div>

        <p data-vb-calc-twentyeight-message>Tax calculation updates automatically.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-twentyeight-demo,
.vb-calc-twentyeight-demo * {
  box-sizing: border-box;
}

.vb-calc-twentyeight-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(14, 165, 233, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  overflow: hidden;
}

.vb-calc-twentyeight-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-twentyeight-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #082f49 0%, #0284c7 52%, #16a34a 100%) !important;
  background-size: 26px 26px, 26px 26px, auto !important;
}

.vb-calc-twentyeight-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-twentyeight-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-calc-twentyeight-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-calc-twentyeight-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(290px, 360px);
  gap: 22px;
  padding: clamp(22px, 4vw, 34px);
  min-width: 0;
}

.vb-calc-twentyeight-controls {
  display: grid;
  gap: 14px;
  min-width: 0;
}

.vb-calc-twentyeight-controls label {
  display: grid;
  min-width: 0;
  gap: 8px;
  color: #075985 !important;
  -webkit-text-fill-color: #075985 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-twentyeight-controls input,
.vb-calc-twentyeight-controls select {
  width: 100%;
  min-width: 0;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #bae6fd;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-twentyeight-result {
  display: grid;
  min-width: 0;
  gap: 12px;
  padding: 18px;
  border-radius: 24px;
  background: #f0f9ff;
  border: 1px solid #bae6fd;
  align-self: start;
}

.vb-calc-twentyeight-result div {
  min-width: 0;
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.86);
}

.vb-calc-twentyeight-total {
  background: linear-gradient(135deg, #e0f2fe, #dcfce7) !important;
}

.vb-calc-twentyeight-result span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-twentyeight-result strong {
  display: block;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: clamp(24px, 4vw, 34px);
  line-height: 1.08;
  font-weight: 950;
  letter-spacing: -0.04em;
  overflow-wrap: anywhere;
}

.vb-calc-twentyeight-total strong {
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: clamp(34px, 5vw, 46px);
}

.vb-calc-twentyeight-result p {
  margin: 0 !important;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-calc-twentyeight-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-twentyeight-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-twentyeight-demo");
  if (!demo) return;

  const modeInput = demo.querySelector("[data-vb-calc-twentyeight-mode]");
  const priceInput = demo.querySelector("[data-vb-calc-twentyeight-price]");
  const rateInput = demo.querySelector("[data-vb-calc-twentyeight-rate]");
  const netOutput = demo.querySelector("[data-vb-calc-twentyeight-net]");
  const taxOutput = demo.querySelector("[data-vb-calc-twentyeight-tax]");
  const grossOutput = demo.querySelector("[data-vb-calc-twentyeight-gross]");
  const messageOutput = demo.querySelector("[data-vb-calc-twentyeight-message]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 2
  });

  function calculateTax() {
    const mode = modeInput.value;
    const price = Math.max(Number(priceInput.value) || 0, 0);
    const rate = Math.max(Number(rateInput.value) || 0, 0) / 100;

    let net;
    let tax;
    let gross;

    if (mode === "add") {
      net = price;
      tax = net * rate;
      gross = net + tax;
      messageOutput.textContent = "Tax was added to the net price.";
    } else {
      gross = price;
      net = rate > 0 ? gross / (1 + rate) : gross;
      tax = gross - net;
      messageOutput.textContent = "Tax was extracted from the gross price.";
    }

    netOutput.textContent = money.format(net);
    taxOutput.textContent = money.format(tax);
    grossOutput.textContent = money.format(gross);
  }

  [modeInput, priceInput, rateInput].forEach(function (field) {
    field.addEventListener("input", calculateTax);
    field.addEventListener("change", calculateTax);
  });

  calculateTax();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-twentyeight-demo");
  if (!demo) return;

  const modeInput = demo.querySelector("[data-vb-calc-twentyeight-mode]");
  const priceInput = demo.querySelector("[data-vb-calc-twentyeight-price]");
  const rateInput = demo.querySelector("[data-vb-calc-twentyeight-rate]");
  const netOutput = demo.querySelector("[data-vb-calc-twentyeight-net]");
  const taxOutput = demo.querySelector("[data-vb-calc-twentyeight-tax]");
  const grossOutput = demo.querySelector("[data-vb-calc-twentyeight-gross]");
  const messageOutput = demo.querySelector("[data-vb-calc-twentyeight-message]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 2
  });

  function calculateTax() {
    const mode = modeInput.value;
    const price = Math.max(Number(priceInput.value) || 0, 0);
    const rate = Math.max(Number(rateInput.value) || 0, 0) / 100;

    let net;
    let tax;
    let gross;

    if (mode === "add") {
      net = price;
      tax = net * rate;
      gross = net + tax;
      messageOutput.textContent = "Tax was added to the net price.";
    } else {
      gross = price;
      net = rate &gt; 0 ? gross / (1 + rate) : gross;
      tax = gross - net;
      messageOutput.textContent = "Tax was extracted from the gross price.";
    }

    netOutput.textContent = money.format(net);
    taxOutput.textContent = money.format(tax);
    grossOutput.textContent = money.format(gross);
  }

  [modeInput, priceInput, rateInput].forEach(function (field) {
    field.addEventListener("input", calculateTax);
    field.addEventListener("change", calculateTax);
  });

  calculateTax();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-twentyeight-demo"&gt;
  &lt;div class="vb-calc-twentyeight-shell"&gt;
    &lt;div class="vb-calc-twentyeight-header"&gt;
      &lt;span&gt;Example 28&lt;/span&gt;
      &lt;h3&gt;Tax and VAT Calculator&lt;/h3&gt;
      &lt;p&gt;Calculate tax amount, net price, and gross price with add-tax or reverse-tax logic.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-twentyeight-body"&gt;
      &lt;div class="vb-calc-twentyeight-controls"&gt;
        &lt;label&gt;
          Calculation mode
          &lt;select data-vb-calc-twentyeight-mode&gt;
            &lt;option value="add" selected&gt;Add tax to net price&lt;/option&gt;
            &lt;option value="extract"&gt;Extract tax from gross price&lt;/option&gt;
          &lt;/select&gt;
        &lt;/label&gt;

        &lt;label&gt;Price amount&lt;input type="number" min="0" step="0.01" value="120" data-vb-calc-twentyeight-price&gt;&lt;/label&gt;
        &lt;label&gt;Tax rate %&lt;input type="number" min="0" max="100" step="0.1" value="22" data-vb-calc-twentyeight-rate&gt;&lt;/label&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-twentyeight-result"&gt;
        &lt;div&gt;&lt;span&gt;Net price&lt;/span&gt;&lt;strong data-vb-calc-twentyeight-net&gt;€0&lt;/strong&gt;&lt;/div&gt;
        &lt;div&gt;&lt;span&gt;Tax amount&lt;/span&gt;&lt;strong data-vb-calc-twentyeight-tax&gt;€0&lt;/strong&gt;&lt;/div&gt;

        &lt;div class="vb-calc-twentyeight-total"&gt;
          &lt;span&gt;Gross price&lt;/span&gt;
          &lt;strong data-vb-calc-twentyeight-gross&gt;€0&lt;/strong&gt;
        &lt;/div&gt;

        &lt;p data-vb-calc-twentyeight-message&gt;Tax calculation updates automatically.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-twentyeight-demo,
.vb-calc-twentyeight-demo * {
  box-sizing: border-box;
}

.vb-calc-twentyeight-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(14, 165, 233, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #f0fdf4 54%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.18);
  overflow: hidden;
}

.vb-calc-twentyeight-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-twentyeight-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    linear-gradient(90deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(255,255,255,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #082f49 0%, #0284c7 52%, #16a34a 100%) !important;
  background-size: 26px 26px, 26px 26px, auto !important;
}

.vb-calc-twentyeight-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-twentyeight-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-calc-twentyeight-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-calc-twentyeight-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(290px, 360px);
  gap: 22px;
  padding: clamp(22px, 4vw, 34px);
  min-width: 0;
}

.vb-calc-twentyeight-controls {
  display: grid;
  gap: 14px;
  min-width: 0;
}

.vb-calc-twentyeight-controls label {
  display: grid;
  min-width: 0;
  gap: 8px;
  color: #075985 !important;
  -webkit-text-fill-color: #075985 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-twentyeight-controls input,
.vb-calc-twentyeight-controls select {
  width: 100%;
  min-width: 0;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #bae6fd;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-twentyeight-result {
  display: grid;
  min-width: 0;
  gap: 12px;
  padding: 18px;
  border-radius: 24px;
  background: #f0f9ff;
  border: 1px solid #bae6fd;
  align-self: start;
}

.vb-calc-twentyeight-result div {
  min-width: 0;
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.86);
}

.vb-calc-twentyeight-total {
  background: linear-gradient(135deg, #e0f2fe, #dcfce7) !important;
}

.vb-calc-twentyeight-result span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-twentyeight-result strong {
  display: block;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: clamp(24px, 4vw, 34px);
  line-height: 1.08;
  font-weight: 950;
  letter-spacing: -0.04em;
  overflow-wrap: anywhere;
}

.vb-calc-twentyeight-total strong {
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: clamp(34px, 5vw, 46px);
}

.vb-calc-twentyeight-result p {
  margin: 0 !important;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-calc-twentyeight-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-twentyeight-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }
}</pre>



<p class="wp-block-paragraph">This tax and VAT calculator is useful for invoice tools, ecommerce checkout pages, accounting dashboards, pricing pages, online stores, order forms, and JavaScript business calculator examples.</p>



<h2 class="wp-block-heading">29. Time Duration Calculator</h2>



<p class="wp-block-paragraph"><strong>A time duration calculator</strong> is useful for productivity apps, timesheet tools, payroll dashboards, booking systems, project tracking pages, workout apps, and scheduling tools. It calculates the time between a start time and an end time, including overnight shifts.</p>



<p class="wp-block-paragraph">This example uses time inputs, break duration, overnight calculation logic, decimal hours, formatted hours and minutes, and billable cost output. The JavaScript handles cases where the end time is on the next day.</p>



<ul class="wp-block-list">
<li>Time duration calculator</li>
<li>Start and end time inputs</li>
<li>Break time deduction</li>
<li>Overnight shift support</li>
<li>Billable cost calculation</li>
</ul>



<div class="vb-calc-twentynine-demo">
  <div class="vb-calc-twentynine-card">
    <div class="vb-calc-twentynine-copy">
      <span>Example 29</span>
      <h3>Time Duration Calculator</h3>
      <p>Calculate work duration, decimal hours, and billable cost from start and end times.</p>
    </div>

    <div class="vb-calc-twentynine-tool">
      <div class="vb-calc-twentynine-grid">
        <label>
          Start time
          <input type="time" value="22:30" data-vb-calc-twentynine-start>
        </label>

        <label>
          End time
          <input type="time" value="06:15" data-vb-calc-twentynine-end>
        </label>

        <label>
          Break minutes
          <input type="number" min="0" value="30" data-vb-calc-twentynine-break>
        </label>

        <label>
          Hourly rate
          <input type="number" min="0" step="0.01" value="35" data-vb-calc-twentynine-rate>
        </label>
      </div>

      <div class="vb-calc-twentynine-result">
        <div class="vb-calc-twentynine-main">
          <span>Total duration</span>
          <strong data-vb-calc-twentynine-duration>0h 0m</strong>
        </div>

        <div>
          <span>Decimal hours</span>
          <strong data-vb-calc-twentynine-decimal>0.00</strong>
        </div>

        <div>
          <span>Billable cost</span>
          <strong data-vb-calc-twentynine-cost>€0</strong>
        </div>

        <p data-vb-calc-twentynine-message>Time duration updates automatically.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-twentynine-demo,
.vb-calc-twentynine-demo * {
  box-sizing: border-box;
}

.vb-calc-twentynine-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(99, 102, 241, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(15, 23, 42, 0.10), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #f8fafc 54%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.18);
  overflow: hidden;
}

.vb-calc-twentynine-card {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
  min-width: 0;
}

.vb-calc-twentynine-copy {
  min-width: 0;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #111827 0%, #4f46e5 54%, #0284c7 100%) !important;
  box-shadow: 0 30px 90px rgba(79, 70, 229, 0.20);
}

.vb-calc-twentynine-copy span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-twentynine-copy h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-calc-twentynine-copy p {
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-calc-twentynine-tool {
  display: grid;
  min-width: 0;
  gap: 16px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-twentynine-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
}

.vb-calc-twentynine-grid label {
  display: grid;
  min-width: 0;
  gap: 8px;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-twentynine-grid input {
  width: 100%;
  min-width: 0;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #c7d2fe;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-twentynine-result {
  display: grid;
  min-width: 0;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  padding: 18px;
  border-radius: 24px;
  background: #eef2ff;
  border: 1px solid #c7d2fe;
}

.vb-calc-twentynine-result div {
  min-width: 0;
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.86);
}

.vb-calc-twentynine-main {
  grid-column: 1 / -1;
  background: linear-gradient(135deg, #e0e7ff, #e0f2fe) !important;
}

.vb-calc-twentynine-result span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-twentynine-result strong {
  display: block;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: clamp(24px, 4vw, 34px);
  line-height: 1.08;
  font-weight: 950;
  letter-spacing: -0.04em;
  overflow-wrap: anywhere;
}

.vb-calc-twentynine-main strong {
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: clamp(36px, 5vw, 50px);
}

.vb-calc-twentynine-result p {
  grid-column: 1 / -1;
  margin: 0 !important;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-calc-twentynine-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-twentynine-copy h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-calc-twentynine-grid,
  .vb-calc-twentynine-result {
    grid-template-columns: 1fr;
  }

  .vb-calc-twentynine-main,
  .vb-calc-twentynine-result p {
    grid-column: auto;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-twentynine-demo");
  if (!demo) return;

  const startInput = demo.querySelector("[data-vb-calc-twentynine-start]");
  const endInput = demo.querySelector("[data-vb-calc-twentynine-end]");
  const breakInput = demo.querySelector("[data-vb-calc-twentynine-break]");
  const rateInput = demo.querySelector("[data-vb-calc-twentynine-rate]");
  const durationOutput = demo.querySelector("[data-vb-calc-twentynine-duration]");
  const decimalOutput = demo.querySelector("[data-vb-calc-twentynine-decimal]");
  const costOutput = demo.querySelector("[data-vb-calc-twentynine-cost]");
  const messageOutput = demo.querySelector("[data-vb-calc-twentynine-message]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 2
  });

  function timeToMinutes(time) {
    const parts = time.split(":");
    return Number(parts[0]) * 60 + Number(parts[1]);
  }

  function calculateDuration() {
    if (!startInput.value || !endInput.value) {
      durationOutput.textContent = "0h 0m";
      decimalOutput.textContent = "0.00";
      costOutput.textContent = money.format(0);
      messageOutput.textContent = "Choose start and end times.";
      return;
    }

    const start = timeToMinutes(startInput.value);
    let end = timeToMinutes(endInput.value);
    const breakMinutes = Math.max(Number(breakInput.value) || 0, 0);
    const hourlyRate = Math.max(Number(rateInput.value) || 0, 0);

    let overnight = false;

    if (end < start) {
      end += 24 * 60;
      overnight = true;
    }

    const rawMinutes = Math.max(end - start - breakMinutes, 0);
    const hours = Math.floor(rawMinutes / 60);
    const minutes = rawMinutes % 60;
    const decimalHours = rawMinutes / 60;
    const cost = decimalHours * hourlyRate;

    durationOutput.textContent = hours + "h " + minutes + "m";
    decimalOutput.textContent = decimalHours.toFixed(2);
    costOutput.textContent = money.format(cost);
    messageOutput.textContent = overnight
      ? "Overnight shift detected. End time was counted as the next day."
      : "Duration calculated from same-day start and end time.";
  }

  [startInput, endInput, breakInput, rateInput].forEach(function (field) {
    field.addEventListener("input", calculateDuration);
    field.addEventListener("change", calculateDuration);
  });

  calculateDuration();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-twentynine-demo");
  if (!demo) return;

  const startInput = demo.querySelector("[data-vb-calc-twentynine-start]");
  const endInput = demo.querySelector("[data-vb-calc-twentynine-end]");
  const breakInput = demo.querySelector("[data-vb-calc-twentynine-break]");
  const rateInput = demo.querySelector("[data-vb-calc-twentynine-rate]");
  const durationOutput = demo.querySelector("[data-vb-calc-twentynine-duration]");
  const decimalOutput = demo.querySelector("[data-vb-calc-twentynine-decimal]");
  const costOutput = demo.querySelector("[data-vb-calc-twentynine-cost]");
  const messageOutput = demo.querySelector("[data-vb-calc-twentynine-message]");

  const money = new Intl.NumberFormat("en-US", {
    style: "currency",
    currency: "EUR",
    maximumFractionDigits: 2
  });

  function timeToMinutes(time) {
    const parts = time.split(":");
    return Number(parts[0]) * 60 + Number(parts[1]);
  }

  function calculateDuration() {
    if (!startInput.value || !endInput.value) {
      durationOutput.textContent = "0h 0m";
      decimalOutput.textContent = "0.00";
      costOutput.textContent = money.format(0);
      messageOutput.textContent = "Choose start and end times.";
      return;
    }

    const start = timeToMinutes(startInput.value);
    let end = timeToMinutes(endInput.value);
    const breakMinutes = Math.max(Number(breakInput.value) || 0, 0);
    const hourlyRate = Math.max(Number(rateInput.value) || 0, 0);

    let overnight = false;

    if (end &lt; start) {
      end += 24 * 60;
      overnight = true;
    }

    const rawMinutes = Math.max(end - start - breakMinutes, 0);
    const hours = Math.floor(rawMinutes / 60);
    const minutes = rawMinutes % 60;
    const decimalHours = rawMinutes / 60;
    const cost = decimalHours * hourlyRate;

    durationOutput.textContent = hours + "h " + minutes + "m";
    decimalOutput.textContent = decimalHours.toFixed(2);
    costOutput.textContent = money.format(cost);
    messageOutput.textContent = overnight
      ? "Overnight shift detected. End time was counted as the next day."
      : "Duration calculated from same-day start and end time.";
  }

  [startInput, endInput, breakInput, rateInput].forEach(function (field) {
    field.addEventListener("input", calculateDuration);
    field.addEventListener("change", calculateDuration);
  });

  calculateDuration();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-twentynine-demo"&gt;
  &lt;div class="vb-calc-twentynine-card"&gt;
    &lt;div class="vb-calc-twentynine-copy"&gt;
      &lt;span&gt;Example 29&lt;/span&gt;
      &lt;h3&gt;Time Duration Calculator&lt;/h3&gt;
      &lt;p&gt;Calculate work duration, decimal hours, and billable cost from start and end times.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-twentynine-tool"&gt;
      &lt;div class="vb-calc-twentynine-grid"&gt;
        &lt;label&gt;Start time&lt;input type="time" value="22:30" data-vb-calc-twentynine-start&gt;&lt;/label&gt;
        &lt;label&gt;End time&lt;input type="time" value="06:15" data-vb-calc-twentynine-end&gt;&lt;/label&gt;
        &lt;label&gt;Break minutes&lt;input type="number" min="0" value="30" data-vb-calc-twentynine-break&gt;&lt;/label&gt;
        &lt;label&gt;Hourly rate&lt;input type="number" min="0" step="0.01" value="35" data-vb-calc-twentynine-rate&gt;&lt;/label&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-twentynine-result"&gt;
        &lt;div class="vb-calc-twentynine-main"&gt;
          &lt;span&gt;Total duration&lt;/span&gt;
          &lt;strong data-vb-calc-twentynine-duration&gt;0h 0m&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div&gt;&lt;span&gt;Decimal hours&lt;/span&gt;&lt;strong data-vb-calc-twentynine-decimal&gt;0.00&lt;/strong&gt;&lt;/div&gt;
        &lt;div&gt;&lt;span&gt;Billable cost&lt;/span&gt;&lt;strong data-vb-calc-twentynine-cost&gt;€0&lt;/strong&gt;&lt;/div&gt;

        &lt;p data-vb-calc-twentynine-message&gt;Time duration updates automatically.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-twentynine-demo,
.vb-calc-twentynine-demo * {
  box-sizing: border-box;
}

.vb-calc-twentynine-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(99, 102, 241, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(15, 23, 42, 0.10), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #f8fafc 54%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.18);
  overflow: hidden;
}

.vb-calc-twentynine-card {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 24px;
  max-width: 1120px;
  margin: 0 auto;
  min-width: 0;
}

.vb-calc-twentynine-copy {
  min-width: 0;
  padding: clamp(22px, 4vw, 36px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #111827 0%, #4f46e5 54%, #0284c7 100%) !important;
  box-shadow: 0 30px 90px rgba(79, 70, 229, 0.20);
}

.vb-calc-twentynine-copy span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-twentynine-copy h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-calc-twentynine-copy p {
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-calc-twentynine-tool {
  display: grid;
  min-width: 0;
  gap: 16px;
  padding: clamp(20px, 4vw, 34px);
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-calc-twentynine-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  min-width: 0;
}

.vb-calc-twentynine-grid label {
  display: grid;
  min-width: 0;
  gap: 8px;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-twentynine-grid input {
  width: 100%;
  min-width: 0;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #c7d2fe;
  border-radius: 16px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-twentynine-result {
  display: grid;
  min-width: 0;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  padding: 18px;
  border-radius: 24px;
  background: #eef2ff;
  border: 1px solid #c7d2fe;
}

.vb-calc-twentynine-result div {
  min-width: 0;
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.86);
}

.vb-calc-twentynine-main {
  grid-column: 1 / -1;
  background: linear-gradient(135deg, #e0e7ff, #e0f2fe) !important;
}

.vb-calc-twentynine-result span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-twentynine-result strong {
  display: block;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: clamp(24px, 4vw, 34px);
  line-height: 1.08;
  font-weight: 950;
  letter-spacing: -0.04em;
  overflow-wrap: anywhere;
}

.vb-calc-twentynine-main strong {
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: clamp(36px, 5vw, 50px);
}

.vb-calc-twentynine-result p {
  grid-column: 1 / -1;
  margin: 0 !important;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-calc-twentynine-card {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-twentynine-copy h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-calc-twentynine-grid,
  .vb-calc-twentynine-result {
    grid-template-columns: 1fr;
  }

  .vb-calc-twentynine-main,
  .vb-calc-twentynine-result p {
    grid-column: auto;
  }
}</pre>



<p class="wp-block-paragraph">This time duration calculator is useful for timesheet tools, payroll dashboards, productivity apps, booking systems, project trackers, freelancer billing pages, and shift duration calculators.</p>



<h2 class="wp-block-heading">30. Custom Formula Calculator</h2>



<p class="wp-block-paragraph"><strong>A custom formula calculator</strong> is useful for dashboards, internal business tools, education pages, admin panels, pricing tools, and no-code calculator demos. It lets users enter values and calculate a result from a selected formula.</p>



<p class="wp-block-paragraph">This example uses predefined formulas, variable inputs, formula switching, safe calculation logic, result formatting, and dynamic explanation text. The JavaScript maps each formula to a specific calculation function instead of using unsafe raw eval.</p>



<ul class="wp-block-list">
<li>Custom formula calculator</li>
<li>Formula selector dropdown</li>
<li>Dynamic variable labels</li>
<li>No unsafe eval usage</li>
<li>Reusable JavaScript formula map</li>
</ul>



<div class="vb-calc-thirty-demo">
  <div class="vb-calc-thirty-shell">
    <div class="vb-calc-thirty-header">
      <span>Example 30</span>
      <h3>Custom Formula Calculator</h3>
      <p>Select a formula, enter values, and calculate the result with reusable JavaScript formula logic.</p>
    </div>

    <div class="vb-calc-thirty-body">
      <div class="vb-calc-thirty-controls">
        <label>
          Formula type
          <select data-vb-calc-thirty-formula>
            <option value="rectangle" selected>Rectangle area</option>
            <option value="circle">Circle area</option>
            <option value="percentage">Percentage of number</option>
            <option value="growth">Growth percentage</option>
          </select>
        </label>

        <div class="vb-calc-thirty-inputs">
          <label>
            <span data-vb-calc-thirty-label-a>Width</span>
            <input type="number" step="0.01" value="12" data-vb-calc-thirty-a>
          </label>

          <label>
            <span data-vb-calc-thirty-label-b>Height</span>
            <input type="number" step="0.01" value="8" data-vb-calc-thirty-b>
          </label>
        </div>
      </div>

      <div class="vb-calc-thirty-result">
        <div class="vb-calc-thirty-main">
          <span>Calculated result</span>
          <strong data-vb-calc-thirty-result>0</strong>
        </div>

        <div>
          <span>Formula</span>
          <strong data-vb-calc-thirty-formula-text>—</strong>
        </div>

        <p data-vb-calc-thirty-message>Choose a formula and enter values.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-calc-thirty-demo,
.vb-calc-thirty-demo * {
  box-sizing: border-box;
}

.vb-calc-thirty-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(168, 85, 247, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(236, 72, 153, 0.14), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #fdf2f8 54%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.18);
  overflow: hidden;
}

.vb-calc-thirty-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-thirty-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #581c87 0%, #9333ea 52%, #db2777 100%) !important;
}

.vb-calc-thirty-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #f3e8ff !important;
  -webkit-text-fill-color: #f3e8ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-thirty-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-calc-thirty-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-calc-thirty-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(290px, 370px);
  gap: 22px;
  padding: clamp(22px, 4vw, 34px);
  min-width: 0;
}

.vb-calc-thirty-controls,
.vb-calc-thirty-inputs {
  display: grid;
  gap: 14px;
  min-width: 0;
}

.vb-calc-thirty-inputs {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.vb-calc-thirty-controls label {
  display: grid;
  min-width: 0;
  gap: 8px;
  color: #6b21a8 !important;
  -webkit-text-fill-color: #6b21a8 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-thirty-controls label span {
  color: #6b21a8 !important;
  -webkit-text-fill-color: #6b21a8 !important;
}

.vb-calc-thirty-controls input,
.vb-calc-thirty-controls select {
  width: 100%;
  min-width: 0;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #e9d5ff;
  border-radius: 16px;
  background: #faf5ff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-thirty-result {
  display: grid;
  min-width: 0;
  gap: 12px;
  padding: 18px;
  border-radius: 24px;
  background: #faf5ff;
  border: 1px solid #e9d5ff;
  align-self: start;
}

.vb-calc-thirty-result div {
  min-width: 0;
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.86);
}

.vb-calc-thirty-main {
  background: linear-gradient(135deg, #f3e8ff, #fce7f3) !important;
}

.vb-calc-thirty-result span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-thirty-result strong {
  display: block;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: clamp(22px, 3.5vw, 32px);
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.04em;
  overflow-wrap: anywhere;
}

.vb-calc-thirty-main strong {
  color: #db2777 !important;
  -webkit-text-fill-color: #db2777 !important;
  font-size: clamp(36px, 5vw, 50px);
}

.vb-calc-thirty-result p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-calc-thirty-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-thirty-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-calc-thirty-inputs {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const demo = document.querySelector(".vb-calc-thirty-demo");
  if (!demo) return;

  const formulaInput = demo.querySelector("[data-vb-calc-thirty-formula]");
  const inputA = demo.querySelector("[data-vb-calc-thirty-a]");
  const inputB = demo.querySelector("[data-vb-calc-thirty-b]");
  const labelA = demo.querySelector("[data-vb-calc-thirty-label-a]");
  const labelB = demo.querySelector("[data-vb-calc-thirty-label-b]");
  const resultOutput = demo.querySelector("[data-vb-calc-thirty-result]");
  const formulaTextOutput = demo.querySelector("[data-vb-calc-thirty-formula-text]");
  const messageOutput = demo.querySelector("[data-vb-calc-thirty-message]");

  const formulas = {
    rectangle: {
      labelA: "Width",
      labelB: "Height",
      text: "Width × Height",
      suffix: " square units",
      calculate: function (a, b) {
        return a * b;
      }
    },
    circle: {
      labelA: "Radius",
      labelB: "Unused",
      text: "π × Radius²",
      suffix: " square units",
      calculate: function (a) {
        return Math.PI * a * a;
      }
    },
    percentage: {
      labelA: "Number",
      labelB: "Percentage %",
      text: "Number × Percentage ÷ 100",
      suffix: "",
      calculate: function (a, b) {
        return a * b / 100;
      }
    },
    growth: {
      labelA: "Old value",
      labelB: "New value",
      text: "(New − Old) ÷ Old × 100",
      suffix: "%",
      calculate: function (a, b) {
        return a !== 0 ? (b - a) / a * 100 : 0;
      }
    }
  };

  function updateLabels() {
    const formula = formulas[formulaInput.value];
    labelA.textContent = formula.labelA;
    labelB.textContent = formula.labelB;
    formulaTextOutput.textContent = formula.text;

    if (formulaInput.value === "circle") {
      inputB.disabled = true;
      inputB.value = 0;
    } else {
      inputB.disabled = false;
      if (Number(inputB.value) === 0) {
        inputB.value = 8;
      }
    }
  }

  function calculateFormula() {
    const formulaKey = formulaInput.value;
    const formula = formulas[formulaKey];
    const a = Number(inputA.value) || 0;
    const b = Number(inputB.value) || 0;
    const result = formula.calculate(a, b);

    const cleanResult = Number(result.toFixed(3)).toLocaleString("en-US");
    resultOutput.textContent = cleanResult + formula.suffix;
    messageOutput.textContent = "Calculated with formula: " + formula.text + ".";
  }

  formulaInput.addEventListener("change", function () {
    updateLabels();
    calculateFormula();
  });

  [inputA, inputB].forEach(function (field) {
    field.addEventListener("input", calculateFormula);
  });

  updateLabels();
  calculateFormula();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const demo = document.querySelector(".vb-calc-thirty-demo");
  if (!demo) return;

  const formulaInput = demo.querySelector("[data-vb-calc-thirty-formula]");
  const inputA = demo.querySelector("[data-vb-calc-thirty-a]");
  const inputB = demo.querySelector("[data-vb-calc-thirty-b]");
  const labelA = demo.querySelector("[data-vb-calc-thirty-label-a]");
  const labelB = demo.querySelector("[data-vb-calc-thirty-label-b]");
  const resultOutput = demo.querySelector("[data-vb-calc-thirty-result]");
  const formulaTextOutput = demo.querySelector("[data-vb-calc-thirty-formula-text]");
  const messageOutput = demo.querySelector("[data-vb-calc-thirty-message]");

  const formulas = {
    rectangle: {
      labelA: "Width",
      labelB: "Height",
      text: "Width × Height",
      suffix: " square units",
      calculate: function (a, b) {
        return a * b;
      }
    },
    circle: {
      labelA: "Radius",
      labelB: "Unused",
      text: "π × Radius²",
      suffix: " square units",
      calculate: function (a) {
        return Math.PI * a * a;
      }
    },
    percentage: {
      labelA: "Number",
      labelB: "Percentage %",
      text: "Number × Percentage ÷ 100",
      suffix: "",
      calculate: function (a, b) {
        return a * b / 100;
      }
    },
    growth: {
      labelA: "Old value",
      labelB: "New value",
      text: "(New − Old) ÷ Old × 100",
      suffix: "%",
      calculate: function (a, b) {
        return a !== 0 ? (b - a) / a * 100 : 0;
      }
    }
  };

  function updateLabels() {
    const formula = formulas[formulaInput.value];
    labelA.textContent = formula.labelA;
    labelB.textContent = formula.labelB;
    formulaTextOutput.textContent = formula.text;

    if (formulaInput.value === "circle") {
      inputB.disabled = true;
      inputB.value = 0;
    } else {
      inputB.disabled = false;
      if (Number(inputB.value) === 0) {
        inputB.value = 8;
      }
    }
  }

  function calculateFormula() {
    const formulaKey = formulaInput.value;
    const formula = formulas[formulaKey];
    const a = Number(inputA.value) || 0;
    const b = Number(inputB.value) || 0;
    const result = formula.calculate(a, b);

    const cleanResult = Number(result.toFixed(3)).toLocaleString("en-US");
    resultOutput.textContent = cleanResult + formula.suffix;
    messageOutput.textContent = "Calculated with formula: " + formula.text + ".";
  }

  formulaInput.addEventListener("change", function () {
    updateLabels();
    calculateFormula();
  });

  [inputA, inputB].forEach(function (field) {
    field.addEventListener("input", calculateFormula);
  });

  updateLabels();
  calculateFormula();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-calc-thirty-demo"&gt;
  &lt;div class="vb-calc-thirty-shell"&gt;
    &lt;div class="vb-calc-thirty-header"&gt;
      &lt;span&gt;Example 30&lt;/span&gt;
      &lt;h3&gt;Custom Formula Calculator&lt;/h3&gt;
      &lt;p&gt;Select a formula, enter values, and calculate the result with reusable JavaScript formula logic.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-calc-thirty-body"&gt;
      &lt;div class="vb-calc-thirty-controls"&gt;
        &lt;label&gt;
          Formula type
          &lt;select data-vb-calc-thirty-formula&gt;
            &lt;option value="rectangle" selected&gt;Rectangle area&lt;/option&gt;
            &lt;option value="circle"&gt;Circle area&lt;/option&gt;
            &lt;option value="percentage"&gt;Percentage of number&lt;/option&gt;
            &lt;option value="growth"&gt;Growth percentage&lt;/option&gt;
          &lt;/select&gt;
        &lt;/label&gt;

        &lt;div class="vb-calc-thirty-inputs"&gt;
          &lt;label&gt;&lt;span data-vb-calc-thirty-label-a&gt;Width&lt;/span&gt;&lt;input type="number" step="0.01" value="12" data-vb-calc-thirty-a&gt;&lt;/label&gt;
          &lt;label&gt;&lt;span data-vb-calc-thirty-label-b&gt;Height&lt;/span&gt;&lt;input type="number" step="0.01" value="8" data-vb-calc-thirty-b&gt;&lt;/label&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-calc-thirty-result"&gt;
        &lt;div class="vb-calc-thirty-main"&gt;
          &lt;span&gt;Calculated result&lt;/span&gt;
          &lt;strong data-vb-calc-thirty-result&gt;0&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div&gt;&lt;span&gt;Formula&lt;/span&gt;&lt;strong data-vb-calc-thirty-formula-text&gt;—&lt;/strong&gt;&lt;/div&gt;

        &lt;p data-vb-calc-thirty-message&gt;Choose a formula and enter values.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-calc-thirty-demo,
.vb-calc-thirty-demo * {
  box-sizing: border-box;
}

.vb-calc-thirty-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 16%, rgba(168, 85, 247, 0.18), transparent 32%),
    radial-gradient(circle at 88% 12%, rgba(236, 72, 153, 0.14), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #fdf2f8 54%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.18);
  overflow: hidden;
}

.vb-calc-thirty-shell {
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.12);
}

.vb-calc-thirty-header {
  padding: clamp(24px, 4vw, 38px);
  background:
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #581c87 0%, #9333ea 52%, #db2777 100%) !important;
}

.vb-calc-thirty-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #f3e8ff !important;
  -webkit-text-fill-color: #f3e8ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-calc-thirty-header h3 {
  max-width: 100%;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
  overflow-wrap: anywhere;
}

.vb-calc-thirty-header p {
  max-width: 780px;
  margin: 0 !important;
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
  overflow-wrap: anywhere;
}

.vb-calc-thirty-body {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(290px, 370px);
  gap: 22px;
  padding: clamp(22px, 4vw, 34px);
  min-width: 0;
}

.vb-calc-thirty-controls,
.vb-calc-thirty-inputs {
  display: grid;
  gap: 14px;
  min-width: 0;
}

.vb-calc-thirty-inputs {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.vb-calc-thirty-controls label {
  display: grid;
  min-width: 0;
  gap: 8px;
  color: #6b21a8 !important;
  -webkit-text-fill-color: #6b21a8 !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-calc-thirty-controls label span {
  color: #6b21a8 !important;
  -webkit-text-fill-color: #6b21a8 !important;
}

.vb-calc-thirty-controls input,
.vb-calc-thirty-controls select {
  width: 100%;
  min-width: 0;
  min-height: 50px;
  padding: 0 14px;
  border: 1px solid #e9d5ff;
  border-radius: 16px;
  background: #faf5ff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 800;
  outline: none;
}

.vb-calc-thirty-result {
  display: grid;
  min-width: 0;
  gap: 12px;
  padding: 18px;
  border-radius: 24px;
  background: #faf5ff;
  border: 1px solid #e9d5ff;
  align-self: start;
}

.vb-calc-thirty-result div {
  min-width: 0;
  padding: 16px;
  border-radius: 18px;
  background: rgba(255,255,255,0.86);
}

.vb-calc-thirty-main {
  background: linear-gradient(135deg, #f3e8ff, #fce7f3) !important;
}

.vb-calc-thirty-result span {
  display: block;
  margin-bottom: 7px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-calc-thirty-result strong {
  display: block;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: clamp(22px, 3.5vw, 32px);
  line-height: 1.1;
  font-weight: 950;
  letter-spacing: -0.04em;
  overflow-wrap: anywhere;
}

.vb-calc-thirty-main strong {
  color: #db2777 !important;
  -webkit-text-fill-color: #db2777 !important;
  font-size: clamp(36px, 5vw, 50px);
}

.vb-calc-thirty-result p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 700;
  overflow-wrap: anywhere;
}

@media (max-width: 900px) {
  .vb-calc-thirty-body {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-calc-thirty-header h3 {
    font-size: 38px !important;
    letter-spacing: -0.045em;
  }

  .vb-calc-thirty-inputs {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This custom formula calculator is useful for dashboards, admin tools, education pages, pricing calculators, internal business tools, no-code calculator demos, and reusable JavaScript formula examples.</p>



<section class="vb24-service-ad-calculator">
  <div class="vb24-service-ad-calculator-inner">
    <div class="vb24-service-ad-calculator-copy">
      <span>Need a custom website?</span>
      <h2>Get a Fast, Modern and SEO-Friendly Website for Your Business</h2>
      <p>Want a website with smart calculators, quote forms, product sections, landing pages, service pages, and clean responsive design? Veebilehed24 builds modern websites that are easy to use, fast to load, and ready for search engines.</p>

      <ul>
        <li>Custom WordPress website development</li>
        <li>Responsive design for desktop, tablet, and mobile</li>
        <li>SEO-friendly structure, headings, content blocks, and technical setup</li>
        <li>Custom forms, calculators, landing pages, and conversion-focused sections</li>
      </ul>

      <a href="https://veebilehed24.ee/en/website-development/" target="_blank" rel="noopener">View Website Development Service</a>
    </div>

    <div class="vb24-service-ad-calculator-card">
      <div class="vb24-service-ad-calculator-screen">
        <div class="vb24-service-ad-calculator-bar">
          <span></span><span></span><span></span>
        </div>

        <div class="vb24-service-ad-calculator-preview">
          <div class="vb24-service-ad-calculator-line large"></div>
          <div class="vb24-service-ad-calculator-line"></div>
          <div class="vb24-service-ad-calculator-grid">
            <div></div>
            <div></div>
          </div>
          <div class="vb24-service-ad-calculator-result">€1,250</div>
        </div>
      </div>

      <strong>Website + smart tools</strong>
      <p>Build a business website with interactive calculators, quote forms, service pages, and conversion-focused UI.</p>
    </div>
  </div>
</section>

<style>
.vb24-service-ad-calculator,
.vb24-service-ad-calculator * {
  box-sizing: border-box;
}

.vb24-service-ad-calculator {
  margin: 46px 0 50px;
  padding: clamp(20px, 4vw, 42px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 18%, rgba(34, 197, 94, 0.22), transparent 34%),
    radial-gradient(circle at 88% 12%, rgba(37, 99, 235, 0.20), transparent 36%),
    linear-gradient(135deg, #0f172a 0%, #14532d 46%, #1e3a8a 100%) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.22);
  overflow: hidden;
}

.vb24-service-ad-calculator-inner {
  display: grid;
  grid-template-columns: minmax(0, 1.1fr) minmax(280px, 0.9fr);
  gap: 28px;
  max-width: 1120px;
  margin: 0 auto;
  align-items: center;
}

.vb24-service-ad-calculator-copy,
.vb24-service-ad-calculator-card {
  min-width: 0;
}

.vb24-service-ad-calculator-copy span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.16);
  border: 1px solid rgba(74, 222, 128, 0.28);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb24-service-ad-calculator-copy h2 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.065em;
  overflow-wrap: anywhere;
}

.vb24-service-ad-calculator-copy p {
  max-width: 720px;
  margin: 0 0 20px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb24-service-ad-calculator-copy ul {
  display: grid;
  gap: 10px;
  margin: 0 0 24px !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb24-service-ad-calculator-copy li {
  position: relative;
  margin: 0 !important;
  padding: 0 0 0 28px !important;
  color: #f8fafc !important;
  -webkit-text-fill-color: #f8fafc !important;
  font-size: 15px;
  line-height: 1.55;
  font-weight: 750;
}

.vb24-service-ad-calculator-copy li::before {
  content: "✓";
  position: absolute;
  left: 0;
  top: 0;
  color: #86efac !important;
  -webkit-text-fill-color: #86efac !important;
  font-weight: 950;
}

.vb24-service-ad-calculator-copy a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 14px 20px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22c55e, #06b6d4 52%, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  font-size: 15px;
  font-weight: 950;
  box-shadow: 0 18px 44px rgba(37, 99, 235, 0.32);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-service-ad-calculator-copy a:hover {
  transform: translateY(-2px);
  filter: saturate(1.08);
  box-shadow: 0 24px 58px rgba(37, 99, 235, 0.42);
}

.vb24-service-ad-calculator-card {
  padding: 18px;
  border-radius: 28px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.16);
  backdrop-filter: blur(12px);
}

.vb24-service-ad-calculator-screen {
  overflow: hidden;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px solid rgba(255,255,255,0.18);
  box-shadow: 0 20px 58px rgba(2, 6, 23, 0.22);
}

.vb24-service-ad-calculator-bar {
  display: flex;
  gap: 7px;
  padding: 13px;
  background: #e2e8f0;
}

.vb24-service-ad-calculator-bar span {
  width: 10px;
  height: 10px;
  border-radius: 999px;
  background: #94a3b8;
}

.vb24-service-ad-calculator-preview {
  padding: 22px;
}

.vb24-service-ad-calculator-line {
  height: 12px;
  max-width: 76%;
  margin-bottom: 12px;
  border-radius: 999px;
  background: #cbd5e1;
}

.vb24-service-ad-calculator-line.large {
  height: 22px;
  max-width: 92%;
  background: linear-gradient(135deg, #22c55e, #2563eb);
}

.vb24-service-ad-calculator-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
  margin: 20px 0;
}

.vb24-service-ad-calculator-grid div {
  min-height: 84px;
  border-radius: 18px;
  background:
    radial-gradient(circle at 18% 18%, rgba(34, 197, 94, 0.18), transparent 34%),
    #ffffff;
  border: 1px solid #e2e8f0;
}

.vb24-service-ad-calculator-result {
  padding: 18px;
  border-radius: 20px;
  background: linear-gradient(135deg, #dcfce7, #dbeafe) !important;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: clamp(34px, 5vw, 48px);
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vb24-service-ad-calculator-card > strong {
  display: block;
  margin: 18px 0 8px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1.2;
  font-weight: 950;
}

.vb24-service-ad-calculator-card > p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb24-service-ad-calculator-inner {
    grid-template-columns: 1fr;
  }

  .vb24-service-ad-calculator-card {
    max-width: 520px;
  }
}

@media (max-width: 640px) {
  .vb24-service-ad-calculator {
    border-radius: 24px;
  }

  .vb24-service-ad-calculator-copy h2 {
    font-size: 34px !important;
    letter-spacing: -0.045em;
  }

  .vb24-service-ad-calculator-copy a {
    width: 100%;
  }

  .vb24-service-ad-calculator-grid {
    grid-template-columns: 1fr;
  }
}
</style>



<h2 class="wp-block-heading" id="javascript-calculator-best-practices">JavaScript Calculator Best Practices</h2>



<p class="wp-block-paragraph">JavaScript calculators work best when the formula is clear, the inputs are easy to understand, and the result updates in a predictable way. A good calculator should not only return a number — it should explain what the number means, format it properly, and prevent confusing outputs such as <code>NaN</code>, <code>Infinity</code>, empty values, or broken totals.</p>



<p class="wp-block-paragraph">For website projects, calculators can improve landing pages, ecommerce pages, quote request forms, SaaS pricing pages, financial tools, health tools, education pages, dashboards, and service websites. They are especially useful when users need a quick estimate before contacting a company, buying a product, submitting a form, or comparing options.</p>



<div class="vb24-js-calc-best-grid">
  <div>
    <span>01</span>
    <h3>Keep the formula visible in your code</h3>
    <p>Use named variables and clear functions so the calculator can be edited later without guessing what each number means.</p>
  </div>

  <div>
    <span>02</span>
    <h3>Validate every input</h3>
    <p>Handle empty fields, negative numbers, zero division, unrealistic values, disabled fields, and missing selections before showing the final result.</p>
  </div>

  <div>
    <span>03</span>
    <h3>Format the result properly</h3>
    <p>Use currency symbols, percentages, units, decimals, thousands separators, and short result explanations when needed.</p>
  </div>

  <div>
    <span>04</span>
    <h3>Keep JavaScript scoped</h3>
    <p>Wrap each calculator in its own function or component scope so multiple examples can work on the same page without conflicts.</p>
  </div>
</div>

<style>
.vb24-js-calc-best-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin: 26px 0 32px;
}

.vb24-js-calc-best-grid div {
  min-width: 0;
  padding: 22px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 16% 12%, rgba(34, 197, 94, 0.12), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.08);
}

.vb24-js-calc-best-grid span {
  display: inline-flex;
  margin-bottom: 14px;
  width: 38px;
  height: 38px;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: linear-gradient(135deg, #22c55e, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb24-js-calc-best-grid h3 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.25 !important;
  font-weight: 900 !important;
}

.vb24-js-calc-best-grid p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb24-js-calc-best-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-js-calc-best-grid {
    grid-template-columns: 1fr;
  }
}
</style>



<p class="wp-block-paragraph">When you build your own JavaScript calculator, start with the user goal. A price calculator should help users understand cost. A loan calculator should show payment values clearly. A BMI calculator should include a readable category. A VAT calculator should explain whether tax was added or extracted. A quote calculator should guide the user toward the next action.</p>



<ul class="wp-block-list">
  <li><strong>Use semantic form labels</strong> so every input is understandable and accessible.</li>
  <li><strong>Use <code>Number()</code> carefully</strong> and always provide fallback values for empty inputs.</li>
  <li><strong>Avoid unsafe <code>eval()</code></strong> for custom formulas. Use mapped functions instead.</li>
  <li><strong>Use <code>Intl.NumberFormat</code></strong> for currency, decimal, and localized number formatting.</li>
  <li><strong>Separate formula logic from UI logic</strong> so formulas are easier to test, reuse, and maintain.</li>
  <li><strong>Show helper text</strong> when a result needs explanation, such as loan payments, health ranges, tax logic, or margins.</li>
  <li><strong>Keep results readable</strong> with large numbers, short labels, and enough spacing around the final value.</li>
  <li><strong>Test edge cases</strong> such as zero values, high values, missing values, and very small mobile screens.</li>
</ul>



<h2 class="wp-block-heading" id="responsive-javascript-calculator-design-tips">Responsive Calculator Design Tips</h2>



<p class="wp-block-paragraph">A JavaScript calculator must work well on mobile because many users will calculate prices, discounts, payments, shipping costs, BMI values, tips, tax amounts, or quote estimates directly from a phone. The design should stay readable, the input fields should be easy to tap, and the result should not overflow its container.</p>



<p class="wp-block-paragraph">For responsive calculator layouts, avoid fixed-width elements inside narrow containers. Use <code>minmax(0, 1fr)</code> for grid columns, add <code>min-width: 0</code> to grid children, use <code>clamp()</code> for large result numbers, and switch multi-column layouts to one column on small screens.</p>



<ul class="wp-block-list">
  <li><strong>Use one-column layouts on mobile</strong> so form fields and results remain readable.</li>
  <li><strong>Keep tap targets large enough</strong> for sliders, buttons, checkboxes, radio buttons, dropdowns, and quantity controls.</li>
  <li><strong>Prevent result overflow</strong> with <code>overflow-wrap: anywhere</code>, <code>min-width: 0</code>, and responsive font sizes.</li>
  <li><strong>Make final totals easy to scan</strong> with strong contrast, short labels, and enough whitespace.</li>
  <li><strong>Avoid hiding important inputs</strong> behind tabs or tiny controls if the calculator needs quick interaction.</li>
  <li><strong>Test long values</strong> such as large currency totals, long formulas, long labels, and percentage values.</li>
</ul>



<p class="wp-block-paragraph">Many calculators are part of a bigger website experience. A price calculator may sit inside a service page, a discount calculator may appear on an ecommerce landing page, a loan calculator may support a financial article, and a quote calculator may work together with a contact form. For form layout ideas, see our <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-forms/">modern CSS forms</a> guide.</p>



<h2 class="wp-block-heading" id="common-javascript-calculator-mistakes">Common JavaScript Calculator Mistakes</h2>



<p class="wp-block-paragraph">The most common JavaScript calculator mistakes are not only design issues. Many broken calculators fail because they do not validate inputs, do not handle zero values, use confusing formulas, display too many decimals, or let the result overflow on mobile screens.</p>



<div class="vb24-js-calc-mistakes">
  <div>
    <h3>Showing broken results</h3>
    <p>A calculator should never show <code>NaN</code>, <code>Infinity</code>, empty totals, or unreadable values. Always validate the input before updating the result.</p>
  </div>

  <div>
    <h3>Using unclear labels</h3>
    <p>Labels like “Amount” or “Value” are often too vague. Use specific labels such as “Loan amount”, “Tax rate %”, “Monthly income”, or “Price per item”.</p>
  </div>

  <div>
    <h3>Forgetting mobile layout</h3>
    <p>Large totals, long labels, and two-column form grids can easily break on mobile. Use responsive CSS and test narrow screens.</p>
  </div>

  <div>
    <h3>Mixing formulas and UI code</h3>
    <p>When formulas are buried inside event handlers, calculators become harder to edit. Use named functions and clear calculation steps.</p>
  </div>
</div>

<style>
.vb24-js-calc-mistakes {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  margin: 26px 0 32px;
}

.vb24-js-calc-mistakes div {
  min-width: 0;
  padding: 22px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 14% 12%, rgba(239, 68, 68, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #fff7ed) !important;
  border: 1px solid rgba(251, 146, 60, 0.28);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.07);
}

.vb24-js-calc-mistakes h3 {
  margin: 0 0 10px !important;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 19px !important;
  line-height: 1.25 !important;
  font-weight: 900 !important;
}

.vb24-js-calc-mistakes p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 720px) {
  .vb24-js-calc-mistakes {
    grid-template-columns: 1fr;
  }
}
</style>



<ul class="wp-block-list">
  <li><strong>Do not trust user input blindly</strong> because users can enter empty, negative, extremely high, or unexpected values.</li>
  <li><strong>Do not use too many decimals</strong> unless the calculator needs technical precision.</li>
  <li><strong>Do not make the result hard to find</strong>. The final value should be visually clear.</li>
  <li><strong>Do not rely only on placeholder text</strong>. Labels should remain visible after users start typing.</li>
  <li><strong>Do not use fake estimates</strong>. If a calculator is only approximate, explain that clearly.</li>
  <li><strong>Do not forget accessibility</strong>. Use real labels, keyboard-friendly buttons, readable contrast, and clear focus states.</li>
</ul>



<h2 class="wp-block-heading" id="javascript-calculator-faq">JavaScript Calculator FAQ</h2>



<p class="wp-block-paragraph">Here are common questions about building JavaScript calculators for websites, landing pages, ecommerce projects, dashboards, service pages, and interactive forms.</p>



<div class="vb24-js-calc-faq" data-vb24-js-calc-faq>
  <div class="vb24-js-calc-faq-item">
    <button type="button" aria-expanded="true">
      <span>What is a JavaScript calculator?</span>
      <strong>+</strong>
    </button>
    <div class="vb24-js-calc-faq-panel">
      <p>A JavaScript calculator is an interactive website component that takes user input, applies a formula, and displays a result directly on the page without reloading. It can calculate prices, loan payments, discounts, BMI values, tax amounts, shipping costs, quote estimates, margins, time duration, and many other values.</p>
    </div>
  </div>

  <div class="vb24-js-calc-faq-item">
    <button type="button" aria-expanded="false">
      <span>Can I use these calculator examples in WordPress?</span>
      <strong>+</strong>
    </button>
    <div class="vb24-js-calc-faq-panel">
      <p>Yes. These examples are written with HTML, CSS, and vanilla JavaScript, so they can be used inside Gutenberg custom HTML blocks, WordPress templates, landing pages, custom themes, or plugin layouts. For production use, it is better to move repeated CSS and JavaScript into theme or plugin files.</p>
    </div>
  </div>

  <div class="vb24-js-calc-faq-item">
    <button type="button" aria-expanded="false">
      <span>Should calculator results update live or after clicking a button?</span>
      <strong>+</strong>
    </button>
    <div class="vb24-js-calc-faq-panel">
      <p>Live updates are useful for simple calculators such as price estimates, discounts, BMI, tips, unit conversion, and totals. A button can be better for complex calculators where users need to enter many values before seeing a final result.</p>
    </div>
  </div>

  <div class="vb24-js-calc-faq-item">
    <button type="button" aria-expanded="false">
      <span>How do I prevent NaN or broken results?</span>
      <strong>+</strong>
    </button>
    <div class="vb24-js-calc-faq-panel">
      <p>Convert input values with care, provide fallback values, validate required fields, prevent division by zero, and check for invalid numbers before displaying the result. A calculator should show a helpful message instead of showing broken output.</p>
    </div>
  </div>

  <div class="vb24-js-calc-faq-item">
    <button type="button" aria-expanded="false">
      <span>Are JavaScript calculators good for SEO?</span>
      <strong>+</strong>
    </button>
    <div class="vb24-js-calc-faq-panel">
      <p>Yes, they can support SEO when the page also has useful written content, clear headings, internal links, fast loading, responsive design, and helpful examples. A calculator can improve engagement and make a page more useful, but it should not replace explanatory content.</p>
    </div>
  </div>

  <div class="vb24-js-calc-faq-item">
    <button type="button" aria-expanded="false">
      <span>What calculators are most useful for business websites?</span>
      <strong>+</strong>
    </button>
    <div class="vb24-js-calc-faq-panel">
      <p>Price estimate calculators, quote calculators, ROI calculators, tax calculators, shipping calculators, subscription calculators, loan calculators, savings calculators, profit margin calculators, and ecommerce cart total calculators are especially useful for business websites.</p>
    </div>
  </div>
</div>

<style>
.vb24-js-calc-faq {
  display: grid;
  gap: 12px;
  margin: 24px 0 34px;
}

.vb24-js-calc-faq-item {
  overflow: hidden;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 14px 36px rgba(15, 23, 42, 0.06);
}

.vb24-js-calc-faq-item button {
  display: flex;
  width: 100%;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 18px 20px;
  border: 0;
  background: linear-gradient(135deg, #ffffff, #f8fafc) !important;
  cursor: pointer;
  text-align: left;
}

.vb24-js-calc-faq-item button span {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 17px;
  line-height: 1.35;
  font-weight: 900;
}

.vb24-js-calc-faq-item button strong {
  display: inline-flex;
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  align-items: center;
  justify-content: center;
  border-radius: 999px;
  background: linear-gradient(135deg, #22c55e, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 19px;
  line-height: 1;
  font-weight: 950;
  transition: transform 0.2s ease;
}

.vb24-js-calc-faq-item button[aria-expanded="true"] strong {
  transform: rotate(45deg);
}

.vb24-js-calc-faq-panel {
  display: none;
  padding: 0 20px 20px;
}

.vb24-js-calc-faq-item.is-open .vb24-js-calc-faq-panel {
  display: block;
}

.vb24-js-calc-faq-panel p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

@media (max-width: 640px) {
  .vb24-js-calc-faq-item button {
    padding: 16px;
  }

  .vb24-js-calc-faq-item button span {
    font-size: 16px;
  }

  .vb24-js-calc-faq-panel {
    padding: 0 16px 18px;
  }
}
</style>

<script>
(function () {
  const faq = document.querySelector("[data-vb24-js-calc-faq]");
  if (!faq) return;

  const items = faq.querySelectorAll(".vb24-js-calc-faq-item");

  items.forEach(function (item, index) {
    const button = item.querySelector("button");

    if (index === 0) {
      item.classList.add("is-open");
      button.setAttribute("aria-expanded", "true");
    }

    button.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(function (otherItem) {
        const otherButton = otherItem.querySelector("button");
        otherItem.classList.remove("is-open");
        otherButton.setAttribute("aria-expanded", "false");
      });

      if (!isOpen) {
        item.classList.add("is-open");
        button.setAttribute("aria-expanded", "true");
      }
    });
  });
})();
</script>



<h2 class="wp-block-heading" id="javascript-calculator-conclusion">Conclusion</h2>



<p class="wp-block-paragraph">JavaScript calculators are one of the most practical interactive tools you can add to a website. They help users calculate prices, discounts, loan payments, BMI values, VAT, shipping costs, quote estimates, margins, savings goals, subscription totals, time duration, and many other useful values directly on the page.</p>



<p class="wp-block-paragraph">The best JavaScript calculators are simple to use, accurate, responsive, and easy to understand. They use clear labels, reliable formulas, validation, formatted results, helpful messages, and scoped JavaScript that does not conflict with other components on the same page.</p>



<p class="wp-block-paragraph">You can use the examples in this guide as starting points for WordPress projects, ecommerce stores, landing pages, SaaS dashboards, service websites, quote request forms, educational tools, financial pages, health calculators, and business websites. Customize the formulas, colors, fields, result cards, validation messages, and layout to match your own project.</p>



<p class="wp-block-paragraph">If you want a complete business website with custom calculators, quote forms, landing pages, service sections, and SEO-friendly structure, you can also explore our <a href="https://veebilehed24.ee/en/website-development/">website development service</a>.</p>



<h2 class="wp-block-heading" id="related-javascript-guides">Related JavaScript Guides</h2>



<p class="wp-block-paragraph">Continue building practical JavaScript functionality with these related guides. These posts work well together when creating interactive websites, business tools, forms, dashboards, search interfaces, menus, sliders, modals, accordions, and complete UI systems.</p>



<div class="vb24-js-calc-related">
  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-form-validation-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Form Validation Examples</strong>
    <p>Input validation, signup forms, checkout validation, password rules, multi-step validation, and real form logic.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-search-filter-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Search Filter Examples</strong>
    <p>Live search, product filtering, card filtering, FAQ search, dashboard filters, and practical filtering systems.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-dropdown-menu-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Dropdown Menu Examples</strong>
    <p>Custom selects, navigation dropdowns, profile menus, category dropdowns, and responsive menu behavior.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-countdown-timer-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Countdown Timer Examples</strong>
    <p>Sale timers, event timers, product launch timers, checkout urgency blocks, and responsive countdown components.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-modal-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Modal Examples</strong>
    <p>Popup windows, dialogs, overlays, confirmation modals, form modals, and accessible modal components.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-accordion-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Accordion Examples</strong>
    <p>FAQ accordions, product toggles, dashboard panels, nested accordions, and content expanders.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-toast-notification-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Toast Notification Examples</strong>
    <p>Alerts, success messages, undo actions, upload progress, clipboard confirmations, and app-style notifications.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-image-gallery-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Image Gallery Examples</strong>
    <p>Responsive galleries, image grids, filtering, lightbox-style behavior, and interactive visual content examples.</p>
  </a>
</div>

<style>
.vb24-js-calc-related {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin: 26px 0 38px;
}

.vb24-js-calc-related a {
  display: grid;
  min-width: 0;
  align-content: start;
  padding: 22px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 16% 12%, rgba(37, 99, 235, 0.12), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.08);
  text-decoration: none !important;
  transition: transform 0.22s ease, box-shadow 0.22s ease, border-color 0.22s ease;
}

.vb24-js-calc-related a:hover {
  transform: translateY(-3px);
  border-color: rgba(37, 99, 235, 0.38);
  box-shadow: 0 22px 56px rgba(15, 23, 42, 0.12);
}

.vb24-js-calc-related span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 12px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb24-js-calc-related strong {
  display: block;
  margin-bottom: 9px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 17px;
  line-height: 1.28;
  font-weight: 950;
  overflow-wrap: anywhere;
}

.vb24-js-calc-related p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 1080px) {
  .vb24-js-calc-related {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-js-calc-related {
    grid-template-columns: 1fr;
  }

  .vb24-js-calc-related a {
    padding: 20px;
  }
}
</style>
]]></content:encoded>
					
					<wfw:commentRss>https://veebilehed24.ee/en/blog/javascript/javascript-calculator-examples/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>30 JavaScript Search Filter Examples – Live Search, Product Filters &#038; UI Filtering</title>
		<link>https://veebilehed24.ee/en/blog/javascript/javascript-search-filter-examples/</link>
					<comments>https://veebilehed24.ee/en/blog/javascript/javascript-search-filter-examples/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Thu, 11 Jun 2026 06:37:54 +0000</pubDate>
				<category><![CDATA[Javascript]]></category>
		<guid isPermaLink="false">https://veebilehed24.ee/?p=1601</guid>

					<description><![CDATA[JavaScript search filters are one of the most useful interactive features for modern websites, ecommerce stores, dashboards, directories, portfolios, blogs, documentation pages, and content-heavy user interfaces. They help users quickly find matching items by typing a keyword, choosing a category, clicking a filter button, selecting tags, or combining multiple filter controls without reloading the page. [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">JavaScript search filters are one of the most useful interactive features for modern websites, ecommerce stores, dashboards, directories, portfolios, blogs, documentation pages, and content-heavy user interfaces. They help users quickly find matching items by typing a keyword, choosing a category, clicking a filter button, selecting tags, or combining multiple filter controls without reloading the page.</p>



<p class="wp-block-paragraph">In this guide, you will find 30 JavaScript search filter examples for real website projects, including live search, product filters, card filters, table filters, category filters, tag filters, portfolio filters, FAQ search, blog post filters, dashboard search panels, ecommerce filtering, multi-filter layouts, and responsive UI filtering patterns you can customize for your own work.</p>



<p class="wp-block-paragraph">This post focuses on filtering logic, visible JavaScript behavior, search input handling, matching text content, filtering cards, updating results, empty states, responsive filter layouts, and reusable UI patterns. For related components, you can also explore our <a href="https://veebilehed24.ee/en/blog/javascript/javascript-dropdown-menu-examples/">JavaScript dropdown menu examples</a>, <a href="https://veebilehed24.ee/en/blog/javascript/javascript-slider-examples/">JavaScript slider examples</a>, <a href="https://veebilehed24.ee/en/blog/javascript/javascript-form-validation-examples/">JavaScript form validation examples</a>, and <a href="https://veebilehed24.ee/en/blog/javascript/javascript-modal-examples/">JavaScript modal examples</a>.</p>



<div class="vb24-js-filter-jump-box">
  <a class="vb24-js-filter-jump-button" href="#javascript-search-filter-examples">View All 30 JavaScript Search Filter Examples</a>
</div>

<style>
.vb24-js-filter-jump-box {
  margin: 28px 0 36px;
}

.vb24-js-filter-jump-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 14px 22px;
  border-radius: 999px;
  background: linear-gradient(135deg, #10b981, #06b6d4 52%, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 850;
  line-height: 1.2;
  text-decoration: none !important;
  box-shadow: 0 16px 38px rgba(14, 165, 233, 0.28);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-js-filter-jump-button::after {
  content: "↓";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.18);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  line-height: 1;
}

.vb24-js-filter-jump-button:hover {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transform: translateY(-2px);
  filter: saturate(1.08);
  box-shadow: 0 20px 46px rgba(14, 165, 233, 0.36);
}

@media (max-width: 640px) {
  .vb24-js-filter-jump-button {
    width: 100%;
    padding: 14px 16px;
    font-size: 14px;
  }
}
</style>



<div class="toc-affiliate-wrap vb24-js-filter-toc-wrap">

  <div class="toc-left vb24-js-filter-toc-left">

    <div class="vb24-js-filter-toc-kicker">On this page</div>

    <h2>Table of Contents</h2>

    <ul class="vl24-toc vb24-js-filter-toc">
      <li><a href="#what-is-a-javascript-search-filter">What Is a JavaScript Search Filter?</a></li>
      <li><a href="#why-live-search-filtering-matters">Why Live Search Filtering Matters</a></li>
      <li><a href="#search-filter-vs-dropdown-vs-sorting">Search Filter vs Dropdown vs Sorting</a></li>
      <li><a href="#what-should-a-good-javascript-filter-include">What Should a Good JavaScript Filter Include?</a></li>
      <li><a class="vb24-featured-toc-link" href="#javascript-search-filter-examples">30 JavaScript Search Filter Examples</a></li>
      <li><a href="#javascript-search-filter-best-practices">JavaScript Search Filter Best Practices</a></li>
      <li><a href="#responsive-filter-design-tips">Responsive Filter Design Tips</a></li>
      <li><a href="#common-javascript-filter-mistakes">Common JavaScript Filter Mistakes</a></li>
      <li><a href="#javascript-search-filter-faq">JavaScript Search Filter FAQ</a></li>
      <li><a href="#javascript-search-filter-conclusion">Conclusion</a></li>
      <li><a href="#related-javascript-and-css-guides">Related JavaScript and CSS Guides</a></li>
    </ul>

  </div>

  <div class="toc-right vb24-js-filter-toc-right">

    <a class="vb24-entityschema-ad-card" href="https://veebilehed24.ee/en/shop/entityschema-pro/" target="_blank" rel="sponsored noopener">
      <span class="vb24-entityschema-ad-badge">WordPress SEO Plugin</span>

      <div class="vb24-entityschema-ad-image">
        <img decoding="async" src="https://veebilehed24.ee/wp-content/uploads/2026/03/entityschema-cover-600x400.webp" width="300" height="200" alt="EntitySchema Pro WordPress structured data and entity SEO plugin" loading="lazy">
      </div>

      <div class="vb24-entityschema-ad-content">
        <h3>EntitySchema Pro</h3>
        <p>Build a real entity-based structured data system for WordPress, modern SEO, and AI-readable websites.</p>

        <div class="vb24-entityschema-ad-price">
          <div class="vb24-entityschema-ad-price-left">
            <span class="vb24-entityschema-ad-price-label">Sale price</span>
            <span class="vb24-entityschema-ad-old-price">59€</span>
          </div>

          <strong class="vb24-entityschema-ad-sale-price">29€</strong>

          <span class="vb24-entityschema-ad-save">Save 30€</span>
        </div>

        <span class="vb24-entityschema-ad-button">View Plugin</span>
      </div>
    </a>

  </div>

</div>

<style>
.vb24-js-filter-toc-wrap {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 26px;
  align-items: stretch;
  margin: 34px 0 44px;
}

.vb24-js-filter-toc-left,
.vb24-js-filter-toc-right {
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 28px;
  background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.18);
}

.vb24-js-filter-toc-left {
  padding: 28px 30px 30px;
}

.vb24-js-filter-toc-kicker {
  margin-bottom: 10px;
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 13px;
  font-weight: 850;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb24-js-filter-toc-left h2 {
  margin: 0 0 22px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px !important;
  line-height: 1.15 !important;
  font-weight: 850 !important;
}

.vb24-js-filter-toc {
  display: grid !important;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px !important;
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb24-js-filter-toc li {
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb24-js-filter-toc li::before {
  display: none !important;
  content: none !important;
}

.vb24-js-filter-toc a {
  display: flex;
  align-items: center;
  min-height: 54px;
  padding: 13px 15px;
  border: 1px solid rgba(148, 163, 184, 0.18);
  border-radius: 15px;
  background: rgba(255, 255, 255, 0.065);
  color: #f3f4f6 !important;
  -webkit-text-fill-color: #f3f4f6 !important;
  font-size: 15px;
  font-weight: 750;
  line-height: 1.35;
  text-decoration: none !important;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.05);
  transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease;
}

.vb24-js-filter-toc a:hover {
  transform: translateY(-2px);
  border-color: rgba(16, 185, 129, 0.62);
  background: rgba(16, 185, 129, 0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb24-js-filter-toc .vb24-featured-toc-link {
  border-color: rgba(16, 185, 129, 0.72);
  background: linear-gradient(135deg, rgba(16, 185, 129, 0.30), rgba(6, 182, 212, 0.28), rgba(37, 99, 235, 0.26));
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb24-js-filter-toc-right {
  display: flex;
  align-items: stretch;
  justify-content: center;
  padding: 16px;
  overflow: hidden;
}

.vb24-entityschema-ad-card,
.vb24-entityschema-ad-card * {
  box-sizing: border-box;
}

.vb24-entityschema-ad-card {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  min-height: 100%;
  padding: 12px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(34, 211, 238, 0.28), transparent 34%),
    radial-gradient(circle at 86% 14%, rgba(236, 72, 153, 0.24), transparent 36%),
    linear-gradient(135deg, #111827 0%, #312e81 52%, #701a75 100%) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  overflow: hidden;
  box-shadow: 0 20px 56px rgba(2, 6, 23, 0.32);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-entityschema-ad-card:hover {
  transform: translateY(-3px);
  filter: saturate(1.08);
  box-shadow: 0 26px 70px rgba(2, 6, 23, 0.42);
}

.vb24-entityschema-ad-badge {
  position: absolute;
  z-index: 3;
  top: 18px;
  left: 18px;
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.70);
  border: 1px solid rgba(255,255,255,0.22);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb24-entityschema-ad-image {
  overflow: hidden;
  border-radius: 17px;
  border: 1px solid rgba(255,255,255,0.16);
  background: rgba(255,255,255,0.08);
}

.vb24-entityschema-ad-image img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 17px;
}

.vb24-entityschema-ad-content {
  padding: 15px 8px 4px;
}

.vb24-entityschema-ad-content h3 {
  margin: 0 0 8px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 23px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb24-entityschema-ad-content p {
  margin: 0 0 14px !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 13px;
  line-height: 1.5;
  font-weight: 650;
}

.vb24-entityschema-ad-price {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin: 0 0 12px;
  padding: 11px 12px;
  border-radius: 16px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.16);
}

.vb24-entityschema-ad-price-left {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.vb24-entityschema-ad-price-label {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 11px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb24-entityschema-ad-old-price {
  color: rgba(255,255,255,0.62) !important;
  -webkit-text-fill-color: rgba(255,255,255,0.62) !important;
  font-size: 15px;
  line-height: 1;
  font-weight: 850;
  text-decoration: line-through;
  text-decoration-thickness: 2px;
  text-decoration-color: rgba(248, 113, 113, 0.95);
}

.vb24-entityschema-ad-sale-price {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 31px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb24-entityschema-ad-save {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 28px;
  padding: 6px 9px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.18);
  border: 1px solid rgba(74, 222, 128, 0.34);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 11px;
  font-weight: 950;
  white-space: nowrap;
}

.vb24-entityschema-ad-button {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 43px;
  padding: 12px 14px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22d3ee, #2563eb 55%, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
  box-shadow: 0 14px 34px rgba(37, 99, 235, 0.30);
}

@media (max-width: 900px) {
  .vb24-js-filter-toc-wrap {
    grid-template-columns: 1fr;
  }

  .vb24-js-filter-toc-right {
    justify-content: flex-start;
    max-width: 360px;
  }
}

@media (max-width: 640px) {
  .vb24-js-filter-toc-left {
    padding: 22px 18px;
    border-radius: 22px;
  }

  .vb24-js-filter-toc-left h2 {
    font-size: 26px !important;
  }

  .vb24-js-filter-toc {
    grid-template-columns: 1fr;
  }

  .vb24-js-filter-toc a {
    min-height: 48px;
    font-size: 14px;
  }

  .vb24-js-filter-toc-right {
    max-width: 100%;
    border-radius: 22px;
  }
}
</style>



<h2 class="wp-block-heading" id="what-is-a-javascript-search-filter">What Is a JavaScript Search Filter?</h2>



<p class="wp-block-paragraph">A JavaScript search filter is an interactive feature that shows, hides, sorts, or updates visible content based on what a user searches or selects. Instead of sending the visitor to a new page, JavaScript reads the current input, compares it with page content, and instantly displays the matching results.</p>



<p class="wp-block-paragraph">Search filters can be simple or advanced. A basic live search may filter a list of names as the user types. A product filter may combine category buttons, price ranges, ratings, tags, and search keywords. A dashboard filter may narrow down table rows, cards, orders, users, tasks, or analytics widgets. The goal is always the same: help users find the right content faster.</p>



<p class="wp-block-paragraph">The best JavaScript search filter examples are easy to understand, fast to use, and clear when no results are found. They should make large content sections feel smaller, more organized, and more useful without forcing the user to refresh the page or open a separate search results screen.</p>



<h2 class="wp-block-heading" id="why-live-search-filtering-matters">Why Live Search Filtering Matters</h2>



<p class="wp-block-paragraph">Live search filtering matters because websites often contain more content than users want to scan manually. Product grids, blog archives, FAQ sections, pricing features, support documents, portfolio items, team directories, admin tables, and card layouts become easier to use when visitors can narrow the content instantly.</p>



<ul class="wp-block-list">
  <li><strong>It reduces friction</strong> by helping users find relevant content without scrolling through every item.</li>
  <li><strong>It improves ecommerce browsing</strong> by letting customers narrow products by keyword, category, price, tag, rating, or feature.</li>
  <li><strong>It improves dashboard usability</strong> by making tables, tasks, orders, users, and records easier to scan.</li>
  <li><strong>It supports content-heavy pages</strong> such as blog archives, documentation pages, FAQ libraries, and resource hubs.</li>
  <li><strong>It creates a faster interface</strong> because many filters can update the visible UI without loading another page.</li>
</ul>



<p class="wp-block-paragraph">Search filters are especially valuable when the user already knows what they are looking for. Someone searching a product catalog may type a material, brand, size, or feature. Someone using a dashboard may search for a customer name, status, invoice number, or project label. A good JavaScript filter turns that intent into visible results immediately.</p>



<h2 class="wp-block-heading" id="search-filter-vs-dropdown-vs-sorting">Search Filter vs Dropdown vs Sorting</h2>



<p class="wp-block-paragraph">Search filtering, dropdown filtering, and sorting are related, but they solve different user experience problems. A search filter lets users type a keyword and match visible content. A dropdown filter lets users choose from a controlled set of categories or values. Sorting changes the order of visible results, such as newest first, lowest price, highest rating, or alphabetical order.</p>



<p class="wp-block-paragraph">In real projects, these patterns often work together. A product page may include a search input, category buttons, price filters, rating filters, and sorting controls. A blog archive may let users search by title, choose a category, filter by tag, and sort recent posts. A dashboard may combine text search with status filters and table sorting.</p>



<ul class="wp-block-list">
  <li><strong>Use live search</strong> when users need to type a keyword and quickly find matching items.</li>
  <li><strong>Use category filters</strong> when content belongs to clear groups such as products, posts, services, tags, or portfolio types.</li>
  <li><strong>Use dropdown filters</strong> when the list of available filter values should stay compact.</li>
  <li><strong>Use checkbox filters</strong> when users may need to combine multiple options at the same time.</li>
  <li><strong>Use sorting controls</strong> when all items should remain visible but appear in a different order.</li>
</ul>



<p class="wp-block-paragraph">This guide focuses on JavaScript search filter interfaces rather than dropdown menu behavior. Some examples may still include buttons, tabs, dropdowns, checkboxes, tags, or sorting controls, but the main goal is filtering visible content based on user input or selected filter rules.</p>



<h2 class="wp-block-heading" id="what-should-a-good-javascript-filter-include">What Should a Good JavaScript Filter Include?</h2>



<p class="wp-block-paragraph">A good JavaScript filter should make a page easier to explore. The search input should be visible, the filter controls should be understandable, the matching results should update quickly, and the empty state should tell users what happened. If the filter changes a product grid, card layout, table, FAQ section, or blog archive, the user should always know which filters are active.</p>



<div class="vb24-js-filter-checklist">
  <div class="vb24-js-filter-check-item">
    <h3>Clear search input</h3>
    <p>The input should explain what users can search for, such as products, posts, names, tags, services, or table rows.</p>
  </div>

  <div class="vb24-js-filter-check-item">
    <h3>Visible results update</h3>
    <p>Users should immediately see which cards, rows, products, FAQ items, or content blocks match their search.</p>
  </div>

  <div class="vb24-js-filter-check-item">
    <h3>Helpful empty state</h3>
    <p>If no results match the filter, show a message instead of leaving the section blank or confusing.</p>
  </div>

  <div class="vb24-js-filter-check-item">
    <h3>Responsive filter layout</h3>
    <p>Filter controls should stay usable on mobile, especially when several buttons, tags, categories, or inputs are included.</p>
  </div>
</div>

<style>
.vb24-js-filter-checklist {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 30px;
}

.vb24-js-filter-check-item {
  padding: 20px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 22px;
  background: #ffffff;
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb24-js-filter-check-item h3 {
  margin: 0 0 10px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 850;
}

.vb24-js-filter-check-item p {
  margin: 0;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb24-js-filter-checklist {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-js-filter-checklist {
    grid-template-columns: 1fr;
  }

  .vb24-js-filter-check-item {
    padding: 18px;
    border-radius: 20px;
  }
}
</style>



<p class="wp-block-paragraph">Before writing JavaScript, decide what the filter should compare. A card filter may compare titles, categories, and tags stored in data attributes. A table filter may compare row text. A product filter may compare price, brand, size, category, stock status, or rating. A FAQ filter may compare questions and answers. Choosing the right content source keeps the JavaScript simple and predictable.</p>



<ul class="wp-block-list">
  <li><strong>Use descriptive placeholders</strong> so users know what they can search inside the section.</li>
  <li><strong>Use data attributes</strong> when cards or products need category, tag, price, brand, or status values.</li>
  <li><strong>Show the number of matching results</strong> when the page contains many items.</li>
  <li><strong>Add a reset button</strong> when multiple filters can be active at the same time.</li>
  <li><strong>Keep filter controls close to the results</strong> so users understand what the controls affect.</li>
  <li><strong>Use active button states</strong> for category filters, tag filters, and selected filter chips.</li>
  <li><strong>Design a no-results message</strong> to avoid empty or broken-looking layouts.</li>
  <li><strong>Test with long content</strong> because short demo text can hide real filtering problems.</li>
  <li><strong>Make mobile filters easy to tap</strong> with enough spacing and readable labels.</li>
  <li><strong>Keep the JavaScript scoped</strong> so multiple filter components can work on the same page.</li>
</ul>



<p class="wp-block-paragraph">You can combine JavaScript filters with many other UI patterns. Product filters can work with <a href="https://veebilehed24.ee/en/blog/css-effects/25-modern-css-cards-for-websites-html-css-examples/">modern CSS card layouts</a>, search inputs can pair with <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-forms/">modern CSS forms</a>, filter controls can use ideas from our <a href="https://veebilehed24.ee/en/blog/javascript/javascript-dropdown-menu-examples/">JavaScript dropdown menu examples</a>, and filtered result sections can be placed inside responsive layouts from our <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-layouts/">modern CSS layouts</a> guide.</p>



<h2 class="wp-block-heading" id="javascript-search-filter-examples">30 JavaScript Search Filter Examples</h2>



<p class="wp-block-paragraph">Now let’s look at 30 JavaScript search filter examples for real website projects. Each example uses a different filtering layout, search input style, result type, category system, product grid, table pattern, card UI, tag filter, empty state, or responsive filtering approach, so you can build live search sections, ecommerce product filters, dashboard filters, portfolio filters, FAQ search components, blog filters, and complete JavaScript filtering interfaces with visible JavaScript, HTML, and CSS code.</p>



<h2 class="wp-block-heading">1. Basic Live Search Filter</h2>



<p class="wp-block-paragraph"><strong>A basic live search filter</strong> is the simplest way to filter visible content with JavaScript. Users type a keyword into the search field, and matching cards stay visible while non-matching cards are hidden instantly.</p>



<p class="wp-block-paragraph">This example filters service cards by title, description, and category text. It also updates the result count and shows a no-results message when nothing matches the search query.</p>



<ul class="wp-block-list">
<li>Live search input</li>
<li>Instant card filtering</li>
<li>Dynamic result count</li>
<li>Clear search button</li>
<li>No-results empty state</li>
</ul>



<div class="vb-filter-one-demo">
  <div class="vb-filter-one-shell" data-vb-filter-one>
    <div class="vb-filter-one-header">
      <span>Example 01</span>
      <h3>Basic Live Search Filter</h3>
      <p>Type a keyword to filter website service cards instantly with vanilla JavaScript.</p>
    </div>

    <div class="vb-filter-one-search">
      <label for="vb-filter-one-input">Search services</label>
      <div class="vb-filter-one-input-wrap">
        <span>⌕</span>
        <input id="vb-filter-one-input" type="search" placeholder="Try website, shop, SEO, dashboard..." data-vb-filter-one-input>
      </div>
    </div>

    <div class="vb-filter-one-meta">
      <strong data-vb-filter-one-count>6 results found</strong>
      <button type="button" data-vb-filter-one-clear>Clear search</button>
    </div>

    <div class="vb-filter-one-grid" data-vb-filter-one-grid>
      <article data-filter-text="business website company service local brand">
        <span>🏢</span>
        <h4>Business Website</h4>
        <p>Clean company websites for service businesses, consultants, and local brands.</p>
        <small>Website</small>
      </article>

      <article data-filter-text="online store ecommerce product catalog woocommerce shop">
        <span>🛒</span>
        <h4>Online Store</h4>
        <p>Product catalogs, ecommerce layouts, cart flows, and modern shop interfaces.</p>
        <small>Ecommerce</small>
      </article>

      <article data-filter-text="seo landing page content optimization search engine">
        <span>📈</span>
        <h4>SEO Landing Page</h4>
        <p>Search-focused landing pages built for leads, ranking, and conversions.</p>
        <small>SEO</small>
      </article>

      <article data-filter-text="dashboard web app interface saas admin panel">
        <span>⚙️</span>
        <h4>Web App Dashboard</h4>
        <p>Modern admin screens, SaaS panels, metrics cards, and app layouts.</p>
        <small>Dashboard</small>
      </article>

      <article data-filter-text="portfolio creative gallery case studies designer developer">
        <span>🎨</span>
        <h4>Portfolio Gallery</h4>
        <p>Filterable work sections for designers, developers, agencies, and creators.</p>
        <small>Portfolio</small>
      </article>

      <article data-filter-text="mobile app landing startup product launch application">
        <span>📱</span>
        <h4>App Landing Page</h4>
        <p>Product-focused sections for mobile apps, SaaS launches, and startups.</p>
        <small>App</small>
      </article>
    </div>

    <div class="vb-filter-one-empty" data-vb-filter-one-empty>
      <strong>No matching services found.</strong>
      <p>Try another keyword such as website, shop, SEO, dashboard, app, or portfolio.</p>
    </div>
  </div>
</div>

<style>
.vb-filter-one-demo,
.vb-filter-one-demo * {
  box-sizing: border-box;
}

.vb-filter-one-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(16, 185, 129, 0.22), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(14, 165, 233, 0.20), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #f0f9ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(167, 243, 208, 0.48);
  box-shadow: 0 24px 70px rgba(6, 95, 70, 0.12);
}

.vb-filter-one-shell {
  max-width: 1080px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-one-header {
  max-width: 760px;
  margin-bottom: 24px;
}

.vb-filter-one-header > span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #d1fae5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-one-header h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-one-header p {
  max-width: 620px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-filter-one-search {
  margin-bottom: 16px;
}

.vb-filter-one-search label {
  display: block;
  margin-bottom: 9px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-one-input-wrap {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr);
  align-items: center;
  min-height: 64px;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.28);
  overflow: hidden;
}

.vb-filter-one-input-wrap span {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: #059669 !important;
  -webkit-text-fill-color: #059669 !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-filter-one-input-wrap input {
  width: 100%;
  min-height: 64px;
  border: 0;
  outline: 0;
  background: transparent;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 16px;
  font-weight: 750;
}

.vb-filter-one-input-wrap input::placeholder {
  color: #94a3b8;
  -webkit-text-fill-color: #94a3b8;
}

.vb-filter-one-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 22px;
}

.vb-filter-one-meta strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-filter-one-meta button {
  min-height: 40px;
  padding: 9px 13px;
  border: 0;
  border-radius: 999px;
  background: #d1fae5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-one-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.vb-filter-one-grid article {
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 18% 12%, rgba(16, 185, 129, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb-filter-one-grid article.is-hidden {
  display: none;
}

.vb-filter-one-grid article > span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  margin-bottom: 16px;
  border-radius: 16px;
  background: #ecfdf5;
  font-size: 21px;
}

.vb-filter-one-grid h4 {
  margin: 0 0 9px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-one-grid p {
  margin: 0 0 14px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-filter-one-grid small {
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: #d1fae5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-filter-one-empty {
  display: none;
  margin-top: 18px;
  padding: 22px;
  border-radius: 22px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.30);
}

.vb-filter-one-empty.is-visible {
  display: block;
}

.vb-filter-one-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 19px;
  font-weight: 950;
}

.vb-filter-one-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.6;
}

@media (max-width: 900px) {
  .vb-filter-one-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-filter-one-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-one-shell {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-one-header h3 {
    font-size: 38px !important;
  }

  .vb-filter-one-grid {
    grid-template-columns: 1fr;
  }

  .vb-filter-one-meta {
    align-items: stretch;
    flex-direction: column;
  }

  .vb-filter-one-meta button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const filter = document.querySelector("[data-vb-filter-one]");
  if (!filter) return;

  const input = filter.querySelector("[data-vb-filter-one-input]");
  const clearButton = filter.querySelector("[data-vb-filter-one-clear]");
  const count = filter.querySelector("[data-vb-filter-one-count]");
  const empty = filter.querySelector("[data-vb-filter-one-empty]");
  const cards = Array.from(filter.querySelectorAll("[data-filter-text]"));

  function updateFilter() {
    const searchValue = input.value.trim().toLowerCase();
    let visibleCount = 0;

    cards.forEach(function (card) {
      const text = card.getAttribute("data-filter-text").toLowerCase();
      const title = card.querySelector("h4").textContent.toLowerCase();
      const description = card.querySelector("p").textContent.toLowerCase();
      const match = text.includes(searchValue) || title.includes(searchValue) || description.includes(searchValue);

      card.classList.toggle("is-hidden", !match);

      if (match) {
        visibleCount += 1;
      }
    });

    count.textContent = visibleCount === 1 ? "1 result found" : visibleCount + " results found";
    empty.classList.toggle("is-visible", visibleCount === 0);
  }

  input.addEventListener("input", updateFilter);

  clearButton.addEventListener("click", function () {
    input.value = "";
    input.focus();
    updateFilter();
  });

  updateFilter();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const filter = document.querySelector("[data-vb-filter-one]");
  if (!filter) return;

  const input = filter.querySelector("[data-vb-filter-one-input]");
  const clearButton = filter.querySelector("[data-vb-filter-one-clear]");
  const count = filter.querySelector("[data-vb-filter-one-count]");
  const empty = filter.querySelector("[data-vb-filter-one-empty]");
  const cards = Array.from(filter.querySelectorAll("[data-filter-text]"));

  function updateFilter() {
    const searchValue = input.value.trim().toLowerCase();
    let visibleCount = 0;

    cards.forEach(function (card) {
      const text = card.getAttribute("data-filter-text").toLowerCase();
      const title = card.querySelector("h4").textContent.toLowerCase();
      const description = card.querySelector("p").textContent.toLowerCase();
      const match = text.includes(searchValue) || title.includes(searchValue) || description.includes(searchValue);

      card.classList.toggle("is-hidden", !match);

      if (match) {
        visibleCount += 1;
      }
    });

    count.textContent = visibleCount === 1 ? "1 result found" : visibleCount + " results found";
    empty.classList.toggle("is-visible", visibleCount === 0);
  }

  input.addEventListener("input", updateFilter);

  clearButton.addEventListener("click", function () {
    input.value = "";
    input.focus();
    updateFilter();
  });

  updateFilter();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-one-demo"&gt;
  &lt;div class="vb-filter-one-shell" data-vb-filter-one&gt;
    &lt;div class="vb-filter-one-header"&gt;
      &lt;span&gt;Example 01&lt;/span&gt;
      &lt;h3&gt;Basic Live Search Filter&lt;/h3&gt;
      &lt;p&gt;Type a keyword to filter website service cards instantly with vanilla JavaScript.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-one-search"&gt;
      &lt;label for="vb-filter-one-input"&gt;Search services&lt;/label&gt;
      &lt;div class="vb-filter-one-input-wrap"&gt;
        &lt;span&gt;⌕&lt;/span&gt;
        &lt;input id="vb-filter-one-input" type="search" placeholder="Try website, shop, SEO, dashboard..." data-vb-filter-one-input&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-one-meta"&gt;
      &lt;strong data-vb-filter-one-count&gt;6 results found&lt;/strong&gt;
      &lt;button type="button" data-vb-filter-one-clear&gt;Clear search&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-one-grid" data-vb-filter-one-grid&gt;
      &lt;article data-filter-text="business website company service local brand"&gt;
        &lt;span&gt;🏢&lt;/span&gt;
        &lt;h4&gt;Business Website&lt;/h4&gt;
        &lt;p&gt;Clean company websites for service businesses, consultants, and local brands.&lt;/p&gt;
        &lt;small&gt;Website&lt;/small&gt;
      &lt;/article&gt;

      &lt;article data-filter-text="online store ecommerce product catalog woocommerce shop"&gt;
        &lt;span&gt;🛒&lt;/span&gt;
        &lt;h4&gt;Online Store&lt;/h4&gt;
        &lt;p&gt;Product catalogs, ecommerce layouts, cart flows, and modern shop interfaces.&lt;/p&gt;
        &lt;small&gt;Ecommerce&lt;/small&gt;
      &lt;/article&gt;

      &lt;article data-filter-text="seo landing page content optimization search engine"&gt;
        &lt;span&gt;📈&lt;/span&gt;
        &lt;h4&gt;SEO Landing Page&lt;/h4&gt;
        &lt;p&gt;Search-focused landing pages built for leads, ranking, and conversions.&lt;/p&gt;
        &lt;small&gt;SEO&lt;/small&gt;
      &lt;/article&gt;

      &lt;article data-filter-text="dashboard web app interface saas admin panel"&gt;
        &lt;span&gt;⚙️&lt;/span&gt;
        &lt;h4&gt;Web App Dashboard&lt;/h4&gt;
        &lt;p&gt;Modern admin screens, SaaS panels, metrics cards, and app layouts.&lt;/p&gt;
        &lt;small&gt;Dashboard&lt;/small&gt;
      &lt;/article&gt;

      &lt;article data-filter-text="portfolio creative gallery case studies designer developer"&gt;
        &lt;span&gt;🎨&lt;/span&gt;
        &lt;h4&gt;Portfolio Gallery&lt;/h4&gt;
        &lt;p&gt;Filterable work sections for designers, developers, agencies, and creators.&lt;/p&gt;
        &lt;small&gt;Portfolio&lt;/small&gt;
      &lt;/article&gt;

      &lt;article data-filter-text="mobile app landing startup product launch application"&gt;
        &lt;span&gt;📱&lt;/span&gt;
        &lt;h4&gt;App Landing Page&lt;/h4&gt;
        &lt;p&gt;Product-focused sections for mobile apps, SaaS launches, and startups.&lt;/p&gt;
        &lt;small&gt;App&lt;/small&gt;
      &lt;/article&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-one-empty" data-vb-filter-one-empty&gt;
      &lt;strong&gt;No matching services found.&lt;/strong&gt;
      &lt;p&gt;Try another keyword such as website, shop, SEO, dashboard, app, or portfolio.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-one-demo,
.vb-filter-one-demo * {
  box-sizing: border-box;
}

.vb-filter-one-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(16, 185, 129, 0.22), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(14, 165, 233, 0.20), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #f0f9ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(167, 243, 208, 0.48);
  box-shadow: 0 24px 70px rgba(6, 95, 70, 0.12);
}

.vb-filter-one-shell {
  max-width: 1080px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-one-header {
  max-width: 760px;
  margin-bottom: 24px;
}

.vb-filter-one-header &gt; span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #d1fae5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-one-header h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-one-header p {
  max-width: 620px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-filter-one-search {
  margin-bottom: 16px;
}

.vb-filter-one-search label {
  display: block;
  margin-bottom: 9px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-one-input-wrap {
  display: grid;
  grid-template-columns: 52px minmax(0, 1fr);
  align-items: center;
  min-height: 64px;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.28);
  overflow: hidden;
}

.vb-filter-one-input-wrap span {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  color: #059669 !important;
  -webkit-text-fill-color: #059669 !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-filter-one-input-wrap input {
  width: 100%;
  min-height: 64px;
  border: 0;
  outline: 0;
  background: transparent;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 16px;
  font-weight: 750;
}

.vb-filter-one-input-wrap input::placeholder {
  color: #94a3b8;
  -webkit-text-fill-color: #94a3b8;
}

.vb-filter-one-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 22px;
}

.vb-filter-one-meta strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-filter-one-meta button {
  min-height: 40px;
  padding: 9px 13px;
  border: 0;
  border-radius: 999px;
  background: #d1fae5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-one-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.vb-filter-one-grid article {
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 18% 12%, rgba(16, 185, 129, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb-filter-one-grid article.is-hidden {
  display: none;
}

.vb-filter-one-grid article &gt; span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  margin-bottom: 16px;
  border-radius: 16px;
  background: #ecfdf5;
  font-size: 21px;
}

.vb-filter-one-grid h4 {
  margin: 0 0 9px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-one-grid p {
  margin: 0 0 14px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-filter-one-grid small {
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: #d1fae5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-filter-one-empty {
  display: none;
  margin-top: 18px;
  padding: 22px;
  border-radius: 22px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.30);
}

.vb-filter-one-empty.is-visible {
  display: block;
}

.vb-filter-one-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 19px;
  font-weight: 950;
}

.vb-filter-one-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.6;
}

@media (max-width: 900px) {
  .vb-filter-one-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-filter-one-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-one-shell {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-one-header h3 {
    font-size: 38px !important;
  }

  .vb-filter-one-grid {
    grid-template-columns: 1fr;
  }

  .vb-filter-one-meta {
    align-items: stretch;
    flex-direction: column;
  }

  .vb-filter-one-meta button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This basic live search filter is a useful foundation for many website sections. You can adapt it for service cards, small directories, blog previews, team members, portfolio items, feature lists, and resource grids.</p>



<h2 class="wp-block-heading">2. Product Grid Search Filter</h2>



<p class="wp-block-paragraph"><strong>A product grid search filter</strong> helps customers narrow ecommerce items without refreshing the page. Instead of browsing every product manually, users can search by product name, category, material, or feature and instantly see matching product cards.</p>



<p class="wp-block-paragraph">This example uses a bold ecommerce-style layout with a search bar, product cards, price labels, stock badges, result count, and an empty state. The JavaScript checks product data attributes and filters the visible grid in real time.</p>



<ul class="wp-block-list">
<li>Live ecommerce product search</li>
<li>Filters by product name, category, and keywords</li>
<li>Product card layout with prices</li>
<li>Result count and empty state</li>
<li>Useful for shop pages, catalogs, and landing pages</li>
</ul>



<div class="vb-filter-two-demo">
  <div class="vb-filter-two-store" data-vb-filter-two>
    <div class="vb-filter-two-sidebar">
      <span>Example 02</span>
      <h3>Product Grid Search Filter</h3>
      <p>Search the product catalog and show only matching ecommerce cards.</p>

      <div class="vb-filter-two-search">
        <label for="vb-filter-two-input">Search products</label>
        <input id="vb-filter-two-input" type="search" placeholder="Search lamp, chair, desk, storage..." data-vb-filter-two-input>
      </div>

      <div class="vb-filter-two-summary">
        <strong data-vb-filter-two-count>8 products found</strong>
        <button type="button" data-vb-filter-two-clear>Reset</button>
      </div>
    </div>

    <div class="vb-filter-two-content">
      <div class="vb-filter-two-grid">
        <article data-product-text="modern desk lamp lighting office black adjustable">
          <div class="vb-filter-two-art lamp"></div>
          <div class="vb-filter-two-info">
            <span>Lighting</span>
            <h4>Modern Desk Lamp</h4>
            <p>Adjustable office lamp with a compact modern base.</p>
            <div><strong>€49</strong><small>In stock</small></div>
          </div>
        </article>

        <article data-product-text="ergonomic chair office furniture mesh black comfort">
          <div class="vb-filter-two-art chair"></div>
          <div class="vb-filter-two-info">
            <span>Furniture</span>
            <h4>Ergonomic Chair</h4>
            <p>Comfort-focused office chair with breathable mesh.</p>
            <div><strong>€189</strong><small>In stock</small></div>
          </div>
        </article>

        <article data-product-text="wooden desk table workspace oak minimal office">
          <div class="vb-filter-two-art desk"></div>
          <div class="vb-filter-two-info">
            <span>Workspace</span>
            <h4>Oak Work Desk</h4>
            <p>Minimal wooden desk for clean home office setups.</p>
            <div><strong>€299</strong><small>Low stock</small></div>
          </div>
        </article>

        <article data-product-text="storage cabinet organizer shelves home office white">
          <div class="vb-filter-two-art storage"></div>
          <div class="vb-filter-two-info">
            <span>Storage</span>
            <h4>Storage Cabinet</h4>
            <p>Compact cabinet for files, supplies, and accessories.</p>
            <div><strong>€129</strong><small>In stock</small></div>
          </div>
        </article>

        <article data-product-text="monitor stand laptop riser aluminum desk accessory">
          <div class="vb-filter-two-art stand"></div>
          <div class="vb-filter-two-info">
            <span>Accessory</span>
            <h4>Monitor Stand</h4>
            <p>Aluminum riser for screens, laptops, and desk space.</p>
            <div><strong>€59</strong><small>In stock</small></div>
          </div>
        </article>

        <article data-product-text="desk mat leather large workspace black accessory">
          <div class="vb-filter-two-art mat"></div>
          <div class="vb-filter-two-info">
            <span>Accessory</span>
            <h4>Large Desk Mat</h4>
            <p>Smooth desk mat for keyboards, mice, and writing.</p>
            <div><strong>€39</strong><small>In stock</small></div>
          </div>
        </article>

        <article data-product-text="bookshelf storage furniture wood shelves living office">
          <div class="vb-filter-two-art shelf"></div>
          <div class="vb-filter-two-info">
            <span>Furniture</span>
            <h4>Wood Bookshelf</h4>
            <p>Open shelving unit for books, decor, and office items.</p>
            <div><strong>€159</strong><small>In stock</small></div>
          </div>
        </article>

        <article data-product-text="wireless charger desk accessory phone charging pad">
          <div class="vb-filter-two-art charger"></div>
          <div class="vb-filter-two-info">
            <span>Tech</span>
            <h4>Wireless Charger</h4>
            <p>Minimal charging pad for phones and desk setups.</p>
            <div><strong>€34</strong><small>In stock</small></div>
          </div>
        </article>
      </div>

      <div class="vb-filter-two-empty" data-vb-filter-two-empty>
        <strong>No products matched your search.</strong>
        <p>Try searching for chair, desk, lamp, storage, accessory, or tech.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-filter-two-demo,
.vb-filter-two-demo * {
  box-sizing: border-box;
}

.vb-filter-two-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 18%, rgba(251, 146, 60, 0.22), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(236, 72, 153, 0.18), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #fdf2f8 52%, #ffffff 100%) !important;
  border: 1px solid rgba(253, 186, 116, 0.46);
  box-shadow: 0 24px 70px rgba(124, 45, 18, 0.12);
}

.vb-filter-two-store {
  display: grid;
  grid-template-columns: 320px minmax(0, 1fr);
  gap: 22px;
  max-width: 1120px;
  margin: 0 auto;
  padding: 18px;
  border-radius: 30px;
  background: #111827;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.24);
}

.vb-filter-two-sidebar {
  padding: 26px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 20% 14%, rgba(251, 146, 60, 0.20), transparent 32%),
    linear-gradient(135deg, #7c2d12, #be123c) !important;
  min-height: 640px;
}

.vb-filter-two-sidebar > span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-two-sidebar h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 4vw, 56px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-two-sidebar p {
  margin: 0 0 28px !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-two-search {
  margin-bottom: 18px;
}

.vb-filter-two-search label {
  display: block;
  margin-bottom: 9px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-two-search input {
  width: 100%;
  min-height: 58px;
  padding: 0 16px;
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: 18px;
  outline: 0;
  background: rgba(255,255,255,0.13);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 800;
}

.vb-filter-two-search input::placeholder {
  color: rgba(255,255,255,0.62);
  -webkit-text-fill-color: rgba(255,255,255,0.62);
}

.vb-filter-two-summary {
  padding: 16px;
  border-radius: 20px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-filter-two-summary strong {
  display: block;
  margin-bottom: 12px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 19px;
  font-weight: 950;
}

.vb-filter-two-summary button {
  width: 100%;
  min-height: 44px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-two-content {
  padding: 10px;
}

.vb-filter-two-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-filter-two-grid article {
  overflow: hidden;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 18px 50px rgba(2, 6, 23, 0.18);
}

.vb-filter-two-grid article.is-hidden {
  display: none;
}

.vb-filter-two-art {
  min-height: 150px;
  background:
    radial-gradient(circle at 30% 24%, rgba(255,255,255,0.40), transparent 32%),
    linear-gradient(135deg, #fb923c, #ec4899) !important;
}

.vb-filter-two-art.chair {
  background:
    radial-gradient(circle at 30% 24%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #6366f1, #06b6d4) !important;
}

.vb-filter-two-art.desk {
  background:
    radial-gradient(circle at 30% 24%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #92400e, #f59e0b) !important;
}

.vb-filter-two-art.storage {
  background:
    radial-gradient(circle at 30% 24%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #0f766e, #22c55e) !important;
}

.vb-filter-two-art.stand {
  background:
    radial-gradient(circle at 30% 24%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #475569, #94a3b8) !important;
}

.vb-filter-two-art.mat {
  background:
    radial-gradient(circle at 30% 24%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #111827, #4b5563) !important;
}

.vb-filter-two-art.shelf {
  background:
    radial-gradient(circle at 30% 24%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #78350f, #d97706) !important;
}

.vb-filter-two-art.charger {
  background:
    radial-gradient(circle at 30% 24%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #2563eb, #7c3aed) !important;
}

.vb-filter-two-info {
  padding: 18px;
}

.vb-filter-two-info > span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #fff7ed;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-two-info h4 {
  margin: 0 0 8px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-two-info p {
  margin: 0 0 15px !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-filter-two-info div {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.vb-filter-two-info strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 25px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-filter-two-info small {
  padding: 7px 9px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-filter-two-empty {
  display: none;
  margin-top: 16px;
  padding: 22px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(251, 146, 60, 0.32);
}

.vb-filter-two-empty.is-visible {
  display: block;
}

.vb-filter-two-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-two-empty p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 960px) {
  .vb-filter-two-store {
    grid-template-columns: 1fr;
  }

  .vb-filter-two-sidebar {
    min-height: auto;
  }
}

@media (max-width: 640px) {
  .vb-filter-two-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-two-store {
    padding: 12px;
    border-radius: 24px;
  }

  .vb-filter-two-sidebar {
    padding: 22px;
    border-radius: 20px;
  }

  .vb-filter-two-sidebar h3 {
    font-size: 38px !important;
  }

  .vb-filter-two-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const store = document.querySelector("[data-vb-filter-two]");
  if (!store) return;

  const input = store.querySelector("[data-vb-filter-two-input]");
  const count = store.querySelector("[data-vb-filter-two-count]");
  const clearButton = store.querySelector("[data-vb-filter-two-clear]");
  const empty = store.querySelector("[data-vb-filter-two-empty]");
  const products = Array.from(store.querySelectorAll("[data-product-text]"));

  function filterProducts() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    products.forEach(function (product) {
      const keywords = product.getAttribute("data-product-text").toLowerCase();
      const title = product.querySelector("h4").textContent.toLowerCase();
      const description = product.querySelector("p").textContent.toLowerCase();
      const category = product.querySelector(".vb-filter-two-info > span").textContent.toLowerCase();

      const isMatch =
        keywords.includes(query) ||
        title.includes(query) ||
        description.includes(query) ||
        category.includes(query);

      product.classList.toggle("is-hidden", !isMatch);

      if (isMatch) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 product found" : visible + " products found";
    empty.classList.toggle("is-visible", visible === 0);
  }

  input.addEventListener("input", filterProducts);

  clearButton.addEventListener("click", function () {
    input.value = "";
    input.focus();
    filterProducts();
  });

  filterProducts();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const store = document.querySelector("[data-vb-filter-two]");
  if (!store) return;

  const input = store.querySelector("[data-vb-filter-two-input]");
  const count = store.querySelector("[data-vb-filter-two-count]");
  const clearButton = store.querySelector("[data-vb-filter-two-clear]");
  const empty = store.querySelector("[data-vb-filter-two-empty]");
  const products = Array.from(store.querySelectorAll("[data-product-text]"));

  function filterProducts() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    products.forEach(function (product) {
      const keywords = product.getAttribute("data-product-text").toLowerCase();
      const title = product.querySelector("h4").textContent.toLowerCase();
      const description = product.querySelector("p").textContent.toLowerCase();
      const category = product.querySelector(".vb-filter-two-info &gt; span").textContent.toLowerCase();

      const isMatch =
        keywords.includes(query) ||
        title.includes(query) ||
        description.includes(query) ||
        category.includes(query);

      product.classList.toggle("is-hidden", !isMatch);

      if (isMatch) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 product found" : visible + " products found";
    empty.classList.toggle("is-visible", visible === 0);
  }

  input.addEventListener("input", filterProducts);

  clearButton.addEventListener("click", function () {
    input.value = "";
    input.focus();
    filterProducts();
  });

  filterProducts();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-two-demo"&gt;
  &lt;div class="vb-filter-two-store" data-vb-filter-two&gt;
    &lt;div class="vb-filter-two-sidebar"&gt;
      &lt;span&gt;Example 02&lt;/span&gt;
      &lt;h3&gt;Product Grid Search Filter&lt;/h3&gt;
      &lt;p&gt;Search the product catalog and show only matching ecommerce cards.&lt;/p&gt;

      &lt;div class="vb-filter-two-search"&gt;
        &lt;label for="vb-filter-two-input"&gt;Search products&lt;/label&gt;
        &lt;input id="vb-filter-two-input" type="search" placeholder="Search lamp, chair, desk, storage..." data-vb-filter-two-input&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-two-summary"&gt;
        &lt;strong data-vb-filter-two-count&gt;8 products found&lt;/strong&gt;
        &lt;button type="button" data-vb-filter-two-clear&gt;Reset&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-two-content"&gt;
      &lt;div class="vb-filter-two-grid"&gt;
        &lt;article data-product-text="modern desk lamp lighting office black adjustable"&gt;
          &lt;div class="vb-filter-two-art lamp"&gt;&lt;/div&gt;
          &lt;div class="vb-filter-two-info"&gt;
            &lt;span&gt;Lighting&lt;/span&gt;
            &lt;h4&gt;Modern Desk Lamp&lt;/h4&gt;
            &lt;p&gt;Adjustable office lamp with a compact modern base.&lt;/p&gt;
            &lt;div&gt;&lt;strong&gt;€49&lt;/strong&gt;&lt;small&gt;In stock&lt;/small&gt;&lt;/div&gt;
          &lt;/div&gt;
        &lt;/article&gt;

        &lt;article data-product-text="ergonomic chair office furniture mesh black comfort"&gt;
          &lt;div class="vb-filter-two-art chair"&gt;&lt;/div&gt;
          &lt;div class="vb-filter-two-info"&gt;
            &lt;span&gt;Furniture&lt;/span&gt;
            &lt;h4&gt;Ergonomic Chair&lt;/h4&gt;
            &lt;p&gt;Comfort-focused office chair with breathable mesh.&lt;/p&gt;
            &lt;div&gt;&lt;strong&gt;€189&lt;/strong&gt;&lt;small&gt;In stock&lt;/small&gt;&lt;/div&gt;
          &lt;/div&gt;
        &lt;/article&gt;

        &lt;article data-product-text="wooden desk table workspace oak minimal office"&gt;
          &lt;div class="vb-filter-two-art desk"&gt;&lt;/div&gt;
          &lt;div class="vb-filter-two-info"&gt;
            &lt;span&gt;Workspace&lt;/span&gt;
            &lt;h4&gt;Oak Work Desk&lt;/h4&gt;
            &lt;p&gt;Minimal wooden desk for clean home office setups.&lt;/p&gt;
            &lt;div&gt;&lt;strong&gt;€299&lt;/strong&gt;&lt;small&gt;Low stock&lt;/small&gt;&lt;/div&gt;
          &lt;/div&gt;
        &lt;/article&gt;

        &lt;article data-product-text="storage cabinet organizer shelves home office white"&gt;
          &lt;div class="vb-filter-two-art storage"&gt;&lt;/div&gt;
          &lt;div class="vb-filter-two-info"&gt;
            &lt;span&gt;Storage&lt;/span&gt;
            &lt;h4&gt;Storage Cabinet&lt;/h4&gt;
            &lt;p&gt;Compact cabinet for files, supplies, and accessories.&lt;/p&gt;
            &lt;div&gt;&lt;strong&gt;€129&lt;/strong&gt;&lt;small&gt;In stock&lt;/small&gt;&lt;/div&gt;
          &lt;/div&gt;
        &lt;/article&gt;

        &lt;article data-product-text="monitor stand laptop riser aluminum desk accessory"&gt;
          &lt;div class="vb-filter-two-art stand"&gt;&lt;/div&gt;
          &lt;div class="vb-filter-two-info"&gt;
            &lt;span&gt;Accessory&lt;/span&gt;
            &lt;h4&gt;Monitor Stand&lt;/h4&gt;
            &lt;p&gt;Aluminum riser for screens, laptops, and desk space.&lt;/p&gt;
            &lt;div&gt;&lt;strong&gt;€59&lt;/strong&gt;&lt;small&gt;In stock&lt;/small&gt;&lt;/div&gt;
          &lt;/div&gt;
        &lt;/article&gt;

        &lt;article data-product-text="desk mat leather large workspace black accessory"&gt;
          &lt;div class="vb-filter-two-art mat"&gt;&lt;/div&gt;
          &lt;div class="vb-filter-two-info"&gt;
            &lt;span&gt;Accessory&lt;/span&gt;
            &lt;h4&gt;Large Desk Mat&lt;/h4&gt;
            &lt;p&gt;Smooth desk mat for keyboards, mice, and writing.&lt;/p&gt;
            &lt;div&gt;&lt;strong&gt;€39&lt;/strong&gt;&lt;small&gt;In stock&lt;/small&gt;&lt;/div&gt;
          &lt;/div&gt;
        &lt;/article&gt;

        &lt;article data-product-text="bookshelf storage furniture wood shelves living office"&gt;
          &lt;div class="vb-filter-two-art shelf"&gt;&lt;/div&gt;
          &lt;div class="vb-filter-two-info"&gt;
            &lt;span&gt;Furniture&lt;/span&gt;
            &lt;h4&gt;Wood Bookshelf&lt;/h4&gt;
            &lt;p&gt;Open shelving unit for books, decor, and office items.&lt;/p&gt;
            &lt;div&gt;&lt;strong&gt;€159&lt;/strong&gt;&lt;small&gt;In stock&lt;/small&gt;&lt;/div&gt;
          &lt;/div&gt;
        &lt;/article&gt;

        &lt;article data-product-text="wireless charger desk accessory phone charging pad"&gt;
          &lt;div class="vb-filter-two-art charger"&gt;&lt;/div&gt;
          &lt;div class="vb-filter-two-info"&gt;
            &lt;span&gt;Tech&lt;/span&gt;
            &lt;h4&gt;Wireless Charger&lt;/h4&gt;
            &lt;p&gt;Minimal charging pad for phones and desk setups.&lt;/p&gt;
            &lt;div&gt;&lt;strong&gt;€34&lt;/strong&gt;&lt;small&gt;In stock&lt;/small&gt;&lt;/div&gt;
          &lt;/div&gt;
        &lt;/article&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-two-empty" data-vb-filter-two-empty&gt;
        &lt;strong&gt;No products matched your search.&lt;/strong&gt;
        &lt;p&gt;Try searching for chair, desk, lamp, storage, accessory, or tech.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-two-demo,
.vb-filter-two-demo * {
  box-sizing: border-box;
}

.vb-filter-two-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 18%, rgba(251, 146, 60, 0.22), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(236, 72, 153, 0.18), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #fdf2f8 52%, #ffffff 100%) !important;
  border: 1px solid rgba(253, 186, 116, 0.46);
  box-shadow: 0 24px 70px rgba(124, 45, 18, 0.12);
}

.vb-filter-two-store {
  display: grid;
  grid-template-columns: 320px minmax(0, 1fr);
  gap: 22px;
  max-width: 1120px;
  margin: 0 auto;
  padding: 18px;
  border-radius: 30px;
  background: #111827;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.24);
}

.vb-filter-two-sidebar {
  padding: 26px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 20% 14%, rgba(251, 146, 60, 0.20), transparent 32%),
    linear-gradient(135deg, #7c2d12, #be123c) !important;
  min-height: 640px;
}

.vb-filter-two-sidebar &gt; span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-two-sidebar h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 4vw, 56px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-two-sidebar p {
  margin: 0 0 28px !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-two-search {
  margin-bottom: 18px;
}

.vb-filter-two-search label {
  display: block;
  margin-bottom: 9px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-two-search input {
  width: 100%;
  min-height: 58px;
  padding: 0 16px;
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: 18px;
  outline: 0;
  background: rgba(255,255,255,0.13);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 800;
}

.vb-filter-two-search input::placeholder {
  color: rgba(255,255,255,0.62);
  -webkit-text-fill-color: rgba(255,255,255,0.62);
}

.vb-filter-two-summary {
  padding: 16px;
  border-radius: 20px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-filter-two-summary strong {
  display: block;
  margin-bottom: 12px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 19px;
  font-weight: 950;
}

.vb-filter-two-summary button {
  width: 100%;
  min-height: 44px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-two-content {
  padding: 10px;
}

.vb-filter-two-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-filter-two-grid article {
  overflow: hidden;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 18px 50px rgba(2, 6, 23, 0.18);
}

.vb-filter-two-grid article.is-hidden {
  display: none;
}

.vb-filter-two-art {
  min-height: 150px;
  background:
    radial-gradient(circle at 30% 24%, rgba(255,255,255,0.40), transparent 32%),
    linear-gradient(135deg, #fb923c, #ec4899) !important;
}

.vb-filter-two-art.chair {
  background:
    radial-gradient(circle at 30% 24%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #6366f1, #06b6d4) !important;
}

.vb-filter-two-art.desk {
  background:
    radial-gradient(circle at 30% 24%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #92400e, #f59e0b) !important;
}

.vb-filter-two-art.storage {
  background:
    radial-gradient(circle at 30% 24%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #0f766e, #22c55e) !important;
}

.vb-filter-two-art.stand {
  background:
    radial-gradient(circle at 30% 24%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #475569, #94a3b8) !important;
}

.vb-filter-two-art.mat {
  background:
    radial-gradient(circle at 30% 24%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #111827, #4b5563) !important;
}

.vb-filter-two-art.shelf {
  background:
    radial-gradient(circle at 30% 24%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #78350f, #d97706) !important;
}

.vb-filter-two-art.charger {
  background:
    radial-gradient(circle at 30% 24%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #2563eb, #7c3aed) !important;
}

.vb-filter-two-info {
  padding: 18px;
}

.vb-filter-two-info &gt; span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #fff7ed;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-two-info h4 {
  margin: 0 0 8px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-two-info p {
  margin: 0 0 15px !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-filter-two-info div {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.vb-filter-two-info strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 25px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-filter-two-info small {
  padding: 7px 9px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-filter-two-empty {
  display: none;
  margin-top: 16px;
  padding: 22px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(251, 146, 60, 0.32);
}

.vb-filter-two-empty.is-visible {
  display: block;
}

.vb-filter-two-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-two-empty p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 960px) {
  .vb-filter-two-store {
    grid-template-columns: 1fr;
  }

  .vb-filter-two-sidebar {
    min-height: auto;
  }
}

@media (max-width: 640px) {
  .vb-filter-two-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-two-store {
    padding: 12px;
    border-radius: 24px;
  }

  .vb-filter-two-sidebar {
    padding: 22px;
    border-radius: 20px;
  }

  .vb-filter-two-sidebar h3 {
    font-size: 38px !important;
  }

  .vb-filter-two-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This product grid search filter is useful for ecommerce pages, small catalogs, product landing pages, digital product sections, and WooCommerce-style layouts where visitors need to find matching products quickly.</p>



<h2 class="wp-block-heading">3. Category Button Filter</h2>



<p class="wp-block-paragraph"><strong>A category button filter</strong> lets users narrow visible items by clicking predefined category buttons. This is useful for portfolios, blog grids, product sections, service lists, resource libraries, and gallery pages where visitors may not want to type a search keyword.</p>



<p class="wp-block-paragraph">This example filters project cards by category. The active button updates visually, the visible result count changes automatically, and a clean reset option brings all cards back.</p>



<ul class="wp-block-list">
<li>Clickable category filter buttons</li>
<li>Active filter state</li>
<li>Dynamic result count</li>
<li>Responsive portfolio card layout</li>
<li>Useful for portfolios, blogs, galleries, and service sections</li>
</ul>



<div class="vb-filter-three-demo">
  <div class="vb-filter-three-board" data-vb-filter-three>
    <div class="vb-filter-three-head">
      <div>
        <span>Example 03</span>
        <h3>Category Button Filter</h3>
        <p>Click a category button to filter the project cards instantly.</p>
      </div>

      <strong data-vb-filter-three-count>9 projects shown</strong>
    </div>

    <div class="vb-filter-three-controls" data-vb-filter-three-controls>
      <button type="button" class="is-active" data-category="all">All Projects</button>
      <button type="button" data-category="website">Websites</button>
      <button type="button" data-category="ecommerce">Ecommerce</button>
      <button type="button" data-category="dashboard">Dashboards</button>
      <button type="button" data-category="branding">Branding</button>
    </div>

    <div class="vb-filter-three-grid">
      <article data-category-card="website">
        <div class="vb-filter-three-visual visual-one"></div>
        <small>Website</small>
        <h4>Agency Homepage</h4>
        <p>Modern service website layout with sections for work, trust, and conversion.</p>
      </article>

      <article data-category-card="ecommerce">
        <div class="vb-filter-three-visual visual-two"></div>
        <small>Ecommerce</small>
        <h4>Product Grid</h4>
        <p>Responsive shop grid with product cards, badges, and filter-friendly content.</p>
      </article>

      <article data-category-card="dashboard">
        <div class="vb-filter-three-visual visual-three"></div>
        <small>Dashboard</small>
        <h4>Analytics Panel</h4>
        <p>Admin-style metrics interface for reports, charts, and activity widgets.</p>
      </article>

      <article data-category-card="branding">
        <div class="vb-filter-three-visual visual-four"></div>
        <small>Branding</small>
        <h4>Brand System</h4>
        <p>Visual identity cards for colors, typography, logo usage, and UI tone.</p>
      </article>

      <article data-category-card="website">
        <div class="vb-filter-three-visual visual-five"></div>
        <small>Website</small>
        <h4>Startup Landing</h4>
        <p>Landing page structure with hero content, benefits, pricing, and CTA blocks.</p>
      </article>

      <article data-category-card="ecommerce">
        <div class="vb-filter-three-visual visual-six"></div>
        <small>Ecommerce</small>
        <h4>Checkout UI</h4>
        <p>Clean checkout section with order summary, form controls, and payment areas.</p>
      </article>

      <article data-category-card="dashboard">
        <div class="vb-filter-three-visual visual-seven"></div>
        <small>Dashboard</small>
        <h4>Task Manager</h4>
        <p>Project board interface with task cards, status chips, and team activity.</p>
      </article>

      <article data-category-card="branding">
        <div class="vb-filter-three-visual visual-eight"></div>
        <small>Branding</small>
        <h4>Social Kit</h4>
        <p>Reusable social graphics, content blocks, and visual campaign assets.</p>
      </article>

      <article data-category-card="website">
        <div class="vb-filter-three-visual visual-nine"></div>
        <small>Website</small>
        <h4>Portfolio Page</h4>
        <p>Case study layout for showing creative work, client results, and services.</p>
      </article>
    </div>
  </div>
</div>

<style>
.vb-filter-three-demo,
.vb-filter-three-demo * {
  box-sizing: border-box;
}

.vb-filter-three-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 16% 18%, rgba(129, 140, 248, 0.22), transparent 34%),
    radial-gradient(circle at 84% 14%, rgba(45, 212, 191, 0.18), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #f0fdfa 52%, #ffffff 100%) !important;
  border: 1px solid rgba(199, 210, 254, 0.50);
  box-shadow: 0 24px 70px rgba(67, 56, 202, 0.12);
}

.vb-filter-three-board {
  max-width: 1120px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-three-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 22px;
  align-items: end;
  margin-bottom: 24px;
}

.vb-filter-three-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #e0e7ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-three-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-three-head p {
  max-width: 620px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-three-head > strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 12px 16px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-filter-three-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 24px;
  padding: 10px;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-filter-three-controls button {
  min-height: 44px;
  padding: 10px 15px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  font-weight: 850;
  cursor: pointer;
  box-shadow: 0 8px 20px rgba(15, 23, 42, 0.06);
  transition: transform 0.18s ease, background 0.18s ease, color 0.18s ease;
}

.vb-filter-three-controls button:hover,
.vb-filter-three-controls button.is-active {
  transform: translateY(-1px);
  background: linear-gradient(135deg, #4f46e5, #14b8a6);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-three-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.vb-filter-three-grid article {
  overflow: hidden;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.08);
}

.vb-filter-three-grid article.is-hidden {
  display: none;
}

.vb-filter-three-visual {
  min-height: 130px;
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #4f46e5, #14b8a6) !important;
}

.vb-filter-three-visual.visual-two {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #f97316, #ec4899) !important;
}

.vb-filter-three-visual.visual-three {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #0f172a, #2563eb) !important;
}

.vb-filter-three-visual.visual-four {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #7c3aed, #db2777) !important;
}

.vb-filter-three-visual.visual-five {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #06b6d4, #2563eb) !important;
}

.vb-filter-three-visual.visual-six {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #16a34a, #f59e0b) !important;
}

.vb-filter-three-visual.visual-seven {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #1e293b, #64748b) !important;
}

.vb-filter-three-visual.visual-eight {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #be123c, #fb7185) !important;
}

.vb-filter-three-visual.visual-nine {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #0f766e, #84cc16) !important;
}

.vb-filter-three-grid small {
  display: inline-flex;
  margin: 18px 18px 10px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #eef2ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-three-grid h4 {
  margin: 0 18px 9px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-three-grid p {
  margin: 0 18px 20px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-filter-three-head {
    grid-template-columns: 1fr;
  }

  .vb-filter-three-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-filter-three-head > strong {
    width: fit-content;
  }
}

@media (max-width: 640px) {
  .vb-filter-three-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-three-board {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-three-head h3 {
    font-size: 38px !important;
  }

  .vb-filter-three-controls {
    display: grid;
    grid-template-columns: 1fr;
  }

  .vb-filter-three-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const board = document.querySelector("[data-vb-filter-three]");
  if (!board) return;

  const buttons = board.querySelectorAll("[data-category]");
  const cards = board.querySelectorAll("[data-category-card]");
  const count = board.querySelector("[data-vb-filter-three-count]");

  function updateCategory(category) {
    let visible = 0;

    cards.forEach(function (card) {
      const cardCategory = card.getAttribute("data-category-card");
      const shouldShow = category === "all" || cardCategory === category;

      card.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 project shown" : visible + " projects shown";
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      const category = button.getAttribute("data-category");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateCategory(category);
    });
  });

  updateCategory("all");
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const board = document.querySelector("[data-vb-filter-three]");
  if (!board) return;

  const buttons = board.querySelectorAll("[data-category]");
  const cards = board.querySelectorAll("[data-category-card]");
  const count = board.querySelector("[data-vb-filter-three-count]");

  function updateCategory(category) {
    let visible = 0;

    cards.forEach(function (card) {
      const cardCategory = card.getAttribute("data-category-card");
      const shouldShow = category === "all" || cardCategory === category;

      card.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 project shown" : visible + " projects shown";
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      const category = button.getAttribute("data-category");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateCategory(category);
    });
  });

  updateCategory("all");
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-three-demo"&gt;
  &lt;div class="vb-filter-three-board" data-vb-filter-three&gt;
    &lt;div class="vb-filter-three-head"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 03&lt;/span&gt;
        &lt;h3&gt;Category Button Filter&lt;/h3&gt;
        &lt;p&gt;Click a category button to filter the project cards instantly.&lt;/p&gt;
      &lt;/div&gt;

      &lt;strong data-vb-filter-three-count&gt;9 projects shown&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-three-controls" data-vb-filter-three-controls&gt;
      &lt;button type="button" class="is-active" data-category="all"&gt;All Projects&lt;/button&gt;
      &lt;button type="button" data-category="website"&gt;Websites&lt;/button&gt;
      &lt;button type="button" data-category="ecommerce"&gt;Ecommerce&lt;/button&gt;
      &lt;button type="button" data-category="dashboard"&gt;Dashboards&lt;/button&gt;
      &lt;button type="button" data-category="branding"&gt;Branding&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-three-grid"&gt;
      &lt;article data-category-card="website"&gt;
        &lt;div class="vb-filter-three-visual visual-one"&gt;&lt;/div&gt;
        &lt;small&gt;Website&lt;/small&gt;
        &lt;h4&gt;Agency Homepage&lt;/h4&gt;
        &lt;p&gt;Modern service website layout with sections for work, trust, and conversion.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-category-card="ecommerce"&gt;
        &lt;div class="vb-filter-three-visual visual-two"&gt;&lt;/div&gt;
        &lt;small&gt;Ecommerce&lt;/small&gt;
        &lt;h4&gt;Product Grid&lt;/h4&gt;
        &lt;p&gt;Responsive shop grid with product cards, badges, and filter-friendly content.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-category-card="dashboard"&gt;
        &lt;div class="vb-filter-three-visual visual-three"&gt;&lt;/div&gt;
        &lt;small&gt;Dashboard&lt;/small&gt;
        &lt;h4&gt;Analytics Panel&lt;/h4&gt;
        &lt;p&gt;Admin-style metrics interface for reports, charts, and activity widgets.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-category-card="branding"&gt;
        &lt;div class="vb-filter-three-visual visual-four"&gt;&lt;/div&gt;
        &lt;small&gt;Branding&lt;/small&gt;
        &lt;h4&gt;Brand System&lt;/h4&gt;
        &lt;p&gt;Visual identity cards for colors, typography, logo usage, and UI tone.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-category-card="website"&gt;
        &lt;div class="vb-filter-three-visual visual-five"&gt;&lt;/div&gt;
        &lt;small&gt;Website&lt;/small&gt;
        &lt;h4&gt;Startup Landing&lt;/h4&gt;
        &lt;p&gt;Landing page structure with hero content, benefits, pricing, and CTA blocks.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-category-card="ecommerce"&gt;
        &lt;div class="vb-filter-three-visual visual-six"&gt;&lt;/div&gt;
        &lt;small&gt;Ecommerce&lt;/small&gt;
        &lt;h4&gt;Checkout UI&lt;/h4&gt;
        &lt;p&gt;Clean checkout section with order summary, form controls, and payment areas.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-category-card="dashboard"&gt;
        &lt;div class="vb-filter-three-visual visual-seven"&gt;&lt;/div&gt;
        &lt;small&gt;Dashboard&lt;/small&gt;
        &lt;h4&gt;Task Manager&lt;/h4&gt;
        &lt;p&gt;Project board interface with task cards, status chips, and team activity.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-category-card="branding"&gt;
        &lt;div class="vb-filter-three-visual visual-eight"&gt;&lt;/div&gt;
        &lt;small&gt;Branding&lt;/small&gt;
        &lt;h4&gt;Social Kit&lt;/h4&gt;
        &lt;p&gt;Reusable social graphics, content blocks, and visual campaign assets.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-category-card="website"&gt;
        &lt;div class="vb-filter-three-visual visual-nine"&gt;&lt;/div&gt;
        &lt;small&gt;Website&lt;/small&gt;
        &lt;h4&gt;Portfolio Page&lt;/h4&gt;
        &lt;p&gt;Case study layout for showing creative work, client results, and services.&lt;/p&gt;
      &lt;/article&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-three-demo,
.vb-filter-three-demo * {
  box-sizing: border-box;
}

.vb-filter-three-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 16% 18%, rgba(129, 140, 248, 0.22), transparent 34%),
    radial-gradient(circle at 84% 14%, rgba(45, 212, 191, 0.18), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #f0fdfa 52%, #ffffff 100%) !important;
  border: 1px solid rgba(199, 210, 254, 0.50);
  box-shadow: 0 24px 70px rgba(67, 56, 202, 0.12);
}

.vb-filter-three-board {
  max-width: 1120px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-three-head {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 22px;
  align-items: end;
  margin-bottom: 24px;
}

.vb-filter-three-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #e0e7ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-three-head h3 {
  margin: 0 0 12px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-three-head p {
  max-width: 620px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-three-head &gt; strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  padding: 12px 16px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-filter-three-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 24px;
  padding: 10px;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-filter-three-controls button {
  min-height: 44px;
  padding: 10px 15px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  font-weight: 850;
  cursor: pointer;
  box-shadow: 0 8px 20px rgba(15, 23, 42, 0.06);
  transition: transform 0.18s ease, background 0.18s ease, color 0.18s ease;
}

.vb-filter-three-controls button:hover,
.vb-filter-three-controls button.is-active {
  transform: translateY(-1px);
  background: linear-gradient(135deg, #4f46e5, #14b8a6);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-three-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.vb-filter-three-grid article {
  overflow: hidden;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.08);
}

.vb-filter-three-grid article.is-hidden {
  display: none;
}

.vb-filter-three-visual {
  min-height: 130px;
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #4f46e5, #14b8a6) !important;
}

.vb-filter-three-visual.visual-two {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #f97316, #ec4899) !important;
}

.vb-filter-three-visual.visual-three {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #0f172a, #2563eb) !important;
}

.vb-filter-three-visual.visual-four {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #7c3aed, #db2777) !important;
}

.vb-filter-three-visual.visual-five {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #06b6d4, #2563eb) !important;
}

.vb-filter-three-visual.visual-six {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #16a34a, #f59e0b) !important;
}

.vb-filter-three-visual.visual-seven {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #1e293b, #64748b) !important;
}

.vb-filter-three-visual.visual-eight {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #be123c, #fb7185) !important;
}

.vb-filter-three-visual.visual-nine {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #0f766e, #84cc16) !important;
}

.vb-filter-three-grid small {
  display: inline-flex;
  margin: 18px 18px 10px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #eef2ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-three-grid h4 {
  margin: 0 18px 9px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-three-grid p {
  margin: 0 18px 20px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-filter-three-head {
    grid-template-columns: 1fr;
  }

  .vb-filter-three-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-filter-three-head &gt; strong {
    width: fit-content;
  }
}

@media (max-width: 640px) {
  .vb-filter-three-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-three-board {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-three-head h3 {
    font-size: 38px !important;
  }

  .vb-filter-three-controls {
    display: grid;
    grid-template-columns: 1fr;
  }

  .vb-filter-three-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This category button filter is useful when users need quick visual filtering without typing. You can adapt it for portfolio grids, blog category sections, product collections, service pages, gallery layouts, and resource hubs.</p>



<h2 class="wp-block-heading">4. Searchable FAQ Filter</h2>



<p class="wp-block-paragraph"><strong>A searchable FAQ filter</strong> helps users find answers faster on support pages, documentation sections, product help centers, and service websites. Instead of scrolling through every question, users can type a keyword and only matching FAQ items remain visible.</p>



<p class="wp-block-paragraph">This example combines a live search input with expandable FAQ items. The JavaScript filters questions and answers, updates the count, and displays a friendly no-results message when no FAQ item matches the query.</p>



<ul class="wp-block-list">
<li>Live FAQ search</li>
<li>Expandable details elements</li>
<li>Filters questions and answers</li>
<li>Dynamic answer count</li>
<li>Useful for support pages, documentation, product help, and service websites</li>
</ul>



<div class="vb-filter-four-demo">
  <div class="vb-filter-four-help" data-vb-filter-four>
    <div class="vb-filter-four-hero">
      <span>Example 04</span>
      <h3>Searchable FAQ Filter</h3>
      <p>Search common questions and instantly show only matching FAQ answers.</p>

      <div class="vb-filter-four-search">
        <input type="search" placeholder="Search setup, pricing, support, license..." data-vb-filter-four-input>
        <button type="button" data-vb-filter-four-clear>Clear</button>
      </div>

      <strong data-vb-filter-four-count>7 answers found</strong>
    </div>

    <div class="vb-filter-four-list">
      <details data-faq-text="setup install installation plugin wordpress start">
        <summary>How do I install the plugin?</summary>
        <div>
          <p>Upload the plugin ZIP file inside WordPress, activate it, and open the plugin settings page to complete the setup.</p>
        </div>
      </details>

      <details data-faq-text="pricing price cost license payment sale">
        <summary>How does pricing work?</summary>
        <div>
          <p>The plugin can use a one-time license, yearly license, or sale price depending on the product setup.</p>
        </div>
      </details>

      <details data-faq-text="support help contact ticket email response">
        <summary>Do you offer support?</summary>
        <div>
          <p>Support can be provided through email, contact forms, documentation, or a support ticket system.</p>
        </div>
      </details>

      <details data-faq-text="updates update version compatibility wordpress">
        <summary>Will I receive updates?</summary>
        <div>
          <p>Yes, licensed users can receive updates when new improvements, compatibility fixes, or features are released.</p>
        </div>
      </details>

      <details data-faq-text="license activation domain website sites">
        <summary>Can I use one license on multiple websites?</summary>
        <div>
          <p>That depends on the license plan. Some plans are for one domain, while agency plans may support multiple websites.</p>
        </div>
      </details>

      <details data-faq-text="customize settings design colors layout">
        <summary>Can I customize the design?</summary>
        <div>
          <p>Most modern plugins and UI components include settings for colors, layout, labels, spacing, and display options.</p>
        </div>
      </details>

      <details data-faq-text="refund money back cancel purchase">
        <summary>Is there a refund policy?</summary>
        <div>
          <p>A refund policy should explain eligibility, time limits, support requirements, and how users can request a refund.</p>
        </div>
      </details>

      <div class="vb-filter-four-empty" data-vb-filter-four-empty>
        <strong>No FAQ answers found.</strong>
        <p>Try searching for setup, pricing, license, support, updates, or design.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-filter-four-demo,
.vb-filter-four-demo * {
  box-sizing: border-box;
}

.vb-filter-four-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 16%, rgba(245, 158, 11, 0.22), transparent 34%),
    radial-gradient(circle at 86% 20%, rgba(239, 68, 68, 0.16), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fff1f2 52%, #ffffff 100%) !important;
  border: 1px solid rgba(253, 230, 138, 0.54);
  box-shadow: 0 24px 70px rgba(120, 53, 15, 0.12);
}

.vb-filter-four-help {
  display: grid;
  grid-template-columns: minmax(300px, 0.85fr) minmax(0, 1.15fr);
  gap: 22px;
  max-width: 1100px;
  margin: 0 auto;
  padding: 18px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-four-hero {
  position: sticky;
  top: 20px;
  align-self: start;
  padding: 28px;
  border-radius: 26px;
  background:
    radial-gradient(circle at 20% 14%, rgba(255,255,255,0.24), transparent 34%),
    linear-gradient(135deg, #92400e, #dc2626) !important;
  box-shadow: 0 28px 70px rgba(185, 28, 28, 0.20);
}

.vb-filter-four-hero > span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-four-hero h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 4vw, 56px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-four-hero p {
  margin: 0 0 24px !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-four-search {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 8px;
  margin-bottom: 18px;
}

.vb-filter-four-search input {
  min-height: 54px;
  width: 100%;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: 17px;
  outline: 0;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-four-search input::placeholder {
  color: rgba(255,255,255,0.66);
  -webkit-text-fill-color: rgba(255,255,255,0.66);
}

.vb-filter-four-search button {
  min-height: 54px;
  padding: 0 14px;
  border: 0;
  border-radius: 17px;
  background: #ffffff;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-four-hero > strong {
  display: inline-flex;
  min-height: 42px;
  align-items: center;
  padding: 10px 13px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-filter-four-list {
  display: grid;
  gap: 12px;
  align-self: start;
}

.vb-filter-four-list details {
  overflow: hidden;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 36px rgba(15, 23, 42, 0.07);
}

.vb-filter-four-list details.is-hidden {
  display: none;
}

.vb-filter-four-list summary {
  position: relative;
  display: block;
  padding: 19px 58px 19px 20px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 17px;
  line-height: 1.35;
  font-weight: 950;
  cursor: pointer;
  list-style: none;
}

.vb-filter-four-list summary::-webkit-details-marker {
  display: none;
}

.vb-filter-four-list summary::after {
  content: "+";
  position: absolute;
  top: 50%;
  right: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  line-height: 1;
  font-weight: 950;
  transform: translateY(-50%);
}

.vb-filter-four-list details[open] summary::after {
  content: "−";
}

.vb-filter-four-list details > div {
  padding: 0 20px 20px;
}

.vb-filter-four-list p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-four-empty {
  display: none;
  padding: 22px;
  border-radius: 20px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.34);
}

.vb-filter-four-empty.is-visible {
  display: block;
}

.vb-filter-four-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-four-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.6;
}

@media (max-width: 900px) {
  .vb-filter-four-help {
    grid-template-columns: 1fr;
  }

  .vb-filter-four-hero {
    position: static;
  }
}

@media (max-width: 640px) {
  .vb-filter-four-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-four-help {
    padding: 12px;
    border-radius: 24px;
  }

  .vb-filter-four-hero {
    padding: 22px;
    border-radius: 20px;
  }

  .vb-filter-four-hero h3 {
    font-size: 38px !important;
  }

  .vb-filter-four-search {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const faq = document.querySelector("[data-vb-filter-four]");
  if (!faq) return;

  const input = faq.querySelector("[data-vb-filter-four-input]");
  const clearButton = faq.querySelector("[data-vb-filter-four-clear]");
  const count = faq.querySelector("[data-vb-filter-four-count]");
  const empty = faq.querySelector("[data-vb-filter-four-empty]");
  const items = Array.from(faq.querySelectorAll("[data-faq-text]"));

  function updateFaqFilter() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    items.forEach(function (item) {
      const keywords = item.getAttribute("data-faq-text").toLowerCase();
      const question = item.querySelector("summary").textContent.toLowerCase();
      const answer = item.querySelector("p").textContent.toLowerCase();
      const match = keywords.includes(query) || question.includes(query) || answer.includes(query);

      item.classList.toggle("is-hidden", !match);

      if (match) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 answer found" : visible + " answers found";
    empty.classList.toggle("is-visible", visible === 0);
  }

  input.addEventListener("input", updateFaqFilter);

  clearButton.addEventListener("click", function () {
    input.value = "";
    input.focus();
    updateFaqFilter();
  });

  updateFaqFilter();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const faq = document.querySelector("[data-vb-filter-four]");
  if (!faq) return;

  const input = faq.querySelector("[data-vb-filter-four-input]");
  const clearButton = faq.querySelector("[data-vb-filter-four-clear]");
  const count = faq.querySelector("[data-vb-filter-four-count]");
  const empty = faq.querySelector("[data-vb-filter-four-empty]");
  const items = Array.from(faq.querySelectorAll("[data-faq-text]"));

  function updateFaqFilter() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    items.forEach(function (item) {
      const keywords = item.getAttribute("data-faq-text").toLowerCase();
      const question = item.querySelector("summary").textContent.toLowerCase();
      const answer = item.querySelector("p").textContent.toLowerCase();
      const match = keywords.includes(query) || question.includes(query) || answer.includes(query);

      item.classList.toggle("is-hidden", !match);

      if (match) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 answer found" : visible + " answers found";
    empty.classList.toggle("is-visible", visible === 0);
  }

  input.addEventListener("input", updateFaqFilter);

  clearButton.addEventListener("click", function () {
    input.value = "";
    input.focus();
    updateFaqFilter();
  });

  updateFaqFilter();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-four-demo"&gt;
  &lt;div class="vb-filter-four-help" data-vb-filter-four&gt;
    &lt;div class="vb-filter-four-hero"&gt;
      &lt;span&gt;Example 04&lt;/span&gt;
      &lt;h3&gt;Searchable FAQ Filter&lt;/h3&gt;
      &lt;p&gt;Search common questions and instantly show only matching FAQ answers.&lt;/p&gt;

      &lt;div class="vb-filter-four-search"&gt;
        &lt;input type="search" placeholder="Search setup, pricing, support, license..." data-vb-filter-four-input&gt;
        &lt;button type="button" data-vb-filter-four-clear&gt;Clear&lt;/button&gt;
      &lt;/div&gt;

      &lt;strong data-vb-filter-four-count&gt;7 answers found&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-four-list"&gt;
      &lt;details data-faq-text="setup install installation plugin wordpress start"&gt;
        &lt;summary&gt;How do I install the plugin?&lt;/summary&gt;
        &lt;div&gt;
          &lt;p&gt;Upload the plugin ZIP file inside WordPress, activate it, and open the plugin settings page to complete the setup.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/details&gt;

      &lt;details data-faq-text="pricing price cost license payment sale"&gt;
        &lt;summary&gt;How does pricing work?&lt;/summary&gt;
        &lt;div&gt;
          &lt;p&gt;The plugin can use a one-time license, yearly license, or sale price depending on the product setup.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/details&gt;

      &lt;details data-faq-text="support help contact ticket email response"&gt;
        &lt;summary&gt;Do you offer support?&lt;/summary&gt;
        &lt;div&gt;
          &lt;p&gt;Support can be provided through email, contact forms, documentation, or a support ticket system.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/details&gt;

      &lt;details data-faq-text="updates update version compatibility wordpress"&gt;
        &lt;summary&gt;Will I receive updates?&lt;/summary&gt;
        &lt;div&gt;
          &lt;p&gt;Yes, licensed users can receive updates when new improvements, compatibility fixes, or features are released.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/details&gt;

      &lt;details data-faq-text="license activation domain website sites"&gt;
        &lt;summary&gt;Can I use one license on multiple websites?&lt;/summary&gt;
        &lt;div&gt;
          &lt;p&gt;That depends on the license plan. Some plans are for one domain, while agency plans may support multiple websites.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/details&gt;

      &lt;details data-faq-text="customize settings design colors layout"&gt;
        &lt;summary&gt;Can I customize the design?&lt;/summary&gt;
        &lt;div&gt;
          &lt;p&gt;Most modern plugins and UI components include settings for colors, layout, labels, spacing, and display options.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/details&gt;

      &lt;details data-faq-text="refund money back cancel purchase"&gt;
        &lt;summary&gt;Is there a refund policy?&lt;/summary&gt;
        &lt;div&gt;
          &lt;p&gt;A refund policy should explain eligibility, time limits, support requirements, and how users can request a refund.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/details&gt;

      &lt;div class="vb-filter-four-empty" data-vb-filter-four-empty&gt;
        &lt;strong&gt;No FAQ answers found.&lt;/strong&gt;
        &lt;p&gt;Try searching for setup, pricing, license, support, updates, or design.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-four-demo,
.vb-filter-four-demo * {
  box-sizing: border-box;
}

.vb-filter-four-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 16%, rgba(245, 158, 11, 0.22), transparent 34%),
    radial-gradient(circle at 86% 20%, rgba(239, 68, 68, 0.16), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fff1f2 52%, #ffffff 100%) !important;
  border: 1px solid rgba(253, 230, 138, 0.54);
  box-shadow: 0 24px 70px rgba(120, 53, 15, 0.12);
}

.vb-filter-four-help {
  display: grid;
  grid-template-columns: minmax(300px, 0.85fr) minmax(0, 1.15fr);
  gap: 22px;
  max-width: 1100px;
  margin: 0 auto;
  padding: 18px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-four-hero {
  position: sticky;
  top: 20px;
  align-self: start;
  padding: 28px;
  border-radius: 26px;
  background:
    radial-gradient(circle at 20% 14%, rgba(255,255,255,0.24), transparent 34%),
    linear-gradient(135deg, #92400e, #dc2626) !important;
  box-shadow: 0 28px 70px rgba(185, 28, 28, 0.20);
}

.vb-filter-four-hero &gt; span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-four-hero h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 4vw, 56px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-four-hero p {
  margin: 0 0 24px !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-four-search {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 8px;
  margin-bottom: 18px;
}

.vb-filter-four-search input {
  min-height: 54px;
  width: 100%;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: 17px;
  outline: 0;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-four-search input::placeholder {
  color: rgba(255,255,255,0.66);
  -webkit-text-fill-color: rgba(255,255,255,0.66);
}

.vb-filter-four-search button {
  min-height: 54px;
  padding: 0 14px;
  border: 0;
  border-radius: 17px;
  background: #ffffff;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-four-hero &gt; strong {
  display: inline-flex;
  min-height: 42px;
  align-items: center;
  padding: 10px 13px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-filter-four-list {
  display: grid;
  gap: 12px;
  align-self: start;
}

.vb-filter-four-list details {
  overflow: hidden;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 36px rgba(15, 23, 42, 0.07);
}

.vb-filter-four-list details.is-hidden {
  display: none;
}

.vb-filter-four-list summary {
  position: relative;
  display: block;
  padding: 19px 58px 19px 20px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 17px;
  line-height: 1.35;
  font-weight: 950;
  cursor: pointer;
  list-style: none;
}

.vb-filter-four-list summary::-webkit-details-marker {
  display: none;
}

.vb-filter-four-list summary::after {
  content: "+";
  position: absolute;
  top: 50%;
  right: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  line-height: 1;
  font-weight: 950;
  transform: translateY(-50%);
}

.vb-filter-four-list details[open] summary::after {
  content: "−";
}

.vb-filter-four-list details &gt; div {
  padding: 0 20px 20px;
}

.vb-filter-four-list p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-four-empty {
  display: none;
  padding: 22px;
  border-radius: 20px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.34);
}

.vb-filter-four-empty.is-visible {
  display: block;
}

.vb-filter-four-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-four-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.6;
}

@media (max-width: 900px) {
  .vb-filter-four-help {
    grid-template-columns: 1fr;
  }

  .vb-filter-four-hero {
    position: static;
  }
}

@media (max-width: 640px) {
  .vb-filter-four-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-four-help {
    padding: 12px;
    border-radius: 24px;
  }

  .vb-filter-four-hero {
    padding: 22px;
    border-radius: 20px;
  }

  .vb-filter-four-hero h3 {
    font-size: 38px !important;
  }

  .vb-filter-four-search {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This searchable FAQ filter is useful for support pages, help centers, product documentation, plugin pages, service websites, and long FAQ sections where users need to find specific answers quickly.</p>



<h2 class="wp-block-heading">5. Blog Post Search Filter</h2>



<p class="wp-block-paragraph"><strong>A blog post search filter</strong> helps readers quickly find matching articles inside a blog archive, resource hub, news section, tutorial library, or content-heavy website. Instead of scrolling through every post, users can type a topic and instantly filter visible article cards.</p>



<p class="wp-block-paragraph">This example uses a clean editorial layout with a large search input, blog post cards, category labels, reading time, result count, and empty state. The JavaScript filters posts by title, category, excerpt, and keywords stored in data attributes.</p>



<ul class="wp-block-list">
<li>Live blog post search</li>
<li>Filters by title, category, excerpt, and keywords</li>
<li>Editorial card layout</li>
<li>Dynamic result count</li>
<li>Useful for blog archives, tutorials, resource hubs, and content libraries</li>
</ul>



<div class="vb-filter-five-demo">
  <div class="vb-filter-five-blog" data-vb-filter-five>
    <div class="vb-filter-five-intro">
      <span>Example 05</span>
      <h3>Blog Post Search Filter</h3>
      <p>Search articles by topic, category, keyword, or description and update the visible post cards instantly.</p>
    </div>

    <div class="vb-filter-five-toolbar">
      <div class="vb-filter-five-search">
        <label for="vb-filter-five-input">Search blog posts</label>
        <input id="vb-filter-five-input" type="search" placeholder="Search JavaScript, CSS, SEO, WordPress..." data-vb-filter-five-input>
      </div>

      <div class="vb-filter-five-stats">
        <small>Visible posts</small>
        <strong data-vb-filter-five-count>8 posts</strong>
      </div>

      <button type="button" class="vb-filter-five-clear" data-vb-filter-five-clear>Reset search</button>
    </div>

    <div class="vb-filter-five-grid">
      <article data-post-text="javascript dropdown menu custom select navigation ui components">
        <span>JavaScript</span>
        <h4>JavaScript Dropdown Menu Examples</h4>
        <p>Build custom select menus, navigation dropdowns, action panels, and responsive menu components.</p>
        <small>8 min read</small>
      </article>

      <article data-post-text="javascript slider carousel image content product hero responsive">
        <span>JavaScript</span>
        <h4>JavaScript Slider Examples</h4>
        <p>Create image sliders, product carousels, hero sliders, testimonial sliders, and content sliders.</p>
        <small>11 min read</small>
      </article>

      <article data-post-text="css forms contact login checkout form ui design responsive">
        <span>CSS</span>
        <h4>Modern CSS Forms</h4>
        <p>Explore contact forms, login screens, checkout forms, newsletter forms, and responsive form layouts.</p>
        <small>12 min read</small>
      </article>

      <article data-post-text="wordpress seo structured data schema entity ai readable plugin">
        <span>SEO</span>
        <h4>Entity SEO and Structured Data</h4>
        <p>Improve WordPress SEO with structured data, entity relationships, schema markup, and AI-readable content.</p>
        <small>9 min read</small>
      </article>

      <article data-post-text="css pricing tables responsive pricing cards saas comparison">
        <span>CSS</span>
        <h4>CSS Pricing Table Examples</h4>
        <p>Design responsive pricing cards, comparison tables, SaaS pricing sections, and featured plan layouts.</p>
        <small>10 min read</small>
      </article>

      <article data-post-text="javascript modal popup dialog overlay confirmation window">
        <span>JavaScript</span>
        <h4>JavaScript Modal Examples</h4>
        <p>Build popups, dialogs, overlays, confirmations, newsletter modals, and interactive modal windows.</p>
        <small>7 min read</small>
      </article>

      <article data-post-text="css navigation menu navbar dropdown mega menu hamburger">
        <span>CSS</span>
        <h4>CSS Navigation Menu Examples</h4>
        <p>Create responsive navbars, dropdown menus, mega menus, mobile menus, and website header layouts.</p>
        <small>13 min read</small>
      </article>

      <article data-post-text="javascript form validation input signup checkout password email">
        <span>JavaScript</span>
        <h4>JavaScript Form Validation Examples</h4>
        <p>Validate signup fields, checkout inputs, passwords, email addresses, error states, and form messages.</p>
        <small>10 min read</small>
      </article>
    </div>

    <div class="vb-filter-five-empty" data-vb-filter-five-empty>
      <strong>No blog posts found.</strong>
      <p>Try searching for JavaScript, CSS, SEO, WordPress, forms, sliders, modals, or navigation.</p>
    </div>
  </div>
</div>

<style>
.vb-filter-five-demo,
.vb-filter-five-demo * {
  box-sizing: border-box;
}

.vb-filter-five-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 16% 18%, rgba(59, 130, 246, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #faf5ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(191, 219, 254, 0.50);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.10);
}

.vb-filter-five-blog {
  max-width: 1120px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-five-intro {
  max-width: 780px;
  margin-bottom: 26px;
}

.vb-filter-five-intro > span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-five-intro h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-five-intro p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-filter-five-toolbar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 150px auto;
  gap: 12px;
  align-items: end;
  margin-bottom: 22px;
  padding: 14px;
  border-radius: 24px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-filter-five-search label {
  display: block;
  margin-bottom: 8px;
  color: #1e293b !important;
  -webkit-text-fill-color: #1e293b !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-five-search input {
  width: 100%;
  min-height: 56px;
  padding: 0 16px;
  border: 1px solid rgba(148, 163, 184, 0.24);
  border-radius: 18px;
  outline: 0;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 800;
}

.vb-filter-five-stats {
  min-height: 56px;
  padding: 10px 12px;
  border-radius: 18px;
  background: #0f172a;
}

.vb-filter-five-stats small {
  display: block;
  margin-bottom: 4px;
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-five-stats strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-filter-five-clear {
  min-height: 56px;
  padding: 0 16px;
  border: 0;
  border-radius: 18px;
  background: linear-gradient(135deg, #2563eb, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-five-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-filter-five-grid article {
  min-height: 260px;
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 18% 14%, rgba(59, 130, 246, 0.10), transparent 32%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
  display: flex;
  flex-direction: column;
}

.vb-filter-five-grid article.is-hidden {
  display: none;
}

.vb-filter-five-grid article > span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 16px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #eef2ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-five-grid h4 {
  margin: 0 0 10px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-five-grid p {
  margin: 0 0 18px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-filter-five-grid small {
  margin-top: auto;
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-filter-five-empty {
  display: none;
  margin-top: 18px;
  padding: 22px;
  border-radius: 22px;
  background: #eff6ff;
  border: 1px solid rgba(147, 197, 253, 0.40);
}

.vb-filter-five-empty.is-visible {
  display: block;
}

.vb-filter-five-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-five-empty p {
  margin: 0 !important;
  color: #1e40af !important;
  -webkit-text-fill-color: #1e40af !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb-filter-five-toolbar {
    grid-template-columns: 1fr;
  }

  .vb-filter-five-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-filter-five-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-five-blog {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-five-intro h3 {
    font-size: 38px !important;
  }

  .vb-filter-five-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const blog = document.querySelector("[data-vb-filter-five]");
  if (!blog) return;

  const input = blog.querySelector("[data-vb-filter-five-input]");
  const clearButton = blog.querySelector("[data-vb-filter-five-clear]");
  const count = blog.querySelector("[data-vb-filter-five-count]");
  const empty = blog.querySelector("[data-vb-filter-five-empty]");
  const posts = Array.from(blog.querySelectorAll("[data-post-text]"));

  function updatePosts() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    posts.forEach(function (post) {
      const keywords = post.getAttribute("data-post-text").toLowerCase();
      const title = post.querySelector("h4").textContent.toLowerCase();
      const excerpt = post.querySelector("p").textContent.toLowerCase();
      const category = post.querySelector("span").textContent.toLowerCase();

      const match =
        keywords.includes(query) ||
        title.includes(query) ||
        excerpt.includes(query) ||
        category.includes(query);

      post.classList.toggle("is-hidden", !match);

      if (match) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 post" : visible + " posts";
    empty.classList.toggle("is-visible", visible === 0);
  }

  input.addEventListener("input", updatePosts);

  clearButton.addEventListener("click", function () {
    input.value = "";
    input.focus();
    updatePosts();
  });

  updatePosts();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const blog = document.querySelector("[data-vb-filter-five]");
  if (!blog) return;

  const input = blog.querySelector("[data-vb-filter-five-input]");
  const clearButton = blog.querySelector("[data-vb-filter-five-clear]");
  const count = blog.querySelector("[data-vb-filter-five-count]");
  const empty = blog.querySelector("[data-vb-filter-five-empty]");
  const posts = Array.from(blog.querySelectorAll("[data-post-text]"));

  function updatePosts() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    posts.forEach(function (post) {
      const keywords = post.getAttribute("data-post-text").toLowerCase();
      const title = post.querySelector("h4").textContent.toLowerCase();
      const excerpt = post.querySelector("p").textContent.toLowerCase();
      const category = post.querySelector("span").textContent.toLowerCase();

      const match =
        keywords.includes(query) ||
        title.includes(query) ||
        excerpt.includes(query) ||
        category.includes(query);

      post.classList.toggle("is-hidden", !match);

      if (match) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 post" : visible + " posts";
    empty.classList.toggle("is-visible", visible === 0);
  }

  input.addEventListener("input", updatePosts);

  clearButton.addEventListener("click", function () {
    input.value = "";
    input.focus();
    updatePosts();
  });

  updatePosts();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-five-demo"&gt;
  &lt;div class="vb-filter-five-blog" data-vb-filter-five&gt;
    &lt;div class="vb-filter-five-intro"&gt;
      &lt;span&gt;Example 05&lt;/span&gt;
      &lt;h3&gt;Blog Post Search Filter&lt;/h3&gt;
      &lt;p&gt;Search articles by topic, category, keyword, or description and update the visible post cards instantly.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-five-toolbar"&gt;
      &lt;div class="vb-filter-five-search"&gt;
        &lt;label for="vb-filter-five-input"&gt;Search blog posts&lt;/label&gt;
        &lt;input id="vb-filter-five-input" type="search" placeholder="Search JavaScript, CSS, SEO, WordPress..." data-vb-filter-five-input&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-five-stats"&gt;
        &lt;small&gt;Visible posts&lt;/small&gt;
        &lt;strong data-vb-filter-five-count&gt;8 posts&lt;/strong&gt;
      &lt;/div&gt;

      &lt;button type="button" class="vb-filter-five-clear" data-vb-filter-five-clear&gt;Reset search&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-five-grid"&gt;
      &lt;article data-post-text="javascript dropdown menu custom select navigation ui components"&gt;
        &lt;span&gt;JavaScript&lt;/span&gt;
        &lt;h4&gt;JavaScript Dropdown Menu Examples&lt;/h4&gt;
        &lt;p&gt;Build custom select menus, navigation dropdowns, action panels, and responsive menu components.&lt;/p&gt;
        &lt;small&gt;8 min read&lt;/small&gt;
      &lt;/article&gt;

      &lt;article data-post-text="javascript slider carousel image content product hero responsive"&gt;
        &lt;span&gt;JavaScript&lt;/span&gt;
        &lt;h4&gt;JavaScript Slider Examples&lt;/h4&gt;
        &lt;p&gt;Create image sliders, product carousels, hero sliders, testimonial sliders, and content sliders.&lt;/p&gt;
        &lt;small&gt;11 min read&lt;/small&gt;
      &lt;/article&gt;

      &lt;article data-post-text="css forms contact login checkout form ui design responsive"&gt;
        &lt;span&gt;CSS&lt;/span&gt;
        &lt;h4&gt;Modern CSS Forms&lt;/h4&gt;
        &lt;p&gt;Explore contact forms, login screens, checkout forms, newsletter forms, and responsive form layouts.&lt;/p&gt;
        &lt;small&gt;12 min read&lt;/small&gt;
      &lt;/article&gt;

      &lt;article data-post-text="wordpress seo structured data schema entity ai readable plugin"&gt;
        &lt;span&gt;SEO&lt;/span&gt;
        &lt;h4&gt;Entity SEO and Structured Data&lt;/h4&gt;
        &lt;p&gt;Improve WordPress SEO with structured data, entity relationships, schema markup, and AI-readable content.&lt;/p&gt;
        &lt;small&gt;9 min read&lt;/small&gt;
      &lt;/article&gt;

      &lt;article data-post-text="css pricing tables responsive pricing cards saas comparison"&gt;
        &lt;span&gt;CSS&lt;/span&gt;
        &lt;h4&gt;CSS Pricing Table Examples&lt;/h4&gt;
        &lt;p&gt;Design responsive pricing cards, comparison tables, SaaS pricing sections, and featured plan layouts.&lt;/p&gt;
        &lt;small&gt;10 min read&lt;/small&gt;
      &lt;/article&gt;

      &lt;article data-post-text="javascript modal popup dialog overlay confirmation window"&gt;
        &lt;span&gt;JavaScript&lt;/span&gt;
        &lt;h4&gt;JavaScript Modal Examples&lt;/h4&gt;
        &lt;p&gt;Build popups, dialogs, overlays, confirmations, newsletter modals, and interactive modal windows.&lt;/p&gt;
        &lt;small&gt;7 min read&lt;/small&gt;
      &lt;/article&gt;

      &lt;article data-post-text="css navigation menu navbar dropdown mega menu hamburger"&gt;
        &lt;span&gt;CSS&lt;/span&gt;
        &lt;h4&gt;CSS Navigation Menu Examples&lt;/h4&gt;
        &lt;p&gt;Create responsive navbars, dropdown menus, mega menus, mobile menus, and website header layouts.&lt;/p&gt;
        &lt;small&gt;13 min read&lt;/small&gt;
      &lt;/article&gt;

      &lt;article data-post-text="javascript form validation input signup checkout password email"&gt;
        &lt;span&gt;JavaScript&lt;/span&gt;
        &lt;h4&gt;JavaScript Form Validation Examples&lt;/h4&gt;
        &lt;p&gt;Validate signup fields, checkout inputs, passwords, email addresses, error states, and form messages.&lt;/p&gt;
        &lt;small&gt;10 min read&lt;/small&gt;
      &lt;/article&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-five-empty" data-vb-filter-five-empty&gt;
      &lt;strong&gt;No blog posts found.&lt;/strong&gt;
      &lt;p&gt;Try searching for JavaScript, CSS, SEO, WordPress, forms, sliders, modals, or navigation.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-five-demo,
.vb-filter-five-demo * {
  box-sizing: border-box;
}

.vb-filter-five-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 16% 18%, rgba(59, 130, 246, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #faf5ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(191, 219, 254, 0.50);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.10);
}

.vb-filter-five-blog {
  max-width: 1120px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-five-intro {
  max-width: 780px;
  margin-bottom: 26px;
}

.vb-filter-five-intro &gt; span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-five-intro h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-five-intro p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-filter-five-toolbar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 150px auto;
  gap: 12px;
  align-items: end;
  margin-bottom: 22px;
  padding: 14px;
  border-radius: 24px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-filter-five-search label {
  display: block;
  margin-bottom: 8px;
  color: #1e293b !important;
  -webkit-text-fill-color: #1e293b !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-five-search input {
  width: 100%;
  min-height: 56px;
  padding: 0 16px;
  border: 1px solid rgba(148, 163, 184, 0.24);
  border-radius: 18px;
  outline: 0;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 800;
}

.vb-filter-five-stats {
  min-height: 56px;
  padding: 10px 12px;
  border-radius: 18px;
  background: #0f172a;
}

.vb-filter-five-stats small {
  display: block;
  margin-bottom: 4px;
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-five-stats strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-filter-five-clear {
  min-height: 56px;
  padding: 0 16px;
  border: 0;
  border-radius: 18px;
  background: linear-gradient(135deg, #2563eb, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-five-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-filter-five-grid article {
  min-height: 260px;
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 18% 14%, rgba(59, 130, 246, 0.10), transparent 32%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
  display: flex;
  flex-direction: column;
}

.vb-filter-five-grid article.is-hidden {
  display: none;
}

.vb-filter-five-grid article &gt; span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 16px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #eef2ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-five-grid h4 {
  margin: 0 0 10px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-five-grid p {
  margin: 0 0 18px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-filter-five-grid small {
  margin-top: auto;
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-filter-five-empty {
  display: none;
  margin-top: 18px;
  padding: 22px;
  border-radius: 22px;
  background: #eff6ff;
  border: 1px solid rgba(147, 197, 253, 0.40);
}

.vb-filter-five-empty.is-visible {
  display: block;
}

.vb-filter-five-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-five-empty p {
  margin: 0 !important;
  color: #1e40af !important;
  -webkit-text-fill-color: #1e40af !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb-filter-five-toolbar {
    grid-template-columns: 1fr;
  }

  .vb-filter-five-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-filter-five-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-five-blog {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-five-intro h3 {
    font-size: 38px !important;
  }

  .vb-filter-five-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This blog post search filter is useful for article archives, tutorials, resource hubs, documentation libraries, news sections, and content-heavy websites where readers need to find matching topics quickly.</p>



<h2 class="wp-block-heading">6. Table Row Search Filter</h2>



<p class="wp-block-paragraph"><strong>A table row search filter</strong> is useful for dashboards, admin panels, CRM systems, invoices, order lists, user directories, booking tables, and data-heavy interfaces. Users can type a keyword and instantly narrow visible table rows.</p>



<p class="wp-block-paragraph">This example filters a customer order table by customer name, email, status, plan, or order number. It uses a dashboard-style design, status pills, result count, and a no-results state.</p>



<ul class="wp-block-list">
<li>Live table row search</li>
<li>Filters customer and order data</li>
<li>Status badges and dashboard styling</li>
<li>Dynamic row count</li>
<li>Useful for admin panels, CRM tables, invoices, orders, and dashboards</li>
</ul>



<div class="vb-filter-six-demo">
  <div class="vb-filter-six-dashboard" data-vb-filter-six>
    <div class="vb-filter-six-top">
      <div>
        <span>Example 06</span>
        <h3>Table Row Search Filter</h3>
        <p>Filter dashboard table rows by order number, customer name, plan, email, or status.</p>
      </div>

      <div class="vb-filter-six-search">
        <label for="vb-filter-six-input">Search table</label>
        <input id="vb-filter-six-input" type="search" placeholder="Search paid, pending, pro, customer..." data-vb-filter-six-input>
      </div>
    </div>

    <div class="vb-filter-six-meta">
      <strong data-vb-filter-six-count>7 rows visible</strong>
      <button type="button" data-vb-filter-six-clear>Clear filter</button>
    </div>

    <div class="vb-filter-six-table-wrap">
      <table class="vb-filter-six-table">
        <thead>
          <tr>
            <th>Order</th>
            <th>Customer</th>
            <th>Email</th>
            <th>Plan</th>
            <th>Status</th>
            <th>Total</th>
          </tr>
        </thead>
        <tbody>
          <tr data-row-text="order 1001 anna smith anna@example.com pro paid 149">
            <td>#1001</td>
            <td>Anna Smith</td>
            <td>anna@example.com</td>
            <td>Pro</td>
            <td><span class="paid">Paid</span></td>
            <td>€149</td>
          </tr>

          <tr data-row-text="order 1002 mark davis mark@example.com starter pending 49">
            <td>#1002</td>
            <td>Mark Davis</td>
            <td>mark@example.com</td>
            <td>Starter</td>
            <td><span class="pending">Pending</span></td>
            <td>€49</td>
          </tr>

          <tr data-row-text="order 1003 laura green laura@example.com agency paid 299">
            <td>#1003</td>
            <td>Laura Green</td>
            <td>laura@example.com</td>
            <td>Agency</td>
            <td><span class="paid">Paid</span></td>
            <td>€299</td>
          </tr>

          <tr data-row-text="order 1004 tom brown tom@example.com pro refunded 149">
            <td>#1004</td>
            <td>Tom Brown</td>
            <td>tom@example.com</td>
            <td>Pro</td>
            <td><span class="refunded">Refunded</span></td>
            <td>€149</td>
          </tr>

          <tr data-row-text="order 1005 nina stone nina@example.com starter paid 49">
            <td>#1005</td>
            <td>Nina Stone</td>
            <td>nina@example.com</td>
            <td>Starter</td>
            <td><span class="paid">Paid</span></td>
            <td>€49</td>
          </tr>

          <tr data-row-text="order 1006 alex white alex@example.com agency pending 299">
            <td>#1006</td>
            <td>Alex White</td>
            <td>alex@example.com</td>
            <td>Agency</td>
            <td><span class="pending">Pending</span></td>
            <td>€299</td>
          </tr>

          <tr data-row-text="order 1007 sara black sara@example.com pro failed 149">
            <td>#1007</td>
            <td>Sara Black</td>
            <td>sara@example.com</td>
            <td>Pro</td>
            <td><span class="failed">Failed</span></td>
            <td>€149</td>
          </tr>
        </tbody>
      </table>

      <div class="vb-filter-six-empty" data-vb-filter-six-empty>
        <strong>No table rows found.</strong>
        <p>Try searching for paid, pending, pro, agency, starter, customer name, or order number.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-filter-six-demo,
.vb-filter-six-demo * {
  box-sizing: border-box;
}

.vb-filter-six-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 16% 18%, rgba(34, 197, 94, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(59, 130, 246, 0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #1e293b 52%, #0f766e 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.30);
}

.vb-filter-six-dashboard {
  max-width: 1120px;
  margin: 0 auto;
  padding: 30px;
  border-radius: 30px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
}

.vb-filter-six-top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(280px, 360px);
  gap: 24px;
  align-items: end;
  margin-bottom: 18px;
}

.vb-filter-six-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.14);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-six-top h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-six-top p {
  max-width: 640px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-filter-six-search label {
  display: block;
  margin-bottom: 8px;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-six-search input {
  width: 100%;
  min-height: 58px;
  padding: 0 16px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 18px;
  outline: 0;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 800;
}

.vb-filter-six-search input::placeholder {
  color: rgba(255,255,255,0.62);
  -webkit-text-fill-color: rgba(255,255,255,0.62);
}

.vb-filter-six-meta {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: center;
  margin-bottom: 16px;
  padding: 12px;
  border-radius: 20px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-filter-six-meta strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-filter-six-meta button {
  min-height: 40px;
  padding: 9px 13px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-six-table-wrap {
  overflow-x: auto;
  border-radius: 24px;
  background: #ffffff;
  box-shadow: 0 28px 80px rgba(2, 6, 23, 0.26);
}

.vb-filter-six-table {
  width: 100%;
  min-width: 820px;
  border-collapse: collapse;
}

.vb-filter-six-table th {
  padding: 16px;
  background: #f8fafc;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-align: left;
  text-transform: uppercase;
  border-bottom: 1px solid #e2e8f0;
}

.vb-filter-six-table td {
  padding: 16px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 750;
  border-bottom: 1px solid #e2e8f0;
}

.vb-filter-six-table tr.is-hidden {
  display: none;
}

.vb-filter-six-table tr:last-child td {
  border-bottom: 0;
}

.vb-filter-six-table span {
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  font-size: 12px;
  line-height: 1;
  font-weight: 950;
}

.vb-filter-six-table .paid {
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
}

.vb-filter-six-table .pending {
  background: #fef3c7;
  color: #b45309 !important;
  -webkit-text-fill-color: #b45309 !important;
}

.vb-filter-six-table .refunded {
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
}

.vb-filter-six-table .failed {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-filter-six-empty {
  display: none;
  padding: 24px;
  background: #fff7ed;
  border-top: 1px solid rgba(251, 146, 60, 0.34);
}

.vb-filter-six-empty.is-visible {
  display: block;
}

.vb-filter-six-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-six-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 900px) {
  .vb-filter-six-top {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-filter-six-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-six-dashboard {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-six-top h3 {
    font-size: 38px !important;
  }

  .vb-filter-six-meta {
    align-items: stretch;
    flex-direction: column;
  }

  .vb-filter-six-meta button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const dashboard = document.querySelector("[data-vb-filter-six]");
  if (!dashboard) return;

  const input = dashboard.querySelector("[data-vb-filter-six-input]");
  const clearButton = dashboard.querySelector("[data-vb-filter-six-clear]");
  const count = dashboard.querySelector("[data-vb-filter-six-count]");
  const empty = dashboard.querySelector("[data-vb-filter-six-empty]");
  const rows = Array.from(dashboard.querySelectorAll("[data-row-text]"));

  function updateRows() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    rows.forEach(function (row) {
      const rowText = row.getAttribute("data-row-text").toLowerCase();
      const fullText = row.textContent.toLowerCase();
      const match = rowText.includes(query) || fullText.includes(query);

      row.classList.toggle("is-hidden", !match);

      if (match) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 row visible" : visible + " rows visible";
    empty.classList.toggle("is-visible", visible === 0);
  }

  input.addEventListener("input", updateRows);

  clearButton.addEventListener("click", function () {
    input.value = "";
    input.focus();
    updateRows();
  });

  updateRows();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dashboard = document.querySelector("[data-vb-filter-six]");
  if (!dashboard) return;

  const input = dashboard.querySelector("[data-vb-filter-six-input]");
  const clearButton = dashboard.querySelector("[data-vb-filter-six-clear]");
  const count = dashboard.querySelector("[data-vb-filter-six-count]");
  const empty = dashboard.querySelector("[data-vb-filter-six-empty]");
  const rows = Array.from(dashboard.querySelectorAll("[data-row-text]"));

  function updateRows() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    rows.forEach(function (row) {
      const rowText = row.getAttribute("data-row-text").toLowerCase();
      const fullText = row.textContent.toLowerCase();
      const match = rowText.includes(query) || fullText.includes(query);

      row.classList.toggle("is-hidden", !match);

      if (match) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 row visible" : visible + " rows visible";
    empty.classList.toggle("is-visible", visible === 0);
  }

  input.addEventListener("input", updateRows);

  clearButton.addEventListener("click", function () {
    input.value = "";
    input.focus();
    updateRows();
  });

  updateRows();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-six-demo"&gt;
  &lt;div class="vb-filter-six-dashboard" data-vb-filter-six&gt;
    &lt;div class="vb-filter-six-top"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 06&lt;/span&gt;
        &lt;h3&gt;Table Row Search Filter&lt;/h3&gt;
        &lt;p&gt;Filter dashboard table rows by order number, customer name, plan, email, or status.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-six-search"&gt;
        &lt;label for="vb-filter-six-input"&gt;Search table&lt;/label&gt;
        &lt;input id="vb-filter-six-input" type="search" placeholder="Search paid, pending, pro, customer..." data-vb-filter-six-input&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-six-meta"&gt;
      &lt;strong data-vb-filter-six-count&gt;7 rows visible&lt;/strong&gt;
      &lt;button type="button" data-vb-filter-six-clear&gt;Clear filter&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-six-table-wrap"&gt;
      &lt;table class="vb-filter-six-table"&gt;
        &lt;thead&gt;
          &lt;tr&gt;
            &lt;th&gt;Order&lt;/th&gt;
            &lt;th&gt;Customer&lt;/th&gt;
            &lt;th&gt;Email&lt;/th&gt;
            &lt;th&gt;Plan&lt;/th&gt;
            &lt;th&gt;Status&lt;/th&gt;
            &lt;th&gt;Total&lt;/th&gt;
          &lt;/tr&gt;
        &lt;/thead&gt;
        &lt;tbody&gt;
          &lt;tr data-row-text="order 1001 anna smith anna@example.com pro paid 149"&gt;
            &lt;td&gt;#1001&lt;/td&gt;
            &lt;td&gt;Anna Smith&lt;/td&gt;
            &lt;td&gt;anna@example.com&lt;/td&gt;
            &lt;td&gt;Pro&lt;/td&gt;
            &lt;td&gt;&lt;span class="paid"&gt;Paid&lt;/span&gt;&lt;/td&gt;
            &lt;td&gt;€149&lt;/td&gt;
          &lt;/tr&gt;

          &lt;tr data-row-text="order 1002 mark davis mark@example.com starter pending 49"&gt;
            &lt;td&gt;#1002&lt;/td&gt;
            &lt;td&gt;Mark Davis&lt;/td&gt;
            &lt;td&gt;mark@example.com&lt;/td&gt;
            &lt;td&gt;Starter&lt;/td&gt;
            &lt;td&gt;&lt;span class="pending"&gt;Pending&lt;/span&gt;&lt;/td&gt;
            &lt;td&gt;€49&lt;/td&gt;
          &lt;/tr&gt;

          &lt;tr data-row-text="order 1003 laura green laura@example.com agency paid 299"&gt;
            &lt;td&gt;#1003&lt;/td&gt;
            &lt;td&gt;Laura Green&lt;/td&gt;
            &lt;td&gt;laura@example.com&lt;/td&gt;
            &lt;td&gt;Agency&lt;/td&gt;
            &lt;td&gt;&lt;span class="paid"&gt;Paid&lt;/span&gt;&lt;/td&gt;
            &lt;td&gt;€299&lt;/td&gt;
          &lt;/tr&gt;

          &lt;tr data-row-text="order 1004 tom brown tom@example.com pro refunded 149"&gt;
            &lt;td&gt;#1004&lt;/td&gt;
            &lt;td&gt;Tom Brown&lt;/td&gt;
            &lt;td&gt;tom@example.com&lt;/td&gt;
            &lt;td&gt;Pro&lt;/td&gt;
            &lt;td&gt;&lt;span class="refunded"&gt;Refunded&lt;/span&gt;&lt;/td&gt;
            &lt;td&gt;€149&lt;/td&gt;
          &lt;/tr&gt;

          &lt;tr data-row-text="order 1005 nina stone nina@example.com starter paid 49"&gt;
            &lt;td&gt;#1005&lt;/td&gt;
            &lt;td&gt;Nina Stone&lt;/td&gt;
            &lt;td&gt;nina@example.com&lt;/td&gt;
            &lt;td&gt;Starter&lt;/td&gt;
            &lt;td&gt;&lt;span class="paid"&gt;Paid&lt;/span&gt;&lt;/td&gt;
            &lt;td&gt;€49&lt;/td&gt;
          &lt;/tr&gt;

          &lt;tr data-row-text="order 1006 alex white alex@example.com agency pending 299"&gt;
            &lt;td&gt;#1006&lt;/td&gt;
            &lt;td&gt;Alex White&lt;/td&gt;
            &lt;td&gt;alex@example.com&lt;/td&gt;
            &lt;td&gt;Agency&lt;/td&gt;
            &lt;td&gt;&lt;span class="pending"&gt;Pending&lt;/span&gt;&lt;/td&gt;
            &lt;td&gt;€299&lt;/td&gt;
          &lt;/tr&gt;

          &lt;tr data-row-text="order 1007 sara black sara@example.com pro failed 149"&gt;
            &lt;td&gt;#1007&lt;/td&gt;
            &lt;td&gt;Sara Black&lt;/td&gt;
            &lt;td&gt;sara@example.com&lt;/td&gt;
            &lt;td&gt;Pro&lt;/td&gt;
            &lt;td&gt;&lt;span class="failed"&gt;Failed&lt;/span&gt;&lt;/td&gt;
            &lt;td&gt;€149&lt;/td&gt;
          &lt;/tr&gt;
        &lt;/tbody&gt;
      &lt;/table&gt;

      &lt;div class="vb-filter-six-empty" data-vb-filter-six-empty&gt;
        &lt;strong&gt;No table rows found.&lt;/strong&gt;
        &lt;p&gt;Try searching for paid, pending, pro, agency, starter, customer name, or order number.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-six-demo,
.vb-filter-six-demo * {
  box-sizing: border-box;
}

.vb-filter-six-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 16% 18%, rgba(34, 197, 94, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(59, 130, 246, 0.18), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #1e293b 52%, #0f766e 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.30);
}

.vb-filter-six-dashboard {
  max-width: 1120px;
  margin: 0 auto;
  padding: 30px;
  border-radius: 30px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
}

.vb-filter-six-top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(280px, 360px);
  gap: 24px;
  align-items: end;
  margin-bottom: 18px;
}

.vb-filter-six-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.14);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-six-top h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-six-top p {
  max-width: 640px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-filter-six-search label {
  display: block;
  margin-bottom: 8px;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-six-search input {
  width: 100%;
  min-height: 58px;
  padding: 0 16px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 18px;
  outline: 0;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 800;
}

.vb-filter-six-search input::placeholder {
  color: rgba(255,255,255,0.62);
  -webkit-text-fill-color: rgba(255,255,255,0.62);
}

.vb-filter-six-meta {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: center;
  margin-bottom: 16px;
  padding: 12px;
  border-radius: 20px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-filter-six-meta strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-filter-six-meta button {
  min-height: 40px;
  padding: 9px 13px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-six-table-wrap {
  overflow-x: auto;
  border-radius: 24px;
  background: #ffffff;
  box-shadow: 0 28px 80px rgba(2, 6, 23, 0.26);
}

.vb-filter-six-table {
  width: 100%;
  min-width: 820px;
  border-collapse: collapse;
}

.vb-filter-six-table th {
  padding: 16px;
  background: #f8fafc;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-align: left;
  text-transform: uppercase;
  border-bottom: 1px solid #e2e8f0;
}

.vb-filter-six-table td {
  padding: 16px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 750;
  border-bottom: 1px solid #e2e8f0;
}

.vb-filter-six-table tr.is-hidden {
  display: none;
}

.vb-filter-six-table tr:last-child td {
  border-bottom: 0;
}

.vb-filter-six-table span {
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  font-size: 12px;
  line-height: 1;
  font-weight: 950;
}

.vb-filter-six-table .paid {
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
}

.vb-filter-six-table .pending {
  background: #fef3c7;
  color: #b45309 !important;
  -webkit-text-fill-color: #b45309 !important;
}

.vb-filter-six-table .refunded {
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
}

.vb-filter-six-table .failed {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-filter-six-empty {
  display: none;
  padding: 24px;
  background: #fff7ed;
  border-top: 1px solid rgba(251, 146, 60, 0.34);
}

.vb-filter-six-empty.is-visible {
  display: block;
}

.vb-filter-six-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-six-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 900px) {
  .vb-filter-six-top {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-filter-six-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-six-dashboard {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-six-top h3 {
    font-size: 38px !important;
  }

  .vb-filter-six-meta {
    align-items: stretch;
    flex-direction: column;
  }

  .vb-filter-six-meta button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This table row search filter is useful for admin dashboards, CRM systems, customer lists, order management pages, invoice tables, booking systems, and data-heavy interfaces where users need to locate specific rows quickly.</p>



<h2 class="wp-block-heading">7. Tag Filter with Search</h2>



<p class="wp-block-paragraph"><strong>A tag filter with search</strong> combines clickable filter chips with a live search input. This is useful for resource libraries, tutorial collections, blog hubs, documentation pages, design galleries, and tool directories where users may want to filter by topic and keyword at the same time.</p>



<p class="wp-block-paragraph">This example lets users click a tag such as JavaScript, CSS, WordPress, SEO, or UI Design, then search inside the selected tag. The result count updates automatically, and the reset button clears both the tag and search query.</p>



<ul class="wp-block-list">
<li>Clickable tag filter chips</li>
<li>Live keyword search</li>
<li>Combines tag and search logic</li>
<li>Active tag styling</li>
<li>Useful for resource hubs, blogs, documentation, and tutorial libraries</li>
</ul>



<div class="vb-filter-seven-demo">
  <div class="vb-filter-seven-library" data-vb-filter-seven>
    <div class="vb-filter-seven-top">
      <span>Example 07</span>
      <h3>Tag Filter with Search</h3>
      <p>Choose a topic tag and type a keyword to filter the resource cards together.</p>
    </div>

    <div class="vb-filter-seven-panel">
      <div class="vb-filter-seven-search">
        <label for="vb-filter-seven-input">Search resources</label>
        <input id="vb-filter-seven-input" type="search" placeholder="Search components, schema, layout, forms..." data-vb-filter-seven-input>
      </div>

      <div class="vb-filter-seven-tags" data-vb-filter-seven-tags>
        <button type="button" class="is-active" data-tag="all">All</button>
        <button type="button" data-tag="javascript">JavaScript</button>
        <button type="button" data-tag="css">CSS</button>
        <button type="button" data-tag="wordpress">WordPress</button>
        <button type="button" data-tag="seo">SEO</button>
        <button type="button" data-tag="ui">UI Design</button>
      </div>

      <div class="vb-filter-seven-status">
        <strong data-vb-filter-seven-count>9 resources found</strong>
        <button type="button" data-vb-filter-seven-reset>Reset filters</button>
      </div>
    </div>

    <div class="vb-filter-seven-grid">
      <article data-tag-card="javascript" data-resource-text="javascript modal popup dialog overlay ui component">
        <small>JavaScript</small>
        <h4>Modal Components</h4>
        <p>Popup windows, overlays, dialogs, confirmation boxes, and interaction patterns.</p>
      </article>

      <article data-tag-card="javascript" data-resource-text="javascript dropdown menu custom select navigation search">
        <small>JavaScript</small>
        <h4>Dropdown Menus</h4>
        <p>Custom selects, navigation dropdowns, profile menus, and menu panels.</p>
      </article>

      <article data-tag-card="css" data-resource-text="css forms contact login checkout inputs responsive layout">
        <small>CSS</small>
        <h4>Form Layouts</h4>
        <p>Contact forms, login screens, checkout inputs, and responsive form sections.</p>
      </article>

      <article data-tag-card="css" data-resource-text="css pricing cards tables saas plans comparison">
        <small>CSS</small>
        <h4>Pricing Cards</h4>
        <p>SaaS pricing cards, comparison tables, plan toggles, and CTA sections.</p>
      </article>

      <article data-tag-card="wordpress" data-resource-text="wordpress gutenberg plugin theme woocommerce shortcode">
        <small>WordPress</small>
        <h4>Gutenberg Blocks</h4>
        <p>Custom content blocks, shortcode sections, plugin UI, and reusable layouts.</p>
      </article>

      <article data-tag-card="wordpress" data-resource-text="wordpress woocommerce product filter shop catalog">
        <small>WordPress</small>
        <h4>WooCommerce UI</h4>
        <p>Shop pages, product filters, cart sections, checkout layouts, and catalog grids.</p>
      </article>

      <article data-tag-card="seo" data-resource-text="seo schema structured data entity ai readable search">
        <small>SEO</small>
        <h4>Structured Data</h4>
        <p>Schema markup, entity SEO, AI-readable content, and search visibility systems.</p>
      </article>

      <article data-tag-card="ui" data-resource-text="ui design cards layout dashboard interface components">
        <small>UI Design</small>
        <h4>Dashboard Cards</h4>
        <p>Modern interface cards, admin panels, metrics blocks, and app layouts.</p>
      </article>

      <article data-tag-card="ui" data-resource-text="ui design hero section landing page buttons visual">
        <small>UI Design</small>
        <h4>Landing UI Kit</h4>
        <p>Hero layouts, buttons, feature sections, trust blocks, and visual content areas.</p>
      </article>
    </div>

    <div class="vb-filter-seven-empty" data-vb-filter-seven-empty>
      <strong>No matching resources found.</strong>
      <p>Try another tag or search for JavaScript, CSS, WordPress, SEO, forms, schema, layout, or UI.</p>
    </div>
  </div>
</div>

<style>
.vb-filter-seven-demo,
.vb-filter-seven-demo * {
  box-sizing: border-box;
}

.vb-filter-seven-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 18%, rgba(168, 85, 247, 0.20), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(20, 184, 166, 0.18), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #f0fdfa 52%, #ffffff 100%) !important;
  border: 1px solid rgba(216, 180, 254, 0.48);
  box-shadow: 0 24px 70px rgba(88, 28, 135, 0.12);
}

.vb-filter-seven-library {
  max-width: 1120px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 80% 16%, rgba(20, 184, 166, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-seven-top {
  max-width: 780px;
  margin-bottom: 24px;
}

.vb-filter-seven-top > span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-seven-top h3 {
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-seven-top p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-filter-seven-panel {
  display: grid;
  grid-template-columns: minmax(260px, 0.8fr) minmax(0, 1.2fr);
  gap: 14px;
  margin-bottom: 22px;
  padding: 16px;
  border-radius: 26px;
  background: #111827;
}

.vb-filter-seven-search {
  grid-row: span 2;
}

.vb-filter-seven-search label {
  display: block;
  margin-bottom: 8px;
  color: #d8b4fe !important;
  -webkit-text-fill-color: #d8b4fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-seven-search input {
  width: 100%;
  min-height: 58px;
  padding: 0 16px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 18px;
  outline: 0;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 800;
}

.vb-filter-seven-search input::placeholder {
  color: rgba(255,255,255,0.60);
  -webkit-text-fill-color: rgba(255,255,255,0.60);
}

.vb-filter-seven-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-filter-seven-tags button {
  min-height: 40px;
  padding: 9px 13px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 999px;
  background: rgba(255,255,255,0.08);
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 13px;
  font-weight: 900;
  cursor: pointer;
}

.vb-filter-seven-tags button.is-active,
.vb-filter-seven-tags button:hover {
  background: linear-gradient(135deg, #a855f7, #14b8a6);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-seven-status {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
}

.vb-filter-seven-status strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-filter-seven-status button {
  min-height: 38px;
  padding: 8px 12px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-seven-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.vb-filter-seven-grid article {
  padding: 22px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.08);
}

.vb-filter-seven-grid article.is-hidden {
  display: none;
}

.vb-filter-seven-grid small {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-seven-grid h4 {
  margin: 0 0 10px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-seven-grid p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-filter-seven-empty {
  display: none;
  margin-top: 18px;
  padding: 22px;
  border-radius: 22px;
  background: #faf5ff;
  border: 1px solid rgba(216, 180, 254, 0.46);
}

.vb-filter-seven-empty.is-visible {
  display: block;
}

.vb-filter-seven-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-seven-empty p {
  margin: 0 !important;
  color: #6b21a8 !important;
  -webkit-text-fill-color: #6b21a8 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 900px) {
  .vb-filter-seven-panel {
    grid-template-columns: 1fr;
  }

  .vb-filter-seven-search {
    grid-row: auto;
  }

  .vb-filter-seven-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-filter-seven-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-seven-library {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-seven-top h3 {
    font-size: 38px !important;
  }

  .vb-filter-seven-status {
    align-items: stretch;
    flex-direction: column;
  }

  .vb-filter-seven-status button {
    width: 100%;
  }

  .vb-filter-seven-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const library = document.querySelector("[data-vb-filter-seven]");
  if (!library) return;

  const input = library.querySelector("[data-vb-filter-seven-input]");
  const buttons = library.querySelectorAll("[data-tag]");
  const reset = library.querySelector("[data-vb-filter-seven-reset]");
  const count = library.querySelector("[data-vb-filter-seven-count]");
  const empty = library.querySelector("[data-vb-filter-seven-empty]");
  const cards = Array.from(library.querySelectorAll("[data-tag-card]"));

  let activeTag = "all";

  function updateLibrary() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    cards.forEach(function (card) {
      const tag = card.getAttribute("data-tag-card");
      const text = card.getAttribute("data-resource-text").toLowerCase();
      const title = card.querySelector("h4").textContent.toLowerCase();
      const description = card.querySelector("p").textContent.toLowerCase();

      const tagMatch = activeTag === "all" || tag === activeTag;
      const searchMatch = text.includes(query) || title.includes(query) || description.includes(query);
      const shouldShow = tagMatch && searchMatch;

      card.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 resource found" : visible + " resources found";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeTag = button.getAttribute("data-tag");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateLibrary();
    });
  });

  input.addEventListener("input", updateLibrary);

  reset.addEventListener("click", function () {
    activeTag = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-tag") === "all");
    });

    input.focus();
    updateLibrary();
  });

  updateLibrary();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const library = document.querySelector("[data-vb-filter-seven]");
  if (!library) return;

  const input = library.querySelector("[data-vb-filter-seven-input]");
  const buttons = library.querySelectorAll("[data-tag]");
  const reset = library.querySelector("[data-vb-filter-seven-reset]");
  const count = library.querySelector("[data-vb-filter-seven-count]");
  const empty = library.querySelector("[data-vb-filter-seven-empty]");
  const cards = Array.from(library.querySelectorAll("[data-tag-card]"));

  let activeTag = "all";

  function updateLibrary() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    cards.forEach(function (card) {
      const tag = card.getAttribute("data-tag-card");
      const text = card.getAttribute("data-resource-text").toLowerCase();
      const title = card.querySelector("h4").textContent.toLowerCase();
      const description = card.querySelector("p").textContent.toLowerCase();

      const tagMatch = activeTag === "all" || tag === activeTag;
      const searchMatch = text.includes(query) || title.includes(query) || description.includes(query);
      const shouldShow = tagMatch && searchMatch;

      card.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 resource found" : visible + " resources found";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeTag = button.getAttribute("data-tag");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateLibrary();
    });
  });

  input.addEventListener("input", updateLibrary);

  reset.addEventListener("click", function () {
    activeTag = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-tag") === "all");
    });

    input.focus();
    updateLibrary();
  });

  updateLibrary();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-seven-demo"&gt;
  &lt;div class="vb-filter-seven-library" data-vb-filter-seven&gt;
    &lt;div class="vb-filter-seven-top"&gt;
      &lt;span&gt;Example 07&lt;/span&gt;
      &lt;h3&gt;Tag Filter with Search&lt;/h3&gt;
      &lt;p&gt;Choose a topic tag and type a keyword to filter the resource cards together.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-seven-panel"&gt;
      &lt;div class="vb-filter-seven-search"&gt;
        &lt;label for="vb-filter-seven-input"&gt;Search resources&lt;/label&gt;
        &lt;input id="vb-filter-seven-input" type="search" placeholder="Search components, schema, layout, forms..." data-vb-filter-seven-input&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-seven-tags" data-vb-filter-seven-tags&gt;
        &lt;button type="button" class="is-active" data-tag="all"&gt;All&lt;/button&gt;
        &lt;button type="button" data-tag="javascript"&gt;JavaScript&lt;/button&gt;
        &lt;button type="button" data-tag="css"&gt;CSS&lt;/button&gt;
        &lt;button type="button" data-tag="wordpress"&gt;WordPress&lt;/button&gt;
        &lt;button type="button" data-tag="seo"&gt;SEO&lt;/button&gt;
        &lt;button type="button" data-tag="ui"&gt;UI Design&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-seven-status"&gt;
        &lt;strong data-vb-filter-seven-count&gt;9 resources found&lt;/strong&gt;
        &lt;button type="button" data-vb-filter-seven-reset&gt;Reset filters&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-seven-grid"&gt;
      &lt;article data-tag-card="javascript" data-resource-text="javascript modal popup dialog overlay ui component"&gt;
        &lt;small&gt;JavaScript&lt;/small&gt;
        &lt;h4&gt;Modal Components&lt;/h4&gt;
        &lt;p&gt;Popup windows, overlays, dialogs, confirmation boxes, and interaction patterns.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-tag-card="javascript" data-resource-text="javascript dropdown menu custom select navigation search"&gt;
        &lt;small&gt;JavaScript&lt;/small&gt;
        &lt;h4&gt;Dropdown Menus&lt;/h4&gt;
        &lt;p&gt;Custom selects, navigation dropdowns, profile menus, and menu panels.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-tag-card="css" data-resource-text="css forms contact login checkout inputs responsive layout"&gt;
        &lt;small&gt;CSS&lt;/small&gt;
        &lt;h4&gt;Form Layouts&lt;/h4&gt;
        &lt;p&gt;Contact forms, login screens, checkout inputs, and responsive form sections.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-tag-card="css" data-resource-text="css pricing cards tables saas plans comparison"&gt;
        &lt;small&gt;CSS&lt;/small&gt;
        &lt;h4&gt;Pricing Cards&lt;/h4&gt;
        &lt;p&gt;SaaS pricing cards, comparison tables, plan toggles, and CTA sections.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-tag-card="wordpress" data-resource-text="wordpress gutenberg plugin theme woocommerce shortcode"&gt;
        &lt;small&gt;WordPress&lt;/small&gt;
        &lt;h4&gt;Gutenberg Blocks&lt;/h4&gt;
        &lt;p&gt;Custom content blocks, shortcode sections, plugin UI, and reusable layouts.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-tag-card="wordpress" data-resource-text="wordpress woocommerce product filter shop catalog"&gt;
        &lt;small&gt;WordPress&lt;/small&gt;
        &lt;h4&gt;WooCommerce UI&lt;/h4&gt;
        &lt;p&gt;Shop pages, product filters, cart sections, checkout layouts, and catalog grids.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-tag-card="seo" data-resource-text="seo schema structured data entity ai readable search"&gt;
        &lt;small&gt;SEO&lt;/small&gt;
        &lt;h4&gt;Structured Data&lt;/h4&gt;
        &lt;p&gt;Schema markup, entity SEO, AI-readable content, and search visibility systems.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-tag-card="ui" data-resource-text="ui design cards layout dashboard interface components"&gt;
        &lt;small&gt;UI Design&lt;/small&gt;
        &lt;h4&gt;Dashboard Cards&lt;/h4&gt;
        &lt;p&gt;Modern interface cards, admin panels, metrics blocks, and app layouts.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-tag-card="ui" data-resource-text="ui design hero section landing page buttons visual"&gt;
        &lt;small&gt;UI Design&lt;/small&gt;
        &lt;h4&gt;Landing UI Kit&lt;/h4&gt;
        &lt;p&gt;Hero layouts, buttons, feature sections, trust blocks, and visual content areas.&lt;/p&gt;
      &lt;/article&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-seven-empty" data-vb-filter-seven-empty&gt;
      &lt;strong&gt;No matching resources found.&lt;/strong&gt;
      &lt;p&gt;Try another tag or search for JavaScript, CSS, WordPress, SEO, forms, schema, layout, or UI.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-seven-demo,
.vb-filter-seven-demo * {
  box-sizing: border-box;
}

.vb-filter-seven-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 18%, rgba(168, 85, 247, 0.20), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(20, 184, 166, 0.18), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #f0fdfa 52%, #ffffff 100%) !important;
  border: 1px solid rgba(216, 180, 254, 0.48);
  box-shadow: 0 24px 70px rgba(88, 28, 135, 0.12);
}

.vb-filter-seven-library {
  max-width: 1120px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 80% 16%, rgba(20, 184, 166, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-seven-top {
  max-width: 780px;
  margin-bottom: 24px;
}

.vb-filter-seven-top &gt; span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-seven-top h3 {
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-seven-top p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-filter-seven-panel {
  display: grid;
  grid-template-columns: minmax(260px, 0.8fr) minmax(0, 1.2fr);
  gap: 14px;
  margin-bottom: 22px;
  padding: 16px;
  border-radius: 26px;
  background: #111827;
}

.vb-filter-seven-search {
  grid-row: span 2;
}

.vb-filter-seven-search label {
  display: block;
  margin-bottom: 8px;
  color: #d8b4fe !important;
  -webkit-text-fill-color: #d8b4fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-seven-search input {
  width: 100%;
  min-height: 58px;
  padding: 0 16px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 18px;
  outline: 0;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 800;
}

.vb-filter-seven-search input::placeholder {
  color: rgba(255,255,255,0.60);
  -webkit-text-fill-color: rgba(255,255,255,0.60);
}

.vb-filter-seven-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-filter-seven-tags button {
  min-height: 40px;
  padding: 9px 13px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 999px;
  background: rgba(255,255,255,0.08);
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 13px;
  font-weight: 900;
  cursor: pointer;
}

.vb-filter-seven-tags button.is-active,
.vb-filter-seven-tags button:hover {
  background: linear-gradient(135deg, #a855f7, #14b8a6);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-seven-status {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 12px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
}

.vb-filter-seven-status strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-filter-seven-status button {
  min-height: 38px;
  padding: 8px 12px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-seven-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.vb-filter-seven-grid article {
  padding: 22px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.08);
}

.vb-filter-seven-grid article.is-hidden {
  display: none;
}

.vb-filter-seven-grid small {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-seven-grid h4 {
  margin: 0 0 10px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-seven-grid p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-filter-seven-empty {
  display: none;
  margin-top: 18px;
  padding: 22px;
  border-radius: 22px;
  background: #faf5ff;
  border: 1px solid rgba(216, 180, 254, 0.46);
}

.vb-filter-seven-empty.is-visible {
  display: block;
}

.vb-filter-seven-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-seven-empty p {
  margin: 0 !important;
  color: #6b21a8 !important;
  -webkit-text-fill-color: #6b21a8 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 900px) {
  .vb-filter-seven-panel {
    grid-template-columns: 1fr;
  }

  .vb-filter-seven-search {
    grid-row: auto;
  }

  .vb-filter-seven-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-filter-seven-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-seven-library {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-seven-top h3 {
    font-size: 38px !important;
  }

  .vb-filter-seven-status {
    align-items: stretch;
    flex-direction: column;
  }

  .vb-filter-seven-status button {
    width: 100%;
  }

  .vb-filter-seven-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This tag filter with search is useful for resource libraries, tutorial indexes, blog hubs, documentation pages, tool directories, course libraries, and knowledge base sections where users need both category filtering and keyword search.</p>



<h2 class="wp-block-heading">8. Portfolio Search and Category Filter</h2>



<p class="wp-block-paragraph"><strong>A portfolio search and category filter</strong> helps visitors browse creative work by type and keyword. This pattern is useful for designers, developers, agencies, photographers, studios, freelancers, architects, and service businesses that want to organize case studies into searchable groups.</p>



<p class="wp-block-paragraph">This example uses a visual portfolio wall with category buttons, a compact search input, project cards, active filter styling, result count, and a no-results message. Users can filter by project type and search inside project names or descriptions.</p>



<ul class="wp-block-list">
<li>Portfolio category filtering</li>
<li>Live keyword search</li>
<li>Visual case study cards</li>
<li>Active category state</li>
<li>Useful for agencies, portfolios, studios, galleries, and case study pages</li>
</ul>



<div class="vb-filter-eight-demo">
  <div class="vb-filter-eight-portfolio" data-vb-filter-eight>
    <div class="vb-filter-eight-header">
      <div>
        <span>Example 08</span>
        <h3>Portfolio Search and Category Filter</h3>
        <p>Filter case studies by project type, then search inside the visible portfolio cards.</p>
      </div>

      <div class="vb-filter-eight-mini">
        <small>Visible projects</small>
        <strong data-vb-filter-eight-count>8 projects</strong>
      </div>
    </div>

    <div class="vb-filter-eight-toolbar">
      <div class="vb-filter-eight-cats">
        <button type="button" class="is-active" data-type="all">All</button>
        <button type="button" data-type="web">Web Design</button>
        <button type="button" data-type="brand">Branding</button>
        <button type="button" data-type="app">App UI</button>
        <button type="button" data-type="photo">Photography</button>
      </div>

      <div class="vb-filter-eight-search">
        <input type="search" placeholder="Search portfolio..." data-vb-filter-eight-input>
        <button type="button" data-vb-filter-eight-reset>Reset</button>
      </div>
    </div>

    <div class="vb-filter-eight-grid">
      <article data-project-type="web" data-project-text="web design corporate website responsive landing page">
        <div class="vb-filter-eight-image web-one"></div>
        <div>
          <small>Web Design</small>
          <h4>Corporate Website</h4>
          <p>Responsive service website with strong hero, CTA areas, and trust sections.</p>
        </div>
      </article>

      <article data-project-type="brand" data-project-text="branding logo visual identity color system packaging">
        <div class="vb-filter-eight-image brand-one"></div>
        <div>
          <small>Branding</small>
          <h4>Visual Identity</h4>
          <p>Logo direction, color system, typography, and reusable brand elements.</p>
        </div>
      </article>

      <article data-project-type="app" data-project-text="app ui dashboard product interface analytics saas">
        <div class="vb-filter-eight-image app-one"></div>
        <div>
          <small>App UI</small>
          <h4>SaaS Dashboard</h4>
          <p>Analytics widgets, product navigation, metric cards, and app panels.</p>
        </div>
      </article>

      <article data-project-type="photo" data-project-text="photography product photos lifestyle campaign studio">
        <div class="vb-filter-eight-image photo-one"></div>
        <div>
          <small>Photography</small>
          <h4>Product Campaign</h4>
          <p>Studio-style product shots, lifestyle visuals, and promotional imagery.</p>
        </div>
      </article>

      <article data-project-type="web" data-project-text="web design ecommerce shop catalog checkout product">
        <div class="vb-filter-eight-image web-two"></div>
        <div>
          <small>Web Design</small>
          <h4>Ecommerce Store</h4>
          <p>Product grid, checkout flow, category pages, and modern shop UI.</p>
        </div>
      </article>

      <article data-project-type="brand" data-project-text="branding social media kit content templates brand">
        <div class="vb-filter-eight-image brand-two"></div>
        <div>
          <small>Branding</small>
          <h4>Social Media Kit</h4>
          <p>Reusable social templates, campaign graphics, and brand content blocks.</p>
        </div>
      </article>

      <article data-project-type="app" data-project-text="app ui mobile onboarding screens fitness tracking">
        <div class="vb-filter-eight-image app-two"></div>
        <div>
          <small>App UI</small>
          <h4>Mobile Onboarding</h4>
          <p>App introduction screens, feature slides, signup flow, and user guidance.</p>
        </div>
      </article>

      <article data-project-type="photo" data-project-text="photography architecture interior real estate portfolio">
        <div class="vb-filter-eight-image photo-two"></div>
        <div>
          <small>Photography</small>
          <h4>Interior Photos</h4>
          <p>Architecture and interior visuals for real estate, design, and portfolio use.</p>
        </div>
      </article>
    </div>

    <div class="vb-filter-eight-empty" data-vb-filter-eight-empty>
      <strong>No projects matched your filters.</strong>
      <p>Try another category or search for website, branding, app, dashboard, product, mobile, or photography.</p>
    </div>
  </div>
</div>

<style>
.vb-filter-eight-demo,
.vb-filter-eight-demo * {
  box-sizing: border-box;
}

.vb-filter-eight-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 18%, rgba(251, 113, 133, 0.20), transparent 34%),
    radial-gradient(circle at 86% 14%, rgba(249, 115, 22, 0.18), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #fff7ed 52%, #ffffff 100%) !important;
  border: 1px solid rgba(253, 164, 175, 0.48);
  box-shadow: 0 24px 70px rgba(136, 19, 55, 0.12);
}

.vb-filter-eight-portfolio {
  max-width: 1120px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background: #111827;
  border: 1px solid rgba(255,255,255,0.10);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.26);
}

.vb-filter-eight-header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 170px;
  gap: 24px;
  align-items: end;
  margin-bottom: 24px;
}

.vb-filter-eight-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(251, 113, 133, 0.15);
  color: #fecdd3 !important;
  -webkit-text-fill-color: #fecdd3 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-eight-header h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-eight-header p {
  max-width: 660px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-filter-eight-mini {
  padding: 16px;
  border-radius: 22px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-filter-eight-mini small {
  display: block;
  margin-bottom: 6px;
  color: #fecdd3 !important;
  -webkit-text-fill-color: #fecdd3 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-eight-mini strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-eight-toolbar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(270px, 360px);
  gap: 12px;
  margin-bottom: 18px;
}

.vb-filter-eight-cats {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 10px;
  border-radius: 20px;
  background: rgba(255,255,255,0.07);
}

.vb-filter-eight-cats button {
  min-height: 40px;
  padding: 9px 13px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 999px;
  background: rgba(255,255,255,0.08);
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 13px;
  font-weight: 900;
  cursor: pointer;
}

.vb-filter-eight-cats button.is-active,
.vb-filter-eight-cats button:hover {
  background: linear-gradient(135deg, #fb7185, #f97316);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-eight-search {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 8px;
  padding: 10px;
  border-radius: 20px;
  background: rgba(255,255,255,0.07);
}

.vb-filter-eight-search input {
  min-height: 40px;
  width: 100%;
  padding: 0 12px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 999px;
  outline: 0;
  background: rgba(255,255,255,0.08);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-filter-eight-search input::placeholder {
  color: rgba(255,255,255,0.58);
  -webkit-text-fill-color: rgba(255,255,255,0.58);
}

.vb-filter-eight-search button {
  min-height: 40px;
  padding: 0 13px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-eight-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
}

.vb-filter-eight-grid article {
  overflow: hidden;
  border-radius: 22px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.11);
}

.vb-filter-eight-grid article.is-hidden {
  display: none;
}

.vb-filter-eight-image {
  min-height: 150px;
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #fb7185, #f97316) !important;
}

.vb-filter-eight-image.brand-one {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #a855f7, #ec4899) !important;
}

.vb-filter-eight-image.app-one {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #2563eb, #06b6d4) !important;
}

.vb-filter-eight-image.photo-one {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #78350f, #f59e0b) !important;
}

.vb-filter-eight-image.web-two {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #16a34a, #0f766e) !important;
}

.vb-filter-eight-image.brand-two {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #be123c, #7c3aed) !important;
}

.vb-filter-eight-image.app-two {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #0f172a, #6366f1) !important;
}

.vb-filter-eight-image.photo-two {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #475569, #94a3b8) !important;
}

.vb-filter-eight-grid article > div:last-child {
  padding: 16px;
}

.vb-filter-eight-grid small {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 6px 9px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #fecdd3 !important;
  -webkit-text-fill-color: #fecdd3 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-eight-grid h4 {
  margin: 0 0 8px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 21px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-eight-grid p {
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 13px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-filter-eight-empty {
  display: none;
  margin-top: 16px;
  padding: 22px;
  border-radius: 22px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-filter-eight-empty.is-visible {
  display: block;
}

.vb-filter-eight-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-eight-empty p {
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb-filter-eight-header,
  .vb-filter-eight-toolbar {
    grid-template-columns: 1fr;
  }

  .vb-filter-eight-mini {
    width: fit-content;
  }

  .vb-filter-eight-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-filter-eight-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-eight-portfolio {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-eight-header h3 {
    font-size: 38px !important;
  }

  .vb-filter-eight-search {
    grid-template-columns: 1fr;
  }

  .vb-filter-eight-search button {
    width: 100%;
  }

  .vb-filter-eight-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const portfolio = document.querySelector("[data-vb-filter-eight]");
  if (!portfolio) return;

  const buttons = portfolio.querySelectorAll("[data-type]");
  const input = portfolio.querySelector("[data-vb-filter-eight-input]");
  const reset = portfolio.querySelector("[data-vb-filter-eight-reset]");
  const count = portfolio.querySelector("[data-vb-filter-eight-count]");
  const empty = portfolio.querySelector("[data-vb-filter-eight-empty]");
  const projects = Array.from(portfolio.querySelectorAll("[data-project-type]"));

  let activeType = "all";

  function updatePortfolio() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    projects.forEach(function (project) {
      const type = project.getAttribute("data-project-type");
      const text = project.getAttribute("data-project-text").toLowerCase();
      const title = project.querySelector("h4").textContent.toLowerCase();
      const description = project.querySelector("p").textContent.toLowerCase();

      const typeMatch = activeType === "all" || type === activeType;
      const queryMatch = text.includes(query) || title.includes(query) || description.includes(query);
      const shouldShow = typeMatch && queryMatch;

      project.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 project" : visible + " projects";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeType = button.getAttribute("data-type");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updatePortfolio();
    });
  });

  input.addEventListener("input", updatePortfolio);

  reset.addEventListener("click", function () {
    activeType = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-type") === "all");
    });

    input.focus();
    updatePortfolio();
  });

  updatePortfolio();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const portfolio = document.querySelector("[data-vb-filter-eight]");
  if (!portfolio) return;

  const buttons = portfolio.querySelectorAll("[data-type]");
  const input = portfolio.querySelector("[data-vb-filter-eight-input]");
  const reset = portfolio.querySelector("[data-vb-filter-eight-reset]");
  const count = portfolio.querySelector("[data-vb-filter-eight-count]");
  const empty = portfolio.querySelector("[data-vb-filter-eight-empty]");
  const projects = Array.from(portfolio.querySelectorAll("[data-project-type]"));

  let activeType = "all";

  function updatePortfolio() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    projects.forEach(function (project) {
      const type = project.getAttribute("data-project-type");
      const text = project.getAttribute("data-project-text").toLowerCase();
      const title = project.querySelector("h4").textContent.toLowerCase();
      const description = project.querySelector("p").textContent.toLowerCase();

      const typeMatch = activeType === "all" || type === activeType;
      const queryMatch = text.includes(query) || title.includes(query) || description.includes(query);
      const shouldShow = typeMatch && queryMatch;

      project.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 project" : visible + " projects";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeType = button.getAttribute("data-type");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updatePortfolio();
    });
  });

  input.addEventListener("input", updatePortfolio);

  reset.addEventListener("click", function () {
    activeType = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-type") === "all");
    });

    input.focus();
    updatePortfolio();
  });

  updatePortfolio();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-eight-demo"&gt;
  &lt;div class="vb-filter-eight-portfolio" data-vb-filter-eight&gt;
    &lt;div class="vb-filter-eight-header"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 08&lt;/span&gt;
        &lt;h3&gt;Portfolio Search and Category Filter&lt;/h3&gt;
        &lt;p&gt;Filter case studies by project type, then search inside the visible portfolio cards.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-eight-mini"&gt;
        &lt;small&gt;Visible projects&lt;/small&gt;
        &lt;strong data-vb-filter-eight-count&gt;8 projects&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-eight-toolbar"&gt;
      &lt;div class="vb-filter-eight-cats"&gt;
        &lt;button type="button" class="is-active" data-type="all"&gt;All&lt;/button&gt;
        &lt;button type="button" data-type="web"&gt;Web Design&lt;/button&gt;
        &lt;button type="button" data-type="brand"&gt;Branding&lt;/button&gt;
        &lt;button type="button" data-type="app"&gt;App UI&lt;/button&gt;
        &lt;button type="button" data-type="photo"&gt;Photography&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-eight-search"&gt;
        &lt;input type="search" placeholder="Search portfolio..." data-vb-filter-eight-input&gt;
        &lt;button type="button" data-vb-filter-eight-reset&gt;Reset&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-eight-grid"&gt;
      &lt;article data-project-type="web" data-project-text="web design corporate website responsive landing page"&gt;
        &lt;div class="vb-filter-eight-image web-one"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Web Design&lt;/small&gt;
          &lt;h4&gt;Corporate Website&lt;/h4&gt;
          &lt;p&gt;Responsive service website with strong hero, CTA areas, and trust sections.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-project-type="brand" data-project-text="branding logo visual identity color system packaging"&gt;
        &lt;div class="vb-filter-eight-image brand-one"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Branding&lt;/small&gt;
          &lt;h4&gt;Visual Identity&lt;/h4&gt;
          &lt;p&gt;Logo direction, color system, typography, and reusable brand elements.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-project-type="app" data-project-text="app ui dashboard product interface analytics saas"&gt;
        &lt;div class="vb-filter-eight-image app-one"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;App UI&lt;/small&gt;
          &lt;h4&gt;SaaS Dashboard&lt;/h4&gt;
          &lt;p&gt;Analytics widgets, product navigation, metric cards, and app panels.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-project-type="photo" data-project-text="photography product photos lifestyle campaign studio"&gt;
        &lt;div class="vb-filter-eight-image photo-one"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Photography&lt;/small&gt;
          &lt;h4&gt;Product Campaign&lt;/h4&gt;
          &lt;p&gt;Studio-style product shots, lifestyle visuals, and promotional imagery.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-project-type="web" data-project-text="web design ecommerce shop catalog checkout product"&gt;
        &lt;div class="vb-filter-eight-image web-two"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Web Design&lt;/small&gt;
          &lt;h4&gt;Ecommerce Store&lt;/h4&gt;
          &lt;p&gt;Product grid, checkout flow, category pages, and modern shop UI.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-project-type="brand" data-project-text="branding social media kit content templates brand"&gt;
        &lt;div class="vb-filter-eight-image brand-two"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Branding&lt;/small&gt;
          &lt;h4&gt;Social Media Kit&lt;/h4&gt;
          &lt;p&gt;Reusable social templates, campaign graphics, and brand content blocks.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-project-type="app" data-project-text="app ui mobile onboarding screens fitness tracking"&gt;
        &lt;div class="vb-filter-eight-image app-two"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;App UI&lt;/small&gt;
          &lt;h4&gt;Mobile Onboarding&lt;/h4&gt;
          &lt;p&gt;App introduction screens, feature slides, signup flow, and user guidance.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-project-type="photo" data-project-text="photography architecture interior real estate portfolio"&gt;
        &lt;div class="vb-filter-eight-image photo-two"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Photography&lt;/small&gt;
          &lt;h4&gt;Interior Photos&lt;/h4&gt;
          &lt;p&gt;Architecture and interior visuals for real estate, design, and portfolio use.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-eight-empty" data-vb-filter-eight-empty&gt;
      &lt;strong&gt;No projects matched your filters.&lt;/strong&gt;
      &lt;p&gt;Try another category or search for website, branding, app, dashboard, product, mobile, or photography.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-eight-demo,
.vb-filter-eight-demo * {
  box-sizing: border-box;
}

.vb-filter-eight-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 18%, rgba(251, 113, 133, 0.20), transparent 34%),
    radial-gradient(circle at 86% 14%, rgba(249, 115, 22, 0.18), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #fff7ed 52%, #ffffff 100%) !important;
  border: 1px solid rgba(253, 164, 175, 0.48);
  box-shadow: 0 24px 70px rgba(136, 19, 55, 0.12);
}

.vb-filter-eight-portfolio {
  max-width: 1120px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background: #111827;
  border: 1px solid rgba(255,255,255,0.10);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.26);
}

.vb-filter-eight-header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 170px;
  gap: 24px;
  align-items: end;
  margin-bottom: 24px;
}

.vb-filter-eight-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(251, 113, 133, 0.15);
  color: #fecdd3 !important;
  -webkit-text-fill-color: #fecdd3 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-eight-header h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-eight-header p {
  max-width: 660px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-filter-eight-mini {
  padding: 16px;
  border-radius: 22px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-filter-eight-mini small {
  display: block;
  margin-bottom: 6px;
  color: #fecdd3 !important;
  -webkit-text-fill-color: #fecdd3 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-eight-mini strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-eight-toolbar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(270px, 360px);
  gap: 12px;
  margin-bottom: 18px;
}

.vb-filter-eight-cats {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding: 10px;
  border-radius: 20px;
  background: rgba(255,255,255,0.07);
}

.vb-filter-eight-cats button {
  min-height: 40px;
  padding: 9px 13px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 999px;
  background: rgba(255,255,255,0.08);
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 13px;
  font-weight: 900;
  cursor: pointer;
}

.vb-filter-eight-cats button.is-active,
.vb-filter-eight-cats button:hover {
  background: linear-gradient(135deg, #fb7185, #f97316);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-eight-search {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 8px;
  padding: 10px;
  border-radius: 20px;
  background: rgba(255,255,255,0.07);
}

.vb-filter-eight-search input {
  min-height: 40px;
  width: 100%;
  padding: 0 12px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 999px;
  outline: 0;
  background: rgba(255,255,255,0.08);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-filter-eight-search input::placeholder {
  color: rgba(255,255,255,0.58);
  -webkit-text-fill-color: rgba(255,255,255,0.58);
}

.vb-filter-eight-search button {
  min-height: 40px;
  padding: 0 13px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-eight-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
}

.vb-filter-eight-grid article {
  overflow: hidden;
  border-radius: 22px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.11);
}

.vb-filter-eight-grid article.is-hidden {
  display: none;
}

.vb-filter-eight-image {
  min-height: 150px;
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #fb7185, #f97316) !important;
}

.vb-filter-eight-image.brand-one {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #a855f7, #ec4899) !important;
}

.vb-filter-eight-image.app-one {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #2563eb, #06b6d4) !important;
}

.vb-filter-eight-image.photo-one {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #78350f, #f59e0b) !important;
}

.vb-filter-eight-image.web-two {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #16a34a, #0f766e) !important;
}

.vb-filter-eight-image.brand-two {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #be123c, #7c3aed) !important;
}

.vb-filter-eight-image.app-two {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #0f172a, #6366f1) !important;
}

.vb-filter-eight-image.photo-two {
  background:
    radial-gradient(circle at 30% 20%, rgba(255,255,255,0.36), transparent 32%),
    linear-gradient(135deg, #475569, #94a3b8) !important;
}

.vb-filter-eight-grid article &gt; div:last-child {
  padding: 16px;
}

.vb-filter-eight-grid small {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 6px 9px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #fecdd3 !important;
  -webkit-text-fill-color: #fecdd3 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-eight-grid h4 {
  margin: 0 0 8px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 21px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-eight-grid p {
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 13px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-filter-eight-empty {
  display: none;
  margin-top: 16px;
  padding: 22px;
  border-radius: 22px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-filter-eight-empty.is-visible {
  display: block;
}

.vb-filter-eight-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-eight-empty p {
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb-filter-eight-header,
  .vb-filter-eight-toolbar {
    grid-template-columns: 1fr;
  }

  .vb-filter-eight-mini {
    width: fit-content;
  }

  .vb-filter-eight-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-filter-eight-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-eight-portfolio {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-eight-header h3 {
    font-size: 38px !important;
  }

  .vb-filter-eight-search {
    grid-template-columns: 1fr;
  }

  .vb-filter-eight-search button {
    width: 100%;
  }

  .vb-filter-eight-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This portfolio search and category filter is useful for creative agencies, freelancers, design studios, photography websites, developer portfolios, case study pages, and project galleries where visitors need to browse work by type and keyword.</p>



<h2 class="wp-block-heading">9. Job Listings Search Filter</h2>



<p class="wp-block-paragraph"><strong>A job listings search filter</strong> helps visitors narrow open roles by title, department, location, work type, or skill keyword. This pattern is useful for career pages, recruiting websites, company job boards, SaaS hiring pages, HR dashboards, and freelance marketplaces.</p>



<p class="wp-block-paragraph">This example filters job cards with a live search input and department buttons. Users can search inside the selected department, reset all filters, and see the visible job count update instantly.</p>



<ul class="wp-block-list">
<li>Live job listing search</li>
<li>Department filter buttons</li>
<li>Remote, hybrid, and office labels</li>
<li>Dynamic visible job count</li>
<li>Useful for career pages, HR tools, job boards, and hiring sections</li>
</ul>



<div class="vb-filter-nine-demo">
  <div class="vb-filter-nine-jobs" data-vb-filter-nine>
    <div class="vb-filter-nine-header">
      <div>
        <span>Example 09</span>
        <h3>Job Listings Search Filter</h3>
        <p>Search open roles by title, department, location, work type, or skill keyword.</p>
      </div>

      <div class="vb-filter-nine-count">
        <small>Open roles</small>
        <strong data-vb-filter-nine-count>8 jobs</strong>
      </div>
    </div>

    <div class="vb-filter-nine-controls">
      <div class="vb-filter-nine-input">
        <label for="vb-filter-nine-input">Search jobs</label>
        <input id="vb-filter-nine-input" type="search" placeholder="Search frontend, remote, design, sales..." data-vb-filter-nine-input>
      </div>

      <div class="vb-filter-nine-buttons">
        <button type="button" class="is-active" data-department="all">All</button>
        <button type="button" data-department="engineering">Engineering</button>
        <button type="button" data-department="design">Design</button>
        <button type="button" data-department="marketing">Marketing</button>
        <button type="button" data-department="sales">Sales</button>
      </div>

      <button type="button" class="vb-filter-nine-reset" data-vb-filter-nine-reset>Reset</button>
    </div>

    <div class="vb-filter-nine-list">
      <article data-job-department="engineering" data-job-text="frontend developer engineering javascript react remote ui components">
        <div>
          <small>Engineering</small>
          <h4>Frontend Developer</h4>
          <p>Build reusable JavaScript components, responsive interfaces, and product UI systems.</p>
        </div>
        <span>Remote</span>
      </article>

      <article data-job-department="design" data-job-text="product designer design figma ui ux hybrid interface">
        <div>
          <small>Design</small>
          <h4>Product Designer</h4>
          <p>Design modern app screens, design systems, user flows, and conversion-focused UI.</p>
        </div>
        <span>Hybrid</span>
      </article>

      <article data-job-department="marketing" data-job-text="seo content strategist marketing blog search engine remote">
        <div>
          <small>Marketing</small>
          <h4>SEO Content Strategist</h4>
          <p>Plan search-focused content, optimize blog pages, and improve organic visibility.</p>
        </div>
        <span>Remote</span>
      </article>

      <article data-job-department="sales" data-job-text="account executive sales customers crm pipeline office">
        <div>
          <small>Sales</small>
          <h4>Account Executive</h4>
          <p>Manage leads, customer conversations, CRM pipeline, proposals, and sales demos.</p>
        </div>
        <span>Office</span>
      </article>

      <article data-job-department="engineering" data-job-text="backend engineer engineering node api database cloud hybrid">
        <div>
          <small>Engineering</small>
          <h4>Backend Engineer</h4>
          <p>Create APIs, database structures, integrations, authentication, and scalable services.</p>
        </div>
        <span>Hybrid</span>
      </article>

      <article data-job-department="design" data-job-text="brand designer design visual identity landing pages social">
        <div>
          <small>Design</small>
          <h4>Brand Designer</h4>
          <p>Create visual identity assets, campaign graphics, social templates, and landing visuals.</p>
        </div>
        <span>Remote</span>
      </article>

      <article data-job-department="marketing" data-job-text="growth marketer marketing analytics ads funnel landing page">
        <div>
          <small>Marketing</small>
          <h4>Growth Marketer</h4>
          <p>Improve acquisition funnels, landing pages, experiments, analytics, and paid campaigns.</p>
        </div>
        <span>Office</span>
      </article>

      <article data-job-department="sales" data-job-text="customer success sales support onboarding account remote">
        <div>
          <small>Sales</small>
          <h4>Customer Success Manager</h4>
          <p>Support onboarding, improve account health, answer product questions, and reduce churn.</p>
        </div>
        <span>Remote</span>
      </article>
    </div>

    <div class="vb-filter-nine-empty" data-vb-filter-nine-empty>
      <strong>No jobs found.</strong>
      <p>Try another department or search for frontend, designer, SEO, sales, backend, remote, or hybrid.</p>
    </div>
  </div>
</div>

<style>
.vb-filter-nine-demo,
.vb-filter-nine-demo * {
  box-sizing: border-box;
}

.vb-filter-nine-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 18%, rgba(37, 99, 235, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(16, 185, 129, 0.18), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 52%, #ffffff 100%) !important;
  border: 1px solid rgba(191, 219, 254, 0.52);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.12);
}

.vb-filter-nine-jobs {
  max-width: 1120px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background:
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-nine-header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 170px;
  gap: 24px;
  align-items: end;
  margin-bottom: 24px;
}

.vb-filter-nine-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-nine-header h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-nine-header p {
  max-width: 660px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-filter-nine-count {
  padding: 16px;
  border-radius: 22px;
  background: #0f172a;
}

.vb-filter-nine-count small {
  display: block;
  margin-bottom: 6px;
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-nine-count strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 21px;
  font-weight: 950;
}

.vb-filter-nine-controls {
  display: grid;
  grid-template-columns: minmax(280px, 0.85fr) minmax(0, 1.15fr) auto;
  gap: 12px;
  align-items: end;
  margin-bottom: 18px;
  padding: 14px;
  border-radius: 24px;
  background: #f1f5f9;
}

.vb-filter-nine-input label {
  display: block;
  margin-bottom: 8px;
  color: #1e293b !important;
  -webkit-text-fill-color: #1e293b !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-nine-input input {
  width: 100%;
  min-height: 52px;
  padding: 0 15px;
  border: 1px solid rgba(148, 163, 184, 0.28);
  border-radius: 17px;
  outline: 0;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-nine-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-filter-nine-buttons button,
.vb-filter-nine-reset {
  min-height: 52px;
  padding: 10px 14px;
  border: 0;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-nine-buttons button {
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  box-shadow: 0 8px 20px rgba(15, 23, 42, 0.06);
}

.vb-filter-nine-buttons button.is-active,
.vb-filter-nine-buttons button:hover {
  background: linear-gradient(135deg, #2563eb, #10b981);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-nine-reset {
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  white-space: nowrap;
}

.vb-filter-nine-list {
  display: grid;
  gap: 12px;
}

.vb-filter-nine-list article {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 18px;
  align-items: center;
  padding: 20px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.07);
}

.vb-filter-nine-list article.is-hidden {
  display: none;
}

.vb-filter-nine-list small {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-nine-list h4 {
  margin: 0 0 8px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-nine-list p {
  max-width: 720px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-filter-nine-list article > span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 86px;
  min-height: 40px;
  padding: 9px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-filter-nine-empty {
  display: none;
  margin-top: 16px;
  padding: 22px;
  border-radius: 22px;
  background: #eff6ff;
  border: 1px solid rgba(147, 197, 253, 0.40);
}

.vb-filter-nine-empty.is-visible {
  display: block;
}

.vb-filter-nine-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-nine-empty p {
  margin: 0 !important;
  color: #1e40af !important;
  -webkit-text-fill-color: #1e40af !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb-filter-nine-header,
  .vb-filter-nine-controls {
    grid-template-columns: 1fr;
  }

  .vb-filter-nine-count {
    width: fit-content;
  }
}

@media (max-width: 640px) {
  .vb-filter-nine-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-nine-jobs {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-nine-header h3 {
    font-size: 38px !important;
  }

  .vb-filter-nine-buttons,
  .vb-filter-nine-controls {
    display: grid;
    grid-template-columns: 1fr;
  }

  .vb-filter-nine-list article {
    grid-template-columns: 1fr;
  }

  .vb-filter-nine-list article > span {
    width: fit-content;
  }
}
</style>

<script>
(function () {
  const jobs = document.querySelector("[data-vb-filter-nine]");
  if (!jobs) return;

  const input = jobs.querySelector("[data-vb-filter-nine-input]");
  const buttons = jobs.querySelectorAll("[data-department]");
  const reset = jobs.querySelector("[data-vb-filter-nine-reset]");
  const count = jobs.querySelector("[data-vb-filter-nine-count]");
  const empty = jobs.querySelector("[data-vb-filter-nine-empty]");
  const cards = Array.from(jobs.querySelectorAll("[data-job-department]"));

  let activeDepartment = "all";

  function updateJobs() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    cards.forEach(function (card) {
      const department = card.getAttribute("data-job-department");
      const text = card.getAttribute("data-job-text").toLowerCase();
      const fullText = card.textContent.toLowerCase();

      const departmentMatch = activeDepartment === "all" || department === activeDepartment;
      const queryMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = departmentMatch && queryMatch;

      card.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 job" : visible + " jobs";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeDepartment = button.getAttribute("data-department");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateJobs();
    });
  });

  input.addEventListener("input", updateJobs);

  reset.addEventListener("click", function () {
    activeDepartment = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-department") === "all");
    });

    input.focus();
    updateJobs();
  });

  updateJobs();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const jobs = document.querySelector("[data-vb-filter-nine]");
  if (!jobs) return;

  const input = jobs.querySelector("[data-vb-filter-nine-input]");
  const buttons = jobs.querySelectorAll("[data-department]");
  const reset = jobs.querySelector("[data-vb-filter-nine-reset]");
  const count = jobs.querySelector("[data-vb-filter-nine-count]");
  const empty = jobs.querySelector("[data-vb-filter-nine-empty]");
  const cards = Array.from(jobs.querySelectorAll("[data-job-department]"));

  let activeDepartment = "all";

  function updateJobs() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    cards.forEach(function (card) {
      const department = card.getAttribute("data-job-department");
      const text = card.getAttribute("data-job-text").toLowerCase();
      const fullText = card.textContent.toLowerCase();

      const departmentMatch = activeDepartment === "all" || department === activeDepartment;
      const queryMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = departmentMatch && queryMatch;

      card.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 job" : visible + " jobs";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeDepartment = button.getAttribute("data-department");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateJobs();
    });
  });

  input.addEventListener("input", updateJobs);

  reset.addEventListener("click", function () {
    activeDepartment = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-department") === "all");
    });

    input.focus();
    updateJobs();
  });

  updateJobs();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-nine-demo"&gt;
  &lt;div class="vb-filter-nine-jobs" data-vb-filter-nine&gt;
    &lt;div class="vb-filter-nine-header"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 09&lt;/span&gt;
        &lt;h3&gt;Job Listings Search Filter&lt;/h3&gt;
        &lt;p&gt;Search open roles by title, department, location, work type, or skill keyword.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-nine-count"&gt;
        &lt;small&gt;Open roles&lt;/small&gt;
        &lt;strong data-vb-filter-nine-count&gt;8 jobs&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-nine-controls"&gt;
      &lt;div class="vb-filter-nine-input"&gt;
        &lt;label for="vb-filter-nine-input"&gt;Search jobs&lt;/label&gt;
        &lt;input id="vb-filter-nine-input" type="search" placeholder="Search frontend, remote, design, sales..." data-vb-filter-nine-input&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-nine-buttons"&gt;
        &lt;button type="button" class="is-active" data-department="all"&gt;All&lt;/button&gt;
        &lt;button type="button" data-department="engineering"&gt;Engineering&lt;/button&gt;
        &lt;button type="button" data-department="design"&gt;Design&lt;/button&gt;
        &lt;button type="button" data-department="marketing"&gt;Marketing&lt;/button&gt;
        &lt;button type="button" data-department="sales"&gt;Sales&lt;/button&gt;
      &lt;/div&gt;

      &lt;button type="button" class="vb-filter-nine-reset" data-vb-filter-nine-reset&gt;Reset&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-nine-list"&gt;
      &lt;article data-job-department="engineering" data-job-text="frontend developer engineering javascript react remote ui components"&gt;
        &lt;div&gt;
          &lt;small&gt;Engineering&lt;/small&gt;
          &lt;h4&gt;Frontend Developer&lt;/h4&gt;
          &lt;p&gt;Build reusable JavaScript components, responsive interfaces, and product UI systems.&lt;/p&gt;
        &lt;/div&gt;
        &lt;span&gt;Remote&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-job-department="design" data-job-text="product designer design figma ui ux hybrid interface"&gt;
        &lt;div&gt;
          &lt;small&gt;Design&lt;/small&gt;
          &lt;h4&gt;Product Designer&lt;/h4&gt;
          &lt;p&gt;Design modern app screens, design systems, user flows, and conversion-focused UI.&lt;/p&gt;
        &lt;/div&gt;
        &lt;span&gt;Hybrid&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-job-department="marketing" data-job-text="seo content strategist marketing blog search engine remote"&gt;
        &lt;div&gt;
          &lt;small&gt;Marketing&lt;/small&gt;
          &lt;h4&gt;SEO Content Strategist&lt;/h4&gt;
          &lt;p&gt;Plan search-focused content, optimize blog pages, and improve organic visibility.&lt;/p&gt;
        &lt;/div&gt;
        &lt;span&gt;Remote&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-job-department="sales" data-job-text="account executive sales customers crm pipeline office"&gt;
        &lt;div&gt;
          &lt;small&gt;Sales&lt;/small&gt;
          &lt;h4&gt;Account Executive&lt;/h4&gt;
          &lt;p&gt;Manage leads, customer conversations, CRM pipeline, proposals, and sales demos.&lt;/p&gt;
        &lt;/div&gt;
        &lt;span&gt;Office&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-job-department="engineering" data-job-text="backend engineer engineering node api database cloud hybrid"&gt;
        &lt;div&gt;
          &lt;small&gt;Engineering&lt;/small&gt;
          &lt;h4&gt;Backend Engineer&lt;/h4&gt;
          &lt;p&gt;Create APIs, database structures, integrations, authentication, and scalable services.&lt;/p&gt;
        &lt;/div&gt;
        &lt;span&gt;Hybrid&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-job-department="design" data-job-text="brand designer design visual identity landing pages social"&gt;
        &lt;div&gt;
          &lt;small&gt;Design&lt;/small&gt;
          &lt;h4&gt;Brand Designer&lt;/h4&gt;
          &lt;p&gt;Create visual identity assets, campaign graphics, social templates, and landing visuals.&lt;/p&gt;
        &lt;/div&gt;
        &lt;span&gt;Remote&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-job-department="marketing" data-job-text="growth marketer marketing analytics ads funnel landing page"&gt;
        &lt;div&gt;
          &lt;small&gt;Marketing&lt;/small&gt;
          &lt;h4&gt;Growth Marketer&lt;/h4&gt;
          &lt;p&gt;Improve acquisition funnels, landing pages, experiments, analytics, and paid campaigns.&lt;/p&gt;
        &lt;/div&gt;
        &lt;span&gt;Office&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-job-department="sales" data-job-text="customer success sales support onboarding account remote"&gt;
        &lt;div&gt;
          &lt;small&gt;Sales&lt;/small&gt;
          &lt;h4&gt;Customer Success Manager&lt;/h4&gt;
          &lt;p&gt;Support onboarding, improve account health, answer product questions, and reduce churn.&lt;/p&gt;
        &lt;/div&gt;
        &lt;span&gt;Remote&lt;/span&gt;
      &lt;/article&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-nine-empty" data-vb-filter-nine-empty&gt;
      &lt;strong&gt;No jobs found.&lt;/strong&gt;
      &lt;p&gt;Try another department or search for frontend, designer, SEO, sales, backend, remote, or hybrid.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-nine-demo,
.vb-filter-nine-demo * {
  box-sizing: border-box;
}

.vb-filter-nine-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 18%, rgba(37, 99, 235, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(16, 185, 129, 0.18), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 52%, #ffffff 100%) !important;
  border: 1px solid rgba(191, 219, 254, 0.52);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.12);
}

.vb-filter-nine-jobs {
  max-width: 1120px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background:
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-nine-header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 170px;
  gap: 24px;
  align-items: end;
  margin-bottom: 24px;
}

.vb-filter-nine-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-nine-header h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-nine-header p {
  max-width: 660px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-filter-nine-count {
  padding: 16px;
  border-radius: 22px;
  background: #0f172a;
}

.vb-filter-nine-count small {
  display: block;
  margin-bottom: 6px;
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-nine-count strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 21px;
  font-weight: 950;
}

.vb-filter-nine-controls {
  display: grid;
  grid-template-columns: minmax(280px, 0.85fr) minmax(0, 1.15fr) auto;
  gap: 12px;
  align-items: end;
  margin-bottom: 18px;
  padding: 14px;
  border-radius: 24px;
  background: #f1f5f9;
}

.vb-filter-nine-input label {
  display: block;
  margin-bottom: 8px;
  color: #1e293b !important;
  -webkit-text-fill-color: #1e293b !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-nine-input input {
  width: 100%;
  min-height: 52px;
  padding: 0 15px;
  border: 1px solid rgba(148, 163, 184, 0.28);
  border-radius: 17px;
  outline: 0;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-nine-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-filter-nine-buttons button,
.vb-filter-nine-reset {
  min-height: 52px;
  padding: 10px 14px;
  border: 0;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-nine-buttons button {
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  box-shadow: 0 8px 20px rgba(15, 23, 42, 0.06);
}

.vb-filter-nine-buttons button.is-active,
.vb-filter-nine-buttons button:hover {
  background: linear-gradient(135deg, #2563eb, #10b981);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-nine-reset {
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  white-space: nowrap;
}

.vb-filter-nine-list {
  display: grid;
  gap: 12px;
}

.vb-filter-nine-list article {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 18px;
  align-items: center;
  padding: 20px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.07);
}

.vb-filter-nine-list article.is-hidden {
  display: none;
}

.vb-filter-nine-list small {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-nine-list h4 {
  margin: 0 0 8px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-nine-list p {
  max-width: 720px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-filter-nine-list article &gt; span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 86px;
  min-height: 40px;
  padding: 9px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-filter-nine-empty {
  display: none;
  margin-top: 16px;
  padding: 22px;
  border-radius: 22px;
  background: #eff6ff;
  border: 1px solid rgba(147, 197, 253, 0.40);
}

.vb-filter-nine-empty.is-visible {
  display: block;
}

.vb-filter-nine-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-nine-empty p {
  margin: 0 !important;
  color: #1e40af !important;
  -webkit-text-fill-color: #1e40af !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb-filter-nine-header,
  .vb-filter-nine-controls {
    grid-template-columns: 1fr;
  }

  .vb-filter-nine-count {
    width: fit-content;
  }
}

@media (max-width: 640px) {
  .vb-filter-nine-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-nine-jobs {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-nine-header h3 {
    font-size: 38px !important;
  }

  .vb-filter-nine-buttons,
  .vb-filter-nine-controls {
    display: grid;
    grid-template-columns: 1fr;
  }

  .vb-filter-nine-list article {
    grid-template-columns: 1fr;
  }

  .vb-filter-nine-list article &gt; span {
    width: fit-content;
  }
}</pre>



<p class="wp-block-paragraph">This job listings search filter is useful for career pages, hiring sections, company job boards, HR dashboards, recruitment websites, and marketplaces where users need to search open roles by department, location, title, or work type.</p>



<h2 class="wp-block-heading">10. Recipe Search Filter</h2>



<p class="wp-block-paragraph"><strong>A recipe search filter</strong> helps users find meals by ingredient, cuisine, meal type, difficulty, or dietary keyword. This pattern is useful for food blogs, recipe websites, cooking apps, meal planning tools, restaurant pages, and lifestyle content hubs.</p>



<p class="wp-block-paragraph">This example uses recipe cards with meal type buttons, a live ingredient search, cook time labels, and a visual no-results state. Users can combine a meal category with a search keyword.</p>



<ul class="wp-block-list">
<li>Recipe card filtering</li>
<li>Meal type category buttons</li>
<li>Ingredient keyword search</li>
<li>Cook time and difficulty labels</li>
<li>Useful for food blogs, recipe apps, cooking websites, and meal planners</li>
</ul>



<div class="vb-filter-ten-demo">
  <div class="vb-filter-ten-kitchen" data-vb-filter-ten>
    <div class="vb-filter-ten-hero">
      <span>Example 10</span>
      <h3>Recipe Search Filter</h3>
      <p>Filter recipes by meal type and search for ingredients, cuisine, or difficulty.</p>
    </div>

    <div class="vb-filter-ten-bar">
      <div class="vb-filter-ten-search">
        <input type="search" placeholder="Search chicken, vegan, pasta, quick..." data-vb-filter-ten-input>
      </div>

      <div class="vb-filter-ten-types">
        <button type="button" class="is-active" data-meal="all">All</button>
        <button type="button" data-meal="breakfast">Breakfast</button>
        <button type="button" data-meal="lunch">Lunch</button>
        <button type="button" data-meal="dinner">Dinner</button>
        <button type="button" data-meal="dessert">Dessert</button>
      </div>

      <div class="vb-filter-ten-info">
        <strong data-vb-filter-ten-count>8 recipes</strong>
        <button type="button" data-vb-filter-ten-reset>Reset</button>
      </div>
    </div>

    <div class="vb-filter-ten-grid">
      <article data-meal-card="breakfast" data-recipe-text="breakfast oats berries yogurt healthy quick vegetarian">
        <div class="vb-filter-ten-photo oats"></div>
        <div>
          <small>Breakfast</small>
          <h4>Berry Yogurt Oats</h4>
          <p>Quick overnight oats with berries, yogurt, honey, and crunchy seeds.</p>
          <span>10 min · Easy</span>
        </div>
      </article>

      <article data-meal-card="lunch" data-recipe-text="lunch chicken wrap salad protein quick">
        <div class="vb-filter-ten-photo wrap"></div>
        <div>
          <small>Lunch</small>
          <h4>Chicken Salad Wrap</h4>
          <p>Fresh wrap with grilled chicken, greens, tomato, and creamy dressing.</p>
          <span>18 min · Easy</span>
        </div>
      </article>

      <article data-meal-card="dinner" data-recipe-text="dinner pasta tomato basil italian vegetarian">
        <div class="vb-filter-ten-photo pasta"></div>
        <div>
          <small>Dinner</small>
          <h4>Tomato Basil Pasta</h4>
          <p>Simple pasta with tomato sauce, basil, garlic, and parmesan.</p>
          <span>25 min · Medium</span>
        </div>
      </article>

      <article data-meal-card="dessert" data-recipe-text="dessert chocolate cake sweet baking">
        <div class="vb-filter-ten-photo cake"></div>
        <div>
          <small>Dessert</small>
          <h4>Chocolate Mini Cake</h4>
          <p>Rich mini cake with chocolate glaze, cocoa, and soft sponge layers.</p>
          <span>45 min · Medium</span>
        </div>
      </article>

      <article data-meal-card="breakfast" data-recipe-text="breakfast avocado toast eggs healthy quick">
        <div class="vb-filter-ten-photo toast"></div>
        <div>
          <small>Breakfast</small>
          <h4>Avocado Egg Toast</h4>
          <p>Toasted bread with avocado, egg, chili flakes, and lemon.</p>
          <span>12 min · Easy</span>
        </div>
      </article>

      <article data-meal-card="lunch" data-recipe-text="lunch vegan bowl rice vegetables tofu healthy">
        <div class="vb-filter-ten-photo bowl"></div>
        <div>
          <small>Lunch</small>
          <h4>Vegan Rice Bowl</h4>
          <p>Rice bowl with tofu, vegetables, sesame dressing, and fresh herbs.</p>
          <span>22 min · Easy</span>
        </div>
      </article>

      <article data-meal-card="dinner" data-recipe-text="dinner salmon fish potato lemon protein">
        <div class="vb-filter-ten-photo salmon"></div>
        <div>
          <small>Dinner</small>
          <h4>Lemon Salmon Plate</h4>
          <p>Salmon with roasted potatoes, lemon butter, and green vegetables.</p>
          <span>35 min · Medium</span>
        </div>
      </article>

      <article data-meal-card="dessert" data-recipe-text="dessert strawberry cream no bake sweet easy">
        <div class="vb-filter-ten-photo berry"></div>
        <div>
          <small>Dessert</small>
          <h4>Strawberry Cream Cups</h4>
          <p>No-bake dessert cups with strawberries, cream, and biscuit crumble.</p>
          <span>15 min · Easy</span>
        </div>
      </article>
    </div>

    <div class="vb-filter-ten-empty" data-vb-filter-ten-empty>
      <strong>No recipes found.</strong>
      <p>Try another meal type or search for pasta, chicken, vegan, salmon, chocolate, breakfast, or quick.</p>
    </div>
  </div>
</div>

<style>
.vb-filter-ten-demo,
.vb-filter-ten-demo * {
  box-sizing: border-box;
}

.vb-filter-ten-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 18%, rgba(251, 146, 60, 0.24), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(34, 197, 94, 0.18), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #f0fdf4 52%, #ffffff 100%) !important;
  border: 1px solid rgba(253, 186, 116, 0.48);
  box-shadow: 0 24px 70px rgba(124, 45, 18, 0.12);
}

.vb-filter-ten-kitchen {
  max-width: 1120px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 80% 12%, rgba(251, 146, 60, 0.12), transparent 34%),
    linear-gradient(135deg, #ffffff, #fffbeb) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-ten-hero {
  max-width: 780px;
  margin-bottom: 24px;
}

.vb-filter-ten-hero span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-ten-hero h3 {
  margin: 0 0 14px !important;
  color: #431407 !important;
  -webkit-text-fill-color: #431407 !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-ten-hero p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-filter-ten-bar {
  display: grid;
  grid-template-columns: minmax(260px, 0.8fr) minmax(0, 1.2fr) 170px;
  gap: 12px;
  align-items: center;
  margin-bottom: 18px;
  padding: 14px;
  border-radius: 24px;
  background: #431407;
}

.vb-filter-ten-search input {
  width: 100%;
  min-height: 52px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  outline: 0;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-ten-search input::placeholder {
  color: rgba(255,255,255,0.62);
  -webkit-text-fill-color: rgba(255,255,255,0.62);
}

.vb-filter-ten-types {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-filter-ten-types button {
  min-height: 40px;
  padding: 9px 13px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 999px;
  background: rgba(255,255,255,0.08);
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 13px;
  font-weight: 900;
  cursor: pointer;
}

.vb-filter-ten-types button.is-active,
.vb-filter-ten-types button:hover {
  background: linear-gradient(135deg, #f97316, #22c55e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-ten-info {
  display: grid;
  gap: 8px;
}

.vb-filter-ten-info strong {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 24px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-filter-ten-info button {
  min-height: 38px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-ten-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-filter-ten-grid article {
  overflow: hidden;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb-filter-ten-grid article.is-hidden {
  display: none;
}

.vb-filter-ten-photo {
  min-height: 140px;
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #f97316, #22c55e) !important;
}

.vb-filter-ten-photo.wrap {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #16a34a, #84cc16) !important;
}

.vb-filter-ten-photo.pasta {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #dc2626, #f97316) !important;
}

.vb-filter-ten-photo.cake {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #7f1d1d, #be123c) !important;
}

.vb-filter-ten-photo.toast {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #65a30d, #f59e0b) !important;
}

.vb-filter-ten-photo.bowl {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #0f766e, #22c55e) !important;
}

.vb-filter-ten-photo.salmon {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #fb7185, #f97316) !important;
}

.vb-filter-ten-photo.berry {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #e11d48, #f9a8d4) !important;
}

.vb-filter-ten-grid article > div:last-child {
  padding: 18px;
}

.vb-filter-ten-grid small {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-ten-grid h4 {
  margin: 0 0 8px !important;
  color: #431407 !important;
  -webkit-text-fill-color: #431407 !important;
  font-size: 21px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-ten-grid p {
  margin: 0 0 14px !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 13px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-filter-ten-grid article span {
  color: #16a34a !important;
  -webkit-text-fill-color: #16a34a !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-filter-ten-empty {
  display: none;
  margin-top: 16px;
  padding: 22px;
  border-radius: 22px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.38);
}

.vb-filter-ten-empty.is-visible {
  display: block;
}

.vb-filter-ten-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-ten-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb-filter-ten-bar {
    grid-template-columns: 1fr;
  }

  .vb-filter-ten-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-filter-ten-info {
    max-width: 220px;
  }
}

@media (max-width: 640px) {
  .vb-filter-ten-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-ten-kitchen {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-ten-hero h3 {
    font-size: 38px !important;
  }

  .vb-filter-ten-types,
  .vb-filter-ten-info {
    display: grid;
    grid-template-columns: 1fr;
    max-width: none;
  }

  .vb-filter-ten-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const kitchen = document.querySelector("[data-vb-filter-ten]");
  if (!kitchen) return;

  const input = kitchen.querySelector("[data-vb-filter-ten-input]");
  const buttons = kitchen.querySelectorAll("[data-meal]");
  const reset = kitchen.querySelector("[data-vb-filter-ten-reset]");
  const count = kitchen.querySelector("[data-vb-filter-ten-count]");
  const empty = kitchen.querySelector("[data-vb-filter-ten-empty]");
  const recipes = Array.from(kitchen.querySelectorAll("[data-meal-card]"));

  let activeMeal = "all";

  function updateRecipes() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    recipes.forEach(function (recipe) {
      const meal = recipe.getAttribute("data-meal-card");
      const text = recipe.getAttribute("data-recipe-text").toLowerCase();
      const fullText = recipe.textContent.toLowerCase();

      const mealMatch = activeMeal === "all" || meal === activeMeal;
      const queryMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = mealMatch && queryMatch;

      recipe.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 recipe" : visible + " recipes";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeMeal = button.getAttribute("data-meal");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateRecipes();
    });
  });

  input.addEventListener("input", updateRecipes);

  reset.addEventListener("click", function () {
    activeMeal = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-meal") === "all");
    });

    input.focus();
    updateRecipes();
  });

  updateRecipes();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const kitchen = document.querySelector("[data-vb-filter-ten]");
  if (!kitchen) return;

  const input = kitchen.querySelector("[data-vb-filter-ten-input]");
  const buttons = kitchen.querySelectorAll("[data-meal]");
  const reset = kitchen.querySelector("[data-vb-filter-ten-reset]");
  const count = kitchen.querySelector("[data-vb-filter-ten-count]");
  const empty = kitchen.querySelector("[data-vb-filter-ten-empty]");
  const recipes = Array.from(kitchen.querySelectorAll("[data-meal-card]"));

  let activeMeal = "all";

  function updateRecipes() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    recipes.forEach(function (recipe) {
      const meal = recipe.getAttribute("data-meal-card");
      const text = recipe.getAttribute("data-recipe-text").toLowerCase();
      const fullText = recipe.textContent.toLowerCase();

      const mealMatch = activeMeal === "all" || meal === activeMeal;
      const queryMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = mealMatch && queryMatch;

      recipe.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 recipe" : visible + " recipes";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeMeal = button.getAttribute("data-meal");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateRecipes();
    });
  });

  input.addEventListener("input", updateRecipes);

  reset.addEventListener("click", function () {
    activeMeal = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-meal") === "all");
    });

    input.focus();
    updateRecipes();
  });

  updateRecipes();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-ten-demo"&gt;
  &lt;div class="vb-filter-ten-kitchen" data-vb-filter-ten&gt;
    &lt;div class="vb-filter-ten-hero"&gt;
      &lt;span&gt;Example 10&lt;/span&gt;
      &lt;h3&gt;Recipe Search Filter&lt;/h3&gt;
      &lt;p&gt;Filter recipes by meal type and search for ingredients, cuisine, or difficulty.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-ten-bar"&gt;
      &lt;div class="vb-filter-ten-search"&gt;
        &lt;input type="search" placeholder="Search chicken, vegan, pasta, quick..." data-vb-filter-ten-input&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-ten-types"&gt;
        &lt;button type="button" class="is-active" data-meal="all"&gt;All&lt;/button&gt;
        &lt;button type="button" data-meal="breakfast"&gt;Breakfast&lt;/button&gt;
        &lt;button type="button" data-meal="lunch"&gt;Lunch&lt;/button&gt;
        &lt;button type="button" data-meal="dinner"&gt;Dinner&lt;/button&gt;
        &lt;button type="button" data-meal="dessert"&gt;Dessert&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-ten-info"&gt;
        &lt;strong data-vb-filter-ten-count&gt;8 recipes&lt;/strong&gt;
        &lt;button type="button" data-vb-filter-ten-reset&gt;Reset&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-ten-grid"&gt;
      &lt;article data-meal-card="breakfast" data-recipe-text="breakfast oats berries yogurt healthy quick vegetarian"&gt;
        &lt;div class="vb-filter-ten-photo oats"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Breakfast&lt;/small&gt;
          &lt;h4&gt;Berry Yogurt Oats&lt;/h4&gt;
          &lt;p&gt;Quick overnight oats with berries, yogurt, honey, and crunchy seeds.&lt;/p&gt;
          &lt;span&gt;10 min · Easy&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-meal-card="lunch" data-recipe-text="lunch chicken wrap salad protein quick"&gt;
        &lt;div class="vb-filter-ten-photo wrap"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Lunch&lt;/small&gt;
          &lt;h4&gt;Chicken Salad Wrap&lt;/h4&gt;
          &lt;p&gt;Fresh wrap with grilled chicken, greens, tomato, and creamy dressing.&lt;/p&gt;
          &lt;span&gt;18 min · Easy&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-meal-card="dinner" data-recipe-text="dinner pasta tomato basil italian vegetarian"&gt;
        &lt;div class="vb-filter-ten-photo pasta"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Dinner&lt;/small&gt;
          &lt;h4&gt;Tomato Basil Pasta&lt;/h4&gt;
          &lt;p&gt;Simple pasta with tomato sauce, basil, garlic, and parmesan.&lt;/p&gt;
          &lt;span&gt;25 min · Medium&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-meal-card="dessert" data-recipe-text="dessert chocolate cake sweet baking"&gt;
        &lt;div class="vb-filter-ten-photo cake"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Dessert&lt;/small&gt;
          &lt;h4&gt;Chocolate Mini Cake&lt;/h4&gt;
          &lt;p&gt;Rich mini cake with chocolate glaze, cocoa, and soft sponge layers.&lt;/p&gt;
          &lt;span&gt;45 min · Medium&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-meal-card="breakfast" data-recipe-text="breakfast avocado toast eggs healthy quick"&gt;
        &lt;div class="vb-filter-ten-photo toast"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Breakfast&lt;/small&gt;
          &lt;h4&gt;Avocado Egg Toast&lt;/h4&gt;
          &lt;p&gt;Toasted bread with avocado, egg, chili flakes, and lemon.&lt;/p&gt;
          &lt;span&gt;12 min · Easy&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-meal-card="lunch" data-recipe-text="lunch vegan bowl rice vegetables tofu healthy"&gt;
        &lt;div class="vb-filter-ten-photo bowl"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Lunch&lt;/small&gt;
          &lt;h4&gt;Vegan Rice Bowl&lt;/h4&gt;
          &lt;p&gt;Rice bowl with tofu, vegetables, sesame dressing, and fresh herbs.&lt;/p&gt;
          &lt;span&gt;22 min · Easy&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-meal-card="dinner" data-recipe-text="dinner salmon fish potato lemon protein"&gt;
        &lt;div class="vb-filter-ten-photo salmon"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Dinner&lt;/small&gt;
          &lt;h4&gt;Lemon Salmon Plate&lt;/h4&gt;
          &lt;p&gt;Salmon with roasted potatoes, lemon butter, and green vegetables.&lt;/p&gt;
          &lt;span&gt;35 min · Medium&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-meal-card="dessert" data-recipe-text="dessert strawberry cream no bake sweet easy"&gt;
        &lt;div class="vb-filter-ten-photo berry"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Dessert&lt;/small&gt;
          &lt;h4&gt;Strawberry Cream Cups&lt;/h4&gt;
          &lt;p&gt;No-bake dessert cups with strawberries, cream, and biscuit crumble.&lt;/p&gt;
          &lt;span&gt;15 min · Easy&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-ten-empty" data-vb-filter-ten-empty&gt;
      &lt;strong&gt;No recipes found.&lt;/strong&gt;
      &lt;p&gt;Try another meal type or search for pasta, chicken, vegan, salmon, chocolate, breakfast, or quick.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-ten-demo,
.vb-filter-ten-demo * {
  box-sizing: border-box;
}

.vb-filter-ten-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 18%, rgba(251, 146, 60, 0.24), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(34, 197, 94, 0.18), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #f0fdf4 52%, #ffffff 100%) !important;
  border: 1px solid rgba(253, 186, 116, 0.48);
  box-shadow: 0 24px 70px rgba(124, 45, 18, 0.12);
}

.vb-filter-ten-kitchen {
  max-width: 1120px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 80% 12%, rgba(251, 146, 60, 0.12), transparent 34%),
    linear-gradient(135deg, #ffffff, #fffbeb) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-ten-hero {
  max-width: 780px;
  margin-bottom: 24px;
}

.vb-filter-ten-hero span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-ten-hero h3 {
  margin: 0 0 14px !important;
  color: #431407 !important;
  -webkit-text-fill-color: #431407 !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-ten-hero p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-filter-ten-bar {
  display: grid;
  grid-template-columns: minmax(260px, 0.8fr) minmax(0, 1.2fr) 170px;
  gap: 12px;
  align-items: center;
  margin-bottom: 18px;
  padding: 14px;
  border-radius: 24px;
  background: #431407;
}

.vb-filter-ten-search input {
  width: 100%;
  min-height: 52px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  outline: 0;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-ten-search input::placeholder {
  color: rgba(255,255,255,0.62);
  -webkit-text-fill-color: rgba(255,255,255,0.62);
}

.vb-filter-ten-types {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-filter-ten-types button {
  min-height: 40px;
  padding: 9px 13px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 999px;
  background: rgba(255,255,255,0.08);
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 13px;
  font-weight: 900;
  cursor: pointer;
}

.vb-filter-ten-types button.is-active,
.vb-filter-ten-types button:hover {
  background: linear-gradient(135deg, #f97316, #22c55e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-ten-info {
  display: grid;
  gap: 8px;
}

.vb-filter-ten-info strong {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 24px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-filter-ten-info button {
  min-height: 38px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-ten-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-filter-ten-grid article {
  overflow: hidden;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb-filter-ten-grid article.is-hidden {
  display: none;
}

.vb-filter-ten-photo {
  min-height: 140px;
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #f97316, #22c55e) !important;
}

.vb-filter-ten-photo.wrap {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #16a34a, #84cc16) !important;
}

.vb-filter-ten-photo.pasta {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #dc2626, #f97316) !important;
}

.vb-filter-ten-photo.cake {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #7f1d1d, #be123c) !important;
}

.vb-filter-ten-photo.toast {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #65a30d, #f59e0b) !important;
}

.vb-filter-ten-photo.bowl {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #0f766e, #22c55e) !important;
}

.vb-filter-ten-photo.salmon {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #fb7185, #f97316) !important;
}

.vb-filter-ten-photo.berry {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.44), transparent 32%),
    linear-gradient(135deg, #e11d48, #f9a8d4) !important;
}

.vb-filter-ten-grid article &gt; div:last-child {
  padding: 18px;
}

.vb-filter-ten-grid small {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-ten-grid h4 {
  margin: 0 0 8px !important;
  color: #431407 !important;
  -webkit-text-fill-color: #431407 !important;
  font-size: 21px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-ten-grid p {
  margin: 0 0 14px !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 13px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-filter-ten-grid article span {
  color: #16a34a !important;
  -webkit-text-fill-color: #16a34a !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-filter-ten-empty {
  display: none;
  margin-top: 16px;
  padding: 22px;
  border-radius: 22px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.38);
}

.vb-filter-ten-empty.is-visible {
  display: block;
}

.vb-filter-ten-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-ten-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb-filter-ten-bar {
    grid-template-columns: 1fr;
  }

  .vb-filter-ten-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-filter-ten-info {
    max-width: 220px;
  }
}

@media (max-width: 640px) {
  .vb-filter-ten-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-ten-kitchen {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-ten-hero h3 {
    font-size: 38px !important;
  }

  .vb-filter-ten-types,
  .vb-filter-ten-info {
    display: grid;
    grid-template-columns: 1fr;
    max-width: none;
  }

  .vb-filter-ten-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This recipe search filter is useful for food blogs, recipe archives, cooking apps, meal planning pages, restaurant content hubs, health websites, and lifestyle sections where visitors need to find meals by type, ingredient, or keyword.</p>



<h2 class="wp-block-heading">11. Documentation Search Filter</h2>



<p class="wp-block-paragraph"><strong>A documentation search filter</strong> helps users find guides, setup steps, API notes, troubleshooting articles, and product instructions faster. This pattern is useful for SaaS documentation, plugin docs, developer portals, help centers, onboarding pages, and technical knowledge bases.</p>



<p class="wp-block-paragraph">This example uses a documentation-style layout with a left search panel, topic filters, doc cards, difficulty labels, result count, and a no-results state. Users can search documentation pages and filter by topic at the same time.</p>



<ul class="wp-block-list">
<li>Documentation article search</li>
<li>Topic filter buttons</li>
<li>Searches titles, descriptions, and keywords</li>
<li>Documentation-style UI layout</li>
<li>Useful for SaaS docs, plugin docs, help centers, and knowledge bases</li>
</ul>



<div class="vb-filter-eleven-demo">
  <div class="vb-filter-eleven-docs" data-vb-filter-eleven>
    <aside class="vb-filter-eleven-sidebar">
      <span>Example 11</span>
      <h3>Documentation Search Filter</h3>
      <p>Search documentation pages by topic, keyword, setup step, or technical feature.</p>

      <div class="vb-filter-eleven-search">
        <label for="vb-filter-eleven-input">Search docs</label>
        <input id="vb-filter-eleven-input" type="search" placeholder="Search API, setup, billing, errors..." data-vb-filter-eleven-input>
      </div>

      <div class="vb-filter-eleven-topics">
        <button type="button" class="is-active" data-doc-topic="all">All Docs</button>
        <button type="button" data-doc-topic="setup">Setup</button>
        <button type="button" data-doc-topic="api">API</button>
        <button type="button" data-doc-topic="billing">Billing</button>
        <button type="button" data-doc-topic="support">Support</button>
      </div>

      <div class="vb-filter-eleven-actions">
        <strong data-vb-filter-eleven-count>8 docs found</strong>
        <button type="button" data-vb-filter-eleven-reset>Reset</button>
      </div>
    </aside>

    <main class="vb-filter-eleven-main">
      <article data-doc-card="setup" data-doc-text="setup installation getting started account onboarding first steps">
        <small>Setup</small>
        <h4>Getting Started Guide</h4>
        <p>Learn how to create your account, configure basic settings, and launch your first project.</p>
        <span>Beginner</span>
      </article>

      <article data-doc-card="setup" data-doc-text="setup wordpress plugin install activate configuration">
        <small>Setup</small>
        <h4>Plugin Installation</h4>
        <p>Install the plugin, activate it in WordPress, and connect the required project settings.</p>
        <span>Beginner</span>
      </article>

      <article data-doc-card="api" data-doc-text="api authentication token endpoint request header integration">
        <small>API</small>
        <h4>API Authentication</h4>
        <p>Use access tokens, request headers, and secure authentication for private API endpoints.</p>
        <span>Advanced</span>
      </article>

      <article data-doc-card="api" data-doc-text="api webhook event payload response automation">
        <small>API</small>
        <h4>Webhook Events</h4>
        <p>Receive event payloads when users subscribe, update settings, complete actions, or trigger workflows.</p>
        <span>Advanced</span>
      </article>

      <article data-doc-card="billing" data-doc-text="billing invoice payment subscription license renewal">
        <small>Billing</small>
        <h4>Invoices and Payments</h4>
        <p>Find invoices, update payment details, manage subscriptions, and review renewal information.</p>
        <span>Standard</span>
      </article>

      <article data-doc-card="billing" data-doc-text="billing license activation domain limit plan upgrade">
        <small>Billing</small>
        <h4>License Activation</h4>
        <p>Activate your license, manage connected domains, upgrade plans, and check usage limits.</p>
        <span>Standard</span>
      </article>

      <article data-doc-card="support" data-doc-text="support troubleshooting error failed request not working">
        <small>Support</small>
        <h4>Troubleshooting Errors</h4>
        <p>Fix failed requests, setup issues, missing settings, connection problems, and common error messages.</p>
        <span>Standard</span>
      </article>

      <article data-doc-card="support" data-doc-text="support contact help ticket response documentation question">
        <small>Support</small>
        <h4>Contact Support</h4>
        <p>Learn what details to include when opening a support ticket or asking for technical help.</p>
        <span>Beginner</span>
      </article>

      <div class="vb-filter-eleven-empty" data-vb-filter-eleven-empty>
        <strong>No documentation pages found.</strong>
        <p>Try searching for setup, API, webhook, billing, license, error, support, or installation.</p>
      </div>
    </main>
  </div>
</div>

<style>
.vb-filter-eleven-demo,
.vb-filter-eleven-demo * {
  box-sizing: border-box;
}

.vb-filter-eleven-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 20%, rgba(14, 165, 233, 0.20), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(99, 102, 241, 0.18), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(186, 230, 253, 0.54);
  box-shadow: 0 24px 70px rgba(14, 116, 144, 0.12);
}

.vb-filter-eleven-docs {
  display: grid;
  grid-template-columns: 330px minmax(0, 1fr);
  gap: 18px;
  max-width: 1120px;
  margin: 0 auto;
  padding: 18px;
  border-radius: 30px;
  background: #0f172a;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
}

.vb-filter-eleven-sidebar {
  padding: 26px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 20% 14%, rgba(255,255,255,0.16), transparent 32%),
    linear-gradient(135deg, #075985, #312e81) !important;
}

.vb-filter-eleven-sidebar > span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-eleven-sidebar h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 4vw, 56px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-eleven-sidebar p {
  margin: 0 0 24px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-eleven-search {
  margin-bottom: 18px;
}

.vb-filter-eleven-search label {
  display: block;
  margin-bottom: 8px;
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-eleven-search input {
  width: 100%;
  min-height: 56px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.17);
  border-radius: 18px;
  outline: 0;
  background: rgba(255,255,255,0.11);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-eleven-search input::placeholder {
  color: rgba(255,255,255,0.62);
  -webkit-text-fill-color: rgba(255,255,255,0.62);
}

.vb-filter-eleven-topics {
  display: grid;
  gap: 8px;
  margin-bottom: 18px;
}

.vb-filter-eleven-topics button {
  min-height: 44px;
  padding: 10px 13px;
  border: 1px solid rgba(255,255,255,0.13);
  border-radius: 14px;
  background: rgba(255,255,255,0.09);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 13px;
  font-weight: 900;
  cursor: pointer;
  text-align: left;
}

.vb-filter-eleven-topics button.is-active,
.vb-filter-eleven-topics button:hover {
  background: #ffffff;
  color: #075985 !important;
  -webkit-text-fill-color: #075985 !important;
}

.vb-filter-eleven-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 13px;
  border-radius: 18px;
  background: rgba(255,255,255,0.10);
}

.vb-filter-eleven-actions strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-filter-eleven-actions button {
  min-height: 38px;
  padding: 8px 12px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #312e81 !important;
  -webkit-text-fill-color: #312e81 !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-eleven-main {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-filter-eleven-main article {
  padding: 22px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(255,255,255,0.10);
  box-shadow: 0 18px 44px rgba(2, 6, 23, 0.16);
}

.vb-filter-eleven-main article.is-hidden {
  display: none;
}

.vb-filter-eleven-main small {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-eleven-main h4 {
  margin: 0 0 10px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-eleven-main p {
  margin: 0 0 16px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-filter-eleven-main article span {
  display: inline-flex;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-filter-eleven-empty {
  display: none;
  grid-column: 1 / -1;
  padding: 22px;
  border-radius: 22px;
  background: #eff6ff;
  border: 1px solid rgba(147, 197, 253, 0.42);
}

.vb-filter-eleven-empty.is-visible {
  display: block;
}

.vb-filter-eleven-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-eleven-empty p {
  margin: 0 !important;
  color: #1e40af !important;
  -webkit-text-fill-color: #1e40af !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 920px) {
  .vb-filter-eleven-docs {
    grid-template-columns: 1fr;
  }

  .vb-filter-eleven-main {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-filter-eleven-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-eleven-docs {
    padding: 12px;
    border-radius: 24px;
  }

  .vb-filter-eleven-sidebar {
    padding: 22px;
    border-radius: 20px;
  }

  .vb-filter-eleven-sidebar h3 {
    font-size: 38px !important;
  }

  .vb-filter-eleven-actions {
    align-items: stretch;
    flex-direction: column;
  }

  .vb-filter-eleven-actions button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const docs = document.querySelector("[data-vb-filter-eleven]");
  if (!docs) return;

  const input = docs.querySelector("[data-vb-filter-eleven-input]");
  const buttons = docs.querySelectorAll("[data-doc-topic]");
  const reset = docs.querySelector("[data-vb-filter-eleven-reset]");
  const count = docs.querySelector("[data-vb-filter-eleven-count]");
  const empty = docs.querySelector("[data-vb-filter-eleven-empty]");
  const cards = Array.from(docs.querySelectorAll("[data-doc-card]"));

  let activeTopic = "all";

  function updateDocs() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    cards.forEach(function (card) {
      const topic = card.getAttribute("data-doc-card");
      const text = card.getAttribute("data-doc-text").toLowerCase();
      const fullText = card.textContent.toLowerCase();

      const topicMatch = activeTopic === "all" || topic === activeTopic;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = topicMatch && searchMatch;

      card.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 doc found" : visible + " docs found";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeTopic = button.getAttribute("data-doc-topic");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateDocs();
    });
  });

  input.addEventListener("input", updateDocs);

  reset.addEventListener("click", function () {
    activeTopic = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-doc-topic") === "all");
    });

    input.focus();
    updateDocs();
  });

  updateDocs();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const docs = document.querySelector("[data-vb-filter-eleven]");
  if (!docs) return;

  const input = docs.querySelector("[data-vb-filter-eleven-input]");
  const buttons = docs.querySelectorAll("[data-doc-topic]");
  const reset = docs.querySelector("[data-vb-filter-eleven-reset]");
  const count = docs.querySelector("[data-vb-filter-eleven-count]");
  const empty = docs.querySelector("[data-vb-filter-eleven-empty]");
  const cards = Array.from(docs.querySelectorAll("[data-doc-card]"));

  let activeTopic = "all";

  function updateDocs() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    cards.forEach(function (card) {
      const topic = card.getAttribute("data-doc-card");
      const text = card.getAttribute("data-doc-text").toLowerCase();
      const fullText = card.textContent.toLowerCase();

      const topicMatch = activeTopic === "all" || topic === activeTopic;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = topicMatch && searchMatch;

      card.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 doc found" : visible + " docs found";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeTopic = button.getAttribute("data-doc-topic");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateDocs();
    });
  });

  input.addEventListener("input", updateDocs);

  reset.addEventListener("click", function () {
    activeTopic = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-doc-topic") === "all");
    });

    input.focus();
    updateDocs();
  });

  updateDocs();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-eleven-demo"&gt;
  &lt;div class="vb-filter-eleven-docs" data-vb-filter-eleven&gt;
    &lt;aside class="vb-filter-eleven-sidebar"&gt;
      &lt;span&gt;Example 11&lt;/span&gt;
      &lt;h3&gt;Documentation Search Filter&lt;/h3&gt;
      &lt;p&gt;Search documentation pages by topic, keyword, setup step, or technical feature.&lt;/p&gt;

      &lt;div class="vb-filter-eleven-search"&gt;
        &lt;label for="vb-filter-eleven-input"&gt;Search docs&lt;/label&gt;
        &lt;input id="vb-filter-eleven-input" type="search" placeholder="Search API, setup, billing, errors..." data-vb-filter-eleven-input&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-eleven-topics"&gt;
        &lt;button type="button" class="is-active" data-doc-topic="all"&gt;All Docs&lt;/button&gt;
        &lt;button type="button" data-doc-topic="setup"&gt;Setup&lt;/button&gt;
        &lt;button type="button" data-doc-topic="api"&gt;API&lt;/button&gt;
        &lt;button type="button" data-doc-topic="billing"&gt;Billing&lt;/button&gt;
        &lt;button type="button" data-doc-topic="support"&gt;Support&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-eleven-actions"&gt;
        &lt;strong data-vb-filter-eleven-count&gt;8 docs found&lt;/strong&gt;
        &lt;button type="button" data-vb-filter-eleven-reset&gt;Reset&lt;/button&gt;
      &lt;/div&gt;
    &lt;/aside&gt;

    &lt;main class="vb-filter-eleven-main"&gt;
      &lt;article data-doc-card="setup" data-doc-text="setup installation getting started account onboarding first steps"&gt;
        &lt;small&gt;Setup&lt;/small&gt;
        &lt;h4&gt;Getting Started Guide&lt;/h4&gt;
        &lt;p&gt;Learn how to create your account, configure basic settings, and launch your first project.&lt;/p&gt;
        &lt;span&gt;Beginner&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-doc-card="setup" data-doc-text="setup wordpress plugin install activate configuration"&gt;
        &lt;small&gt;Setup&lt;/small&gt;
        &lt;h4&gt;Plugin Installation&lt;/h4&gt;
        &lt;p&gt;Install the plugin, activate it in WordPress, and connect the required project settings.&lt;/p&gt;
        &lt;span&gt;Beginner&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-doc-card="api" data-doc-text="api authentication token endpoint request header integration"&gt;
        &lt;small&gt;API&lt;/small&gt;
        &lt;h4&gt;API Authentication&lt;/h4&gt;
        &lt;p&gt;Use access tokens, request headers, and secure authentication for private API endpoints.&lt;/p&gt;
        &lt;span&gt;Advanced&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-doc-card="api" data-doc-text="api webhook event payload response automation"&gt;
        &lt;small&gt;API&lt;/small&gt;
        &lt;h4&gt;Webhook Events&lt;/h4&gt;
        &lt;p&gt;Receive event payloads when users subscribe, update settings, complete actions, or trigger workflows.&lt;/p&gt;
        &lt;span&gt;Advanced&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-doc-card="billing" data-doc-text="billing invoice payment subscription license renewal"&gt;
        &lt;small&gt;Billing&lt;/small&gt;
        &lt;h4&gt;Invoices and Payments&lt;/h4&gt;
        &lt;p&gt;Find invoices, update payment details, manage subscriptions, and review renewal information.&lt;/p&gt;
        &lt;span&gt;Standard&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-doc-card="billing" data-doc-text="billing license activation domain limit plan upgrade"&gt;
        &lt;small&gt;Billing&lt;/small&gt;
        &lt;h4&gt;License Activation&lt;/h4&gt;
        &lt;p&gt;Activate your license, manage connected domains, upgrade plans, and check usage limits.&lt;/p&gt;
        &lt;span&gt;Standard&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-doc-card="support" data-doc-text="support troubleshooting error failed request not working"&gt;
        &lt;small&gt;Support&lt;/small&gt;
        &lt;h4&gt;Troubleshooting Errors&lt;/h4&gt;
        &lt;p&gt;Fix failed requests, setup issues, missing settings, connection problems, and common error messages.&lt;/p&gt;
        &lt;span&gt;Standard&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-doc-card="support" data-doc-text="support contact help ticket response documentation question"&gt;
        &lt;small&gt;Support&lt;/small&gt;
        &lt;h4&gt;Contact Support&lt;/h4&gt;
        &lt;p&gt;Learn what details to include when opening a support ticket or asking for technical help.&lt;/p&gt;
        &lt;span&gt;Beginner&lt;/span&gt;
      &lt;/article&gt;

      &lt;div class="vb-filter-eleven-empty" data-vb-filter-eleven-empty&gt;
        &lt;strong&gt;No documentation pages found.&lt;/strong&gt;
        &lt;p&gt;Try searching for setup, API, webhook, billing, license, error, support, or installation.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/main&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-eleven-demo,
.vb-filter-eleven-demo * {
  box-sizing: border-box;
}

.vb-filter-eleven-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 20%, rgba(14, 165, 233, 0.20), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(99, 102, 241, 0.18), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(186, 230, 253, 0.54);
  box-shadow: 0 24px 70px rgba(14, 116, 144, 0.12);
}

.vb-filter-eleven-docs {
  display: grid;
  grid-template-columns: 330px minmax(0, 1fr);
  gap: 18px;
  max-width: 1120px;
  margin: 0 auto;
  padding: 18px;
  border-radius: 30px;
  background: #0f172a;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
}

.vb-filter-eleven-sidebar {
  padding: 26px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 20% 14%, rgba(255,255,255,0.16), transparent 32%),
    linear-gradient(135deg, #075985, #312e81) !important;
}

.vb-filter-eleven-sidebar &gt; span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-eleven-sidebar h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 4vw, 56px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-eleven-sidebar p {
  margin: 0 0 24px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-eleven-search {
  margin-bottom: 18px;
}

.vb-filter-eleven-search label {
  display: block;
  margin-bottom: 8px;
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-eleven-search input {
  width: 100%;
  min-height: 56px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.17);
  border-radius: 18px;
  outline: 0;
  background: rgba(255,255,255,0.11);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-eleven-search input::placeholder {
  color: rgba(255,255,255,0.62);
  -webkit-text-fill-color: rgba(255,255,255,0.62);
}

.vb-filter-eleven-topics {
  display: grid;
  gap: 8px;
  margin-bottom: 18px;
}

.vb-filter-eleven-topics button {
  min-height: 44px;
  padding: 10px 13px;
  border: 1px solid rgba(255,255,255,0.13);
  border-radius: 14px;
  background: rgba(255,255,255,0.09);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 13px;
  font-weight: 900;
  cursor: pointer;
  text-align: left;
}

.vb-filter-eleven-topics button.is-active,
.vb-filter-eleven-topics button:hover {
  background: #ffffff;
  color: #075985 !important;
  -webkit-text-fill-color: #075985 !important;
}

.vb-filter-eleven-actions {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 13px;
  border-radius: 18px;
  background: rgba(255,255,255,0.10);
}

.vb-filter-eleven-actions strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-filter-eleven-actions button {
  min-height: 38px;
  padding: 8px 12px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #312e81 !important;
  -webkit-text-fill-color: #312e81 !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-eleven-main {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px;
}

.vb-filter-eleven-main article {
  padding: 22px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(255,255,255,0.10);
  box-shadow: 0 18px 44px rgba(2, 6, 23, 0.16);
}

.vb-filter-eleven-main article.is-hidden {
  display: none;
}

.vb-filter-eleven-main small {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-eleven-main h4 {
  margin: 0 0 10px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-eleven-main p {
  margin: 0 0 16px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-filter-eleven-main article span {
  display: inline-flex;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-filter-eleven-empty {
  display: none;
  grid-column: 1 / -1;
  padding: 22px;
  border-radius: 22px;
  background: #eff6ff;
  border: 1px solid rgba(147, 197, 253, 0.42);
}

.vb-filter-eleven-empty.is-visible {
  display: block;
}

.vb-filter-eleven-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-eleven-empty p {
  margin: 0 !important;
  color: #1e40af !important;
  -webkit-text-fill-color: #1e40af !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 920px) {
  .vb-filter-eleven-docs {
    grid-template-columns: 1fr;
  }

  .vb-filter-eleven-main {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-filter-eleven-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-eleven-docs {
    padding: 12px;
    border-radius: 24px;
  }

  .vb-filter-eleven-sidebar {
    padding: 22px;
    border-radius: 20px;
  }

  .vb-filter-eleven-sidebar h3 {
    font-size: 38px !important;
  }

  .vb-filter-eleven-actions {
    align-items: stretch;
    flex-direction: column;
  }

  .vb-filter-eleven-actions button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This documentation search filter is useful for SaaS documentation, WordPress plugin docs, developer portals, help centers, onboarding libraries, API references, and technical knowledge bases where users need to find support content quickly.</p>



<h2 class="wp-block-heading">12. Team Directory Search Filter</h2>



<p class="wp-block-paragraph"><strong>A team directory search filter</strong> helps users find people by name, role, department, location, skill, or availability. This pattern is useful for company team pages, internal dashboards, agency directories, HR systems, intranets, university departments, and community platforms.</p>



<p class="wp-block-paragraph">This example uses a people-directory layout with department pills, a live search input, team profile cards, location labels, availability badges, and a no-results state. Users can filter the team by department and search inside each profile.</p>



<ul class="wp-block-list">
<li>Team member directory search</li>
<li>Department filter pills</li>
<li>Filters by role, name, location, and skills</li>
<li>Profile-card layout</li>
<li>Useful for team pages, intranets, HR systems, and agency websites</li>
</ul>



<div class="vb-filter-twelve-demo">
  <div class="vb-filter-twelve-team" data-vb-filter-twelve>
    <div class="vb-filter-twelve-top">
      <span>Example 12</span>
      <h3>Team Directory Search Filter</h3>
      <p>Search team members by name, role, department, location, or skill.</p>
    </div>

    <div class="vb-filter-twelve-toolbar">
      <div class="vb-filter-twelve-search">
        <input type="search" placeholder="Search designer, Tallinn, React, SEO..." data-vb-filter-twelve-input>
      </div>

      <div class="vb-filter-twelve-departments">
        <button type="button" class="is-active" data-team-dept="all">All</button>
        <button type="button" data-team-dept="design">Design</button>
        <button type="button" data-team-dept="development">Development</button>
        <button type="button" data-team-dept="marketing">Marketing</button>
        <button type="button" data-team-dept="support">Support</button>
      </div>

      <div class="vb-filter-twelve-status">
        <strong data-vb-filter-twelve-count>8 people</strong>
        <button type="button" data-vb-filter-twelve-reset>Reset</button>
      </div>
    </div>

    <div class="vb-filter-twelve-grid">
      <article data-team-card="design" data-team-text="maria kane product designer figma ux tallinn available">
        <div class="vb-filter-twelve-avatar avatar-one">MK</div>
        <div>
          <small>Design</small>
          <h4>Maria Kane</h4>
          <p>Product Designer · Figma, UX flows, dashboards · Tallinn</p>
          <span>Available</span>
        </div>
      </article>

      <article data-team-card="development" data-team-text="john reed frontend developer javascript react remote busy">
        <div class="vb-filter-twelve-avatar avatar-two">JR</div>
        <div>
          <small>Development</small>
          <h4>John Reed</h4>
          <p>Frontend Developer · JavaScript, React, UI systems · Remote</p>
          <span>Busy</span>
        </div>
      </article>

      <article data-team-card="marketing" data-team-text="sara lee seo specialist content analytics tartu available">
        <div class="vb-filter-twelve-avatar avatar-three">SL</div>
        <div>
          <small>Marketing</small>
          <h4>Sara Lee</h4>
          <p>SEO Specialist · Content, analytics, keyword research · Tartu</p>
          <span>Available</span>
        </div>
      </article>

      <article data-team-card="support" data-team-text="alex norman support manager tickets onboarding london busy">
        <div class="vb-filter-twelve-avatar avatar-four">AN</div>
        <div>
          <small>Support</small>
          <h4>Alex Norman</h4>
          <p>Support Manager · Tickets, onboarding, user questions · London</p>
          <span>Busy</span>
        </div>
      </article>

      <article data-team-card="development" data-team-text="nina stone backend developer api node database berlin available">
        <div class="vb-filter-twelve-avatar avatar-five">NS</div>
        <div>
          <small>Development</small>
          <h4>Nina Stone</h4>
          <p>Backend Developer · APIs, Node, databases · Berlin</p>
          <span>Available</span>
        </div>
      </article>

      <article data-team-card="design" data-team-text="tom gray brand designer visual identity social helsinki available">
        <div class="vb-filter-twelve-avatar avatar-six">TG</div>
        <div>
          <small>Design</small>
          <h4>Tom Gray</h4>
          <p>Brand Designer · Visual identity, campaigns, social kits · Helsinki</p>
          <span>Available</span>
        </div>
      </article>

      <article data-team-card="marketing" data-team-text="laura white growth marketer ads funnel conversion riga busy">
        <div class="vb-filter-twelve-avatar avatar-seven">LW</div>
        <div>
          <small>Marketing</small>
          <h4>Laura White</h4>
          <p>Growth Marketer · Ads, funnels, experiments · Riga</p>
          <span>Busy</span>
        </div>
      </article>

      <article data-team-card="support" data-team-text="mark bell technical support wordpress plugin docs tallinn available">
        <div class="vb-filter-twelve-avatar avatar-eight">MB</div>
        <div>
          <small>Support</small>
          <h4>Mark Bell</h4>
          <p>Technical Support · WordPress, plugin docs, troubleshooting · Tallinn</p>
          <span>Available</span>
        </div>
      </article>
    </div>

    <div class="vb-filter-twelve-empty" data-vb-filter-twelve-empty>
      <strong>No team members found.</strong>
      <p>Try searching for designer, developer, Tallinn, React, SEO, support, WordPress, or available.</p>
    </div>
  </div>
</div>

<style>
.vb-filter-twelve-demo,
.vb-filter-twelve-demo * {
  box-sizing: border-box;
}

.vb-filter-twelve-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 18%, rgba(236, 72, 153, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(14, 165, 233, 0.18), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #ecfeff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(251, 207, 232, 0.52);
  box-shadow: 0 24px 70px rgba(157, 23, 77, 0.10);
}

.vb-filter-twelve-team {
  max-width: 1120px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 78% 18%, rgba(14, 165, 233, 0.12), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-twelve-top {
  max-width: 760px;
  margin-bottom: 24px;
}

.vb-filter-twelve-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fce7f3;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-twelve-top h3 {
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-twelve-top p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-filter-twelve-toolbar {
  display: grid;
  grid-template-columns: minmax(250px, 0.8fr) minmax(0, 1.2fr) 160px;
  gap: 12px;
  align-items: center;
  margin-bottom: 18px;
  padding: 14px;
  border-radius: 24px;
  background: #111827;
}

.vb-filter-twelve-search input {
  width: 100%;
  min-height: 52px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.15);
  border-radius: 999px;
  outline: 0;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-twelve-search input::placeholder {
  color: rgba(255,255,255,0.62);
  -webkit-text-fill-color: rgba(255,255,255,0.62);
}

.vb-filter-twelve-departments {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-filter-twelve-departments button {
  min-height: 40px;
  padding: 9px 13px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 999px;
  background: rgba(255,255,255,0.08);
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 13px;
  font-weight: 900;
  cursor: pointer;
}

.vb-filter-twelve-departments button.is-active,
.vb-filter-twelve-departments button:hover {
  background: linear-gradient(135deg, #ec4899, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-twelve-status {
  display: grid;
  gap: 8px;
}

.vb-filter-twelve-status strong {
  display: flex;
  justify-content: center;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-filter-twelve-status button {
  min-height: 38px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-twelve-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-filter-twelve-grid article {
  display: grid;
  grid-template-columns: 76px minmax(0, 1fr);
  gap: 16px;
  align-items: center;
  padding: 20px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb-filter-twelve-grid article.is-hidden {
  display: none;
}

.vb-filter-twelve-avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 76px;
  height: 76px;
  border-radius: 24px;
  background: linear-gradient(135deg, #ec4899, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-filter-twelve-avatar.avatar-two {
  background: linear-gradient(135deg, #2563eb, #7c3aed);
}

.vb-filter-twelve-avatar.avatar-three {
  background: linear-gradient(135deg, #16a34a, #84cc16);
}

.vb-filter-twelve-avatar.avatar-four {
  background: linear-gradient(135deg, #f97316, #ef4444);
}

.vb-filter-twelve-avatar.avatar-five {
  background: linear-gradient(135deg, #0f766e, #14b8a6);
}

.vb-filter-twelve-avatar.avatar-six {
  background: linear-gradient(135deg, #be123c, #ec4899);
}

.vb-filter-twelve-avatar.avatar-seven {
  background: linear-gradient(135deg, #7c3aed, #db2777);
}

.vb-filter-twelve-avatar.avatar-eight {
  background: linear-gradient(135deg, #0f172a, #475569);
}

.vb-filter-twelve-grid small {
  display: inline-flex;
  margin-bottom: 8px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #fce7f3;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-twelve-grid h4 {
  margin: 0 0 7px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-twelve-grid p {
  margin: 0 0 10px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-filter-twelve-grid article span {
  color: #0891b2 !important;
  -webkit-text-fill-color: #0891b2 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-filter-twelve-empty {
  display: none;
  margin-top: 16px;
  padding: 22px;
  border-radius: 22px;
  background: #fdf2f8;
  border: 1px solid rgba(244, 114, 182, 0.34);
}

.vb-filter-twelve-empty.is-visible {
  display: block;
}

.vb-filter-twelve-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-twelve-empty p {
  margin: 0 !important;
  color: #9d174d !important;
  -webkit-text-fill-color: #9d174d !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb-filter-twelve-toolbar {
    grid-template-columns: 1fr;
  }

  .vb-filter-twelve-status {
    max-width: 220px;
  }

  .vb-filter-twelve-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-filter-twelve-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-twelve-team {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-twelve-top h3 {
    font-size: 38px !important;
  }

  .vb-filter-twelve-departments,
  .vb-filter-twelve-status {
    display: grid;
    grid-template-columns: 1fr;
    max-width: none;
  }

  .vb-filter-twelve-grid article {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const team = document.querySelector("[data-vb-filter-twelve]");
  if (!team) return;

  const input = team.querySelector("[data-vb-filter-twelve-input]");
  const buttons = team.querySelectorAll("[data-team-dept]");
  const reset = team.querySelector("[data-vb-filter-twelve-reset]");
  const count = team.querySelector("[data-vb-filter-twelve-count]");
  const empty = team.querySelector("[data-vb-filter-twelve-empty]");
  const cards = Array.from(team.querySelectorAll("[data-team-card]"));

  let activeDepartment = "all";

  function updateTeam() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    cards.forEach(function (card) {
      const department = card.getAttribute("data-team-card");
      const text = card.getAttribute("data-team-text").toLowerCase();
      const fullText = card.textContent.toLowerCase();

      const departmentMatch = activeDepartment === "all" || department === activeDepartment;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = departmentMatch && searchMatch;

      card.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 person" : visible + " people";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeDepartment = button.getAttribute("data-team-dept");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateTeam();
    });
  });

  input.addEventListener("input", updateTeam);

  reset.addEventListener("click", function () {
    activeDepartment = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-team-dept") === "all");
    });

    input.focus();
    updateTeam();
  });

  updateTeam();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const team = document.querySelector("[data-vb-filter-twelve]");
  if (!team) return;

  const input = team.querySelector("[data-vb-filter-twelve-input]");
  const buttons = team.querySelectorAll("[data-team-dept]");
  const reset = team.querySelector("[data-vb-filter-twelve-reset]");
  const count = team.querySelector("[data-vb-filter-twelve-count]");
  const empty = team.querySelector("[data-vb-filter-twelve-empty]");
  const cards = Array.from(team.querySelectorAll("[data-team-card]"));

  let activeDepartment = "all";

  function updateTeam() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    cards.forEach(function (card) {
      const department = card.getAttribute("data-team-card");
      const text = card.getAttribute("data-team-text").toLowerCase();
      const fullText = card.textContent.toLowerCase();

      const departmentMatch = activeDepartment === "all" || department === activeDepartment;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = departmentMatch && searchMatch;

      card.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 person" : visible + " people";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeDepartment = button.getAttribute("data-team-dept");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateTeam();
    });
  });

  input.addEventListener("input", updateTeam);

  reset.addEventListener("click", function () {
    activeDepartment = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-team-dept") === "all");
    });

    input.focus();
    updateTeam();
  });

  updateTeam();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-twelve-demo"&gt;
  &lt;div class="vb-filter-twelve-team" data-vb-filter-twelve&gt;
    &lt;div class="vb-filter-twelve-top"&gt;
      &lt;span&gt;Example 12&lt;/span&gt;
      &lt;h3&gt;Team Directory Search Filter&lt;/h3&gt;
      &lt;p&gt;Search team members by name, role, department, location, or skill.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-twelve-toolbar"&gt;
      &lt;div class="vb-filter-twelve-search"&gt;
        &lt;input type="search" placeholder="Search designer, Tallinn, React, SEO..." data-vb-filter-twelve-input&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-twelve-departments"&gt;
        &lt;button type="button" class="is-active" data-team-dept="all"&gt;All&lt;/button&gt;
        &lt;button type="button" data-team-dept="design"&gt;Design&lt;/button&gt;
        &lt;button type="button" data-team-dept="development"&gt;Development&lt;/button&gt;
        &lt;button type="button" data-team-dept="marketing"&gt;Marketing&lt;/button&gt;
        &lt;button type="button" data-team-dept="support"&gt;Support&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-twelve-status"&gt;
        &lt;strong data-vb-filter-twelve-count&gt;8 people&lt;/strong&gt;
        &lt;button type="button" data-vb-filter-twelve-reset&gt;Reset&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-twelve-grid"&gt;
      &lt;article data-team-card="design" data-team-text="maria kane product designer figma ux tallinn available"&gt;
        &lt;div class="vb-filter-twelve-avatar avatar-one"&gt;MK&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Design&lt;/small&gt;
          &lt;h4&gt;Maria Kane&lt;/h4&gt;
          &lt;p&gt;Product Designer · Figma, UX flows, dashboards · Tallinn&lt;/p&gt;
          &lt;span&gt;Available&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-team-card="development" data-team-text="john reed frontend developer javascript react remote busy"&gt;
        &lt;div class="vb-filter-twelve-avatar avatar-two"&gt;JR&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Development&lt;/small&gt;
          &lt;h4&gt;John Reed&lt;/h4&gt;
          &lt;p&gt;Frontend Developer · JavaScript, React, UI systems · Remote&lt;/p&gt;
          &lt;span&gt;Busy&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-team-card="marketing" data-team-text="sara lee seo specialist content analytics tartu available"&gt;
        &lt;div class="vb-filter-twelve-avatar avatar-three"&gt;SL&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Marketing&lt;/small&gt;
          &lt;h4&gt;Sara Lee&lt;/h4&gt;
          &lt;p&gt;SEO Specialist · Content, analytics, keyword research · Tartu&lt;/p&gt;
          &lt;span&gt;Available&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-team-card="support" data-team-text="alex norman support manager tickets onboarding london busy"&gt;
        &lt;div class="vb-filter-twelve-avatar avatar-four"&gt;AN&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Support&lt;/small&gt;
          &lt;h4&gt;Alex Norman&lt;/h4&gt;
          &lt;p&gt;Support Manager · Tickets, onboarding, user questions · London&lt;/p&gt;
          &lt;span&gt;Busy&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-team-card="development" data-team-text="nina stone backend developer api node database berlin available"&gt;
        &lt;div class="vb-filter-twelve-avatar avatar-five"&gt;NS&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Development&lt;/small&gt;
          &lt;h4&gt;Nina Stone&lt;/h4&gt;
          &lt;p&gt;Backend Developer · APIs, Node, databases · Berlin&lt;/p&gt;
          &lt;span&gt;Available&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-team-card="design" data-team-text="tom gray brand designer visual identity social helsinki available"&gt;
        &lt;div class="vb-filter-twelve-avatar avatar-six"&gt;TG&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Design&lt;/small&gt;
          &lt;h4&gt;Tom Gray&lt;/h4&gt;
          &lt;p&gt;Brand Designer · Visual identity, campaigns, social kits · Helsinki&lt;/p&gt;
          &lt;span&gt;Available&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-team-card="marketing" data-team-text="laura white growth marketer ads funnel conversion riga busy"&gt;
        &lt;div class="vb-filter-twelve-avatar avatar-seven"&gt;LW&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Marketing&lt;/small&gt;
          &lt;h4&gt;Laura White&lt;/h4&gt;
          &lt;p&gt;Growth Marketer · Ads, funnels, experiments · Riga&lt;/p&gt;
          &lt;span&gt;Busy&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-team-card="support" data-team-text="mark bell technical support wordpress plugin docs tallinn available"&gt;
        &lt;div class="vb-filter-twelve-avatar avatar-eight"&gt;MB&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Support&lt;/small&gt;
          &lt;h4&gt;Mark Bell&lt;/h4&gt;
          &lt;p&gt;Technical Support · WordPress, plugin docs, troubleshooting · Tallinn&lt;/p&gt;
          &lt;span&gt;Available&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-twelve-empty" data-vb-filter-twelve-empty&gt;
      &lt;strong&gt;No team members found.&lt;/strong&gt;
      &lt;p&gt;Try searching for designer, developer, Tallinn, React, SEO, support, WordPress, or available.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-twelve-demo,
.vb-filter-twelve-demo * {
  box-sizing: border-box;
}

.vb-filter-twelve-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 18%, rgba(236, 72, 153, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(14, 165, 233, 0.18), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #ecfeff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(251, 207, 232, 0.52);
  box-shadow: 0 24px 70px rgba(157, 23, 77, 0.10);
}

.vb-filter-twelve-team {
  max-width: 1120px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 78% 18%, rgba(14, 165, 233, 0.12), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-twelve-top {
  max-width: 760px;
  margin-bottom: 24px;
}

.vb-filter-twelve-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fce7f3;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-twelve-top h3 {
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-twelve-top p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-filter-twelve-toolbar {
  display: grid;
  grid-template-columns: minmax(250px, 0.8fr) minmax(0, 1.2fr) 160px;
  gap: 12px;
  align-items: center;
  margin-bottom: 18px;
  padding: 14px;
  border-radius: 24px;
  background: #111827;
}

.vb-filter-twelve-search input {
  width: 100%;
  min-height: 52px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.15);
  border-radius: 999px;
  outline: 0;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-twelve-search input::placeholder {
  color: rgba(255,255,255,0.62);
  -webkit-text-fill-color: rgba(255,255,255,0.62);
}

.vb-filter-twelve-departments {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-filter-twelve-departments button {
  min-height: 40px;
  padding: 9px 13px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 999px;
  background: rgba(255,255,255,0.08);
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 13px;
  font-weight: 900;
  cursor: pointer;
}

.vb-filter-twelve-departments button.is-active,
.vb-filter-twelve-departments button:hover {
  background: linear-gradient(135deg, #ec4899, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-twelve-status {
  display: grid;
  gap: 8px;
}

.vb-filter-twelve-status strong {
  display: flex;
  justify-content: center;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-filter-twelve-status button {
  min-height: 38px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-twelve-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-filter-twelve-grid article {
  display: grid;
  grid-template-columns: 76px minmax(0, 1fr);
  gap: 16px;
  align-items: center;
  padding: 20px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb-filter-twelve-grid article.is-hidden {
  display: none;
}

.vb-filter-twelve-avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 76px;
  height: 76px;
  border-radius: 24px;
  background: linear-gradient(135deg, #ec4899, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-filter-twelve-avatar.avatar-two {
  background: linear-gradient(135deg, #2563eb, #7c3aed);
}

.vb-filter-twelve-avatar.avatar-three {
  background: linear-gradient(135deg, #16a34a, #84cc16);
}

.vb-filter-twelve-avatar.avatar-four {
  background: linear-gradient(135deg, #f97316, #ef4444);
}

.vb-filter-twelve-avatar.avatar-five {
  background: linear-gradient(135deg, #0f766e, #14b8a6);
}

.vb-filter-twelve-avatar.avatar-six {
  background: linear-gradient(135deg, #be123c, #ec4899);
}

.vb-filter-twelve-avatar.avatar-seven {
  background: linear-gradient(135deg, #7c3aed, #db2777);
}

.vb-filter-twelve-avatar.avatar-eight {
  background: linear-gradient(135deg, #0f172a, #475569);
}

.vb-filter-twelve-grid small {
  display: inline-flex;
  margin-bottom: 8px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #fce7f3;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-twelve-grid h4 {
  margin: 0 0 7px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-twelve-grid p {
  margin: 0 0 10px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-filter-twelve-grid article span {
  color: #0891b2 !important;
  -webkit-text-fill-color: #0891b2 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-filter-twelve-empty {
  display: none;
  margin-top: 16px;
  padding: 22px;
  border-radius: 22px;
  background: #fdf2f8;
  border: 1px solid rgba(244, 114, 182, 0.34);
}

.vb-filter-twelve-empty.is-visible {
  display: block;
}

.vb-filter-twelve-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-twelve-empty p {
  margin: 0 !important;
  color: #9d174d !important;
  -webkit-text-fill-color: #9d174d !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb-filter-twelve-toolbar {
    grid-template-columns: 1fr;
  }

  .vb-filter-twelve-status {
    max-width: 220px;
  }

  .vb-filter-twelve-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-filter-twelve-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-twelve-team {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-twelve-top h3 {
    font-size: 38px !important;
  }

  .vb-filter-twelve-departments,
  .vb-filter-twelve-status {
    display: grid;
    grid-template-columns: 1fr;
    max-width: none;
  }

  .vb-filter-twelve-grid article {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This team directory search filter is useful for team pages, company directories, HR dashboards, agency websites, community platforms, intranet pages, university departments, and people-focused profile grids.</p>



<h2 class="wp-block-heading">13. Command Palette Search Filter</h2>



<p class="wp-block-paragraph"><strong>A command palette search filter</strong> is useful for dashboards, admin panels, web apps, SaaS products, documentation tools, and productivity interfaces. Instead of showing cards in a normal grid, this layout works like a searchable action menu where users can quickly find pages, commands, shortcuts, settings, and tools.</p>



<p class="wp-block-paragraph">This example uses a dark command interface, keyboard-style command rows, category labels, shortcut badges, live search, and a no-results state. It feels very different from a normal website card filter and works well for app-style UI examples.</p>



<ul class="wp-block-list">
<li>Command palette style search</li>
<li>Filters actions, pages, tools, and settings</li>
<li>Keyboard shortcut inspired layout</li>
<li>Dark app-style interface</li>
<li>Useful for dashboards, SaaS apps, admin panels, and productivity tools</li>
</ul>



<div class="vb-filter-thirteen-demo">
  <div class="vb-filter-thirteen-palette" data-vb-filter-thirteen>
    <div class="vb-filter-thirteen-window">
      <div class="vb-filter-thirteen-titlebar">
        <div class="vb-filter-thirteen-dots">
          <span></span>
          <span></span>
          <span></span>
        </div>
        <strong>Command Search</strong>
        <small data-vb-filter-thirteen-count>9 commands</small>
      </div>

      <div class="vb-filter-thirteen-search">
        <span>⌘</span>
        <input type="search" placeholder="Search commands, pages, settings, tools..." data-vb-filter-thirteen-input>
        <button type="button" data-vb-filter-thirteen-clear>Clear</button>
      </div>

      <div class="vb-filter-thirteen-list">
        <button type="button" data-command-text="dashboard overview analytics metrics reports homepage">
          <span class="vb-filter-thirteen-icon">⌁</span>
          <span class="vb-filter-thirteen-copy">
            <strong>Open Dashboard Overview</strong>
            <small>Analytics · Metrics · Reports</small>
          </span>
          <kbd>⌘ 1</kbd>
        </button>

        <button type="button" data-command-text="create new project website client workspace">
          <span class="vb-filter-thirteen-icon">＋</span>
          <span class="vb-filter-thirteen-copy">
            <strong>Create New Project</strong>
            <small>Workspace · Website · Client</small>
          </span>
          <kbd>⌘ N</kbd>
        </button>

        <button type="button" data-command-text="billing invoices payments subscription plan license">
          <span class="vb-filter-thirteen-icon">€</span>
          <span class="vb-filter-thirteen-copy">
            <strong>Manage Billing</strong>
            <small>Invoices · Payments · License</small>
          </span>
          <kbd>⌘ B</kbd>
        </button>

        <button type="button" data-command-text="team members users roles permissions invite">
          <span class="vb-filter-thirteen-icon">◎</span>
          <span class="vb-filter-thirteen-copy">
            <strong>Invite Team Members</strong>
            <small>Users · Roles · Permissions</small>
          </span>
          <kbd>⌘ U</kbd>
        </button>

        <button type="button" data-command-text="api keys tokens integration webhook developer">
          <span class="vb-filter-thirteen-icon">◆</span>
          <span class="vb-filter-thirteen-copy">
            <strong>View API Keys</strong>
            <small>Tokens · Webhooks · Developer</small>
          </span>
          <kbd>⌘ K</kbd>
        </button>

        <button type="button" data-command-text="settings profile password security account preferences">
          <span class="vb-filter-thirteen-icon">⚙</span>
          <span class="vb-filter-thirteen-copy">
            <strong>Account Settings</strong>
            <small>Profile · Password · Security</small>
          </span>
          <kbd>⌘ ,</kbd>
        </button>

        <button type="button" data-command-text="documentation help center guide support articles">
          <span class="vb-filter-thirteen-icon">?</span>
          <span class="vb-filter-thirteen-copy">
            <strong>Search Documentation</strong>
            <small>Help Center · Guides · Support</small>
          </span>
          <kbd>⌘ /</kbd>
        </button>

        <button type="button" data-command-text="export data csv download report backup">
          <span class="vb-filter-thirteen-icon">⇩</span>
          <span class="vb-filter-thirteen-copy">
            <strong>Export Data</strong>
            <small>CSV · Reports · Backup</small>
          </span>
          <kbd>⌘ E</kbd>
        </button>

        <button type="button" data-command-text="theme appearance dark mode color interface design">
          <span class="vb-filter-thirteen-icon">◐</span>
          <span class="vb-filter-thirteen-copy">
            <strong>Change Appearance</strong>
            <small>Theme · Dark Mode · Colors</small>
          </span>
          <kbd>⌘ T</kbd>
        </button>
      </div>

      <div class="vb-filter-thirteen-empty" data-vb-filter-thirteen-empty>
        <strong>No commands found.</strong>
        <p>Try searching for dashboard, billing, API, team, settings, export, or documentation.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-filter-thirteen-demo,
.vb-filter-thirteen-demo * {
  box-sizing: border-box;
}

.vb-filter-thirteen-demo {
  margin: 28px 0;
  padding: 42px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 18% 16%, rgba(34, 211, 238, 0.28), transparent 34%),
    radial-gradient(circle at 82% 18%, rgba(168, 85, 247, 0.24), transparent 34%),
    linear-gradient(135deg, #1e1b4b 0%, #0f172a 46%, #042f2e 100%) !important;
  border: 1px solid rgba(125, 211, 252, 0.20);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.34);
}

.vb-filter-thirteen-palette {
  max-width: 860px;
  margin: 0 auto;
  perspective: 1200px;
}

.vb-filter-thirteen-window {
  overflow: hidden;
  border-radius: 28px;
  background: rgba(15, 23, 42, 0.88);
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow:
    0 36px 100px rgba(0,0,0,0.42),
    inset 0 1px 0 rgba(255,255,255,0.08);
  backdrop-filter: blur(18px);
}

.vb-filter-thirteen-titlebar {
  display: grid;
  grid-template-columns: 90px minmax(0, 1fr) auto;
  gap: 16px;
  align-items: center;
  padding: 16px 18px;
  border-bottom: 1px solid rgba(255,255,255,0.10);
  background: rgba(255,255,255,0.05);
}

.vb-filter-thirteen-dots {
  display: flex;
  gap: 8px;
}

.vb-filter-thirteen-dots span {
  width: 12px;
  height: 12px;
  border-radius: 999px;
  background: #fb7185;
}

.vb-filter-thirteen-dots span:nth-child(2) {
  background: #facc15;
}

.vb-filter-thirteen-dots span:nth-child(3) {
  background: #34d399;
}

.vb-filter-thirteen-titlebar strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  letter-spacing: -0.02em;
  text-align: center;
}

.vb-filter-thirteen-titlebar small {
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(34, 211, 238, 0.12);
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-filter-thirteen-search {
  display: grid;
  grid-template-columns: 54px minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  padding: 18px;
  border-bottom: 1px solid rgba(255,255,255,0.10);
}

.vb-filter-thirteen-search > span {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 54px;
  border-radius: 18px;
  background: linear-gradient(135deg, #22d3ee, #8b5cf6);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  font-weight: 950;
}

.vb-filter-thirteen-search input {
  width: 100%;
  min-height: 54px;
  padding: 0 16px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 18px;
  outline: 0;
  background: rgba(255,255,255,0.08);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 800;
}

.vb-filter-thirteen-search input::placeholder {
  color: rgba(255,255,255,0.56);
  -webkit-text-fill-color: rgba(255,255,255,0.56);
}

.vb-filter-thirteen-search button {
  min-height: 54px;
  padding: 0 16px;
  border: 0;
  border-radius: 18px;
  background: #ffffff;
  color: #4c1d95 !important;
  -webkit-text-fill-color: #4c1d95 !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-thirteen-list {
  display: grid;
  gap: 6px;
  padding: 12px;
}

.vb-filter-thirteen-list button {
  display: grid;
  grid-template-columns: 48px minmax(0, 1fr) auto;
  gap: 14px;
  align-items: center;
  width: 100%;
  padding: 12px;
  border: 1px solid transparent;
  border-radius: 18px;
  background: transparent;
  text-align: left;
  cursor: pointer;
}

.vb-filter-thirteen-list button:hover {
  background: rgba(255,255,255,0.08);
  border-color: rgba(255,255,255,0.12);
}

.vb-filter-thirteen-list button.is-hidden {
  display: none;
}

.vb-filter-thirteen-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 16px;
  background: rgba(255,255,255,0.08);
  color: #67e8f9 !important;
  -webkit-text-fill-color: #67e8f9 !important;
  font-size: 22px;
  font-weight: 950;
}

.vb-filter-thirteen-copy strong {
  display: block;
  margin-bottom: 4px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-filter-thirteen-copy small {
  color: #94a3b8 !important;
  -webkit-text-fill-color: #94a3b8 !important;
  font-size: 13px;
  font-weight: 750;
}

.vb-filter-thirteen-list kbd {
  display: inline-flex;
  min-width: 54px;
  justify-content: center;
  padding: 7px 10px;
  border-radius: 10px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 12px;
  font-weight: 950;
  font-family: inherit;
}

.vb-filter-thirteen-empty {
  display: none;
  margin: 0 12px 12px;
  padding: 20px;
  border-radius: 18px;
  background: rgba(251, 146, 60, 0.12);
  border: 1px solid rgba(251, 146, 60, 0.22);
}

.vb-filter-thirteen-empty.is-visible {
  display: block;
}

.vb-filter-thirteen-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-filter-thirteen-empty p {
  margin: 0 !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 14px;
  line-height: 1.6;
}

@media (max-width: 640px) {
  .vb-filter-thirteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-thirteen-titlebar {
    grid-template-columns: 1fr;
    text-align: left;
  }

  .vb-filter-thirteen-titlebar strong {
    text-align: left;
  }

  .vb-filter-thirteen-search {
    grid-template-columns: 1fr;
  }

  .vb-filter-thirteen-list button {
    grid-template-columns: 44px minmax(0, 1fr);
  }

  .vb-filter-thirteen-list kbd {
    grid-column: 2;
    width: fit-content;
  }
}
</style>

<script>
(function () {
  const palette = document.querySelector("[data-vb-filter-thirteen]");
  if (!palette) return;

  const input = palette.querySelector("[data-vb-filter-thirteen-input]");
  const clear = palette.querySelector("[data-vb-filter-thirteen-clear]");
  const count = palette.querySelector("[data-vb-filter-thirteen-count]");
  const empty = palette.querySelector("[data-vb-filter-thirteen-empty]");
  const commands = Array.from(palette.querySelectorAll("[data-command-text]"));

  function updateCommands() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    commands.forEach(function (command) {
      const keywords = command.getAttribute("data-command-text").toLowerCase();
      const label = command.textContent.toLowerCase();
      const match = keywords.includes(query) || label.includes(query);

      command.classList.toggle("is-hidden", !match);

      if (match) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 command" : visible + " commands";
    empty.classList.toggle("is-visible", visible === 0);
  }

  input.addEventListener("input", updateCommands);

  clear.addEventListener("click", function () {
    input.value = "";
    input.focus();
    updateCommands();
  });

  updateCommands();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const palette = document.querySelector("[data-vb-filter-thirteen]");
  if (!palette) return;

  const input = palette.querySelector("[data-vb-filter-thirteen-input]");
  const clear = palette.querySelector("[data-vb-filter-thirteen-clear]");
  const count = palette.querySelector("[data-vb-filter-thirteen-count]");
  const empty = palette.querySelector("[data-vb-filter-thirteen-empty]");
  const commands = Array.from(palette.querySelectorAll("[data-command-text]"));

  function updateCommands() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    commands.forEach(function (command) {
      const keywords = command.getAttribute("data-command-text").toLowerCase();
      const label = command.textContent.toLowerCase();
      const match = keywords.includes(query) || label.includes(query);

      command.classList.toggle("is-hidden", !match);

      if (match) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 command" : visible + " commands";
    empty.classList.toggle("is-visible", visible === 0);
  }

  input.addEventListener("input", updateCommands);

  clear.addEventListener("click", function () {
    input.value = "";
    input.focus();
    updateCommands();
  });

  updateCommands();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-thirteen-demo"&gt;
  &lt;div class="vb-filter-thirteen-palette" data-vb-filter-thirteen&gt;
    &lt;div class="vb-filter-thirteen-window"&gt;
      &lt;div class="vb-filter-thirteen-titlebar"&gt;
        &lt;div class="vb-filter-thirteen-dots"&gt;
          &lt;span&gt;&lt;/span&gt;
          &lt;span&gt;&lt;/span&gt;
          &lt;span&gt;&lt;/span&gt;
        &lt;/div&gt;
        &lt;strong&gt;Command Search&lt;/strong&gt;
        &lt;small data-vb-filter-thirteen-count&gt;9 commands&lt;/small&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-thirteen-search"&gt;
        &lt;span&gt;⌘&lt;/span&gt;
        &lt;input type="search" placeholder="Search commands, pages, settings, tools..." data-vb-filter-thirteen-input&gt;
        &lt;button type="button" data-vb-filter-thirteen-clear&gt;Clear&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-thirteen-list"&gt;
        &lt;button type="button" data-command-text="dashboard overview analytics metrics reports homepage"&gt;
          &lt;span class="vb-filter-thirteen-icon"&gt;⌁&lt;/span&gt;
          &lt;span class="vb-filter-thirteen-copy"&gt;
            &lt;strong&gt;Open Dashboard Overview&lt;/strong&gt;
            &lt;small&gt;Analytics · Metrics · Reports&lt;/small&gt;
          &lt;/span&gt;
          &lt;kbd&gt;⌘ 1&lt;/kbd&gt;
        &lt;/button&gt;

        &lt;button type="button" data-command-text="create new project website client workspace"&gt;
          &lt;span class="vb-filter-thirteen-icon"&gt;＋&lt;/span&gt;
          &lt;span class="vb-filter-thirteen-copy"&gt;
            &lt;strong&gt;Create New Project&lt;/strong&gt;
            &lt;small&gt;Workspace · Website · Client&lt;/small&gt;
          &lt;/span&gt;
          &lt;kbd&gt;⌘ N&lt;/kbd&gt;
        &lt;/button&gt;

        &lt;button type="button" data-command-text="billing invoices payments subscription plan license"&gt;
          &lt;span class="vb-filter-thirteen-icon"&gt;€&lt;/span&gt;
          &lt;span class="vb-filter-thirteen-copy"&gt;
            &lt;strong&gt;Manage Billing&lt;/strong&gt;
            &lt;small&gt;Invoices · Payments · License&lt;/small&gt;
          &lt;/span&gt;
          &lt;kbd&gt;⌘ B&lt;/kbd&gt;
        &lt;/button&gt;

        &lt;button type="button" data-command-text="team members users roles permissions invite"&gt;
          &lt;span class="vb-filter-thirteen-icon"&gt;◎&lt;/span&gt;
          &lt;span class="vb-filter-thirteen-copy"&gt;
            &lt;strong&gt;Invite Team Members&lt;/strong&gt;
            &lt;small&gt;Users · Roles · Permissions&lt;/small&gt;
          &lt;/span&gt;
          &lt;kbd&gt;⌘ U&lt;/kbd&gt;
        &lt;/button&gt;

        &lt;button type="button" data-command-text="api keys tokens integration webhook developer"&gt;
          &lt;span class="vb-filter-thirteen-icon"&gt;◆&lt;/span&gt;
          &lt;span class="vb-filter-thirteen-copy"&gt;
            &lt;strong&gt;View API Keys&lt;/strong&gt;
            &lt;small&gt;Tokens · Webhooks · Developer&lt;/small&gt;
          &lt;/span&gt;
          &lt;kbd&gt;⌘ K&lt;/kbd&gt;
        &lt;/button&gt;

        &lt;button type="button" data-command-text="settings profile password security account preferences"&gt;
          &lt;span class="vb-filter-thirteen-icon"&gt;⚙&lt;/span&gt;
          &lt;span class="vb-filter-thirteen-copy"&gt;
            &lt;strong&gt;Account Settings&lt;/strong&gt;
            &lt;small&gt;Profile · Password · Security&lt;/small&gt;
          &lt;/span&gt;
          &lt;kbd&gt;⌘ ,&lt;/kbd&gt;
        &lt;/button&gt;

        &lt;button type="button" data-command-text="documentation help center guide support articles"&gt;
          &lt;span class="vb-filter-thirteen-icon"&gt;?&lt;/span&gt;
          &lt;span class="vb-filter-thirteen-copy"&gt;
            &lt;strong&gt;Search Documentation&lt;/strong&gt;
            &lt;small&gt;Help Center · Guides · Support&lt;/small&gt;
          &lt;/span&gt;
          &lt;kbd&gt;⌘ /&lt;/kbd&gt;
        &lt;/button&gt;

        &lt;button type="button" data-command-text="export data csv download report backup"&gt;
          &lt;span class="vb-filter-thirteen-icon"&gt;⇩&lt;/span&gt;
          &lt;span class="vb-filter-thirteen-copy"&gt;
            &lt;strong&gt;Export Data&lt;/strong&gt;
            &lt;small&gt;CSV · Reports · Backup&lt;/small&gt;
          &lt;/span&gt;
          &lt;kbd&gt;⌘ E&lt;/kbd&gt;
        &lt;/button&gt;

        &lt;button type="button" data-command-text="theme appearance dark mode color interface design"&gt;
          &lt;span class="vb-filter-thirteen-icon"&gt;◐&lt;/span&gt;
          &lt;span class="vb-filter-thirteen-copy"&gt;
            &lt;strong&gt;Change Appearance&lt;/strong&gt;
            &lt;small&gt;Theme · Dark Mode · Colors&lt;/small&gt;
          &lt;/span&gt;
          &lt;kbd&gt;⌘ T&lt;/kbd&gt;
        &lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-thirteen-empty" data-vb-filter-thirteen-empty&gt;
        &lt;strong&gt;No commands found.&lt;/strong&gt;
        &lt;p&gt;Try searching for dashboard, billing, API, team, settings, export, or documentation.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-thirteen-demo,
.vb-filter-thirteen-demo * {
  box-sizing: border-box;
}

.vb-filter-thirteen-demo {
  margin: 28px 0;
  padding: 42px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 18% 16%, rgba(34, 211, 238, 0.28), transparent 34%),
    radial-gradient(circle at 82% 18%, rgba(168, 85, 247, 0.24), transparent 34%),
    linear-gradient(135deg, #1e1b4b 0%, #0f172a 46%, #042f2e 100%) !important;
  border: 1px solid rgba(125, 211, 252, 0.20);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.34);
}

.vb-filter-thirteen-palette {
  max-width: 860px;
  margin: 0 auto;
  perspective: 1200px;
}

.vb-filter-thirteen-window {
  overflow: hidden;
  border-radius: 28px;
  background: rgba(15, 23, 42, 0.88);
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow:
    0 36px 100px rgba(0,0,0,0.42),
    inset 0 1px 0 rgba(255,255,255,0.08);
  backdrop-filter: blur(18px);
}

.vb-filter-thirteen-titlebar {
  display: grid;
  grid-template-columns: 90px minmax(0, 1fr) auto;
  gap: 16px;
  align-items: center;
  padding: 16px 18px;
  border-bottom: 1px solid rgba(255,255,255,0.10);
  background: rgba(255,255,255,0.05);
}

.vb-filter-thirteen-dots {
  display: flex;
  gap: 8px;
}

.vb-filter-thirteen-dots span {
  width: 12px;
  height: 12px;
  border-radius: 999px;
  background: #fb7185;
}

.vb-filter-thirteen-dots span:nth-child(2) {
  background: #facc15;
}

.vb-filter-thirteen-dots span:nth-child(3) {
  background: #34d399;
}

.vb-filter-thirteen-titlebar strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
  letter-spacing: -0.02em;
  text-align: center;
}

.vb-filter-thirteen-titlebar small {
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(34, 211, 238, 0.12);
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-filter-thirteen-search {
  display: grid;
  grid-template-columns: 54px minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  padding: 18px;
  border-bottom: 1px solid rgba(255,255,255,0.10);
}

.vb-filter-thirteen-search &gt; span {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 54px;
  border-radius: 18px;
  background: linear-gradient(135deg, #22d3ee, #8b5cf6);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  font-weight: 950;
}

.vb-filter-thirteen-search input {
  width: 100%;
  min-height: 54px;
  padding: 0 16px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 18px;
  outline: 0;
  background: rgba(255,255,255,0.08);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 800;
}

.vb-filter-thirteen-search input::placeholder {
  color: rgba(255,255,255,0.56);
  -webkit-text-fill-color: rgba(255,255,255,0.56);
}

.vb-filter-thirteen-search button {
  min-height: 54px;
  padding: 0 16px;
  border: 0;
  border-radius: 18px;
  background: #ffffff;
  color: #4c1d95 !important;
  -webkit-text-fill-color: #4c1d95 !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-thirteen-list {
  display: grid;
  gap: 6px;
  padding: 12px;
}

.vb-filter-thirteen-list button {
  display: grid;
  grid-template-columns: 48px minmax(0, 1fr) auto;
  gap: 14px;
  align-items: center;
  width: 100%;
  padding: 12px;
  border: 1px solid transparent;
  border-radius: 18px;
  background: transparent;
  text-align: left;
  cursor: pointer;
}

.vb-filter-thirteen-list button:hover {
  background: rgba(255,255,255,0.08);
  border-color: rgba(255,255,255,0.12);
}

.vb-filter-thirteen-list button.is-hidden {
  display: none;
}

.vb-filter-thirteen-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 16px;
  background: rgba(255,255,255,0.08);
  color: #67e8f9 !important;
  -webkit-text-fill-color: #67e8f9 !important;
  font-size: 22px;
  font-weight: 950;
}

.vb-filter-thirteen-copy strong {
  display: block;
  margin-bottom: 4px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-filter-thirteen-copy small {
  color: #94a3b8 !important;
  -webkit-text-fill-color: #94a3b8 !important;
  font-size: 13px;
  font-weight: 750;
}

.vb-filter-thirteen-list kbd {
  display: inline-flex;
  min-width: 54px;
  justify-content: center;
  padding: 7px 10px;
  border-radius: 10px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 12px;
  font-weight: 950;
  font-family: inherit;
}

.vb-filter-thirteen-empty {
  display: none;
  margin: 0 12px 12px;
  padding: 20px;
  border-radius: 18px;
  background: rgba(251, 146, 60, 0.12);
  border: 1px solid rgba(251, 146, 60, 0.22);
}

.vb-filter-thirteen-empty.is-visible {
  display: block;
}

.vb-filter-thirteen-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-filter-thirteen-empty p {
  margin: 0 !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 14px;
  line-height: 1.6;
}

@media (max-width: 640px) {
  .vb-filter-thirteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-thirteen-titlebar {
    grid-template-columns: 1fr;
    text-align: left;
  }

  .vb-filter-thirteen-titlebar strong {
    text-align: left;
  }

  .vb-filter-thirteen-search {
    grid-template-columns: 1fr;
  }

  .vb-filter-thirteen-list button {
    grid-template-columns: 44px minmax(0, 1fr);
  }

  .vb-filter-thirteen-list kbd {
    grid-column: 2;
    width: fit-content;
  }
}</pre>



<p class="wp-block-paragraph">This command palette search filter is useful for dashboards, SaaS apps, admin panels, productivity tools, developer platforms, documentation systems, and any web app where users need to quickly search actions instead of browsing a normal menu.</p>



<h2 class="wp-block-heading">14. Timeline Event Search Filter</h2>



<p class="wp-block-paragraph"><strong>A timeline event search filter</strong> helps users search milestones, release notes, roadmap updates, project phases, event schedules, changelogs, and product history. Instead of using cards in a normal grid, this example displays results as a vertical timeline with dates, markers, and event descriptions.</p>



<p class="wp-block-paragraph">This example filters timeline items by keyword and event type. It uses a completely different visual structure with a timeline rail, colored event dots, date blocks, search controls, and hidden timeline rows.</p>



<ul class="wp-block-list">
<li>Timeline-style search filter</li>
<li>Filters milestones, launches, updates, and events</li>
<li>Vertical rail layout instead of cards</li>
<li>Search and event type buttons</li>
<li>Useful for roadmaps, changelogs, event schedules, and project timelines</li>
</ul>



<div class="vb-filter-fourteen-demo">
  <div class="vb-filter-fourteen-timeline" data-vb-filter-fourteen>
    <div class="vb-filter-fourteen-header">
      <span>Example 14</span>
      <h3>Timeline Event Search Filter</h3>
      <p>Search project milestones, product launches, updates, and roadmap events in a vertical timeline.</p>
    </div>

    <div class="vb-filter-fourteen-controls">
      <div class="vb-filter-fourteen-search">
        <input type="search" placeholder="Search launch, beta, design, API, release..." data-vb-filter-fourteen-input>
      </div>

      <div class="vb-filter-fourteen-types">
        <button type="button" class="is-active" data-event-type="all">All</button>
        <button type="button" data-event-type="launch">Launch</button>
        <button type="button" data-event-type="update">Update</button>
        <button type="button" data-event-type="design">Design</button>
        <button type="button" data-event-type="api">API</button>
      </div>

      <div class="vb-filter-fourteen-count">
        <strong data-vb-filter-fourteen-count>8 events</strong>
        <button type="button" data-vb-filter-fourteen-reset>Reset</button>
      </div>
    </div>

    <div class="vb-filter-fourteen-rail">
      <article data-event-card="launch" data-event-text="launch public release product website go live">
        <time>Jan 12</time>
        <div class="vb-filter-fourteen-dot launch"></div>
        <div class="vb-filter-fourteen-event">
          <small>Launch</small>
          <h4>Public Website Launch</h4>
          <p>The new product website goes live with a full landing page, pricing section, FAQ, and conversion-focused UI.</p>
        </div>
      </article>

      <article data-event-card="design" data-event-text="design system colors typography components figma">
        <time>Feb 03</time>
        <div class="vb-filter-fourteen-dot design"></div>
        <div class="vb-filter-fourteen-event">
          <small>Design</small>
          <h4>Design System Refresh</h4>
          <p>Updated colors, type scale, spacing rules, button components, cards, forms, and shared Figma tokens.</p>
        </div>
      </article>

      <article data-event-card="api" data-event-text="api webhook integration token endpoints developer">
        <time>Mar 18</time>
        <div class="vb-filter-fourteen-dot api"></div>
        <div class="vb-filter-fourteen-event">
          <small>API</small>
          <h4>Webhook API Released</h4>
          <p>New webhook events and secure API token support are added for automation and external integrations.</p>
        </div>
      </article>

      <article data-event-card="update" data-event-text="update performance speed core web vitals optimization">
        <time>Apr 09</time>
        <div class="vb-filter-fourteen-dot update"></div>
        <div class="vb-filter-fourteen-event">
          <small>Update</small>
          <h4>Performance Update</h4>
          <p>CSS loading, JavaScript execution, image assets, and page rendering are optimized for faster loading.</p>
        </div>
      </article>

      <article data-event-card="launch" data-event-text="launch beta customer onboarding invite early access">
        <time>May 21</time>
        <div class="vb-filter-fourteen-dot launch"></div>
        <div class="vb-filter-fourteen-event">
          <small>Launch</small>
          <h4>Beta Access Opens</h4>
          <p>Early users are invited to test onboarding, billing, account setup, and the main product workflow.</p>
        </div>
      </article>

      <article data-event-card="design" data-event-text="design dashboard ui analytics cards charts interface">
        <time>Jun 07</time>
        <div class="vb-filter-fourteen-dot design"></div>
        <div class="vb-filter-fourteen-event">
          <small>Design</small>
          <h4>Dashboard UI Concept</h4>
          <p>New analytics cards, sidebar navigation, activity panels, and reporting widgets are designed.</p>
        </div>
      </article>

      <article data-event-card="api" data-event-text="api documentation examples sdk developer guide">
        <time>Jul 14</time>
        <div class="vb-filter-fourteen-dot api"></div>
        <div class="vb-filter-fourteen-event">
          <small>API</small>
          <h4>Developer Docs Added</h4>
          <p>API examples, authentication notes, request examples, response samples, and setup guides are published.</p>
        </div>
      </article>

      <article data-event-card="update" data-event-text="update accessibility keyboard navigation aria focus">
        <time>Aug 29</time>
        <div class="vb-filter-fourteen-dot update"></div>
        <div class="vb-filter-fourteen-event">
          <small>Update</small>
          <h4>Accessibility Improvements</h4>
          <p>Keyboard navigation, focus states, labels, contrast, ARIA attributes, and screen reader support are improved.</p>
        </div>
      </article>
    </div>

    <div class="vb-filter-fourteen-empty" data-vb-filter-fourteen-empty>
      <strong>No timeline events found.</strong>
      <p>Try searching for launch, API, design, performance, beta, accessibility, dashboard, or documentation.</p>
    </div>
  </div>
</div>

<style>
.vb-filter-fourteen-demo,
.vb-filter-fourteen-demo * {
  box-sizing: border-box;
}

.vb-filter-fourteen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 16% 18%, rgba(251, 191, 36, 0.26), transparent 34%),
    radial-gradient(circle at 84% 14%, rgba(244, 63, 94, 0.18), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fff1f2 52%, #ffffff 100%) !important;
  border: 1px solid rgba(253, 230, 138, 0.54);
  box-shadow: 0 24px 70px rgba(120, 53, 15, 0.12);
}

.vb-filter-fourteen-timeline {
  max-width: 980px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-fourteen-header {
  max-width: 760px;
  margin-bottom: 24px;
}

.vb-filter-fourteen-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fef3c7;
  color: #b45309 !important;
  -webkit-text-fill-color: #b45309 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-fourteen-header h3 {
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-fourteen-header p {
  margin: 0 !important;
  color: #57534e !important;
  -webkit-text-fill-color: #57534e !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-filter-fourteen-controls {
  display: grid;
  grid-template-columns: minmax(250px, 1fr) minmax(0, 1fr) 150px;
  gap: 12px;
  align-items: center;
  margin-bottom: 28px;
  padding: 14px;
  border-radius: 24px;
  background: #1c1917;
}

.vb-filter-fourteen-search input {
  width: 100%;
  min-height: 50px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 16px;
  outline: 0;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-fourteen-search input::placeholder {
  color: rgba(255,255,255,0.60);
  -webkit-text-fill-color: rgba(255,255,255,0.60);
}

.vb-filter-fourteen-types {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-filter-fourteen-types button {
  min-height: 38px;
  padding: 8px 12px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 999px;
  background: rgba(255,255,255,0.08);
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 12px;
  font-weight: 900;
  cursor: pointer;
}

.vb-filter-fourteen-types button.is-active,
.vb-filter-fourteen-types button:hover {
  background: linear-gradient(135deg, #f59e0b, #e11d48);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-fourteen-count {
  display: grid;
  gap: 8px;
}

.vb-filter-fourteen-count strong {
  display: flex;
  justify-content: center;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-filter-fourteen-count button {
  min-height: 36px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-fourteen-rail {
  position: relative;
  display: grid;
  gap: 18px;
}

.vb-filter-fourteen-rail::before {
  content: "";
  position: absolute;
  top: 12px;
  bottom: 12px;
  left: 116px;
  width: 4px;
  border-radius: 999px;
  background: linear-gradient(#f59e0b, #e11d48, #7c3aed);
}

.vb-filter-fourteen-rail article {
  position: relative;
  display: grid;
  grid-template-columns: 86px 32px minmax(0, 1fr);
  gap: 14px;
  align-items: start;
}

.vb-filter-fourteen-rail article.is-hidden {
  display: none;
}

.vb-filter-fourteen-rail time {
  padding-top: 12px;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 14px;
  font-weight: 950;
  text-align: right;
}

.vb-filter-fourteen-dot {
  position: relative;
  z-index: 2;
  width: 32px;
  height: 32px;
  margin-top: 6px;
  border-radius: 999px;
  background: #f59e0b;
  border: 5px solid #ffffff;
  box-shadow: 0 0 0 4px rgba(245, 158, 11, 0.18);
}

.vb-filter-fourteen-dot.launch {
  background: #f59e0b;
  box-shadow: 0 0 0 4px rgba(245, 158, 11, 0.18);
}

.vb-filter-fourteen-dot.update {
  background: #e11d48;
  box-shadow: 0 0 0 4px rgba(225, 29, 72, 0.16);
}

.vb-filter-fourteen-dot.design {
  background: #7c3aed;
  box-shadow: 0 0 0 4px rgba(124, 58, 237, 0.16);
}

.vb-filter-fourteen-dot.api {
  background: #0891b2;
  box-shadow: 0 0 0 4px rgba(8, 145, 178, 0.16);
}

.vb-filter-fourteen-event {
  padding: 20px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.08);
}

.vb-filter-fourteen-event small {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #fef3c7;
  color: #b45309 !important;
  -webkit-text-fill-color: #b45309 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-fourteen-event h4 {
  margin: 0 0 9px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-fourteen-event p {
  margin: 0 !important;
  color: #57534e !important;
  -webkit-text-fill-color: #57534e !important;
  font-size: 14px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-filter-fourteen-empty {
  display: none;
  margin-top: 20px;
  padding: 22px;
  border-radius: 22px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.38);
}

.vb-filter-fourteen-empty.is-visible {
  display: block;
}

.vb-filter-fourteen-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-fourteen-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 820px) {
  .vb-filter-fourteen-controls {
    grid-template-columns: 1fr;
  }

  .vb-filter-fourteen-count {
    max-width: 180px;
  }
}

@media (max-width: 640px) {
  .vb-filter-fourteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-fourteen-timeline {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-fourteen-header h3 {
    font-size: 38px !important;
  }

  .vb-filter-fourteen-rail::before {
    left: 15px;
  }

  .vb-filter-fourteen-rail article {
    grid-template-columns: 32px minmax(0, 1fr);
  }

  .vb-filter-fourteen-rail time {
    grid-column: 2;
    padding-top: 0;
    text-align: left;
  }

  .vb-filter-fourteen-dot {
    grid-column: 1;
    grid-row: 1 / span 2;
  }

  .vb-filter-fourteen-event {
    grid-column: 2;
  }
}
</style>

<script>
(function () {
  const timeline = document.querySelector("[data-vb-filter-fourteen]");
  if (!timeline) return;

  const input = timeline.querySelector("[data-vb-filter-fourteen-input]");
  const buttons = timeline.querySelectorAll("[data-event-type]");
  const reset = timeline.querySelector("[data-vb-filter-fourteen-reset]");
  const count = timeline.querySelector("[data-vb-filter-fourteen-count]");
  const empty = timeline.querySelector("[data-vb-filter-fourteen-empty]");
  const events = Array.from(timeline.querySelectorAll("[data-event-card]"));

  let activeType = "all";

  function updateEvents() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    events.forEach(function (event) {
      const type = event.getAttribute("data-event-card");
      const text = event.getAttribute("data-event-text").toLowerCase();
      const fullText = event.textContent.toLowerCase();

      const typeMatch = activeType === "all" || type === activeType;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = typeMatch && searchMatch;

      event.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 event" : visible + " events";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeType = button.getAttribute("data-event-type");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateEvents();
    });
  });

  input.addEventListener("input", updateEvents);

  reset.addEventListener("click", function () {
    activeType = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-event-type") === "all");
    });

    input.focus();
    updateEvents();
  });

  updateEvents();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const timeline = document.querySelector("[data-vb-filter-fourteen]");
  if (!timeline) return;

  const input = timeline.querySelector("[data-vb-filter-fourteen-input]");
  const buttons = timeline.querySelectorAll("[data-event-type]");
  const reset = timeline.querySelector("[data-vb-filter-fourteen-reset]");
  const count = timeline.querySelector("[data-vb-filter-fourteen-count]");
  const empty = timeline.querySelector("[data-vb-filter-fourteen-empty]");
  const events = Array.from(timeline.querySelectorAll("[data-event-card]"));

  let activeType = "all";

  function updateEvents() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    events.forEach(function (event) {
      const type = event.getAttribute("data-event-card");
      const text = event.getAttribute("data-event-text").toLowerCase();
      const fullText = event.textContent.toLowerCase();

      const typeMatch = activeType === "all" || type === activeType;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = typeMatch && searchMatch;

      event.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 event" : visible + " events";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeType = button.getAttribute("data-event-type");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateEvents();
    });
  });

  input.addEventListener("input", updateEvents);

  reset.addEventListener("click", function () {
    activeType = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-event-type") === "all");
    });

    input.focus();
    updateEvents();
  });

  updateEvents();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-fourteen-demo"&gt;
  &lt;div class="vb-filter-fourteen-timeline" data-vb-filter-fourteen&gt;
    &lt;div class="vb-filter-fourteen-header"&gt;
      &lt;span&gt;Example 14&lt;/span&gt;
      &lt;h3&gt;Timeline Event Search Filter&lt;/h3&gt;
      &lt;p&gt;Search project milestones, product launches, updates, and roadmap events in a vertical timeline.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-fourteen-controls"&gt;
      &lt;div class="vb-filter-fourteen-search"&gt;
        &lt;input type="search" placeholder="Search launch, beta, design, API, release..." data-vb-filter-fourteen-input&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-fourteen-types"&gt;
        &lt;button type="button" class="is-active" data-event-type="all"&gt;All&lt;/button&gt;
        &lt;button type="button" data-event-type="launch"&gt;Launch&lt;/button&gt;
        &lt;button type="button" data-event-type="update"&gt;Update&lt;/button&gt;
        &lt;button type="button" data-event-type="design"&gt;Design&lt;/button&gt;
        &lt;button type="button" data-event-type="api"&gt;API&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-fourteen-count"&gt;
        &lt;strong data-vb-filter-fourteen-count&gt;8 events&lt;/strong&gt;
        &lt;button type="button" data-vb-filter-fourteen-reset&gt;Reset&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-fourteen-rail"&gt;
      &lt;article data-event-card="launch" data-event-text="launch public release product website go live"&gt;
        &lt;time&gt;Jan 12&lt;/time&gt;
        &lt;div class="vb-filter-fourteen-dot launch"&gt;&lt;/div&gt;
        &lt;div class="vb-filter-fourteen-event"&gt;
          &lt;small&gt;Launch&lt;/small&gt;
          &lt;h4&gt;Public Website Launch&lt;/h4&gt;
          &lt;p&gt;The new product website goes live with a full landing page, pricing section, FAQ, and conversion-focused UI.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-event-card="design" data-event-text="design system colors typography components figma"&gt;
        &lt;time&gt;Feb 03&lt;/time&gt;
        &lt;div class="vb-filter-fourteen-dot design"&gt;&lt;/div&gt;
        &lt;div class="vb-filter-fourteen-event"&gt;
          &lt;small&gt;Design&lt;/small&gt;
          &lt;h4&gt;Design System Refresh&lt;/h4&gt;
          &lt;p&gt;Updated colors, type scale, spacing rules, button components, cards, forms, and shared Figma tokens.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-event-card="api" data-event-text="api webhook integration token endpoints developer"&gt;
        &lt;time&gt;Mar 18&lt;/time&gt;
        &lt;div class="vb-filter-fourteen-dot api"&gt;&lt;/div&gt;
        &lt;div class="vb-filter-fourteen-event"&gt;
          &lt;small&gt;API&lt;/small&gt;
          &lt;h4&gt;Webhook API Released&lt;/h4&gt;
          &lt;p&gt;New webhook events and secure API token support are added for automation and external integrations.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-event-card="update" data-event-text="update performance speed core web vitals optimization"&gt;
        &lt;time&gt;Apr 09&lt;/time&gt;
        &lt;div class="vb-filter-fourteen-dot update"&gt;&lt;/div&gt;
        &lt;div class="vb-filter-fourteen-event"&gt;
          &lt;small&gt;Update&lt;/small&gt;
          &lt;h4&gt;Performance Update&lt;/h4&gt;
          &lt;p&gt;CSS loading, JavaScript execution, image assets, and page rendering are optimized for faster loading.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-event-card="launch" data-event-text="launch beta customer onboarding invite early access"&gt;
        &lt;time&gt;May 21&lt;/time&gt;
        &lt;div class="vb-filter-fourteen-dot launch"&gt;&lt;/div&gt;
        &lt;div class="vb-filter-fourteen-event"&gt;
          &lt;small&gt;Launch&lt;/small&gt;
          &lt;h4&gt;Beta Access Opens&lt;/h4&gt;
          &lt;p&gt;Early users are invited to test onboarding, billing, account setup, and the main product workflow.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-event-card="design" data-event-text="design dashboard ui analytics cards charts interface"&gt;
        &lt;time&gt;Jun 07&lt;/time&gt;
        &lt;div class="vb-filter-fourteen-dot design"&gt;&lt;/div&gt;
        &lt;div class="vb-filter-fourteen-event"&gt;
          &lt;small&gt;Design&lt;/small&gt;
          &lt;h4&gt;Dashboard UI Concept&lt;/h4&gt;
          &lt;p&gt;New analytics cards, sidebar navigation, activity panels, and reporting widgets are designed.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-event-card="api" data-event-text="api documentation examples sdk developer guide"&gt;
        &lt;time&gt;Jul 14&lt;/time&gt;
        &lt;div class="vb-filter-fourteen-dot api"&gt;&lt;/div&gt;
        &lt;div class="vb-filter-fourteen-event"&gt;
          &lt;small&gt;API&lt;/small&gt;
          &lt;h4&gt;Developer Docs Added&lt;/h4&gt;
          &lt;p&gt;API examples, authentication notes, request examples, response samples, and setup guides are published.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-event-card="update" data-event-text="update accessibility keyboard navigation aria focus"&gt;
        &lt;time&gt;Aug 29&lt;/time&gt;
        &lt;div class="vb-filter-fourteen-dot update"&gt;&lt;/div&gt;
        &lt;div class="vb-filter-fourteen-event"&gt;
          &lt;small&gt;Update&lt;/small&gt;
          &lt;h4&gt;Accessibility Improvements&lt;/h4&gt;
          &lt;p&gt;Keyboard navigation, focus states, labels, contrast, ARIA attributes, and screen reader support are improved.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-fourteen-empty" data-vb-filter-fourteen-empty&gt;
      &lt;strong&gt;No timeline events found.&lt;/strong&gt;
      &lt;p&gt;Try searching for launch, API, design, performance, beta, accessibility, dashboard, or documentation.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-fourteen-demo,
.vb-filter-fourteen-demo * {
  box-sizing: border-box;
}

.vb-filter-fourteen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 16% 18%, rgba(251, 191, 36, 0.26), transparent 34%),
    radial-gradient(circle at 84% 14%, rgba(244, 63, 94, 0.18), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fff1f2 52%, #ffffff 100%) !important;
  border: 1px solid rgba(253, 230, 138, 0.54);
  box-shadow: 0 24px 70px rgba(120, 53, 15, 0.12);
}

.vb-filter-fourteen-timeline {
  max-width: 980px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-fourteen-header {
  max-width: 760px;
  margin-bottom: 24px;
}

.vb-filter-fourteen-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fef3c7;
  color: #b45309 !important;
  -webkit-text-fill-color: #b45309 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-fourteen-header h3 {
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-fourteen-header p {
  margin: 0 !important;
  color: #57534e !important;
  -webkit-text-fill-color: #57534e !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-filter-fourteen-controls {
  display: grid;
  grid-template-columns: minmax(250px, 1fr) minmax(0, 1fr) 150px;
  gap: 12px;
  align-items: center;
  margin-bottom: 28px;
  padding: 14px;
  border-radius: 24px;
  background: #1c1917;
}

.vb-filter-fourteen-search input {
  width: 100%;
  min-height: 50px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 16px;
  outline: 0;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-fourteen-search input::placeholder {
  color: rgba(255,255,255,0.60);
  -webkit-text-fill-color: rgba(255,255,255,0.60);
}

.vb-filter-fourteen-types {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-filter-fourteen-types button {
  min-height: 38px;
  padding: 8px 12px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 999px;
  background: rgba(255,255,255,0.08);
  color: #fef3c7 !important;
  -webkit-text-fill-color: #fef3c7 !important;
  font-size: 12px;
  font-weight: 900;
  cursor: pointer;
}

.vb-filter-fourteen-types button.is-active,
.vb-filter-fourteen-types button:hover {
  background: linear-gradient(135deg, #f59e0b, #e11d48);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-fourteen-count {
  display: grid;
  gap: 8px;
}

.vb-filter-fourteen-count strong {
  display: flex;
  justify-content: center;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-filter-fourteen-count button {
  min-height: 36px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-fourteen-rail {
  position: relative;
  display: grid;
  gap: 18px;
}

.vb-filter-fourteen-rail::before {
  content: "";
  position: absolute;
  top: 12px;
  bottom: 12px;
  left: 116px;
  width: 4px;
  border-radius: 999px;
  background: linear-gradient(#f59e0b, #e11d48, #7c3aed);
}

.vb-filter-fourteen-rail article {
  position: relative;
  display: grid;
  grid-template-columns: 86px 32px minmax(0, 1fr);
  gap: 14px;
  align-items: start;
}

.vb-filter-fourteen-rail article.is-hidden {
  display: none;
}

.vb-filter-fourteen-rail time {
  padding-top: 12px;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 14px;
  font-weight: 950;
  text-align: right;
}

.vb-filter-fourteen-dot {
  position: relative;
  z-index: 2;
  width: 32px;
  height: 32px;
  margin-top: 6px;
  border-radius: 999px;
  background: #f59e0b;
  border: 5px solid #ffffff;
  box-shadow: 0 0 0 4px rgba(245, 158, 11, 0.18);
}

.vb-filter-fourteen-dot.launch {
  background: #f59e0b;
  box-shadow: 0 0 0 4px rgba(245, 158, 11, 0.18);
}

.vb-filter-fourteen-dot.update {
  background: #e11d48;
  box-shadow: 0 0 0 4px rgba(225, 29, 72, 0.16);
}

.vb-filter-fourteen-dot.design {
  background: #7c3aed;
  box-shadow: 0 0 0 4px rgba(124, 58, 237, 0.16);
}

.vb-filter-fourteen-dot.api {
  background: #0891b2;
  box-shadow: 0 0 0 4px rgba(8, 145, 178, 0.16);
}

.vb-filter-fourteen-event {
  padding: 20px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.08);
}

.vb-filter-fourteen-event small {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #fef3c7;
  color: #b45309 !important;
  -webkit-text-fill-color: #b45309 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-fourteen-event h4 {
  margin: 0 0 9px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-fourteen-event p {
  margin: 0 !important;
  color: #57534e !important;
  -webkit-text-fill-color: #57534e !important;
  font-size: 14px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-filter-fourteen-empty {
  display: none;
  margin-top: 20px;
  padding: 22px;
  border-radius: 22px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.38);
}

.vb-filter-fourteen-empty.is-visible {
  display: block;
}

.vb-filter-fourteen-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-fourteen-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 820px) {
  .vb-filter-fourteen-controls {
    grid-template-columns: 1fr;
  }

  .vb-filter-fourteen-count {
    max-width: 180px;
  }
}

@media (max-width: 640px) {
  .vb-filter-fourteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-fourteen-timeline {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-fourteen-header h3 {
    font-size: 38px !important;
  }

  .vb-filter-fourteen-rail::before {
    left: 15px;
  }

  .vb-filter-fourteen-rail article {
    grid-template-columns: 32px minmax(0, 1fr);
  }

  .vb-filter-fourteen-rail time {
    grid-column: 2;
    padding-top: 0;
    text-align: left;
  }

  .vb-filter-fourteen-dot {
    grid-column: 1;
    grid-row: 1 / span 2;
  }

  .vb-filter-fourteen-event {
    grid-column: 2;
  }
}</pre>



<p class="wp-block-paragraph">This timeline event search filter is useful for product roadmaps, release notes, changelogs, company history sections, project timelines, event schedules, launch plans, and milestone-based content where users need to search dated events.</p>



<h2 class="wp-block-heading">15. Location Finder Search Filter</h2>



<p class="wp-block-paragraph"><strong>A location finder search filter</strong> helps users find stores, offices, pickup points, service areas, clinics, restaurants, or branches by city, country, service type, or keyword. This layout is different from a normal grid because it combines a searchable sidebar with a visual map-style panel.</p>



<p class="wp-block-paragraph">This example filters locations by text search and service type. The results appear as a vertical location list beside a decorative map area with matching location pins.</p>



<ul class="wp-block-list">
<li>Location finder layout</li>
<li>Search by city, service, or country</li>
<li>Service type filter buttons</li>
<li>Map-inspired visual panel</li>
<li>Useful for store locators, service areas, offices, clinics, and pickup points</li>
</ul>



<div class="vb-filter-fifteen-demo">
  <div class="vb-filter-fifteen-locator" data-vb-filter-fifteen>
    <section class="vb-filter-fifteen-panel">
      <div class="vb-filter-fifteen-intro">
        <span>Example 15</span>
        <h3>Location Finder Search Filter</h3>
        <p>Search locations by city, country, service, or pickup option.</p>
      </div>

      <div class="vb-filter-fifteen-search">
        <input type="search" placeholder="Search Tallinn, Berlin, pickup, showroom..." data-vb-filter-fifteen-input>
      </div>

      <div class="vb-filter-fifteen-tabs">
        <button type="button" class="is-active" data-location-type="all">All</button>
        <button type="button" data-location-type="showroom">Showrooms</button>
        <button type="button" data-location-type="pickup">Pickup</button>
        <button type="button" data-location-type="support">Support</button>
      </div>

      <div class="vb-filter-fifteen-meta">
        <strong data-vb-filter-fifteen-count>7 locations</strong>
        <button type="button" data-vb-filter-fifteen-reset>Reset</button>
      </div>

      <div class="vb-filter-fifteen-results">
        <article data-location-card="showroom" data-location-text="tallinn estonia showroom products consultation city center">
          <strong>Tallinn Showroom</strong>
          <span>Estonia · Showroom</span>
          <p>Product demos, consultations, and local customer meetings.</p>
        </article>

        <article data-location-card="pickup" data-location-text="tartu estonia pickup warehouse orders collection">
          <strong>Tartu Pickup Point</strong>
          <span>Estonia · Pickup</span>
          <p>Collect online orders and small product packages.</p>
        </article>

        <article data-location-card="support" data-location-text="helsinki finland support technical help customers">
          <strong>Helsinki Support Desk</strong>
          <span>Finland · Support</span>
          <p>Technical help, onboarding calls, and product support.</p>
        </article>

        <article data-location-card="showroom" data-location-text="riga latvia showroom sales consultation display">
          <strong>Riga Display Center</strong>
          <span>Latvia · Showroom</span>
          <p>Visit the product display area and speak with a sales specialist.</p>
        </article>

        <article data-location-card="pickup" data-location-text="berlin germany pickup logistics warehouse eu">
          <strong>Berlin Pickup Hub</strong>
          <span>Germany · Pickup</span>
          <p>European pickup and logistics point for selected orders.</p>
        </article>

        <article data-location-card="support" data-location-text="stockholm sweden support onboarding help team">
          <strong>Stockholm Help Center</strong>
          <span>Sweden · Support</span>
          <p>Customer onboarding, setup guidance, and account support.</p>
        </article>

        <article data-location-card="showroom" data-location-text="warsaw poland showroom products demo sales">
          <strong>Warsaw Demo Room</strong>
          <span>Poland · Showroom</span>
          <p>Product demonstrations and partner sales meetings.</p>
        </article>
      </div>

      <div class="vb-filter-fifteen-empty" data-vb-filter-fifteen-empty>
        <strong>No locations found.</strong>
        <p>Try searching for Tallinn, pickup, showroom, support, Berlin, Riga, or Helsinki.</p>
      </div>
    </section>

    <section class="vb-filter-fifteen-map" aria-label="Decorative location map">
      <div class="vb-filter-fifteen-map-grid"></div>
      <span class="pin pin-one"></span>
      <span class="pin pin-two"></span>
      <span class="pin pin-three"></span>
      <span class="pin pin-four"></span>
      <div class="vb-filter-fifteen-map-card">
        <small>Live filter UI</small>
        <strong>Location Map</strong>
        <p>Use the search and service buttons to narrow visible locations.</p>
      </div>
    </section>
  </div>
</div>

<style>
.vb-filter-fifteen-demo,
.vb-filter-fifteen-demo * {
  box-sizing: border-box;
}

.vb-filter-fifteen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(16, 185, 129, 0.22), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(59, 130, 246, 0.18), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #eff6ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(167, 243, 208, 0.52);
  box-shadow: 0 24px 70px rgba(6, 95, 70, 0.12);
}

.vb-filter-fifteen-locator {
  display: grid;
  grid-template-columns: 420px minmax(0, 1fr);
  gap: 18px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-filter-fifteen-panel {
  padding: 28px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-fifteen-intro span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #d1fae5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-fifteen-intro h3 {
  margin: 0 0 12px !important;
  color: #064e3b !important;
  -webkit-text-fill-color: #064e3b !important;
  font-size: clamp(34px, 4vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-fifteen-intro p {
  margin: 0 0 20px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-fifteen-search {
  margin-bottom: 12px;
}

.vb-filter-fifteen-search input {
  width: 100%;
  min-height: 56px;
  padding: 0 16px;
  border: 1px solid rgba(148, 163, 184, 0.28);
  border-radius: 18px;
  outline: 0;
  background: #f8fafc;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-fifteen-tabs {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
  margin-bottom: 12px;
}

.vb-filter-fifteen-tabs button {
  min-height: 42px;
  border: 0;
  border-radius: 14px;
  background: #ecfdf5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-fifteen-tabs button.is-active,
.vb-filter-fifteen-tabs button:hover {
  background: linear-gradient(135deg, #10b981, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-fifteen-meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  margin-bottom: 14px;
  padding: 12px;
  border-radius: 18px;
  background: #064e3b;
}

.vb-filter-fifteen-meta strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-filter-fifteen-meta button {
  min-height: 36px;
  padding: 8px 12px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-fifteen-results {
  display: grid;
  gap: 10px;
}

.vb-filter-fifteen-results article {
  padding: 16px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 10px 28px rgba(15, 23, 42, 0.06);
}

.vb-filter-fifteen-results article.is-hidden {
  display: none;
}

.vb-filter-fifteen-results strong {
  display: block;
  margin-bottom: 5px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 17px;
  font-weight: 950;
}

.vb-filter-fifteen-results span {
  display: block;
  margin-bottom: 8px;
  color: #059669 !important;
  -webkit-text-fill-color: #059669 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-filter-fifteen-results p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-filter-fifteen-map {
  position: relative;
  overflow: hidden;
  min-height: 720px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 28% 24%, rgba(255,255,255,0.32), transparent 20%),
    radial-gradient(circle at 72% 58%, rgba(255,255,255,0.20), transparent 24%),
    linear-gradient(135deg, #0f766e 0%, #2563eb 54%, #312e81 100%) !important;
  border: 1px solid rgba(255,255,255,0.18);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.24);
}

.vb-filter-fifteen-map-grid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(255,255,255,0.10) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,0.10) 1px, transparent 1px);
  background-size: 54px 54px;
  opacity: 0.42;
}

.vb-filter-fifteen-map .pin {
  position: absolute;
  width: 26px;
  height: 26px;
  border-radius: 999px 999px 999px 4px;
  background: #ffffff;
  transform: rotate(-45deg);
  box-shadow: 0 0 0 8px rgba(255,255,255,0.16), 0 20px 34px rgba(0,0,0,0.26);
}

.vb-filter-fifteen-map .pin::after {
  content: "";
  position: absolute;
  inset: 8px;
  border-radius: 999px;
  background: #10b981;
}

.vb-filter-fifteen-map .pin-one {
  top: 18%;
  left: 22%;
}

.vb-filter-fifteen-map .pin-two {
  top: 38%;
  left: 68%;
}

.vb-filter-fifteen-map .pin-three {
  top: 62%;
  left: 32%;
}

.vb-filter-fifteen-map .pin-four {
  top: 72%;
  left: 72%;
}

.vb-filter-fifteen-map-card {
  position: absolute;
  left: 26px;
  right: 26px;
  bottom: 26px;
  padding: 22px;
  border-radius: 24px;
  background: rgba(15, 23, 42, 0.78);
  border: 1px solid rgba(255,255,255,0.16);
  backdrop-filter: blur(14px);
}

.vb-filter-fifteen-map-card small {
  display: inline-flex;
  margin-bottom: 8px;
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-fifteen-map-card strong {
  display: block;
  margin-bottom: 8px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 28px;
  font-weight: 950;
}

.vb-filter-fifteen-map-card p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 15px;
  line-height: 1.6;
}

.vb-filter-fifteen-empty {
  display: none;
  margin-top: 12px;
  padding: 18px;
  border-radius: 18px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.34);
}

.vb-filter-fifteen-empty.is-visible {
  display: block;
}

.vb-filter-fifteen-empty strong {
  display: block;
  margin-bottom: 6px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-filter-fifteen-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 14px;
  line-height: 1.55;
}

@media (max-width: 960px) {
  .vb-filter-fifteen-locator {
    grid-template-columns: 1fr;
  }

  .vb-filter-fifteen-map {
    min-height: 420px;
  }
}

@media (max-width: 640px) {
  .vb-filter-fifteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-fifteen-panel {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-fifteen-intro h3 {
    font-size: 38px !important;
  }

  .vb-filter-fifteen-tabs {
    grid-template-columns: 1fr;
  }

  .vb-filter-fifteen-meta {
    align-items: stretch;
    flex-direction: column;
  }

  .vb-filter-fifteen-meta button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const locator = document.querySelector("[data-vb-filter-fifteen]");
  if (!locator) return;

  const input = locator.querySelector("[data-vb-filter-fifteen-input]");
  const buttons = locator.querySelectorAll("[data-location-type]");
  const reset = locator.querySelector("[data-vb-filter-fifteen-reset]");
  const count = locator.querySelector("[data-vb-filter-fifteen-count]");
  const empty = locator.querySelector("[data-vb-filter-fifteen-empty]");
  const locations = Array.from(locator.querySelectorAll("[data-location-card]"));

  let activeType = "all";

  function updateLocations() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    locations.forEach(function (location) {
      const type = location.getAttribute("data-location-card");
      const text = location.getAttribute("data-location-text").toLowerCase();
      const fullText = location.textContent.toLowerCase();

      const typeMatch = activeType === "all" || type === activeType;
      const queryMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = typeMatch && queryMatch;

      location.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 location" : visible + " locations";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeType = button.getAttribute("data-location-type");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateLocations();
    });
  });

  input.addEventListener("input", updateLocations);

  reset.addEventListener("click", function () {
    activeType = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-location-type") === "all");
    });

    input.focus();
    updateLocations();
  });

  updateLocations();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const locator = document.querySelector("[data-vb-filter-fifteen]");
  if (!locator) return;

  const input = locator.querySelector("[data-vb-filter-fifteen-input]");
  const buttons = locator.querySelectorAll("[data-location-type]");
  const reset = locator.querySelector("[data-vb-filter-fifteen-reset]");
  const count = locator.querySelector("[data-vb-filter-fifteen-count]");
  const empty = locator.querySelector("[data-vb-filter-fifteen-empty]");
  const locations = Array.from(locator.querySelectorAll("[data-location-card]"));

  let activeType = "all";

  function updateLocations() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    locations.forEach(function (location) {
      const type = location.getAttribute("data-location-card");
      const text = location.getAttribute("data-location-text").toLowerCase();
      const fullText = location.textContent.toLowerCase();

      const typeMatch = activeType === "all" || type === activeType;
      const queryMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = typeMatch && queryMatch;

      location.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 location" : visible + " locations";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeType = button.getAttribute("data-location-type");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateLocations();
    });
  });

  input.addEventListener("input", updateLocations);

  reset.addEventListener("click", function () {
    activeType = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-location-type") === "all");
    });

    input.focus();
    updateLocations();
  });

  updateLocations();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-fifteen-demo"&gt;
  &lt;div class="vb-filter-fifteen-locator" data-vb-filter-fifteen&gt;
    &lt;section class="vb-filter-fifteen-panel"&gt;
      &lt;div class="vb-filter-fifteen-intro"&gt;
        &lt;span&gt;Example 15&lt;/span&gt;
        &lt;h3&gt;Location Finder Search Filter&lt;/h3&gt;
        &lt;p&gt;Search locations by city, country, service, or pickup option.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-fifteen-search"&gt;
        &lt;input type="search" placeholder="Search Tallinn, Berlin, pickup, showroom..." data-vb-filter-fifteen-input&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-fifteen-tabs"&gt;
        &lt;button type="button" class="is-active" data-location-type="all"&gt;All&lt;/button&gt;
        &lt;button type="button" data-location-type="showroom"&gt;Showrooms&lt;/button&gt;
        &lt;button type="button" data-location-type="pickup"&gt;Pickup&lt;/button&gt;
        &lt;button type="button" data-location-type="support"&gt;Support&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-fifteen-meta"&gt;
        &lt;strong data-vb-filter-fifteen-count&gt;7 locations&lt;/strong&gt;
        &lt;button type="button" data-vb-filter-fifteen-reset&gt;Reset&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-fifteen-results"&gt;
        &lt;article data-location-card="showroom" data-location-text="tallinn estonia showroom products consultation city center"&gt;
          &lt;strong&gt;Tallinn Showroom&lt;/strong&gt;
          &lt;span&gt;Estonia · Showroom&lt;/span&gt;
          &lt;p&gt;Product demos, consultations, and local customer meetings.&lt;/p&gt;
        &lt;/article&gt;

        &lt;article data-location-card="pickup" data-location-text="tartu estonia pickup warehouse orders collection"&gt;
          &lt;strong&gt;Tartu Pickup Point&lt;/strong&gt;
          &lt;span&gt;Estonia · Pickup&lt;/span&gt;
          &lt;p&gt;Collect online orders and small product packages.&lt;/p&gt;
        &lt;/article&gt;

        &lt;article data-location-card="support" data-location-text="helsinki finland support technical help customers"&gt;
          &lt;strong&gt;Helsinki Support Desk&lt;/strong&gt;
          &lt;span&gt;Finland · Support&lt;/span&gt;
          &lt;p&gt;Technical help, onboarding calls, and product support.&lt;/p&gt;
        &lt;/article&gt;

        &lt;article data-location-card="showroom" data-location-text="riga latvia showroom sales consultation display"&gt;
          &lt;strong&gt;Riga Display Center&lt;/strong&gt;
          &lt;span&gt;Latvia · Showroom&lt;/span&gt;
          &lt;p&gt;Visit the product display area and speak with a sales specialist.&lt;/p&gt;
        &lt;/article&gt;

        &lt;article data-location-card="pickup" data-location-text="berlin germany pickup logistics warehouse eu"&gt;
          &lt;strong&gt;Berlin Pickup Hub&lt;/strong&gt;
          &lt;span&gt;Germany · Pickup&lt;/span&gt;
          &lt;p&gt;European pickup and logistics point for selected orders.&lt;/p&gt;
        &lt;/article&gt;

        &lt;article data-location-card="support" data-location-text="stockholm sweden support onboarding help team"&gt;
          &lt;strong&gt;Stockholm Help Center&lt;/strong&gt;
          &lt;span&gt;Sweden · Support&lt;/span&gt;
          &lt;p&gt;Customer onboarding, setup guidance, and account support.&lt;/p&gt;
        &lt;/article&gt;

        &lt;article data-location-card="showroom" data-location-text="warsaw poland showroom products demo sales"&gt;
          &lt;strong&gt;Warsaw Demo Room&lt;/strong&gt;
          &lt;span&gt;Poland · Showroom&lt;/span&gt;
          &lt;p&gt;Product demonstrations and partner sales meetings.&lt;/p&gt;
        &lt;/article&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-fifteen-empty" data-vb-filter-fifteen-empty&gt;
        &lt;strong&gt;No locations found.&lt;/strong&gt;
        &lt;p&gt;Try searching for Tallinn, pickup, showroom, support, Berlin, Riga, or Helsinki.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/section&gt;

    &lt;section class="vb-filter-fifteen-map" aria-label="Decorative location map"&gt;
      &lt;div class="vb-filter-fifteen-map-grid"&gt;&lt;/div&gt;
      &lt;span class="pin pin-one"&gt;&lt;/span&gt;
      &lt;span class="pin pin-two"&gt;&lt;/span&gt;
      &lt;span class="pin pin-three"&gt;&lt;/span&gt;
      &lt;span class="pin pin-four"&gt;&lt;/span&gt;
      &lt;div class="vb-filter-fifteen-map-card"&gt;
        &lt;small&gt;Live filter UI&lt;/small&gt;
        &lt;strong&gt;Location Map&lt;/strong&gt;
        &lt;p&gt;Use the search and service buttons to narrow visible locations.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/section&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-fifteen-demo,
.vb-filter-fifteen-demo * {
  box-sizing: border-box;
}

.vb-filter-fifteen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(16, 185, 129, 0.22), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(59, 130, 246, 0.18), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #eff6ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(167, 243, 208, 0.52);
  box-shadow: 0 24px 70px rgba(6, 95, 70, 0.12);
}

.vb-filter-fifteen-locator {
  display: grid;
  grid-template-columns: 420px minmax(0, 1fr);
  gap: 18px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-filter-fifteen-panel {
  padding: 28px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-fifteen-intro span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #d1fae5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-fifteen-intro h3 {
  margin: 0 0 12px !important;
  color: #064e3b !important;
  -webkit-text-fill-color: #064e3b !important;
  font-size: clamp(34px, 4vw, 58px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-fifteen-intro p {
  margin: 0 0 20px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-fifteen-search {
  margin-bottom: 12px;
}

.vb-filter-fifteen-search input {
  width: 100%;
  min-height: 56px;
  padding: 0 16px;
  border: 1px solid rgba(148, 163, 184, 0.28);
  border-radius: 18px;
  outline: 0;
  background: #f8fafc;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-fifteen-tabs {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
  margin-bottom: 12px;
}

.vb-filter-fifteen-tabs button {
  min-height: 42px;
  border: 0;
  border-radius: 14px;
  background: #ecfdf5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-fifteen-tabs button.is-active,
.vb-filter-fifteen-tabs button:hover {
  background: linear-gradient(135deg, #10b981, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-fifteen-meta {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  margin-bottom: 14px;
  padding: 12px;
  border-radius: 18px;
  background: #064e3b;
}

.vb-filter-fifteen-meta strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-filter-fifteen-meta button {
  min-height: 36px;
  padding: 8px 12px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-fifteen-results {
  display: grid;
  gap: 10px;
}

.vb-filter-fifteen-results article {
  padding: 16px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 10px 28px rgba(15, 23, 42, 0.06);
}

.vb-filter-fifteen-results article.is-hidden {
  display: none;
}

.vb-filter-fifteen-results strong {
  display: block;
  margin-bottom: 5px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 17px;
  font-weight: 950;
}

.vb-filter-fifteen-results span {
  display: block;
  margin-bottom: 8px;
  color: #059669 !important;
  -webkit-text-fill-color: #059669 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-filter-fifteen-results p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-filter-fifteen-map {
  position: relative;
  overflow: hidden;
  min-height: 720px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 28% 24%, rgba(255,255,255,0.32), transparent 20%),
    radial-gradient(circle at 72% 58%, rgba(255,255,255,0.20), transparent 24%),
    linear-gradient(135deg, #0f766e 0%, #2563eb 54%, #312e81 100%) !important;
  border: 1px solid rgba(255,255,255,0.18);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.24);
}

.vb-filter-fifteen-map-grid {
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(255,255,255,0.10) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,0.10) 1px, transparent 1px);
  background-size: 54px 54px;
  opacity: 0.42;
}

.vb-filter-fifteen-map .pin {
  position: absolute;
  width: 26px;
  height: 26px;
  border-radius: 999px 999px 999px 4px;
  background: #ffffff;
  transform: rotate(-45deg);
  box-shadow: 0 0 0 8px rgba(255,255,255,0.16), 0 20px 34px rgba(0,0,0,0.26);
}

.vb-filter-fifteen-map .pin::after {
  content: "";
  position: absolute;
  inset: 8px;
  border-radius: 999px;
  background: #10b981;
}

.vb-filter-fifteen-map .pin-one {
  top: 18%;
  left: 22%;
}

.vb-filter-fifteen-map .pin-two {
  top: 38%;
  left: 68%;
}

.vb-filter-fifteen-map .pin-three {
  top: 62%;
  left: 32%;
}

.vb-filter-fifteen-map .pin-four {
  top: 72%;
  left: 72%;
}

.vb-filter-fifteen-map-card {
  position: absolute;
  left: 26px;
  right: 26px;
  bottom: 26px;
  padding: 22px;
  border-radius: 24px;
  background: rgba(15, 23, 42, 0.78);
  border: 1px solid rgba(255,255,255,0.16);
  backdrop-filter: blur(14px);
}

.vb-filter-fifteen-map-card small {
  display: inline-flex;
  margin-bottom: 8px;
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-fifteen-map-card strong {
  display: block;
  margin-bottom: 8px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 28px;
  font-weight: 950;
}

.vb-filter-fifteen-map-card p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 15px;
  line-height: 1.6;
}

.vb-filter-fifteen-empty {
  display: none;
  margin-top: 12px;
  padding: 18px;
  border-radius: 18px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.34);
}

.vb-filter-fifteen-empty.is-visible {
  display: block;
}

.vb-filter-fifteen-empty strong {
  display: block;
  margin-bottom: 6px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-filter-fifteen-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 14px;
  line-height: 1.55;
}

@media (max-width: 960px) {
  .vb-filter-fifteen-locator {
    grid-template-columns: 1fr;
  }

  .vb-filter-fifteen-map {
    min-height: 420px;
  }
}

@media (max-width: 640px) {
  .vb-filter-fifteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-fifteen-panel {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-fifteen-intro h3 {
    font-size: 38px !important;
  }

  .vb-filter-fifteen-tabs {
    grid-template-columns: 1fr;
  }

  .vb-filter-fifteen-meta {
    align-items: stretch;
    flex-direction: column;
  }

  .vb-filter-fifteen-meta button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This location finder search filter is useful for store locator pages, service area pages, pickup point directories, clinic finders, restaurant locations, office directories, and business websites with multiple physical locations.</p>



<h2 class="wp-block-heading">16. Kanban Board Search Filter</h2>



<p class="wp-block-paragraph"><strong>A Kanban board search filter</strong> helps users search tasks across workflow columns such as To Do, In Progress, Review, and Done. This layout is useful for project management dashboards, task apps, CRM pipelines, editorial calendars, software planning tools, and productivity interfaces.</p>



<p class="wp-block-paragraph">This example is not a card grid. It uses a multi-column Kanban board where task cards stay inside their columns while the JavaScript hides non-matching tasks and updates the visible task count.</p>



<ul class="wp-block-list">
<li>Kanban board search layout</li>
<li>Filters tasks across multiple workflow columns</li>
<li>Searches task title, label, owner, and description</li>
<li>Dashboard-style project UI</li>
<li>Useful for task boards, CRM pipelines, roadmaps, and productivity apps</li>
</ul>



<div class="vb-filter-sixteen-demo">
  <div class="vb-filter-sixteen-board" data-vb-filter-sixteen>
    <header class="vb-filter-sixteen-header">
      <div>
        <span>Example 16</span>
        <h3>Kanban Board Search Filter</h3>
        <p>Search tasks across workflow columns without changing the board layout.</p>
      </div>

      <div class="vb-filter-sixteen-tools">
        <input type="search" placeholder="Search design, API, urgent, Laura..." data-vb-filter-sixteen-input>
        <div>
          <strong data-vb-filter-sixteen-count>10 tasks</strong>
          <button type="button" data-vb-filter-sixteen-clear>Clear</button>
        </div>
      </div>
    </header>

    <div class="vb-filter-sixteen-columns">
      <section>
        <h4>To Do</h4>

        <article data-task-text="design hero section landing page laura ui">
          <small>Design</small>
          <strong>Hero section concept</strong>
          <p>Create a new landing page hero with CTA buttons and trust badges.</p>
          <span>Laura</span>
        </article>

        <article data-task-text="seo keyword research blog content mark">
          <small>SEO</small>
          <strong>Keyword research</strong>
          <p>Collect long-tail keywords for the next JavaScript tutorial article.</p>
          <span>Mark</span>
        </article>

        <article data-task-text="support faq documentation nina">
          <small>Docs</small>
          <strong>FAQ updates</strong>
          <p>Rewrite help center answers for onboarding and billing questions.</p>
          <span>Nina</span>
        </article>
      </section>

      <section>
        <h4>In Progress</h4>

        <article data-task-text="api integration webhook backend alex urgent">
          <small>API</small>
          <strong>Webhook integration</strong>
          <p>Connect order events to the automation workflow endpoint.</p>
          <span>Alex</span>
        </article>

        <article data-task-text="frontend filter component javascript sara">
          <small>Frontend</small>
          <strong>Filter component</strong>
          <p>Build reusable JavaScript filtering for cards and table rows.</p>
          <span>Sara</span>
        </article>

        <article data-task-text="checkout ui ecommerce design tom">
          <small>UI</small>
          <strong>Checkout layout</strong>
          <p>Improve cart summary spacing, mobile inputs, and order buttons.</p>
          <span>Tom</span>
        </article>
      </section>

      <section>
        <h4>Review</h4>

        <article data-task-text="accessibility aria keyboard focus review maria">
          <small>A11y</small>
          <strong>Keyboard review</strong>
          <p>Test focus states, ARIA labels, and keyboard navigation flow.</p>
          <span>Maria</span>
        </article>

        <article data-task-text="performance optimization images css javascript dan">
          <small>Speed</small>
          <strong>Performance pass</strong>
          <p>Check image loading, CSS size, and JavaScript execution time.</p>
          <span>Dan</span>
        </article>
      </section>

      <section>
        <h4>Done</h4>

        <article data-task-text="modal examples published blog javascript content">
          <small>Content</small>
          <strong>Modal post published</strong>
          <p>Final article published with examples, SEO settings, and internal links.</p>
          <span>Done</span>
        </article>

        <article data-task-text="dropdown menu article complete navigation javascript">
          <small>Content</small>
          <strong>Dropdown article complete</strong>
          <p>Dropdown guide completed with custom selects and navigation examples.</p>
          <span>Done</span>
        </article>
      </section>
    </div>

    <div class="vb-filter-sixteen-empty" data-vb-filter-sixteen-empty>
      <strong>No tasks found.</strong>
      <p>Try searching for API, design, SEO, urgent, checkout, accessibility, or a person name.</p>
    </div>
  </div>
</div>

<style>
.vb-filter-sixteen-demo,
.vb-filter-sixteen-demo * {
  box-sizing: border-box;
}

.vb-filter-sixteen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 15% 16%, rgba(129, 140, 248, 0.24), transparent 34%),
    radial-gradient(circle at 85% 14%, rgba(244, 114, 182, 0.18), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #fdf2f8 52%, #ffffff 100%) !important;
  border: 1px solid rgba(199, 210, 254, 0.52);
  box-shadow: 0 24px 70px rgba(67, 56, 202, 0.12);
}

.vb-filter-sixteen-board {
  max-width: 1180px;
  margin: 0 auto;
  padding: 24px;
  border-radius: 30px;
  background: #111827;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
}

.vb-filter-sixteen-header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 380px;
  gap: 22px;
  align-items: end;
  margin-bottom: 20px;
}

.vb-filter-sixteen-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(129, 140, 248, 0.18);
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-sixteen-header h3 {
  margin: 0 0 12px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-sixteen-header p {
  max-width: 700px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-sixteen-tools {
  display: grid;
  gap: 10px;
  padding: 14px;
  border-radius: 22px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-filter-sixteen-tools input {
  width: 100%;
  min-height: 52px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 16px;
  outline: 0;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-sixteen-tools input::placeholder {
  color: rgba(255,255,255,0.58);
  -webkit-text-fill-color: rgba(255,255,255,0.58);
}

.vb-filter-sixteen-tools div {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.vb-filter-sixteen-tools strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-filter-sixteen-tools button {
  min-height: 36px;
  padding: 8px 12px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-sixteen-columns {
  display: grid;
  grid-template-columns: repeat(4, minmax(230px, 1fr));
  gap: 14px;
  overflow-x: auto;
  padding-bottom: 4px;
}

.vb-filter-sixteen-columns section {
  min-width: 230px;
  padding: 12px;
  border-radius: 22px;
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-filter-sixteen-columns h4 {
  margin: 0 0 12px !important;
  padding: 10px 10px 0;
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 15px !important;
  font-weight: 950 !important;
  letter-spacing: -0.02em;
}

.vb-filter-sixteen-columns article {
  padding: 16px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(255,255,255,0.10);
  box-shadow: 0 14px 34px rgba(2, 6, 23, 0.18);
}

.vb-filter-sixteen-columns article + article {
  margin-top: 10px;
}

.vb-filter-sixteen-columns article.is-hidden {
  display: none;
}

.vb-filter-sixteen-columns small {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #eef2ff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-sixteen-columns strong {
  display: block;
  margin-bottom: 8px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 17px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-filter-sixteen-columns p {
  margin: 0 0 12px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-filter-sixteen-columns article span {
  display: inline-flex;
  color: #db2777 !important;
  -webkit-text-fill-color: #db2777 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-filter-sixteen-empty {
  display: none;
  margin-top: 16px;
  padding: 20px;
  border-radius: 20px;
  background: rgba(251, 146, 60, 0.12);
  border: 1px solid rgba(251, 146, 60, 0.24);
}

.vb-filter-sixteen-empty.is-visible {
  display: block;
}

.vb-filter-sixteen-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-sixteen-empty p {
  margin: 0 !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 14px;
  line-height: 1.6;
}

@media (max-width: 980px) {
  .vb-filter-sixteen-header {
    grid-template-columns: 1fr;
  }

  .vb-filter-sixteen-tools {
    max-width: 520px;
  }
}

@media (max-width: 640px) {
  .vb-filter-sixteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-sixteen-board {
    padding: 18px;
    border-radius: 22px;
  }

  .vb-filter-sixteen-header h3 {
    font-size: 38px !important;
  }

  .vb-filter-sixteen-tools div {
    align-items: stretch;
    flex-direction: column;
  }

  .vb-filter-sixteen-tools button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const board = document.querySelector("[data-vb-filter-sixteen]");
  if (!board) return;

  const input = board.querySelector("[data-vb-filter-sixteen-input]");
  const clear = board.querySelector("[data-vb-filter-sixteen-clear]");
  const count = board.querySelector("[data-vb-filter-sixteen-count]");
  const empty = board.querySelector("[data-vb-filter-sixteen-empty]");
  const tasks = Array.from(board.querySelectorAll("[data-task-text]"));

  function updateTasks() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    tasks.forEach(function (task) {
      const text = task.getAttribute("data-task-text").toLowerCase();
      const fullText = task.textContent.toLowerCase();
      const match = text.includes(query) || fullText.includes(query);

      task.classList.toggle("is-hidden", !match);

      if (match) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 task" : visible + " tasks";
    empty.classList.toggle("is-visible", visible === 0);
  }

  input.addEventListener("input", updateTasks);

  clear.addEventListener("click", function () {
    input.value = "";
    input.focus();
    updateTasks();
  });

  updateTasks();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const board = document.querySelector("[data-vb-filter-sixteen]");
  if (!board) return;

  const input = board.querySelector("[data-vb-filter-sixteen-input]");
  const clear = board.querySelector("[data-vb-filter-sixteen-clear]");
  const count = board.querySelector("[data-vb-filter-sixteen-count]");
  const empty = board.querySelector("[data-vb-filter-sixteen-empty]");
  const tasks = Array.from(board.querySelectorAll("[data-task-text]"));

  function updateTasks() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    tasks.forEach(function (task) {
      const text = task.getAttribute("data-task-text").toLowerCase();
      const fullText = task.textContent.toLowerCase();
      const match = text.includes(query) || fullText.includes(query);

      task.classList.toggle("is-hidden", !match);

      if (match) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 task" : visible + " tasks";
    empty.classList.toggle("is-visible", visible === 0);
  }

  input.addEventListener("input", updateTasks);

  clear.addEventListener("click", function () {
    input.value = "";
    input.focus();
    updateTasks();
  });

  updateTasks();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-sixteen-demo"&gt;
  &lt;div class="vb-filter-sixteen-board" data-vb-filter-sixteen&gt;
    &lt;header class="vb-filter-sixteen-header"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 16&lt;/span&gt;
        &lt;h3&gt;Kanban Board Search Filter&lt;/h3&gt;
        &lt;p&gt;Search tasks across workflow columns without changing the board layout.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-sixteen-tools"&gt;
        &lt;input type="search" placeholder="Search design, API, urgent, Laura..." data-vb-filter-sixteen-input&gt;
        &lt;div&gt;
          &lt;strong data-vb-filter-sixteen-count&gt;10 tasks&lt;/strong&gt;
          &lt;button type="button" data-vb-filter-sixteen-clear&gt;Clear&lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/header&gt;

    &lt;div class="vb-filter-sixteen-columns"&gt;
      &lt;section&gt;
        &lt;h4&gt;To Do&lt;/h4&gt;

        &lt;article data-task-text="design hero section landing page laura ui"&gt;
          &lt;small&gt;Design&lt;/small&gt;
          &lt;strong&gt;Hero section concept&lt;/strong&gt;
          &lt;p&gt;Create a new landing page hero with CTA buttons and trust badges.&lt;/p&gt;
          &lt;span&gt;Laura&lt;/span&gt;
        &lt;/article&gt;

        &lt;article data-task-text="seo keyword research blog content mark"&gt;
          &lt;small&gt;SEO&lt;/small&gt;
          &lt;strong&gt;Keyword research&lt;/strong&gt;
          &lt;p&gt;Collect long-tail keywords for the next JavaScript tutorial article.&lt;/p&gt;
          &lt;span&gt;Mark&lt;/span&gt;
        &lt;/article&gt;

        &lt;article data-task-text="support faq documentation nina"&gt;
          &lt;small&gt;Docs&lt;/small&gt;
          &lt;strong&gt;FAQ updates&lt;/strong&gt;
          &lt;p&gt;Rewrite help center answers for onboarding and billing questions.&lt;/p&gt;
          &lt;span&gt;Nina&lt;/span&gt;
        &lt;/article&gt;
      &lt;/section&gt;

      &lt;section&gt;
        &lt;h4&gt;In Progress&lt;/h4&gt;

        &lt;article data-task-text="api integration webhook backend alex urgent"&gt;
          &lt;small&gt;API&lt;/small&gt;
          &lt;strong&gt;Webhook integration&lt;/strong&gt;
          &lt;p&gt;Connect order events to the automation workflow endpoint.&lt;/p&gt;
          &lt;span&gt;Alex&lt;/span&gt;
        &lt;/article&gt;

        &lt;article data-task-text="frontend filter component javascript sara"&gt;
          &lt;small&gt;Frontend&lt;/small&gt;
          &lt;strong&gt;Filter component&lt;/strong&gt;
          &lt;p&gt;Build reusable JavaScript filtering for cards and table rows.&lt;/p&gt;
          &lt;span&gt;Sara&lt;/span&gt;
        &lt;/article&gt;

        &lt;article data-task-text="checkout ui ecommerce design tom"&gt;
          &lt;small&gt;UI&lt;/small&gt;
          &lt;strong&gt;Checkout layout&lt;/strong&gt;
          &lt;p&gt;Improve cart summary spacing, mobile inputs, and order buttons.&lt;/p&gt;
          &lt;span&gt;Tom&lt;/span&gt;
        &lt;/article&gt;
      &lt;/section&gt;

      &lt;section&gt;
        &lt;h4&gt;Review&lt;/h4&gt;

        &lt;article data-task-text="accessibility aria keyboard focus review maria"&gt;
          &lt;small&gt;A11y&lt;/small&gt;
          &lt;strong&gt;Keyboard review&lt;/strong&gt;
          &lt;p&gt;Test focus states, ARIA labels, and keyboard navigation flow.&lt;/p&gt;
          &lt;span&gt;Maria&lt;/span&gt;
        &lt;/article&gt;

        &lt;article data-task-text="performance optimization images css javascript dan"&gt;
          &lt;small&gt;Speed&lt;/small&gt;
          &lt;strong&gt;Performance pass&lt;/strong&gt;
          &lt;p&gt;Check image loading, CSS size, and JavaScript execution time.&lt;/p&gt;
          &lt;span&gt;Dan&lt;/span&gt;
        &lt;/article&gt;
      &lt;/section&gt;

      &lt;section&gt;
        &lt;h4&gt;Done&lt;/h4&gt;

        &lt;article data-task-text="modal examples published blog javascript content"&gt;
          &lt;small&gt;Content&lt;/small&gt;
          &lt;strong&gt;Modal post published&lt;/strong&gt;
          &lt;p&gt;Final article published with examples, SEO settings, and internal links.&lt;/p&gt;
          &lt;span&gt;Done&lt;/span&gt;
        &lt;/article&gt;

        &lt;article data-task-text="dropdown menu article complete navigation javascript"&gt;
          &lt;small&gt;Content&lt;/small&gt;
          &lt;strong&gt;Dropdown article complete&lt;/strong&gt;
          &lt;p&gt;Dropdown guide completed with custom selects and navigation examples.&lt;/p&gt;
          &lt;span&gt;Done&lt;/span&gt;
        &lt;/article&gt;
      &lt;/section&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-sixteen-empty" data-vb-filter-sixteen-empty&gt;
      &lt;strong&gt;No tasks found.&lt;/strong&gt;
      &lt;p&gt;Try searching for API, design, SEO, urgent, checkout, accessibility, or a person name.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-sixteen-demo,
.vb-filter-sixteen-demo * {
  box-sizing: border-box;
}

.vb-filter-sixteen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 15% 16%, rgba(129, 140, 248, 0.24), transparent 34%),
    radial-gradient(circle at 85% 14%, rgba(244, 114, 182, 0.18), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #fdf2f8 52%, #ffffff 100%) !important;
  border: 1px solid rgba(199, 210, 254, 0.52);
  box-shadow: 0 24px 70px rgba(67, 56, 202, 0.12);
}

.vb-filter-sixteen-board {
  max-width: 1180px;
  margin: 0 auto;
  padding: 24px;
  border-radius: 30px;
  background: #111827;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
}

.vb-filter-sixteen-header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 380px;
  gap: 22px;
  align-items: end;
  margin-bottom: 20px;
}

.vb-filter-sixteen-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(129, 140, 248, 0.18);
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-sixteen-header h3 {
  margin: 0 0 12px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 66px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-sixteen-header p {
  max-width: 700px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-sixteen-tools {
  display: grid;
  gap: 10px;
  padding: 14px;
  border-radius: 22px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-filter-sixteen-tools input {
  width: 100%;
  min-height: 52px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 16px;
  outline: 0;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-sixteen-tools input::placeholder {
  color: rgba(255,255,255,0.58);
  -webkit-text-fill-color: rgba(255,255,255,0.58);
}

.vb-filter-sixteen-tools div {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
}

.vb-filter-sixteen-tools strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-filter-sixteen-tools button {
  min-height: 36px;
  padding: 8px 12px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-sixteen-columns {
  display: grid;
  grid-template-columns: repeat(4, minmax(230px, 1fr));
  gap: 14px;
  overflow-x: auto;
  padding-bottom: 4px;
}

.vb-filter-sixteen-columns section {
  min-width: 230px;
  padding: 12px;
  border-radius: 22px;
  background: rgba(255,255,255,0.06);
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-filter-sixteen-columns h4 {
  margin: 0 0 12px !important;
  padding: 10px 10px 0;
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 15px !important;
  font-weight: 950 !important;
  letter-spacing: -0.02em;
}

.vb-filter-sixteen-columns article {
  padding: 16px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(255,255,255,0.10);
  box-shadow: 0 14px 34px rgba(2, 6, 23, 0.18);
}

.vb-filter-sixteen-columns article + article {
  margin-top: 10px;
}

.vb-filter-sixteen-columns article.is-hidden {
  display: none;
}

.vb-filter-sixteen-columns small {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #eef2ff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-sixteen-columns strong {
  display: block;
  margin-bottom: 8px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 17px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-filter-sixteen-columns p {
  margin: 0 0 12px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-filter-sixteen-columns article span {
  display: inline-flex;
  color: #db2777 !important;
  -webkit-text-fill-color: #db2777 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-filter-sixteen-empty {
  display: none;
  margin-top: 16px;
  padding: 20px;
  border-radius: 20px;
  background: rgba(251, 146, 60, 0.12);
  border: 1px solid rgba(251, 146, 60, 0.24);
}

.vb-filter-sixteen-empty.is-visible {
  display: block;
}

.vb-filter-sixteen-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-sixteen-empty p {
  margin: 0 !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 14px;
  line-height: 1.6;
}

@media (max-width: 980px) {
  .vb-filter-sixteen-header {
    grid-template-columns: 1fr;
  }

  .vb-filter-sixteen-tools {
    max-width: 520px;
  }
}

@media (max-width: 640px) {
  .vb-filter-sixteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-sixteen-board {
    padding: 18px;
    border-radius: 22px;
  }

  .vb-filter-sixteen-header h3 {
    font-size: 38px !important;
  }

  .vb-filter-sixteen-tools div {
    align-items: stretch;
    flex-direction: column;
  }

  .vb-filter-sixteen-tools button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This Kanban board search filter is useful for project management dashboards, task boards, editorial calendars, CRM pipelines, software planning screens, productivity apps, and workflow-based web interfaces.</p>



<h2 class="wp-block-heading">17. Music Playlist Search Filter</h2>



<p class="wp-block-paragraph"><strong>A music playlist search filter</strong> helps users search tracks by artist, genre, mood, duration, or title. This layout is useful for music apps, podcast libraries, video playlists, audio courses, media dashboards, and entertainment websites.</p>



<p class="wp-block-paragraph">This example uses a media-player inspired interface with a featured track panel, genre filter buttons, playlist rows, duration labels, and live keyword search. It looks different from a normal card grid and works well for audio or video content libraries.</p>



<ul class="wp-block-list">
<li>Playlist-style search filter</li>
<li>Filters tracks by genre and keyword</li>
<li>Media player inspired layout</li>
<li>Track duration and artist labels</li>
<li>Useful for music apps, podcast archives, video libraries, and media dashboards</li>
</ul>



<div class="vb-filter-seventeen-demo">
  <div class="vb-filter-seventeen-player" data-vb-filter-seventeen>
    <div class="vb-filter-seventeen-cover">
      <span>Example 17</span>
      <h3>Music Playlist Search Filter</h3>
      <p>Search tracks by artist, genre, mood, title, or playlist keyword.</p>

      <div class="vb-filter-seventeen-now">
        <small>Now browsing</small>
        <strong data-vb-filter-seventeen-count>9 tracks</strong>
      </div>
    </div>

    <div class="vb-filter-seventeen-library">
      <div class="vb-filter-seventeen-search">
        <input type="search" placeholder="Search chill, synth, jazz, workout, Luna..." data-vb-filter-seventeen-input>
        <button type="button" data-vb-filter-seventeen-reset>Reset</button>
      </div>

      <div class="vb-filter-seventeen-genres">
        <button type="button" class="is-active" data-genre="all">All</button>
        <button type="button" data-genre="electronic">Electronic</button>
        <button type="button" data-genre="jazz">Jazz</button>
        <button type="button" data-genre="rock">Rock</button>
        <button type="button" data-genre="ambient">Ambient</button>
      </div>

      <div class="vb-filter-seventeen-list">
        <article data-track-genre="electronic" data-track-text="neon drive luna wave electronic synth night city energy">
          <span>01</span>
          <div>
            <strong>Neon Drive</strong>
            <small>Luna Wave · Electronic</small>
          </div>
          <em>3:42</em>
        </article>

        <article data-track-genre="jazz" data-track-text="blue corner miles stone jazz piano relaxed evening">
          <span>02</span>
          <div>
            <strong>Blue Corner</strong>
            <small>Miles Stone · Jazz</small>
          </div>
          <em>4:18</em>
        </article>

        <article data-track-genre="ambient" data-track-text="soft horizon echo valley ambient calm focus sleep">
          <span>03</span>
          <div>
            <strong>Soft Horizon</strong>
            <small>Echo Valley · Ambient</small>
          </div>
          <em>5:06</em>
        </article>

        <article data-track-genre="rock" data-track-text="electric road northline rock guitar workout energy">
          <span>04</span>
          <div>
            <strong>Electric Road</strong>
            <small>Northline · Rock</small>
          </div>
          <em>3:55</em>
        </article>

        <article data-track-genre="electronic" data-track-text="pixel rain nova dust electronic future synth focus">
          <span>05</span>
          <div>
            <strong>Pixel Rain</strong>
            <small>Nova Dust · Electronic</small>
          </div>
          <em>2:58</em>
        </article>

        <article data-track-genre="jazz" data-track-text="midnight table ella coast jazz lounge saxophone">
          <span>06</span>
          <div>
            <strong>Midnight Table</strong>
            <small>Ella Coast · Jazz</small>
          </div>
          <em>4:44</em>
        </article>

        <article data-track-genre="ambient" data-track-text="cloud station arctic tone ambient meditation calm">
          <span>07</span>
          <div>
            <strong>Cloud Station</strong>
            <small>Arctic Tone · Ambient</small>
          </div>
          <em>6:12</em>
        </article>

        <article data-track-genre="rock" data-track-text="fast signal red atlas rock drums road trip">
          <span>08</span>
          <div>
            <strong>Fast Signal</strong>
            <small>Red Atlas · Rock</small>
          </div>
          <em>3:31</em>
        </article>

        <article data-track-genre="electronic" data-track-text="chrome sunrise vega pulse electronic dance bright">
          <span>09</span>
          <div>
            <strong>Chrome Sunrise</strong>
            <small>Vega Pulse · Electronic</small>
          </div>
          <em>3:26</em>
        </article>
      </div>

      <div class="vb-filter-seventeen-empty" data-vb-filter-seventeen-empty>
        <strong>No tracks found.</strong>
        <p>Try searching for jazz, synth, rock, ambient, Luna, focus, workout, or city.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-filter-seventeen-demo,
.vb-filter-seventeen-demo * {
  box-sizing: border-box;
}

.vb-filter-seventeen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(217, 70, 239, 0.24), transparent 34%),
    radial-gradient(circle at 86% 14%, rgba(34, 211, 238, 0.20), transparent 34%),
    linear-gradient(135deg, #fdf4ff 0%, #ecfeff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(240, 171, 252, 0.52);
  box-shadow: 0 24px 70px rgba(112, 26, 117, 0.12);
}

.vb-filter-seventeen-player {
  display: grid;
  grid-template-columns: 360px minmax(0, 1fr);
  gap: 18px;
  max-width: 1080px;
  margin: 0 auto;
  padding: 18px;
  border-radius: 32px;
  background: #111827;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
}

.vb-filter-seventeen-cover {
  position: relative;
  overflow: hidden;
  min-height: 610px;
  padding: 30px;
  border-radius: 26px;
  background:
    radial-gradient(circle at 34% 22%, rgba(255,255,255,0.30), transparent 26%),
    radial-gradient(circle at 80% 74%, rgba(34,211,238,0.34), transparent 30%),
    linear-gradient(135deg, #a21caf, #0891b2 55%, #0f172a) !important;
}

.vb-filter-seventeen-cover::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: 80px;
  width: 210px;
  height: 210px;
  border-radius: 999px;
  background:
    radial-gradient(circle, #111827 0 22%, #ffffff 23% 25%, rgba(255,255,255,0.18) 26% 100%);
  transform: translateX(-50%);
  box-shadow: 0 28px 70px rgba(0,0,0,0.32);
}

.vb-filter-seventeen-cover > span {
  position: relative;
  z-index: 2;
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  color: #f5d0fe !important;
  -webkit-text-fill-color: #f5d0fe !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-seventeen-cover h3 {
  position: relative;
  z-index: 2;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 4vw, 58px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-seventeen-cover p {
  position: relative;
  z-index: 2;
  margin: 0 !important;
  color: #cffafe !important;
  -webkit-text-fill-color: #cffafe !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-seventeen-now {
  position: absolute;
  z-index: 3;
  left: 24px;
  right: 24px;
  bottom: 24px;
  padding: 18px;
  border-radius: 22px;
  background: rgba(15, 23, 42, 0.76);
  border: 1px solid rgba(255,255,255,0.16);
  backdrop-filter: blur(14px);
}

.vb-filter-seventeen-now small {
  display: block;
  margin-bottom: 6px;
  color: #f0abfc !important;
  -webkit-text-fill-color: #f0abfc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-seventeen-now strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-filter-seventeen-library {
  padding: 22px;
  border-radius: 26px;
  background: #ffffff;
}

.vb-filter-seventeen-search {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  margin-bottom: 12px;
}

.vb-filter-seventeen-search input {
  width: 100%;
  min-height: 54px;
  padding: 0 16px;
  border: 1px solid rgba(148, 163, 184, 0.26);
  border-radius: 18px;
  outline: 0;
  background: #f8fafc;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-seventeen-search button {
  min-height: 54px;
  padding: 0 16px;
  border: 0;
  border-radius: 18px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-seventeen-genres {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-bottom: 16px;
}

.vb-filter-seventeen-genres button {
  min-height: 40px;
  padding: 9px 13px;
  border: 0;
  border-radius: 999px;
  background: #f3e8ff;
  color: #86198f !important;
  -webkit-text-fill-color: #86198f !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-seventeen-genres button.is-active,
.vb-filter-seventeen-genres button:hover {
  background: linear-gradient(135deg, #d946ef, #0891b2);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-seventeen-list {
  display: grid;
  gap: 8px;
}

.vb-filter-seventeen-list article {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr) 54px;
  gap: 12px;
  align-items: center;
  padding: 12px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 10px 26px rgba(15, 23, 42, 0.05);
}

.vb-filter-seventeen-list article.is-hidden {
  display: none;
}

.vb-filter-seventeen-list article > span {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 16px;
  background: #ecfeff;
  color: #0891b2 !important;
  -webkit-text-fill-color: #0891b2 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-filter-seventeen-list strong {
  display: block;
  margin-bottom: 4px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-filter-seventeen-list small {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 750;
}

.vb-filter-seventeen-list em {
  color: #86198f !important;
  -webkit-text-fill-color: #86198f !important;
  font-size: 13px;
  font-style: normal;
  font-weight: 950;
  text-align: right;
}

.vb-filter-seventeen-empty {
  display: none;
  margin-top: 14px;
  padding: 18px;
  border-radius: 18px;
  background: #fdf4ff;
  border: 1px solid rgba(217, 70, 239, 0.24);
}

.vb-filter-seventeen-empty.is-visible {
  display: block;
}

.vb-filter-seventeen-empty strong {
  display: block;
  margin-bottom: 6px;
  color: #86198f !important;
  -webkit-text-fill-color: #86198f !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-filter-seventeen-empty p {
  margin: 0 !important;
  color: #701a75 !important;
  -webkit-text-fill-color: #701a75 !important;
  font-size: 14px;
  line-height: 1.55;
}

@media (max-width: 900px) {
  .vb-filter-seventeen-player {
    grid-template-columns: 1fr;
  }

  .vb-filter-seventeen-cover {
    min-height: 420px;
  }
}

@media (max-width: 640px) {
  .vb-filter-seventeen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-seventeen-player {
    padding: 12px;
    border-radius: 24px;
  }

  .vb-filter-seventeen-cover h3 {
    font-size: 38px !important;
  }

  .vb-filter-seventeen-search {
    grid-template-columns: 1fr;
  }

  .vb-filter-seventeen-list article {
    grid-template-columns: 38px minmax(0, 1fr);
  }

  .vb-filter-seventeen-list em {
    grid-column: 2;
    text-align: left;
  }
}
</style>

<script>
(function () {
  const player = document.querySelector("[data-vb-filter-seventeen]");
  if (!player) return;

  const input = player.querySelector("[data-vb-filter-seventeen-input]");
  const buttons = player.querySelectorAll("[data-genre]");
  const reset = player.querySelector("[data-vb-filter-seventeen-reset]");
  const count = player.querySelector("[data-vb-filter-seventeen-count]");
  const empty = player.querySelector("[data-vb-filter-seventeen-empty]");
  const tracks = Array.from(player.querySelectorAll("[data-track-genre]"));

  let activeGenre = "all";

  function updateTracks() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    tracks.forEach(function (track) {
      const genre = track.getAttribute("data-track-genre");
      const text = track.getAttribute("data-track-text").toLowerCase();
      const fullText = track.textContent.toLowerCase();

      const genreMatch = activeGenre === "all" || genre === activeGenre;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = genreMatch && searchMatch;

      track.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 track" : visible + " tracks";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeGenre = button.getAttribute("data-genre");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateTracks();
    });
  });

  input.addEventListener("input", updateTracks);

  reset.addEventListener("click", function () {
    activeGenre = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-genre") === "all");
    });

    input.focus();
    updateTracks();
  });

  updateTracks();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const player = document.querySelector("[data-vb-filter-seventeen]");
  if (!player) return;

  const input = player.querySelector("[data-vb-filter-seventeen-input]");
  const buttons = player.querySelectorAll("[data-genre]");
  const reset = player.querySelector("[data-vb-filter-seventeen-reset]");
  const count = player.querySelector("[data-vb-filter-seventeen-count]");
  const empty = player.querySelector("[data-vb-filter-seventeen-empty]");
  const tracks = Array.from(player.querySelectorAll("[data-track-genre]"));

  let activeGenre = "all";

  function updateTracks() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    tracks.forEach(function (track) {
      const genre = track.getAttribute("data-track-genre");
      const text = track.getAttribute("data-track-text").toLowerCase();
      const fullText = track.textContent.toLowerCase();

      const genreMatch = activeGenre === "all" || genre === activeGenre;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = genreMatch && searchMatch;

      track.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 track" : visible + " tracks";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeGenre = button.getAttribute("data-genre");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateTracks();
    });
  });

  input.addEventListener("input", updateTracks);

  reset.addEventListener("click", function () {
    activeGenre = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-genre") === "all");
    });

    input.focus();
    updateTracks();
  });

  updateTracks();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-seventeen-demo"&gt;
  &lt;div class="vb-filter-seventeen-player" data-vb-filter-seventeen&gt;
    &lt;div class="vb-filter-seventeen-cover"&gt;
      &lt;span&gt;Example 17&lt;/span&gt;
      &lt;h3&gt;Music Playlist Search Filter&lt;/h3&gt;
      &lt;p&gt;Search tracks by artist, genre, mood, title, or playlist keyword.&lt;/p&gt;

      &lt;div class="vb-filter-seventeen-now"&gt;
        &lt;small&gt;Now browsing&lt;/small&gt;
        &lt;strong data-vb-filter-seventeen-count&gt;9 tracks&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-seventeen-library"&gt;
      &lt;div class="vb-filter-seventeen-search"&gt;
        &lt;input type="search" placeholder="Search chill, synth, jazz, workout, Luna..." data-vb-filter-seventeen-input&gt;
        &lt;button type="button" data-vb-filter-seventeen-reset&gt;Reset&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-seventeen-genres"&gt;
        &lt;button type="button" class="is-active" data-genre="all"&gt;All&lt;/button&gt;
        &lt;button type="button" data-genre="electronic"&gt;Electronic&lt;/button&gt;
        &lt;button type="button" data-genre="jazz"&gt;Jazz&lt;/button&gt;
        &lt;button type="button" data-genre="rock"&gt;Rock&lt;/button&gt;
        &lt;button type="button" data-genre="ambient"&gt;Ambient&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-seventeen-list"&gt;
        &lt;article data-track-genre="electronic" data-track-text="neon drive luna wave electronic synth night city energy"&gt;
          &lt;span&gt;01&lt;/span&gt;
          &lt;div&gt;
            &lt;strong&gt;Neon Drive&lt;/strong&gt;
            &lt;small&gt;Luna Wave · Electronic&lt;/small&gt;
          &lt;/div&gt;
          &lt;em&gt;3:42&lt;/em&gt;
        &lt;/article&gt;

        &lt;article data-track-genre="jazz" data-track-text="blue corner miles stone jazz piano relaxed evening"&gt;
          &lt;span&gt;02&lt;/span&gt;
          &lt;div&gt;
            &lt;strong&gt;Blue Corner&lt;/strong&gt;
            &lt;small&gt;Miles Stone · Jazz&lt;/small&gt;
          &lt;/div&gt;
          &lt;em&gt;4:18&lt;/em&gt;
        &lt;/article&gt;

        &lt;article data-track-genre="ambient" data-track-text="soft horizon echo valley ambient calm focus sleep"&gt;
          &lt;span&gt;03&lt;/span&gt;
          &lt;div&gt;
            &lt;strong&gt;Soft Horizon&lt;/strong&gt;
            &lt;small&gt;Echo Valley · Ambient&lt;/small&gt;
          &lt;/div&gt;
          &lt;em&gt;5:06&lt;/em&gt;
        &lt;/article&gt;

        &lt;article data-track-genre="rock" data-track-text="electric road northline rock guitar workout energy"&gt;
          &lt;span&gt;04&lt;/span&gt;
          &lt;div&gt;
            &lt;strong&gt;Electric Road&lt;/strong&gt;
            &lt;small&gt;Northline · Rock&lt;/small&gt;
          &lt;/div&gt;
          &lt;em&gt;3:55&lt;/em&gt;
        &lt;/article&gt;

        &lt;article data-track-genre="electronic" data-track-text="pixel rain nova dust electronic future synth focus"&gt;
          &lt;span&gt;05&lt;/span&gt;
          &lt;div&gt;
            &lt;strong&gt;Pixel Rain&lt;/strong&gt;
            &lt;small&gt;Nova Dust · Electronic&lt;/small&gt;
          &lt;/div&gt;
          &lt;em&gt;2:58&lt;/em&gt;
        &lt;/article&gt;

        &lt;article data-track-genre="jazz" data-track-text="midnight table ella coast jazz lounge saxophone"&gt;
          &lt;span&gt;06&lt;/span&gt;
          &lt;div&gt;
            &lt;strong&gt;Midnight Table&lt;/strong&gt;
            &lt;small&gt;Ella Coast · Jazz&lt;/small&gt;
          &lt;/div&gt;
          &lt;em&gt;4:44&lt;/em&gt;
        &lt;/article&gt;

        &lt;article data-track-genre="ambient" data-track-text="cloud station arctic tone ambient meditation calm"&gt;
          &lt;span&gt;07&lt;/span&gt;
          &lt;div&gt;
            &lt;strong&gt;Cloud Station&lt;/strong&gt;
            &lt;small&gt;Arctic Tone · Ambient&lt;/small&gt;
          &lt;/div&gt;
          &lt;em&gt;6:12&lt;/em&gt;
        &lt;/article&gt;

        &lt;article data-track-genre="rock" data-track-text="fast signal red atlas rock drums road trip"&gt;
          &lt;span&gt;08&lt;/span&gt;
          &lt;div&gt;
            &lt;strong&gt;Fast Signal&lt;/strong&gt;
            &lt;small&gt;Red Atlas · Rock&lt;/small&gt;
          &lt;/div&gt;
          &lt;em&gt;3:31&lt;/em&gt;
        &lt;/article&gt;

        &lt;article data-track-genre="electronic" data-track-text="chrome sunrise vega pulse electronic dance bright"&gt;
          &lt;span&gt;09&lt;/span&gt;
          &lt;div&gt;
            &lt;strong&gt;Chrome Sunrise&lt;/strong&gt;
            &lt;small&gt;Vega Pulse · Electronic&lt;/small&gt;
          &lt;/div&gt;
          &lt;em&gt;3:26&lt;/em&gt;
        &lt;/article&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-seventeen-empty" data-vb-filter-seventeen-empty&gt;
        &lt;strong&gt;No tracks found.&lt;/strong&gt;
        &lt;p&gt;Try searching for jazz, synth, rock, ambient, Luna, focus, workout, or city.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-seventeen-demo,
.vb-filter-seventeen-demo * {
  box-sizing: border-box;
}

/* CSS is the same as the live preview CSS above. Copy the full CSS from the live preview block if using this standalone. */</pre>



<p class="wp-block-paragraph">This music playlist search filter is useful for audio libraries, podcast archives, video lesson collections, media dashboards, entertainment apps, course platforms, and any content section where users browse media by genre, mood, creator, or keyword.</p>



<h2 class="wp-block-heading">18. Pricing Comparison Matrix Filter</h2>



<p class="wp-block-paragraph"><strong>A pricing comparison matrix filter</strong> helps users narrow pricing plans by feature type, product level, audience, or requirement. Instead of using a normal card layout, this example uses a wide comparison table where non-matching feature rows are hidden as users search.</p>



<p class="wp-block-paragraph">This layout is useful for SaaS pricing pages, plugin comparison pages, hosting plans, subscription products, agency packages, product tiers, and any website that needs a searchable feature comparison table.</p>



<ul class="wp-block-list">
<li>Searchable pricing comparison matrix</li>
<li>Filters feature rows by category and keyword</li>
<li>Sticky-style plan header layout</li>
<li>Useful for SaaS, plugin, hosting, and subscription pricing pages</li>
<li>Different from normal pricing cards or product grids</li>
</ul>



<div class="vb-filter-eighteen-demo">
  <div class="vb-filter-eighteen-matrix" data-vb-filter-eighteen>
    <div class="vb-filter-eighteen-top">
      <div>
        <span>Example 18</span>
        <h3>Pricing Comparison Matrix Filter</h3>
        <p>Search and filter pricing features inside a comparison table layout.</p>
      </div>

      <div class="vb-filter-eighteen-box">
        <strong data-vb-filter-eighteen-count>10 features</strong>
        <button type="button" data-vb-filter-eighteen-reset>Reset</button>
      </div>
    </div>

    <div class="vb-filter-eighteen-controls">
      <input type="search" placeholder="Search API, support, storage, analytics..." data-vb-filter-eighteen-input>

      <div class="vb-filter-eighteen-tabs">
        <button type="button" class="is-active" data-feature-type="all">All</button>
        <button type="button" data-feature-type="core">Core</button>
        <button type="button" data-feature-type="growth">Growth</button>
        <button type="button" data-feature-type="security">Security</button>
        <button type="button" data-feature-type="support">Support</button>
      </div>
    </div>

    <div class="vb-filter-eighteen-table-wrap">
      <table class="vb-filter-eighteen-table">
        <thead>
          <tr>
            <th>Feature</th>
            <th>Starter</th>
            <th>Pro</th>
            <th>Agency</th>
          </tr>
        </thead>

        <tbody>
          <tr data-feature-row="core" data-feature-text="core projects websites workspaces dashboard">
            <td><strong>Projects</strong><span>Core workspace limits</span></td>
            <td>3</td>
            <td>25</td>
            <td>Unlimited</td>
          </tr>

          <tr data-feature-row="core" data-feature-text="core storage files media uploads documents">
            <td><strong>Storage</strong><span>File and media storage</span></td>
            <td>5 GB</td>
            <td>100 GB</td>
            <td>1 TB</td>
          </tr>

          <tr data-feature-row="growth" data-feature-text="growth analytics reports insights dashboard tracking">
            <td><strong>Analytics</strong><span>Reports and insights</span></td>
            <td>Basic</td>
            <td>Advanced</td>
            <td>Custom</td>
          </tr>

          <tr data-feature-row="growth" data-feature-text="growth automation workflows rules triggers">
            <td><strong>Automation</strong><span>Workflow rules and triggers</span></td>
            <td>—</td>
            <td>Included</td>
            <td>Advanced</td>
          </tr>

          <tr data-feature-row="security" data-feature-text="security two factor authentication 2fa login protection">
            <td><strong>Two-Factor Auth</strong><span>Extra login protection</span></td>
            <td>—</td>
            <td>Included</td>
            <td>Included</td>
          </tr>

          <tr data-feature-row="security" data-feature-text="security audit logs user activity permissions">
            <td><strong>Audit Logs</strong><span>User activity history</span></td>
            <td>—</td>
            <td>30 days</td>
            <td>365 days</td>
          </tr>

          <tr data-feature-row="core" data-feature-text="core api access developer endpoints integrations">
            <td><strong>API Access</strong><span>Developer endpoints</span></td>
            <td>Limited</td>
            <td>Full</td>
            <td>Full + Priority</td>
          </tr>

          <tr data-feature-row="support" data-feature-text="support email help tickets assistance response">
            <td><strong>Email Support</strong><span>Support ticket help</span></td>
            <td>Standard</td>
            <td>Priority</td>
            <td>Priority</td>
          </tr>

          <tr data-feature-row="support" data-feature-text="support onboarding setup training account manager">
            <td><strong>Onboarding</strong><span>Setup and training help</span></td>
            <td>—</td>
            <td>Guided</td>
            <td>Dedicated</td>
          </tr>

          <tr data-feature-row="growth" data-feature-text="growth white label branding custom domain clients">
            <td><strong>White Label</strong><span>Branding and client use</span></td>
            <td>—</td>
            <td>—</td>
            <td>Included</td>
          </tr>
        </tbody>
      </table>

      <div class="vb-filter-eighteen-empty" data-vb-filter-eighteen-empty>
        <strong>No matching features found.</strong>
        <p>Try searching for API, support, storage, analytics, security, automation, or onboarding.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-filter-eighteen-demo,
.vb-filter-eighteen-demo * {
  box-sizing: border-box;
}

.vb-filter-eighteen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(79, 70, 229, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(16, 185, 129, 0.18), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #ecfdf5 52%, #ffffff 100%) !important;
  border: 1px solid rgba(199, 210, 254, 0.52);
  box-shadow: 0 24px 70px rgba(49, 46, 129, 0.12);
}

.vb-filter-eighteen-matrix {
  max-width: 1120px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-eighteen-top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 180px;
  gap: 22px;
  align-items: end;
  margin-bottom: 20px;
}

.vb-filter-eighteen-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #e0e7ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-eighteen-top h3 {
  margin: 0 0 12px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-eighteen-top p {
  margin: 0 !important;
  max-width: 680px;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-eighteen-box {
  padding: 16px;
  border-radius: 22px;
  background: #111827;
}

.vb-filter-eighteen-box strong {
  display: block;
  margin-bottom: 10px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-eighteen-box button {
  width: 100%;
  min-height: 38px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-eighteen-controls {
  display: grid;
  grid-template-columns: minmax(260px, 0.8fr) minmax(0, 1.2fr);
  gap: 12px;
  margin-bottom: 18px;
  padding: 14px;
  border-radius: 24px;
  background: #f8fafc;
}

.vb-filter-eighteen-controls input {
  width: 100%;
  min-height: 52px;
  padding: 0 15px;
  border: 1px solid rgba(148, 163, 184, 0.26);
  border-radius: 16px;
  outline: 0;
  background: #ffffff;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-eighteen-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-filter-eighteen-tabs button {
  min-height: 42px;
  padding: 9px 13px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 8px 20px rgba(15, 23, 42, 0.05);
}

.vb-filter-eighteen-tabs button.is-active,
.vb-filter-eighteen-tabs button:hover {
  background: linear-gradient(135deg, #4f46e5, #10b981);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-eighteen-table-wrap {
  overflow-x: auto;
  border-radius: 24px;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-filter-eighteen-table {
  width: 100%;
  min-width: 860px;
  border-collapse: collapse;
}

.vb-filter-eighteen-table th {
  padding: 18px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  text-align: center;
  border-right: 1px solid rgba(255,255,255,0.10);
}

.vb-filter-eighteen-table th:first-child {
  text-align: left;
}

.vb-filter-eighteen-table td {
  padding: 18px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 850;
  text-align: center;
  border-right: 1px solid #e2e8f0;
  border-bottom: 1px solid #e2e8f0;
}

.vb-filter-eighteen-table td:first-child {
  text-align: left;
  min-width: 280px;
}

.vb-filter-eighteen-table tr.is-hidden {
  display: none;
}

.vb-filter-eighteen-table td strong {
  display: block;
  margin-bottom: 5px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-filter-eighteen-table td span {
  display: block;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.4;
  font-weight: 700;
}

.vb-filter-eighteen-empty {
  display: none;
  padding: 22px;
  background: #fff7ed;
  border-top: 1px solid rgba(251, 146, 60, 0.34);
}

.vb-filter-eighteen-empty.is-visible {
  display: block;
}

.vb-filter-eighteen-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-eighteen-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 900px) {
  .vb-filter-eighteen-top,
  .vb-filter-eighteen-controls {
    grid-template-columns: 1fr;
  }

  .vb-filter-eighteen-box {
    width: fit-content;
    min-width: 180px;
  }
}

@media (max-width: 640px) {
  .vb-filter-eighteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-eighteen-matrix {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-eighteen-top h3 {
    font-size: 38px !important;
  }

  .vb-filter-eighteen-tabs {
    display: grid;
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const matrix = document.querySelector("[data-vb-filter-eighteen]");
  if (!matrix) return;

  const input = matrix.querySelector("[data-vb-filter-eighteen-input]");
  const buttons = matrix.querySelectorAll("[data-feature-type]");
  const reset = matrix.querySelector("[data-vb-filter-eighteen-reset]");
  const count = matrix.querySelector("[data-vb-filter-eighteen-count]");
  const empty = matrix.querySelector("[data-vb-filter-eighteen-empty]");
  const rows = Array.from(matrix.querySelectorAll("[data-feature-row]"));

  let activeType = "all";

  function updateRows() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    rows.forEach(function (row) {
      const type = row.getAttribute("data-feature-row");
      const text = row.getAttribute("data-feature-text").toLowerCase();
      const fullText = row.textContent.toLowerCase();

      const typeMatch = activeType === "all" || type === activeType;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = typeMatch && searchMatch;

      row.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 feature" : visible + " features";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeType = button.getAttribute("data-feature-type");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateRows();
    });
  });

  input.addEventListener("input", updateRows);

  reset.addEventListener("click", function () {
    activeType = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-feature-type") === "all");
    });

    input.focus();
    updateRows();
  });

  updateRows();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const matrix = document.querySelector("[data-vb-filter-eighteen]");
  if (!matrix) return;

  const input = matrix.querySelector("[data-vb-filter-eighteen-input]");
  const buttons = matrix.querySelectorAll("[data-feature-type]");
  const reset = matrix.querySelector("[data-vb-filter-eighteen-reset]");
  const count = matrix.querySelector("[data-vb-filter-eighteen-count]");
  const empty = matrix.querySelector("[data-vb-filter-eighteen-empty]");
  const rows = Array.from(matrix.querySelectorAll("[data-feature-row]"));

  let activeType = "all";

  function updateRows() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    rows.forEach(function (row) {
      const type = row.getAttribute("data-feature-row");
      const text = row.getAttribute("data-feature-text").toLowerCase();
      const fullText = row.textContent.toLowerCase();

      const typeMatch = activeType === "all" || type === activeType;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = typeMatch && searchMatch;

      row.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 feature" : visible + " features";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeType = button.getAttribute("data-feature-type");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateRows();
    });
  });

  input.addEventListener("input", updateRows);

  reset.addEventListener("click", function () {
    activeType = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-feature-type") === "all");
    });

    input.focus();
    updateRows();
  });

  updateRows();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-eighteen-demo"&gt;
  &lt;div class="vb-filter-eighteen-matrix" data-vb-filter-eighteen&gt;
    &lt;div class="vb-filter-eighteen-top"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 18&lt;/span&gt;
        &lt;h3&gt;Pricing Comparison Matrix Filter&lt;/h3&gt;
        &lt;p&gt;Search and filter pricing features inside a comparison table layout.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-eighteen-box"&gt;
        &lt;strong data-vb-filter-eighteen-count&gt;10 features&lt;/strong&gt;
        &lt;button type="button" data-vb-filter-eighteen-reset&gt;Reset&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-eighteen-controls"&gt;
      &lt;input type="search" placeholder="Search API, support, storage, analytics..." data-vb-filter-eighteen-input&gt;

      &lt;div class="vb-filter-eighteen-tabs"&gt;
        &lt;button type="button" class="is-active" data-feature-type="all"&gt;All&lt;/button&gt;
        &lt;button type="button" data-feature-type="core"&gt;Core&lt;/button&gt;
        &lt;button type="button" data-feature-type="growth"&gt;Growth&lt;/button&gt;
        &lt;button type="button" data-feature-type="security"&gt;Security&lt;/button&gt;
        &lt;button type="button" data-feature-type="support"&gt;Support&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-eighteen-table-wrap"&gt;
      &lt;table class="vb-filter-eighteen-table"&gt;
        &lt;thead&gt;
          &lt;tr&gt;
            &lt;th&gt;Feature&lt;/th&gt;
            &lt;th&gt;Starter&lt;/th&gt;
            &lt;th&gt;Pro&lt;/th&gt;
            &lt;th&gt;Agency&lt;/th&gt;
          &lt;/tr&gt;
        &lt;/thead&gt;

        &lt;tbody&gt;
          &lt;tr data-feature-row="core" data-feature-text="core projects websites workspaces dashboard"&gt;
            &lt;td&gt;&lt;strong&gt;Projects&lt;/strong&gt;&lt;span&gt;Core workspace limits&lt;/span&gt;&lt;/td&gt;
            &lt;td&gt;3&lt;/td&gt;
            &lt;td&gt;25&lt;/td&gt;
            &lt;td&gt;Unlimited&lt;/td&gt;
          &lt;/tr&gt;

          &lt;tr data-feature-row="core" data-feature-text="core storage files media uploads documents"&gt;
            &lt;td&gt;&lt;strong&gt;Storage&lt;/strong&gt;&lt;span&gt;File and media storage&lt;/span&gt;&lt;/td&gt;
            &lt;td&gt;5 GB&lt;/td&gt;
            &lt;td&gt;100 GB&lt;/td&gt;
            &lt;td&gt;1 TB&lt;/td&gt;
          &lt;/tr&gt;

          &lt;tr data-feature-row="growth" data-feature-text="growth analytics reports insights dashboard tracking"&gt;
            &lt;td&gt;&lt;strong&gt;Analytics&lt;/strong&gt;&lt;span&gt;Reports and insights&lt;/span&gt;&lt;/td&gt;
            &lt;td&gt;Basic&lt;/td&gt;
            &lt;td&gt;Advanced&lt;/td&gt;
            &lt;td&gt;Custom&lt;/td&gt;
          &lt;/tr&gt;

          &lt;tr data-feature-row="growth" data-feature-text="growth automation workflows rules triggers"&gt;
            &lt;td&gt;&lt;strong&gt;Automation&lt;/strong&gt;&lt;span&gt;Workflow rules and triggers&lt;/span&gt;&lt;/td&gt;
            &lt;td&gt;—&lt;/td&gt;
            &lt;td&gt;Included&lt;/td&gt;
            &lt;td&gt;Advanced&lt;/td&gt;
          &lt;/tr&gt;

          &lt;tr data-feature-row="security" data-feature-text="security two factor authentication 2fa login protection"&gt;
            &lt;td&gt;&lt;strong&gt;Two-Factor Auth&lt;/strong&gt;&lt;span&gt;Extra login protection&lt;/span&gt;&lt;/td&gt;
            &lt;td&gt;—&lt;/td&gt;
            &lt;td&gt;Included&lt;/td&gt;
            &lt;td&gt;Included&lt;/td&gt;
          &lt;/tr&gt;

          &lt;tr data-feature-row="security" data-feature-text="security audit logs user activity permissions"&gt;
            &lt;td&gt;&lt;strong&gt;Audit Logs&lt;/strong&gt;&lt;span&gt;User activity history&lt;/span&gt;&lt;/td&gt;
            &lt;td&gt;—&lt;/td&gt;
            &lt;td&gt;30 days&lt;/td&gt;
            &lt;td&gt;365 days&lt;/td&gt;
          &lt;/tr&gt;

          &lt;tr data-feature-row="core" data-feature-text="core api access developer endpoints integrations"&gt;
            &lt;td&gt;&lt;strong&gt;API Access&lt;/strong&gt;&lt;span&gt;Developer endpoints&lt;/span&gt;&lt;/td&gt;
            &lt;td&gt;Limited&lt;/td&gt;
            &lt;td&gt;Full&lt;/td&gt;
            &lt;td&gt;Full + Priority&lt;/td&gt;
          &lt;/tr&gt;

          &lt;tr data-feature-row="support" data-feature-text="support email help tickets assistance response"&gt;
            &lt;td&gt;&lt;strong&gt;Email Support&lt;/strong&gt;&lt;span&gt;Support ticket help&lt;/span&gt;&lt;/td&gt;
            &lt;td&gt;Standard&lt;/td&gt;
            &lt;td&gt;Priority&lt;/td&gt;
            &lt;td&gt;Priority&lt;/td&gt;
          &lt;/tr&gt;

          &lt;tr data-feature-row="support" data-feature-text="support onboarding setup training account manager"&gt;
            &lt;td&gt;&lt;strong&gt;Onboarding&lt;/strong&gt;&lt;span&gt;Setup and training help&lt;/span&gt;&lt;/td&gt;
            &lt;td&gt;—&lt;/td&gt;
            &lt;td&gt;Guided&lt;/td&gt;
            &lt;td&gt;Dedicated&lt;/td&gt;
          &lt;/tr&gt;

          &lt;tr data-feature-row="growth" data-feature-text="growth white label branding custom domain clients"&gt;
            &lt;td&gt;&lt;strong&gt;White Label&lt;/strong&gt;&lt;span&gt;Branding and client use&lt;/span&gt;&lt;/td&gt;
            &lt;td&gt;—&lt;/td&gt;
            &lt;td&gt;—&lt;/td&gt;
            &lt;td&gt;Included&lt;/td&gt;
          &lt;/tr&gt;
        &lt;/tbody&gt;
      &lt;/table&gt;

      &lt;div class="vb-filter-eighteen-empty" data-vb-filter-eighteen-empty&gt;
        &lt;strong&gt;No matching features found.&lt;/strong&gt;
        &lt;p&gt;Try searching for API, support, storage, analytics, security, automation, or onboarding.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-eighteen-demo,
.vb-filter-eighteen-demo * {
  box-sizing: border-box;
}

/* CSS is the same as the live preview CSS above. Copy the full CSS from the live preview block if using this standalone. */</pre>



<p class="wp-block-paragraph">This pricing comparison matrix filter is useful for SaaS pricing pages, plugin comparison tables, hosting plan pages, agency packages, subscription products, product tiers, and any pricing section where visitors need to compare many features quickly.</p>



<h2 class="wp-block-heading">19. Ecommerce Product Sidebar Filter</h2>



<p class="wp-block-paragraph"><strong>An ecommerce product sidebar filter</strong> helps shoppers narrow products by category, keyword, price level, material, use case, or product type. This layout is useful for online shops, WooCommerce category pages, product catalogs, marketplace pages, and landing pages with many product cards.</p>



<p class="wp-block-paragraph">This example uses a shop-style layout with a left filter sidebar and a product grid on the right. Users can search products, choose a product category, reset filters, and see the product count update instantly.</p>



<ul class="wp-block-list">
<li>Ecommerce sidebar filter layout</li>
<li>Searches product names, categories, and keywords</li>
<li>Clickable category filter buttons</li>
<li>Product cards with price and labels</li>
<li>Useful for shops, catalogs, marketplaces, and WooCommerce layouts</li>
</ul>



<div class="vb-filter-nineteen-demo">
  <div class="vb-filter-nineteen-shop" data-vb-filter-nineteen>
    <aside class="vb-filter-nineteen-sidebar">
      <span>Example 19</span>
      <h3>Ecommerce Product Sidebar Filter</h3>
      <p>Search products and filter the catalog by product category.</p>

      <div class="vb-filter-nineteen-search">
        <label for="vb-filter-nineteen-input">Search products</label>
        <input id="vb-filter-nineteen-input" type="search" placeholder="Search desk, lamp, chair, storage..." data-vb-filter-nineteen-input>
      </div>

      <div class="vb-filter-nineteen-categories">
        <button type="button" class="is-active" data-shop-category="all">All Products</button>
        <button type="button" data-shop-category="furniture">Furniture</button>
        <button type="button" data-shop-category="lighting">Lighting</button>
        <button type="button" data-shop-category="storage">Storage</button>
        <button type="button" data-shop-category="decor">Decor</button>
      </div>

      <div class="vb-filter-nineteen-summary">
        <strong data-vb-filter-nineteen-count>8 products</strong>
        <button type="button" data-vb-filter-nineteen-reset>Reset filters</button>
      </div>
    </aside>

    <section class="vb-filter-nineteen-products">
      <article data-product-card="furniture" data-product-text="oak desk furniture office table work home">
        <div class="vb-filter-nineteen-image furniture-one"></div>
        <div>
          <small>Furniture</small>
          <h4>Oak Office Desk</h4>
          <p>Modern wooden desk for workspaces, home offices, and compact rooms.</p>
          <strong>€249</strong>
        </div>
      </article>

      <article data-product-card="lighting" data-product-text="desk lamp lighting led office adjustable">
        <div class="vb-filter-nineteen-image lighting-one"></div>
        <div>
          <small>Lighting</small>
          <h4>Adjustable LED Lamp</h4>
          <p>Focused desk lighting with adjustable arm and warm light mode.</p>
          <strong>€69</strong>
        </div>
      </article>

      <article data-product-card="storage" data-product-text="modular shelf storage books boxes organizer">
        <div class="vb-filter-nineteen-image storage-one"></div>
        <div>
          <small>Storage</small>
          <h4>Modular Shelf Unit</h4>
          <p>Flexible storage for books, boxes, decor pieces, and office items.</p>
          <strong>€139</strong>
        </div>
      </article>

      <article data-product-card="decor" data-product-text="ceramic vase decor home interior minimal">
        <div class="vb-filter-nineteen-image decor-one"></div>
        <div>
          <small>Decor</small>
          <h4>Ceramic Table Vase</h4>
          <p>Minimal ceramic vase for shelves, desks, sideboards, and tables.</p>
          <strong>€34</strong>
        </div>
      </article>

      <article data-product-card="furniture" data-product-text="lounge chair furniture fabric living room">
        <div class="vb-filter-nineteen-image furniture-two"></div>
        <div>
          <small>Furniture</small>
          <h4>Soft Lounge Chair</h4>
          <p>Comfortable accent chair for reading corners and living spaces.</p>
          <strong>€189</strong>
        </div>
      </article>

      <article data-product-card="lighting" data-product-text="floor lamp lighting living room standing lamp">
        <div class="vb-filter-nineteen-image lighting-two"></div>
        <div>
          <small>Lighting</small>
          <h4>Arc Floor Lamp</h4>
          <p>Standing floor lamp for lounge areas, sofas, and room corners.</p>
          <strong>€119</strong>
        </div>
      </article>

      <article data-product-card="storage" data-product-text="drawer cabinet storage office files documents">
        <div class="vb-filter-nineteen-image storage-two"></div>
        <div>
          <small>Storage</small>
          <h4>Drawer Cabinet</h4>
          <p>Compact drawer cabinet for office files, tools, and small accessories.</p>
          <strong>€99</strong>
        </div>
      </article>

      <article data-product-card="decor" data-product-text="wall art decor abstract print interior">
        <div class="vb-filter-nineteen-image decor-two"></div>
        <div>
          <small>Decor</small>
          <h4>Abstract Wall Print</h4>
          <p>Modern wall print for home offices, bedrooms, and gallery walls.</p>
          <strong>€45</strong>
        </div>
      </article>

      <div class="vb-filter-nineteen-empty" data-vb-filter-nineteen-empty>
        <strong>No products found.</strong>
        <p>Try searching for desk, lamp, chair, storage, decor, office, or shelf.</p>
      </div>
    </section>
  </div>
</div>

<style>
.vb-filter-nineteen-demo,
.vb-filter-nineteen-demo * {
  box-sizing: border-box;
}

.vb-filter-nineteen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(245, 158, 11, 0.24), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(59, 130, 246, 0.18), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #eff6ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(253, 230, 138, 0.52);
  box-shadow: 0 24px 70px rgba(120, 53, 15, 0.12);
}

.vb-filter-nineteen-shop {
  display: grid;
  grid-template-columns: 320px minmax(0, 1fr);
  gap: 18px;
  max-width: 1140px;
  margin: 0 auto;
}

.vb-filter-nineteen-sidebar {
  align-self: start;
  padding: 26px;
  border-radius: 30px;
  background: #111827;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.24);
}

.vb-filter-nineteen-sidebar > span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(245, 158, 11, 0.16);
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-nineteen-sidebar h3 {
  margin: 0 0 12px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 4vw, 52px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-nineteen-sidebar p {
  margin: 0 0 22px !important;
  color: #d1d5db !important;
  -webkit-text-fill-color: #d1d5db !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-filter-nineteen-search {
  margin-bottom: 14px;
}

.vb-filter-nineteen-search label {
  display: block;
  margin-bottom: 8px;
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-nineteen-search input {
  width: 100%;
  min-height: 54px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 17px;
  outline: 0;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-nineteen-search input::placeholder {
  color: rgba(255,255,255,0.58);
  -webkit-text-fill-color: rgba(255,255,255,0.58);
}

.vb-filter-nineteen-categories {
  display: grid;
  gap: 8px;
  margin-bottom: 14px;
}

.vb-filter-nineteen-categories button {
  min-height: 44px;
  padding: 10px 13px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 14px;
  background: rgba(255,255,255,0.08);
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 13px;
  font-weight: 900;
  text-align: left;
  cursor: pointer;
}

.vb-filter-nineteen-categories button.is-active,
.vb-filter-nineteen-categories button:hover {
  background: linear-gradient(135deg, #f59e0b, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-nineteen-summary {
  display: grid;
  gap: 10px;
  padding: 14px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
}

.vb-filter-nineteen-summary strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-filter-nineteen-summary button {
  min-height: 40px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-nineteen-products {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-filter-nineteen-products article {
  overflow: hidden;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb-filter-nineteen-products article.is-hidden {
  display: none;
}

.vb-filter-nineteen-image {
  min-height: 150px;
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #f59e0b, #2563eb) !important;
}

.vb-filter-nineteen-image.lighting-one {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #facc15, #f97316) !important;
}

.vb-filter-nineteen-image.storage-one {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #0f766e, #14b8a6) !important;
}

.vb-filter-nineteen-image.decor-one {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #ec4899, #8b5cf6) !important;
}

.vb-filter-nineteen-image.furniture-two {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #92400e, #f59e0b) !important;
}

.vb-filter-nineteen-image.lighting-two {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #f97316, #dc2626) !important;
}

.vb-filter-nineteen-image.storage-two {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #334155, #64748b) !important;
}

.vb-filter-nineteen-image.decor-two {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #7c3aed, #2563eb) !important;
}

.vb-filter-nineteen-products article > div:last-child {
  padding: 18px;
}

.vb-filter-nineteen-products small {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #fffbeb;
  color: #b45309 !important;
  -webkit-text-fill-color: #b45309 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-nineteen-products h4 {
  margin: 0 0 8px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 20px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-nineteen-products p {
  margin: 0 0 14px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-filter-nineteen-products article strong {
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-filter-nineteen-empty {
  display: none;
  grid-column: 1 / -1;
  padding: 22px;
  border-radius: 22px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.34);
}

.vb-filter-nineteen-empty.is-visible {
  display: block;
}

.vb-filter-nineteen-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-nineteen-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 1040px) {
  .vb-filter-nineteen-shop {
    grid-template-columns: 1fr;
  }

  .vb-filter-nineteen-products {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-filter-nineteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-nineteen-sidebar {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-nineteen-sidebar h3 {
    font-size: 38px !important;
  }

  .vb-filter-nineteen-products {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const shop = document.querySelector("[data-vb-filter-nineteen]");
  if (!shop) return;

  const input = shop.querySelector("[data-vb-filter-nineteen-input]");
  const buttons = shop.querySelectorAll("[data-shop-category]");
  const reset = shop.querySelector("[data-vb-filter-nineteen-reset]");
  const count = shop.querySelector("[data-vb-filter-nineteen-count]");
  const empty = shop.querySelector("[data-vb-filter-nineteen-empty]");
  const products = Array.from(shop.querySelectorAll("[data-product-card]"));

  let activeCategory = "all";

  function updateProducts() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    products.forEach(function (product) {
      const category = product.getAttribute("data-product-card");
      const text = product.getAttribute("data-product-text").toLowerCase();
      const fullText = product.textContent.toLowerCase();

      const categoryMatch = activeCategory === "all" || category === activeCategory;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = categoryMatch && searchMatch;

      product.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 product" : visible + " products";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeCategory = button.getAttribute("data-shop-category");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateProducts();
    });
  });

  input.addEventListener("input", updateProducts);

  reset.addEventListener("click", function () {
    activeCategory = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-shop-category") === "all");
    });

    input.focus();
    updateProducts();
  });

  updateProducts();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const shop = document.querySelector("[data-vb-filter-nineteen]");
  if (!shop) return;

  const input = shop.querySelector("[data-vb-filter-nineteen-input]");
  const buttons = shop.querySelectorAll("[data-shop-category]");
  const reset = shop.querySelector("[data-vb-filter-nineteen-reset]");
  const count = shop.querySelector("[data-vb-filter-nineteen-count]");
  const empty = shop.querySelector("[data-vb-filter-nineteen-empty]");
  const products = Array.from(shop.querySelectorAll("[data-product-card]"));

  let activeCategory = "all";

  function updateProducts() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    products.forEach(function (product) {
      const category = product.getAttribute("data-product-card");
      const text = product.getAttribute("data-product-text").toLowerCase();
      const fullText = product.textContent.toLowerCase();

      const categoryMatch = activeCategory === "all" || category === activeCategory;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = categoryMatch && searchMatch;

      product.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 product" : visible + " products";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeCategory = button.getAttribute("data-shop-category");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateProducts();
    });
  });

  input.addEventListener("input", updateProducts);

  reset.addEventListener("click", function () {
    activeCategory = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-shop-category") === "all");
    });

    input.focus();
    updateProducts();
  });

  updateProducts();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-nineteen-demo"&gt;
  &lt;div class="vb-filter-nineteen-shop" data-vb-filter-nineteen&gt;
    &lt;aside class="vb-filter-nineteen-sidebar"&gt;
      &lt;span&gt;Example 19&lt;/span&gt;
      &lt;h3&gt;Ecommerce Product Sidebar Filter&lt;/h3&gt;
      &lt;p&gt;Search products and filter the catalog by product category.&lt;/p&gt;

      &lt;div class="vb-filter-nineteen-search"&gt;
        &lt;label for="vb-filter-nineteen-input"&gt;Search products&lt;/label&gt;
        &lt;input id="vb-filter-nineteen-input" type="search" placeholder="Search desk, lamp, chair, storage..." data-vb-filter-nineteen-input&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-nineteen-categories"&gt;
        &lt;button type="button" class="is-active" data-shop-category="all"&gt;All Products&lt;/button&gt;
        &lt;button type="button" data-shop-category="furniture"&gt;Furniture&lt;/button&gt;
        &lt;button type="button" data-shop-category="lighting"&gt;Lighting&lt;/button&gt;
        &lt;button type="button" data-shop-category="storage"&gt;Storage&lt;/button&gt;
        &lt;button type="button" data-shop-category="decor"&gt;Decor&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-nineteen-summary"&gt;
        &lt;strong data-vb-filter-nineteen-count&gt;8 products&lt;/strong&gt;
        &lt;button type="button" data-vb-filter-nineteen-reset&gt;Reset filters&lt;/button&gt;
      &lt;/div&gt;
    &lt;/aside&gt;

    &lt;section class="vb-filter-nineteen-products"&gt;
      &lt;article data-product-card="furniture" data-product-text="oak desk furniture office table work home"&gt;
        &lt;div class="vb-filter-nineteen-image furniture-one"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Furniture&lt;/small&gt;
          &lt;h4&gt;Oak Office Desk&lt;/h4&gt;
          &lt;p&gt;Modern wooden desk for workspaces, home offices, and compact rooms.&lt;/p&gt;
          &lt;strong&gt;€249&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-product-card="lighting" data-product-text="desk lamp lighting led office adjustable"&gt;
        &lt;div class="vb-filter-nineteen-image lighting-one"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Lighting&lt;/small&gt;
          &lt;h4&gt;Adjustable LED Lamp&lt;/h4&gt;
          &lt;p&gt;Focused desk lighting with adjustable arm and warm light mode.&lt;/p&gt;
          &lt;strong&gt;€69&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-product-card="storage" data-product-text="modular shelf storage books boxes organizer"&gt;
        &lt;div class="vb-filter-nineteen-image storage-one"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Storage&lt;/small&gt;
          &lt;h4&gt;Modular Shelf Unit&lt;/h4&gt;
          &lt;p&gt;Flexible storage for books, boxes, decor pieces, and office items.&lt;/p&gt;
          &lt;strong&gt;€139&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-product-card="decor" data-product-text="ceramic vase decor home interior minimal"&gt;
        &lt;div class="vb-filter-nineteen-image decor-one"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Decor&lt;/small&gt;
          &lt;h4&gt;Ceramic Table Vase&lt;/h4&gt;
          &lt;p&gt;Minimal ceramic vase for shelves, desks, sideboards, and tables.&lt;/p&gt;
          &lt;strong&gt;€34&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-product-card="furniture" data-product-text="lounge chair furniture fabric living room"&gt;
        &lt;div class="vb-filter-nineteen-image furniture-two"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Furniture&lt;/small&gt;
          &lt;h4&gt;Soft Lounge Chair&lt;/h4&gt;
          &lt;p&gt;Comfortable accent chair for reading corners and living spaces.&lt;/p&gt;
          &lt;strong&gt;€189&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-product-card="lighting" data-product-text="floor lamp lighting living room standing lamp"&gt;
        &lt;div class="vb-filter-nineteen-image lighting-two"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Lighting&lt;/small&gt;
          &lt;h4&gt;Arc Floor Lamp&lt;/h4&gt;
          &lt;p&gt;Standing floor lamp for lounge areas, sofas, and room corners.&lt;/p&gt;
          &lt;strong&gt;€119&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-product-card="storage" data-product-text="drawer cabinet storage office files documents"&gt;
        &lt;div class="vb-filter-nineteen-image storage-two"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Storage&lt;/small&gt;
          &lt;h4&gt;Drawer Cabinet&lt;/h4&gt;
          &lt;p&gt;Compact drawer cabinet for office files, tools, and small accessories.&lt;/p&gt;
          &lt;strong&gt;€99&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-product-card="decor" data-product-text="wall art decor abstract print interior"&gt;
        &lt;div class="vb-filter-nineteen-image decor-two"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Decor&lt;/small&gt;
          &lt;h4&gt;Abstract Wall Print&lt;/h4&gt;
          &lt;p&gt;Modern wall print for home offices, bedrooms, and gallery walls.&lt;/p&gt;
          &lt;strong&gt;€45&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;div class="vb-filter-nineteen-empty" data-vb-filter-nineteen-empty&gt;
        &lt;strong&gt;No products found.&lt;/strong&gt;
        &lt;p&gt;Try searching for desk, lamp, chair, storage, decor, office, or shelf.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/section&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-nineteen-demo,
.vb-filter-nineteen-demo * {
  box-sizing: border-box;
}

.vb-filter-nineteen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(245, 158, 11, 0.24), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(59, 130, 246, 0.18), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #eff6ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(253, 230, 138, 0.52);
  box-shadow: 0 24px 70px rgba(120, 53, 15, 0.12);
}

.vb-filter-nineteen-shop {
  display: grid;
  grid-template-columns: 320px minmax(0, 1fr);
  gap: 18px;
  max-width: 1140px;
  margin: 0 auto;
}

.vb-filter-nineteen-sidebar {
  align-self: start;
  padding: 26px;
  border-radius: 30px;
  background: #111827;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.24);
}

.vb-filter-nineteen-sidebar &gt; span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(245, 158, 11, 0.16);
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-nineteen-sidebar h3 {
  margin: 0 0 12px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 4vw, 52px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-nineteen-sidebar p {
  margin: 0 0 22px !important;
  color: #d1d5db !important;
  -webkit-text-fill-color: #d1d5db !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-filter-nineteen-search {
  margin-bottom: 14px;
}

.vb-filter-nineteen-search label {
  display: block;
  margin-bottom: 8px;
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-nineteen-search input {
  width: 100%;
  min-height: 54px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 17px;
  outline: 0;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-nineteen-search input::placeholder {
  color: rgba(255,255,255,0.58);
  -webkit-text-fill-color: rgba(255,255,255,0.58);
}

.vb-filter-nineteen-categories {
  display: grid;
  gap: 8px;
  margin-bottom: 14px;
}

.vb-filter-nineteen-categories button {
  min-height: 44px;
  padding: 10px 13px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 14px;
  background: rgba(255,255,255,0.08);
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 13px;
  font-weight: 900;
  text-align: left;
  cursor: pointer;
}

.vb-filter-nineteen-categories button.is-active,
.vb-filter-nineteen-categories button:hover {
  background: linear-gradient(135deg, #f59e0b, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-nineteen-summary {
  display: grid;
  gap: 10px;
  padding: 14px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
}

.vb-filter-nineteen-summary strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-filter-nineteen-summary button {
  min-height: 40px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-nineteen-products {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-filter-nineteen-products article {
  overflow: hidden;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb-filter-nineteen-products article.is-hidden {
  display: none;
}

.vb-filter-nineteen-image {
  min-height: 150px;
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #f59e0b, #2563eb) !important;
}

.vb-filter-nineteen-image.lighting-one {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #facc15, #f97316) !important;
}

.vb-filter-nineteen-image.storage-one {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #0f766e, #14b8a6) !important;
}

.vb-filter-nineteen-image.decor-one {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #ec4899, #8b5cf6) !important;
}

.vb-filter-nineteen-image.furniture-two {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #92400e, #f59e0b) !important;
}

.vb-filter-nineteen-image.lighting-two {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #f97316, #dc2626) !important;
}

.vb-filter-nineteen-image.storage-two {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #334155, #64748b) !important;
}

.vb-filter-nineteen-image.decor-two {
  background:
    radial-gradient(circle at 32% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #7c3aed, #2563eb) !important;
}

.vb-filter-nineteen-products article &gt; div:last-child {
  padding: 18px;
}

.vb-filter-nineteen-products small {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #fffbeb;
  color: #b45309 !important;
  -webkit-text-fill-color: #b45309 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-nineteen-products h4 {
  margin: 0 0 8px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 20px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-nineteen-products p {
  margin: 0 0 14px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-filter-nineteen-products article strong {
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-filter-nineteen-empty {
  display: none;
  grid-column: 1 / -1;
  padding: 22px;
  border-radius: 22px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.34);
}

.vb-filter-nineteen-empty.is-visible {
  display: block;
}

.vb-filter-nineteen-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-nineteen-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 1040px) {
  .vb-filter-nineteen-shop {
    grid-template-columns: 1fr;
  }

  .vb-filter-nineteen-products {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-filter-nineteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-nineteen-sidebar {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-nineteen-sidebar h3 {
    font-size: 38px !important;
  }

  .vb-filter-nineteen-products {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This ecommerce sidebar search filter is useful for online stores, WooCommerce category pages, shop archives, marketplace layouts, product directories, catalog sections, and landing pages with many products.</p>



<h2 class="wp-block-heading">20. Course Catalog Search Filter</h2>



<p class="wp-block-paragraph"><strong>A course catalog search filter</strong> helps learners find lessons, modules, programs, and learning paths by topic, level, duration, or keyword. This layout is useful for online course platforms, tutorial libraries, LMS dashboards, education websites, bootcamp pages, and training portals.</p>



<p class="wp-block-paragraph">This example uses a learning dashboard style with a featured course panel, level filter buttons, and lesson rows. It is different from a product grid because it feels like a course library or learning path interface.</p>



<ul class="wp-block-list">
<li>Course catalog search layout</li>
<li>Filters lessons by level and keyword</li>
<li>Learning dashboard style</li>
<li>Course rows with duration and lesson type</li>
<li>Useful for LMS pages, course libraries, tutorial hubs, and education websites</li>
</ul>



<div class="vb-filter-twenty-demo">
  <div class="vb-filter-twenty-academy" data-vb-filter-twenty>
    <section class="vb-filter-twenty-feature">
      <span>Example 20</span>
      <h3>Course Catalog Search Filter</h3>
      <p>Search courses by topic, skill level, duration, or learning path keyword.</p>

      <div class="vb-filter-twenty-progress">
        <small>Catalog results</small>
        <strong data-vb-filter-twenty-count>9 courses</strong>
      </div>
    </section>

    <section class="vb-filter-twenty-content">
      <div class="vb-filter-twenty-toolbar">
        <input type="search" placeholder="Search JavaScript, CSS, WordPress, SEO..." data-vb-filter-twenty-input>

        <div class="vb-filter-twenty-levels">
          <button type="button" class="is-active" data-course-level="all">All</button>
          <button type="button" data-course-level="beginner">Beginner</button>
          <button type="button" data-course-level="intermediate">Intermediate</button>
          <button type="button" data-course-level="advanced">Advanced</button>
        </div>

        <button type="button" class="vb-filter-twenty-reset" data-vb-filter-twenty-reset>Reset</button>
      </div>

      <div class="vb-filter-twenty-list">
        <article data-course-card="beginner" data-course-text="javascript basics beginner variables functions dom">
          <div class="vb-filter-twenty-icon">JS</div>
          <div>
            <small>Beginner · 42 min</small>
            <h4>JavaScript Basics</h4>
            <p>Learn variables, functions, events, and simple DOM interaction.</p>
          </div>
          <span>Start</span>
        </article>

        <article data-course-card="intermediate" data-course-text="javascript filter search intermediate arrays dom cards">
          <div class="vb-filter-twenty-icon">JS</div>
          <div>
            <small>Intermediate · 58 min</small>
            <h4>Build Search Filters</h4>
            <p>Create live filters for cards, tables, directories, and content lists.</p>
          </div>
          <span>Open</span>
        </article>

        <article data-course-card="advanced" data-course-text="javascript performance advanced debounce optimization large lists">
          <div class="vb-filter-twenty-icon">JS</div>
          <div>
            <small>Advanced · 74 min</small>
            <h4>Fast Large List Filtering</h4>
            <p>Optimize search filtering with debounce, indexing, and rendering patterns.</p>
          </div>
          <span>Open</span>
        </article>

        <article data-course-card="beginner" data-course-text="css layout beginner flexbox grid responsive">
          <div class="vb-filter-twenty-icon css">CSS</div>
          <div>
            <small>Beginner · 50 min</small>
            <h4>Responsive CSS Layouts</h4>
            <p>Understand Flexbox, Grid, spacing, and mobile-first layout rules.</p>
          </div>
          <span>Start</span>
        </article>

        <article data-course-card="intermediate" data-course-text="wordpress gutenberg intermediate blocks custom content">
          <div class="vb-filter-twenty-icon wp">WP</div>
          <div>
            <small>Intermediate · 63 min</small>
            <h4>Gutenberg Content Blocks</h4>
            <p>Structure long tutorials with headings, code blocks, previews, and reusable sections.</p>
          </div>
          <span>Open</span>
        </article>

        <article data-course-card="advanced" data-course-text="wordpress plugin advanced ajax rest api admin">
          <div class="vb-filter-twenty-icon wp">WP</div>
          <div>
            <small>Advanced · 86 min</small>
            <h4>WordPress Plugin AJAX</h4>
            <p>Create admin actions, frontend forms, REST endpoints, and secure AJAX handlers.</p>
          </div>
          <span>Open</span>
        </article>

        <article data-course-card="beginner" data-course-text="seo basics beginner title description keywords">
          <div class="vb-filter-twenty-icon seo">SEO</div>
          <div>
            <small>Beginner · 39 min</small>
            <h4>SEO Basics for Articles</h4>
            <p>Write better titles, descriptions, headings, slugs, and keyword-focused sections.</p>
          </div>
          <span>Start</span>
        </article>

        <article data-course-card="intermediate" data-course-text="seo internal linking intermediate schema content structure">
          <div class="vb-filter-twenty-icon seo">SEO</div>
          <div>
            <small>Intermediate · 55 min</small>
            <h4>Internal Linking Strategy</h4>
            <p>Build topic clusters, related links, structured sections, and stronger article paths.</p>
          </div>
          <span>Open</span>
        </article>

        <article data-course-card="advanced" data-course-text="seo schema advanced entity structured data ai readable">
          <div class="vb-filter-twenty-icon seo">SEO</div>
          <div>
            <small>Advanced · 92 min</small>
            <h4>Entity SEO and Schema</h4>
            <p>Improve structured data, entity relationships, AI-readable content, and rich results.</p>
          </div>
          <span>Open</span>
        </article>
      </div>

      <div class="vb-filter-twenty-empty" data-vb-filter-twenty-empty>
        <strong>No courses found.</strong>
        <p>Try searching for JavaScript, CSS, WordPress, SEO, beginner, advanced, schema, or filters.</p>
      </div>
    </section>
  </div>
</div>

<style>
.vb-filter-twenty-demo,
.vb-filter-twenty-demo * {
  box-sizing: border-box;
}

.vb-filter-twenty-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(14, 165, 233, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(132, 204, 22, 0.18), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #f7fee7 52%, #ffffff 100%) !important;
  border: 1px solid rgba(186, 230, 253, 0.52);
  box-shadow: 0 24px 70px rgba(14, 116, 144, 0.12);
}

.vb-filter-twenty-academy {
  display: grid;
  grid-template-columns: 340px minmax(0, 1fr);
  gap: 18px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-filter-twenty-feature {
  position: relative;
  overflow: hidden;
  min-height: 620px;
  padding: 30px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 76% 24%, rgba(255,255,255,0.22), transparent 28%),
    linear-gradient(135deg, #0369a1, #16a34a) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.22);
}

.vb-filter-twenty-feature::after {
  content: "";
  position: absolute;
  right: -70px;
  bottom: -70px;
  width: 260px;
  height: 260px;
  border-radius: 50%;
  border: 38px solid rgba(255,255,255,0.16);
}

.vb-filter-twenty-feature > span {
  position: relative;
  z-index: 2;
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-twenty-feature h3 {
  position: relative;
  z-index: 2;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 4vw, 58px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-twenty-feature p {
  position: relative;
  z-index: 2;
  margin: 0 !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-twenty-progress {
  position: absolute;
  z-index: 2;
  left: 26px;
  right: 26px;
  bottom: 26px;
  padding: 20px;
  border-radius: 24px;
  background: rgba(15, 23, 42, 0.72);
  border: 1px solid rgba(255,255,255,0.16);
  backdrop-filter: blur(14px);
}

.vb-filter-twenty-progress small {
  display: block;
  margin-bottom: 6px;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-twenty-progress strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-filter-twenty-content {
  padding: 24px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-twenty-toolbar {
  display: grid;
  grid-template-columns: minmax(240px, 0.9fr) minmax(0, 1.1fr) auto;
  gap: 10px;
  align-items: center;
  margin-bottom: 16px;
  padding: 12px;
  border-radius: 22px;
  background: #f8fafc;
}

.vb-filter-twenty-toolbar input {
  width: 100%;
  min-height: 50px;
  padding: 0 15px;
  border: 1px solid rgba(148, 163, 184, 0.26);
  border-radius: 16px;
  outline: 0;
  background: #ffffff;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-twenty-levels {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-filter-twenty-levels button,
.vb-filter-twenty-reset {
  min-height: 40px;
  padding: 9px 12px;
  border: 0;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-twenty-levels button {
  background: #ecfeff;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
}

.vb-filter-twenty-levels button.is-active,
.vb-filter-twenty-levels button:hover {
  background: linear-gradient(135deg, #0284c7, #16a34a);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-twenty-reset {
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-twenty-list {
  display: grid;
  gap: 10px;
}

.vb-filter-twenty-list article {
  display: grid;
  grid-template-columns: 58px minmax(0, 1fr) auto;
  gap: 14px;
  align-items: center;
  padding: 14px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 12px 28px rgba(15, 23, 42, 0.06);
}

.vb-filter-twenty-list article.is-hidden {
  display: none;
}

.vb-filter-twenty-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 58px;
  height: 58px;
  border-radius: 18px;
  background: linear-gradient(135deg, #facc15, #f97316);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-filter-twenty-icon.css {
  background: linear-gradient(135deg, #2563eb, #06b6d4);
}

.vb-filter-twenty-icon.wp {
  background: linear-gradient(135deg, #0f766e, #14b8a6);
}

.vb-filter-twenty-icon.seo {
  background: linear-gradient(135deg, #16a34a, #84cc16);
}

.vb-filter-twenty-list small {
  display: block;
  margin-bottom: 4px;
  color: #0284c7 !important;
  -webkit-text-fill-color: #0284c7 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-filter-twenty-list h4 {
  margin: 0 0 6px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-twenty-list p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-filter-twenty-list article > span {
  display: inline-flex;
  min-width: 54px;
  justify-content: center;
  padding: 8px 10px;
  border-radius: 999px;
  background: #f7fee7;
  color: #16a34a !important;
  -webkit-text-fill-color: #16a34a !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-filter-twenty-empty {
  display: none;
  margin-top: 14px;
  padding: 20px;
  border-radius: 20px;
  background: #f0f9ff;
  border: 1px solid rgba(125, 211, 252, 0.36);
}

.vb-filter-twenty-empty.is-visible {
  display: block;
}

.vb-filter-twenty-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-twenty-empty p {
  margin: 0 !important;
  color: #075985 !important;
  -webkit-text-fill-color: #075985 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb-filter-twenty-academy {
    grid-template-columns: 1fr;
  }

  .vb-filter-twenty-feature {
    min-height: 400px;
  }

  .vb-filter-twenty-toolbar {
    grid-template-columns: 1fr;
  }

  .vb-filter-twenty-reset {
    width: fit-content;
  }
}

@media (max-width: 640px) {
  .vb-filter-twenty-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-twenty-feature,
  .vb-filter-twenty-content {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-twenty-feature h3 {
    font-size: 38px !important;
  }

  .vb-filter-twenty-levels {
    display: grid;
    grid-template-columns: 1fr;
  }

  .vb-filter-twenty-list article {
    grid-template-columns: 58px minmax(0, 1fr);
  }

  .vb-filter-twenty-list article > span {
    grid-column: 2;
    width: fit-content;
  }
}
</style>

<script>
(function () {
  const academy = document.querySelector("[data-vb-filter-twenty]");
  if (!academy) return;

  const input = academy.querySelector("[data-vb-filter-twenty-input]");
  const buttons = academy.querySelectorAll("[data-course-level]");
  const reset = academy.querySelector("[data-vb-filter-twenty-reset]");
  const count = academy.querySelector("[data-vb-filter-twenty-count]");
  const empty = academy.querySelector("[data-vb-filter-twenty-empty]");
  const courses = Array.from(academy.querySelectorAll("[data-course-card]"));

  let activeLevel = "all";

  function updateCourses() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    courses.forEach(function (course) {
      const level = course.getAttribute("data-course-card");
      const text = course.getAttribute("data-course-text").toLowerCase();
      const fullText = course.textContent.toLowerCase();

      const levelMatch = activeLevel === "all" || level === activeLevel;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = levelMatch && searchMatch;

      course.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 course" : visible + " courses";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeLevel = button.getAttribute("data-course-level");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateCourses();
    });
  });

  input.addEventListener("input", updateCourses);

  reset.addEventListener("click", function () {
    activeLevel = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-course-level") === "all");
    });

    input.focus();
    updateCourses();
  });

  updateCourses();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const academy = document.querySelector("[data-vb-filter-twenty]");
  if (!academy) return;

  const input = academy.querySelector("[data-vb-filter-twenty-input]");
  const buttons = academy.querySelectorAll("[data-course-level]");
  const reset = academy.querySelector("[data-vb-filter-twenty-reset]");
  const count = academy.querySelector("[data-vb-filter-twenty-count]");
  const empty = academy.querySelector("[data-vb-filter-twenty-empty]");
  const courses = Array.from(academy.querySelectorAll("[data-course-card]"));

  let activeLevel = "all";

  function updateCourses() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    courses.forEach(function (course) {
      const level = course.getAttribute("data-course-card");
      const text = course.getAttribute("data-course-text").toLowerCase();
      const fullText = course.textContent.toLowerCase();

      const levelMatch = activeLevel === "all" || level === activeLevel;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = levelMatch && searchMatch;

      course.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 course" : visible + " courses";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeLevel = button.getAttribute("data-course-level");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateCourses();
    });
  });

  input.addEventListener("input", updateCourses);

  reset.addEventListener("click", function () {
    activeLevel = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-course-level") === "all");
    });

    input.focus();
    updateCourses();
  });

  updateCourses();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-twenty-demo"&gt;
  &lt;div class="vb-filter-twenty-academy" data-vb-filter-twenty&gt;
    &lt;section class="vb-filter-twenty-feature"&gt;
      &lt;span&gt;Example 20&lt;/span&gt;
      &lt;h3&gt;Course Catalog Search Filter&lt;/h3&gt;
      &lt;p&gt;Search courses by topic, skill level, duration, or learning path keyword.&lt;/p&gt;

      &lt;div class="vb-filter-twenty-progress"&gt;
        &lt;small&gt;Catalog results&lt;/small&gt;
        &lt;strong data-vb-filter-twenty-count&gt;9 courses&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/section&gt;

    &lt;section class="vb-filter-twenty-content"&gt;
      &lt;div class="vb-filter-twenty-toolbar"&gt;
        &lt;input type="search" placeholder="Search JavaScript, CSS, WordPress, SEO..." data-vb-filter-twenty-input&gt;

        &lt;div class="vb-filter-twenty-levels"&gt;
          &lt;button type="button" class="is-active" data-course-level="all"&gt;All&lt;/button&gt;
          &lt;button type="button" data-course-level="beginner"&gt;Beginner&lt;/button&gt;
          &lt;button type="button" data-course-level="intermediate"&gt;Intermediate&lt;/button&gt;
          &lt;button type="button" data-course-level="advanced"&gt;Advanced&lt;/button&gt;
        &lt;/div&gt;

        &lt;button type="button" class="vb-filter-twenty-reset" data-vb-filter-twenty-reset&gt;Reset&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-twenty-list"&gt;
        &lt;article data-course-card="beginner" data-course-text="javascript basics beginner variables functions dom"&gt;
          &lt;div class="vb-filter-twenty-icon"&gt;JS&lt;/div&gt;
          &lt;div&gt;
            &lt;small&gt;Beginner · 42 min&lt;/small&gt;
            &lt;h4&gt;JavaScript Basics&lt;/h4&gt;
            &lt;p&gt;Learn variables, functions, events, and simple DOM interaction.&lt;/p&gt;
          &lt;/div&gt;
          &lt;span&gt;Start&lt;/span&gt;
        &lt;/article&gt;

        &lt;article data-course-card="intermediate" data-course-text="javascript filter search intermediate arrays dom cards"&gt;
          &lt;div class="vb-filter-twenty-icon"&gt;JS&lt;/div&gt;
          &lt;div&gt;
            &lt;small&gt;Intermediate · 58 min&lt;/small&gt;
            &lt;h4&gt;Build Search Filters&lt;/h4&gt;
            &lt;p&gt;Create live filters for cards, tables, directories, and content lists.&lt;/p&gt;
          &lt;/div&gt;
          &lt;span&gt;Open&lt;/span&gt;
        &lt;/article&gt;

        &lt;article data-course-card="advanced" data-course-text="javascript performance advanced debounce optimization large lists"&gt;
          &lt;div class="vb-filter-twenty-icon"&gt;JS&lt;/div&gt;
          &lt;div&gt;
            &lt;small&gt;Advanced · 74 min&lt;/small&gt;
            &lt;h4&gt;Fast Large List Filtering&lt;/h4&gt;
            &lt;p&gt;Optimize search filtering with debounce, indexing, and rendering patterns.&lt;/p&gt;
          &lt;/div&gt;
          &lt;span&gt;Open&lt;/span&gt;
        &lt;/article&gt;

        &lt;article data-course-card="beginner" data-course-text="css layout beginner flexbox grid responsive"&gt;
          &lt;div class="vb-filter-twenty-icon css"&gt;CSS&lt;/div&gt;
          &lt;div&gt;
            &lt;small&gt;Beginner · 50 min&lt;/small&gt;
            &lt;h4&gt;Responsive CSS Layouts&lt;/h4&gt;
            &lt;p&gt;Understand Flexbox, Grid, spacing, and mobile-first layout rules.&lt;/p&gt;
          &lt;/div&gt;
          &lt;span&gt;Start&lt;/span&gt;
        &lt;/article&gt;

        &lt;article data-course-card="intermediate" data-course-text="wordpress gutenberg intermediate blocks custom content"&gt;
          &lt;div class="vb-filter-twenty-icon wp"&gt;WP&lt;/div&gt;
          &lt;div&gt;
            &lt;small&gt;Intermediate · 63 min&lt;/small&gt;
            &lt;h4&gt;Gutenberg Content Blocks&lt;/h4&gt;
            &lt;p&gt;Structure long tutorials with headings, code blocks, previews, and reusable sections.&lt;/p&gt;
          &lt;/div&gt;
          &lt;span&gt;Open&lt;/span&gt;
        &lt;/article&gt;

        &lt;article data-course-card="advanced" data-course-text="wordpress plugin advanced ajax rest api admin"&gt;
          &lt;div class="vb-filter-twenty-icon wp"&gt;WP&lt;/div&gt;
          &lt;div&gt;
            &lt;small&gt;Advanced · 86 min&lt;/small&gt;
            &lt;h4&gt;WordPress Plugin AJAX&lt;/h4&gt;
            &lt;p&gt;Create admin actions, frontend forms, REST endpoints, and secure AJAX handlers.&lt;/p&gt;
          &lt;/div&gt;
          &lt;span&gt;Open&lt;/span&gt;
        &lt;/article&gt;

        &lt;article data-course-card="beginner" data-course-text="seo basics beginner title description keywords"&gt;
          &lt;div class="vb-filter-twenty-icon seo"&gt;SEO&lt;/div&gt;
          &lt;div&gt;
            &lt;small&gt;Beginner · 39 min&lt;/small&gt;
            &lt;h4&gt;SEO Basics for Articles&lt;/h4&gt;
            &lt;p&gt;Write better titles, descriptions, headings, slugs, and keyword-focused sections.&lt;/p&gt;
          &lt;/div&gt;
          &lt;span&gt;Start&lt;/span&gt;
        &lt;/article&gt;

        &lt;article data-course-card="intermediate" data-course-text="seo internal linking intermediate schema content structure"&gt;
          &lt;div class="vb-filter-twenty-icon seo"&gt;SEO&lt;/div&gt;
          &lt;div&gt;
            &lt;small&gt;Intermediate · 55 min&lt;/small&gt;
            &lt;h4&gt;Internal Linking Strategy&lt;/h4&gt;
            &lt;p&gt;Build topic clusters, related links, structured sections, and stronger article paths.&lt;/p&gt;
          &lt;/div&gt;
          &lt;span&gt;Open&lt;/span&gt;
        &lt;/article&gt;

        &lt;article data-course-card="advanced" data-course-text="seo schema advanced entity structured data ai readable"&gt;
          &lt;div class="vb-filter-twenty-icon seo"&gt;SEO&lt;/div&gt;
          &lt;div&gt;
            &lt;small&gt;Advanced · 92 min&lt;/small&gt;
            &lt;h4&gt;Entity SEO and Schema&lt;/h4&gt;
            &lt;p&gt;Improve structured data, entity relationships, AI-readable content, and rich results.&lt;/p&gt;
          &lt;/div&gt;
          &lt;span&gt;Open&lt;/span&gt;
        &lt;/article&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-twenty-empty" data-vb-filter-twenty-empty&gt;
        &lt;strong&gt;No courses found.&lt;/strong&gt;
        &lt;p&gt;Try searching for JavaScript, CSS, WordPress, SEO, beginner, advanced, schema, or filters.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/section&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-twenty-demo,
.vb-filter-twenty-demo * {
  box-sizing: border-box;
}

.vb-filter-twenty-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(14, 165, 233, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(132, 204, 22, 0.18), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #f7fee7 52%, #ffffff 100%) !important;
  border: 1px solid rgba(186, 230, 253, 0.52);
  box-shadow: 0 24px 70px rgba(14, 116, 144, 0.12);
}

.vb-filter-twenty-academy {
  display: grid;
  grid-template-columns: 340px minmax(0, 1fr);
  gap: 18px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-filter-twenty-feature {
  position: relative;
  overflow: hidden;
  min-height: 620px;
  padding: 30px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 76% 24%, rgba(255,255,255,0.22), transparent 28%),
    linear-gradient(135deg, #0369a1, #16a34a) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.22);
}

.vb-filter-twenty-feature::after {
  content: "";
  position: absolute;
  right: -70px;
  bottom: -70px;
  width: 260px;
  height: 260px;
  border-radius: 50%;
  border: 38px solid rgba(255,255,255,0.16);
}

.vb-filter-twenty-feature &gt; span {
  position: relative;
  z-index: 2;
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-twenty-feature h3 {
  position: relative;
  z-index: 2;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 4vw, 58px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-twenty-feature p {
  position: relative;
  z-index: 2;
  margin: 0 !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-twenty-progress {
  position: absolute;
  z-index: 2;
  left: 26px;
  right: 26px;
  bottom: 26px;
  padding: 20px;
  border-radius: 24px;
  background: rgba(15, 23, 42, 0.72);
  border: 1px solid rgba(255,255,255,0.16);
  backdrop-filter: blur(14px);
}

.vb-filter-twenty-progress small {
  display: block;
  margin-bottom: 6px;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-twenty-progress strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-filter-twenty-content {
  padding: 24px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-twenty-toolbar {
  display: grid;
  grid-template-columns: minmax(240px, 0.9fr) minmax(0, 1.1fr) auto;
  gap: 10px;
  align-items: center;
  margin-bottom: 16px;
  padding: 12px;
  border-radius: 22px;
  background: #f8fafc;
}

.vb-filter-twenty-toolbar input {
  width: 100%;
  min-height: 50px;
  padding: 0 15px;
  border: 1px solid rgba(148, 163, 184, 0.26);
  border-radius: 16px;
  outline: 0;
  background: #ffffff;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-twenty-levels {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-filter-twenty-levels button,
.vb-filter-twenty-reset {
  min-height: 40px;
  padding: 9px 12px;
  border: 0;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-twenty-levels button {
  background: #ecfeff;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
}

.vb-filter-twenty-levels button.is-active,
.vb-filter-twenty-levels button:hover {
  background: linear-gradient(135deg, #0284c7, #16a34a);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-twenty-reset {
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-twenty-list {
  display: grid;
  gap: 10px;
}

.vb-filter-twenty-list article {
  display: grid;
  grid-template-columns: 58px minmax(0, 1fr) auto;
  gap: 14px;
  align-items: center;
  padding: 14px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 12px 28px rgba(15, 23, 42, 0.06);
}

.vb-filter-twenty-list article.is-hidden {
  display: none;
}

.vb-filter-twenty-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 58px;
  height: 58px;
  border-radius: 18px;
  background: linear-gradient(135deg, #facc15, #f97316);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-filter-twenty-icon.css {
  background: linear-gradient(135deg, #2563eb, #06b6d4);
}

.vb-filter-twenty-icon.wp {
  background: linear-gradient(135deg, #0f766e, #14b8a6);
}

.vb-filter-twenty-icon.seo {
  background: linear-gradient(135deg, #16a34a, #84cc16);
}

.vb-filter-twenty-list small {
  display: block;
  margin-bottom: 4px;
  color: #0284c7 !important;
  -webkit-text-fill-color: #0284c7 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-filter-twenty-list h4 {
  margin: 0 0 6px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-twenty-list p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-filter-twenty-list article &gt; span {
  display: inline-flex;
  min-width: 54px;
  justify-content: center;
  padding: 8px 10px;
  border-radius: 999px;
  background: #f7fee7;
  color: #16a34a !important;
  -webkit-text-fill-color: #16a34a !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-filter-twenty-empty {
  display: none;
  margin-top: 14px;
  padding: 20px;
  border-radius: 20px;
  background: #f0f9ff;
  border: 1px solid rgba(125, 211, 252, 0.36);
}

.vb-filter-twenty-empty.is-visible {
  display: block;
}

.vb-filter-twenty-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-twenty-empty p {
  margin: 0 !important;
  color: #075985 !important;
  -webkit-text-fill-color: #075985 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb-filter-twenty-academy {
    grid-template-columns: 1fr;
  }

  .vb-filter-twenty-feature {
    min-height: 400px;
  }

  .vb-filter-twenty-toolbar {
    grid-template-columns: 1fr;
  }

  .vb-filter-twenty-reset {
    width: fit-content;
  }
}

@media (max-width: 640px) {
  .vb-filter-twenty-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-twenty-feature,
  .vb-filter-twenty-content {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-twenty-feature h3 {
    font-size: 38px !important;
  }

  .vb-filter-twenty-levels {
    display: grid;
    grid-template-columns: 1fr;
  }

  .vb-filter-twenty-list article {
    grid-template-columns: 58px minmax(0, 1fr);
  }

  .vb-filter-twenty-list article &gt; span {
    grid-column: 2;
    width: fit-content;
  }
}</pre>



<p class="wp-block-paragraph">This course catalog search filter is useful for LMS dashboards, course libraries, tutorial hubs, online academies, bootcamp websites, education platforms, and training portals where learners need to find relevant content quickly.</p>



<h2 class="wp-block-heading">21. Flight Booking Search Filter</h2>



<p class="wp-block-paragraph"><strong>A flight booking search filter</strong> helps users filter travel results by destination, airline, travel type, or keyword. This layout is useful for travel websites, booking platforms, airport dashboards, hotel packages, tour directories, and transport search pages.</p>



<p class="wp-block-paragraph">This example uses a travel search interface with a boarding-pass style hero panel and a flight results list. Users can search by city, airline, country, or flight type, then narrow the visible results with travel category buttons.</p>



<ul class="wp-block-list">
<li>Travel booking search layout</li>
<li>Filters flights by destination and travel type</li>
<li>Boarding-pass inspired visual style</li>
<li>Flight rows with airline, route, and price</li>
<li>Useful for booking websites, travel directories, and transport dashboards</li>
</ul>



<div class="vb-filter-twentyone-demo">
  <div class="vb-filter-twentyone-flight" data-vb-filter-twentyone>
    <section class="vb-filter-twentyone-pass">
      <div class="vb-filter-twentyone-pass-top">
        <span>Example 21</span>
        <h3>Flight Booking Search Filter</h3>
        <p>Search flights by destination, airline, country, route, or travel type.</p>
      </div>

      <div class="vb-filter-twentyone-ticket">
        <div>
          <small>From</small>
          <strong>TLL</strong>
          <span>Tallinn</span>
        </div>
        <div class="vb-filter-twentyone-plane">✈</div>
        <div>
          <small>Results</small>
          <strong data-vb-filter-twentyone-count>8</strong>
          <span>Flights</span>
        </div>
      </div>
    </section>

    <section class="vb-filter-twentyone-results">
      <div class="vb-filter-twentyone-toolbar">
        <input type="search" placeholder="Search Paris, London, business, Nord Air..." data-vb-filter-twentyone-input>

        <div class="vb-filter-twentyone-types">
          <button type="button" class="is-active" data-flight-type="all">All</button>
          <button type="button" data-flight-type="city">City Break</button>
          <button type="button" data-flight-type="beach">Beach</button>
          <button type="button" data-flight-type="business">Business</button>
          <button type="button" data-flight-type="longhaul">Long Haul</button>
        </div>

        <button type="button" class="vb-filter-twentyone-reset" data-vb-filter-twentyone-reset>Reset</button>
      </div>

      <div class="vb-filter-twentyone-list">
        <article data-flight-card="city" data-flight-text="paris france city break nord air direct weekend">
          <div class="vb-filter-twentyone-route">
            <strong>TLL</strong>
            <span></span>
            <strong>CDG</strong>
          </div>
          <div>
            <small>City Break · Nord Air</small>
            <h4>Paris Weekend Flight</h4>
            <p>Direct flight to Paris with morning departure and flexible return.</p>
          </div>
          <em>€129</em>
        </article>

        <article data-flight-card="business" data-flight-text="london uk business skyline express morning meeting">
          <div class="vb-filter-twentyone-route">
            <strong>TLL</strong>
            <span></span>
            <strong>LHR</strong>
          </div>
          <div>
            <small>Business · Skyline Express</small>
            <h4>London Business Route</h4>
            <p>Early flight for meetings, conferences, and short business trips.</p>
          </div>
          <em>€179</em>
        </article>

        <article data-flight-card="beach" data-flight-text="malaga spain beach sun holiday family coast">
          <div class="vb-filter-twentyone-route">
            <strong>TLL</strong>
            <span></span>
            <strong>AGP</strong>
          </div>
          <div>
            <small>Beach · SunJet</small>
            <h4>Malaga Holiday Flight</h4>
            <p>Sunny coastal route for beach trips, family holidays, and warm weekends.</p>
          </div>
          <em>€156</em>
        </article>

        <article data-flight-card="longhaul" data-flight-text="new york usa long haul atlantic global air">
          <div class="vb-filter-twentyone-route">
            <strong>TLL</strong>
            <span></span>
            <strong>JFK</strong>
          </div>
          <div>
            <small>Long Haul · Global Air</small>
            <h4>New York Connection</h4>
            <p>Atlantic connection with one stop and evening arrival in New York.</p>
          </div>
          <em>€489</em>
        </article>

        <article data-flight-card="city" data-flight-text="rome italy city break classic air culture weekend">
          <div class="vb-filter-twentyone-route">
            <strong>TLL</strong>
            <span></span>
            <strong>FCO</strong>
          </div>
          <div>
            <small>City Break · Classic Air</small>
            <h4>Rome Culture Trip</h4>
            <p>Flight package for museums, historic streets, restaurants, and city exploring.</p>
          </div>
          <em>€142</em>
        </article>

        <article data-flight-card="beach" data-flight-text="crete greece beach island aegean summer">
          <div class="vb-filter-twentyone-route">
            <strong>TLL</strong>
            <span></span>
            <strong>HER</strong>
          </div>
          <div>
            <small>Beach · Aegean Line</small>
            <h4>Crete Island Flight</h4>
            <p>Summer flight to Crete for beaches, resorts, food, and island tours.</p>
          </div>
          <em>€198</em>
        </article>

        <article data-flight-card="business" data-flight-text="stockholm sweden business nordic link quick route">
          <div class="vb-filter-twentyone-route">
            <strong>TLL</strong>
            <span></span>
            <strong>ARN</strong>
          </div>
          <div>
            <small>Business · Nordic Link</small>
            <h4>Stockholm Quick Route</h4>
            <p>Short business flight for same-day meetings and Nordic connections.</p>
          </div>
          <em>€94</em>
        </article>

        <article data-flight-card="longhaul" data-flight-text="tokyo japan long haul asia premium journey">
          <div class="vb-filter-twentyone-route">
            <strong>TLL</strong>
            <span></span>
            <strong>HND</strong>
          </div>
          <div>
            <small>Long Haul · Eastern Wings</small>
            <h4>Tokyo Premium Journey</h4>
            <p>Long-haul route to Tokyo with premium cabin options and flexible dates.</p>
          </div>
          <em>€749</em>
        </article>
      </div>

      <div class="vb-filter-twentyone-empty" data-vb-filter-twentyone-empty>
        <strong>No flights found.</strong>
        <p>Try searching for Paris, London, beach, business, Tokyo, Malaga, or city break.</p>
      </div>
    </section>
  </div>
</div>

<style>
.vb-filter-twentyone-demo,
.vb-filter-twentyone-demo * {
  box-sizing: border-box;
}

.vb-filter-twentyone-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(56, 189, 248, 0.24), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(251, 146, 60, 0.20), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #fff7ed 52%, #ffffff 100%) !important;
  border: 1px solid rgba(186, 230, 253, 0.52);
  box-shadow: 0 24px 70px rgba(12, 74, 110, 0.12);
}

.vb-filter-twentyone-flight {
  display: grid;
  grid-template-columns: 360px minmax(0, 1fr);
  gap: 18px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-filter-twentyone-pass {
  position: relative;
  overflow: hidden;
  min-height: 640px;
  padding: 30px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 78% 24%, rgba(255,255,255,0.30), transparent 28%),
    linear-gradient(135deg, #0284c7, #1d4ed8 52%, #0f172a) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.24);
}

.vb-filter-twentyone-pass::after {
  content: "";
  position: absolute;
  left: -80px;
  bottom: -80px;
  width: 260px;
  height: 260px;
  border-radius: 50%;
  border: 40px solid rgba(255,255,255,0.14);
}

.vb-filter-twentyone-pass-top {
  position: relative;
  z-index: 2;
}

.vb-filter-twentyone-pass-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.15);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-twentyone-pass-top h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 4vw, 58px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-twentyone-pass-top p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-twentyone-ticket {
  position: absolute;
  z-index: 2;
  left: 26px;
  right: 26px;
  bottom: 26px;
  display: grid;
  grid-template-columns: 1fr 68px 1fr;
  gap: 12px;
  align-items: center;
  padding: 18px;
  border-radius: 26px;
  background: #ffffff;
  box-shadow: 0 26px 70px rgba(0,0,0,0.24);
}

.vb-filter-twentyone-ticket small {
  display: block;
  margin-bottom: 5px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-twentyone-ticket strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 34px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.08em;
}

.vb-filter-twentyone-ticket span {
  color: #0284c7 !important;
  -webkit-text-fill-color: #0284c7 !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-filter-twentyone-plane {
  display: flex;
  align-items: center;
  justify-content: center;
  height: 68px;
  border-radius: 22px;
  background: linear-gradient(135deg, #f97316, #0284c7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 30px;
}

.vb-filter-twentyone-results {
  padding: 24px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-twentyone-toolbar {
  display: grid;
  grid-template-columns: minmax(260px, 0.85fr) minmax(0, 1.15fr) auto;
  gap: 10px;
  align-items: center;
  margin-bottom: 16px;
  padding: 12px;
  border-radius: 22px;
  background: #f8fafc;
}

.vb-filter-twentyone-toolbar input {
  width: 100%;
  min-height: 50px;
  padding: 0 15px;
  border: 1px solid rgba(148, 163, 184, 0.26);
  border-radius: 16px;
  outline: 0;
  background: #ffffff;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-twentyone-types {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-filter-twentyone-types button,
.vb-filter-twentyone-reset {
  min-height: 40px;
  padding: 9px 12px;
  border: 0;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-twentyone-types button {
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
}

.vb-filter-twentyone-types button.is-active,
.vb-filter-twentyone-types button:hover {
  background: linear-gradient(135deg, #0284c7, #f97316);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-twentyone-reset {
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-twentyone-list {
  display: grid;
  gap: 10px;
}

.vb-filter-twentyone-list article {
  display: grid;
  grid-template-columns: 110px minmax(0, 1fr) 80px;
  gap: 14px;
  align-items: center;
  padding: 14px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 12px 30px rgba(15, 23, 42, 0.06);
}

.vb-filter-twentyone-list article.is-hidden {
  display: none;
}

.vb-filter-twentyone-route {
  display: grid;
  grid-template-columns: 1fr 28px 1fr;
  gap: 6px;
  align-items: center;
}

.vb-filter-twentyone-route strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 17px;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-filter-twentyone-route span {
  height: 2px;
  border-radius: 999px;
  background: #38bdf8;
}

.vb-filter-twentyone-list small {
  display: block;
  margin-bottom: 4px;
  color: #0284c7 !important;
  -webkit-text-fill-color: #0284c7 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-filter-twentyone-list h4 {
  margin: 0 0 6px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-twentyone-list p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-filter-twentyone-list em {
  color: #ea580c !important;
  -webkit-text-fill-color: #ea580c !important;
  font-size: 18px;
  font-style: normal;
  font-weight: 950;
  text-align: right;
}

.vb-filter-twentyone-empty {
  display: none;
  margin-top: 14px;
  padding: 20px;
  border-radius: 20px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.34);
}

.vb-filter-twentyone-empty.is-visible {
  display: block;
}

.vb-filter-twentyone-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-twentyone-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb-filter-twentyone-flight {
    grid-template-columns: 1fr;
  }

  .vb-filter-twentyone-pass {
    min-height: 430px;
  }

  .vb-filter-twentyone-toolbar {
    grid-template-columns: 1fr;
  }

  .vb-filter-twentyone-reset {
    width: fit-content;
  }
}

@media (max-width: 640px) {
  .vb-filter-twentyone-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-twentyone-pass,
  .vb-filter-twentyone-results {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-twentyone-pass-top h3 {
    font-size: 38px !important;
  }

  .vb-filter-twentyone-ticket {
    grid-template-columns: 1fr;
  }

  .vb-filter-twentyone-list article {
    grid-template-columns: 1fr;
  }

  .vb-filter-twentyone-list em {
    text-align: left;
  }
}
</style>

<script>
(function () {
  const flight = document.querySelector("[data-vb-filter-twentyone]");
  if (!flight) return;

  const input = flight.querySelector("[data-vb-filter-twentyone-input]");
  const buttons = flight.querySelectorAll("[data-flight-type]");
  const reset = flight.querySelector("[data-vb-filter-twentyone-reset]");
  const count = flight.querySelector("[data-vb-filter-twentyone-count]");
  const empty = flight.querySelector("[data-vb-filter-twentyone-empty]");
  const flights = Array.from(flight.querySelectorAll("[data-flight-card]"));

  let activeType = "all";

  function updateFlights() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    flights.forEach(function (item) {
      const type = item.getAttribute("data-flight-card");
      const text = item.getAttribute("data-flight-text").toLowerCase();
      const fullText = item.textContent.toLowerCase();

      const typeMatch = activeType === "all" || type === activeType;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = typeMatch && searchMatch;

      item.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible;
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeType = button.getAttribute("data-flight-type");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateFlights();
    });
  });

  input.addEventListener("input", updateFlights);

  reset.addEventListener("click", function () {
    activeType = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-flight-type") === "all");
    });

    input.focus();
    updateFlights();
  });

  updateFlights();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const flight = document.querySelector("[data-vb-filter-twentyone]");
  if (!flight) return;

  const input = flight.querySelector("[data-vb-filter-twentyone-input]");
  const buttons = flight.querySelectorAll("[data-flight-type]");
  const reset = flight.querySelector("[data-vb-filter-twentyone-reset]");
  const count = flight.querySelector("[data-vb-filter-twentyone-count]");
  const empty = flight.querySelector("[data-vb-filter-twentyone-empty]");
  const flights = Array.from(flight.querySelectorAll("[data-flight-card]"));

  let activeType = "all";

  function updateFlights() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    flights.forEach(function (item) {
      const type = item.getAttribute("data-flight-card");
      const text = item.getAttribute("data-flight-text").toLowerCase();
      const fullText = item.textContent.toLowerCase();

      const typeMatch = activeType === "all" || type === activeType;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = typeMatch && searchMatch;

      item.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible;
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeType = button.getAttribute("data-flight-type");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateFlights();
    });
  });

  input.addEventListener("input", updateFlights);

  reset.addEventListener("click", function () {
    activeType = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-flight-type") === "all");
    });

    input.focus();
    updateFlights();
  });

  updateFlights();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-twentyone-demo"&gt;
  &lt;div class="vb-filter-twentyone-flight" data-vb-filter-twentyone&gt;
    &lt;section class="vb-filter-twentyone-pass"&gt;
      &lt;div class="vb-filter-twentyone-pass-top"&gt;
        &lt;span&gt;Example 21&lt;/span&gt;
        &lt;h3&gt;Flight Booking Search Filter&lt;/h3&gt;
        &lt;p&gt;Search flights by destination, airline, country, route, or travel type.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-twentyone-ticket"&gt;
        &lt;div&gt;
          &lt;small&gt;From&lt;/small&gt;
          &lt;strong&gt;TLL&lt;/strong&gt;
          &lt;span&gt;Tallinn&lt;/span&gt;
        &lt;/div&gt;
        &lt;div class="vb-filter-twentyone-plane"&gt;✈&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Results&lt;/small&gt;
          &lt;strong data-vb-filter-twentyone-count&gt;8&lt;/strong&gt;
          &lt;span&gt;Flights&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/section&gt;

    &lt;section class="vb-filter-twentyone-results"&gt;
      &lt;div class="vb-filter-twentyone-toolbar"&gt;
        &lt;input type="search" placeholder="Search Paris, London, business, Nord Air..." data-vb-filter-twentyone-input&gt;

        &lt;div class="vb-filter-twentyone-types"&gt;
          &lt;button type="button" class="is-active" data-flight-type="all"&gt;All&lt;/button&gt;
          &lt;button type="button" data-flight-type="city"&gt;City Break&lt;/button&gt;
          &lt;button type="button" data-flight-type="beach"&gt;Beach&lt;/button&gt;
          &lt;button type="button" data-flight-type="business"&gt;Business&lt;/button&gt;
          &lt;button type="button" data-flight-type="longhaul"&gt;Long Haul&lt;/button&gt;
        &lt;/div&gt;

        &lt;button type="button" class="vb-filter-twentyone-reset" data-vb-filter-twentyone-reset&gt;Reset&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-twentyone-list"&gt;
        &lt;article data-flight-card="city" data-flight-text="paris france city break nord air direct weekend"&gt;
          &lt;div class="vb-filter-twentyone-route"&gt;
            &lt;strong&gt;TLL&lt;/strong&gt;
            &lt;span&gt;&lt;/span&gt;
            &lt;strong&gt;CDG&lt;/strong&gt;
          &lt;/div&gt;
          &lt;div&gt;
            &lt;small&gt;City Break · Nord Air&lt;/small&gt;
            &lt;h4&gt;Paris Weekend Flight&lt;/h4&gt;
            &lt;p&gt;Direct flight to Paris with morning departure and flexible return.&lt;/p&gt;
          &lt;/div&gt;
          &lt;em&gt;€129&lt;/em&gt;
        &lt;/article&gt;

        &lt;article data-flight-card="business" data-flight-text="london uk business skyline express morning meeting"&gt;
          &lt;div class="vb-filter-twentyone-route"&gt;
            &lt;strong&gt;TLL&lt;/strong&gt;
            &lt;span&gt;&lt;/span&gt;
            &lt;strong&gt;LHR&lt;/strong&gt;
          &lt;/div&gt;
          &lt;div&gt;
            &lt;small&gt;Business · Skyline Express&lt;/small&gt;
            &lt;h4&gt;London Business Route&lt;/h4&gt;
            &lt;p&gt;Early flight for meetings, conferences, and short business trips.&lt;/p&gt;
          &lt;/div&gt;
          &lt;em&gt;€179&lt;/em&gt;
        &lt;/article&gt;

        &lt;article data-flight-card="beach" data-flight-text="malaga spain beach sun holiday family coast"&gt;
          &lt;div class="vb-filter-twentyone-route"&gt;
            &lt;strong&gt;TLL&lt;/strong&gt;
            &lt;span&gt;&lt;/span&gt;
            &lt;strong&gt;AGP&lt;/strong&gt;
          &lt;/div&gt;
          &lt;div&gt;
            &lt;small&gt;Beach · SunJet&lt;/small&gt;
            &lt;h4&gt;Malaga Holiday Flight&lt;/h4&gt;
            &lt;p&gt;Sunny coastal route for beach trips, family holidays, and warm weekends.&lt;/p&gt;
          &lt;/div&gt;
          &lt;em&gt;€156&lt;/em&gt;
        &lt;/article&gt;

        &lt;article data-flight-card="longhaul" data-flight-text="new york usa long haul atlantic global air"&gt;
          &lt;div class="vb-filter-twentyone-route"&gt;
            &lt;strong&gt;TLL&lt;/strong&gt;
            &lt;span&gt;&lt;/span&gt;
            &lt;strong&gt;JFK&lt;/strong&gt;
          &lt;/div&gt;
          &lt;div&gt;
            &lt;small&gt;Long Haul · Global Air&lt;/small&gt;
            &lt;h4&gt;New York Connection&lt;/h4&gt;
            &lt;p&gt;Atlantic connection with one stop and evening arrival in New York.&lt;/p&gt;
          &lt;/div&gt;
          &lt;em&gt;€489&lt;/em&gt;
        &lt;/article&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-twentyone-empty" data-vb-filter-twentyone-empty&gt;
        &lt;strong&gt;No flights found.&lt;/strong&gt;
        &lt;p&gt;Try searching for Paris, London, beach, business, Tokyo, Malaga, or city break.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/section&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-twentyone-demo,
.vb-filter-twentyone-demo * {
  box-sizing: border-box;
}

/* Copy the full CSS from the live preview block above. */</pre>



<p class="wp-block-paragraph">This flight booking search filter is useful for travel websites, booking engines, flight comparison pages, tour package directories, airport dashboards, transport websites, and destination search interfaces.</p>



<h2 class="wp-block-heading">22. Help Desk Ticket Inbox Filter</h2>



<p class="wp-block-paragraph"><strong>A help desk ticket inbox filter</strong> helps support teams search customer requests by status, priority, topic, customer name, or keyword. This layout is useful for SaaS dashboards, support portals, CRM inboxes, admin panels, customer service tools, and ticket management interfaces.</p>



<p class="wp-block-paragraph">This example uses an inbox-style layout with a left status menu and ticket rows on the right. Users can filter tickets by status and search ticket content at the same time.</p>



<ul class="wp-block-list">
<li>Support inbox search layout</li>
<li>Filters tickets by status and keyword</li>
<li>Inbox-style rows instead of cards</li>
<li>Priority labels and customer names</li>
<li>Useful for SaaS dashboards, CRMs, support portals, and admin tools</li>
</ul>



<div class="vb-filter-twentytwo-demo">
  <div class="vb-filter-twentytwo-inbox" data-vb-filter-twentytwo>
    <aside class="vb-filter-twentytwo-sidebar">
      <span>Example 22</span>
      <h3>Help Desk Ticket Inbox Filter</h3>
      <p>Filter support tickets by status, priority, customer, product, or keyword.</p>

      <div class="vb-filter-twentytwo-statuses">
        <button type="button" class="is-active" data-ticket-status="all">All Tickets</button>
        <button type="button" data-ticket-status="open">Open</button>
        <button type="button" data-ticket-status="pending">Pending</button>
        <button type="button" data-ticket-status="solved">Solved</button>
        <button type="button" data-ticket-status="urgent">Urgent</button>
      </div>

      <div class="vb-filter-twentytwo-countbox">
        <small>Visible tickets</small>
        <strong data-vb-filter-twentytwo-count>9 tickets</strong>
      </div>
    </aside>

    <main class="vb-filter-twentytwo-main">
      <div class="vb-filter-twentytwo-searchbar">
        <input type="search" placeholder="Search billing, login, urgent, plugin, API..." data-vb-filter-twentytwo-input>
        <button type="button" data-vb-filter-twentytwo-reset>Reset</button>
      </div>

      <div class="vb-filter-twentytwo-list">
        <article data-ticket-card="urgent" data-ticket-text="urgent login issue account locked password anna">
          <div class="vb-filter-twentytwo-priority high">High</div>
          <div>
            <strong>Account locked after login attempts</strong>
            <p>Anna needs help restoring access after multiple failed password attempts.</p>
            <small>Login · Account · Urgent</small>
          </div>
          <time>09:12</time>
        </article>

        <article data-ticket-card="open" data-ticket-text="open billing invoice vat payment mark">
          <div class="vb-filter-twentytwo-priority normal">Open</div>
          <div>
            <strong>Invoice VAT number update</strong>
            <p>Mark requested an updated invoice with company VAT details.</p>
            <small>Billing · Invoice · Payment</small>
          </div>
          <time>10:45</time>
        </article>

        <article data-ticket-card="pending" data-ticket-text="pending api webhook integration customer reply">
          <div class="vb-filter-twentytwo-priority wait">Pending</div>
          <div>
            <strong>Webhook endpoint verification</strong>
            <p>Waiting for the customer to confirm their production API endpoint.</p>
            <small>API · Webhook · Integration</small>
          </div>
          <time>11:20</time>
        </article>

        <article data-ticket-card="open" data-ticket-text="open wordpress plugin activation license domain">
          <div class="vb-filter-twentytwo-priority normal">Open</div>
          <div>
            <strong>Plugin license activation failed</strong>
            <p>Customer cannot activate a WordPress plugin license on a new domain.</p>
            <small>WordPress · Plugin · License</small>
          </div>
          <time>12:04</time>
        </article>

        <article data-ticket-card="solved" data-ticket-text="solved checkout css button layout fixed">
          <div class="vb-filter-twentytwo-priority done">Solved</div>
          <div>
            <strong>Checkout button alignment fixed</strong>
            <p>Checkout layout issue was resolved with a small CSS update.</p>
            <small>CSS · Checkout · Layout</small>
          </div>
          <time>13:18</time>
        </article>

        <article data-ticket-card="urgent" data-ticket-text="urgent payment failed subscription renewal maria">
          <div class="vb-filter-twentytwo-priority high">High</div>
          <div>
            <strong>Subscription renewal failed</strong>
            <p>Maria reports that the subscription renewal payment failed twice.</p>
            <small>Payment · Subscription · Urgent</small>
          </div>
          <time>14:07</time>
        </article>

        <article data-ticket-card="pending" data-ticket-text="pending design change homepage hero approval">
          <div class="vb-filter-twentytwo-priority wait">Pending</div>
          <div>
            <strong>Homepage hero design approval</strong>
            <p>Waiting for approval before pushing the new hero section live.</p>
            <small>Design · Homepage · Approval</small>
          </div>
          <time>15:31</time>
        </article>

        <article data-ticket-card="solved" data-ticket-text="solved email delivery smtp setup resolved">
          <div class="vb-filter-twentytwo-priority done">Solved</div>
          <div>
            <strong>SMTP email delivery restored</strong>
            <p>Email delivery was restored after updating SMTP authentication settings.</p>
            <small>Email · SMTP · Delivery</small>
          </div>
          <time>16:10</time>
        </article>

        <article data-ticket-card="open" data-ticket-text="open mobile menu javascript dropdown navigation bug">
          <div class="vb-filter-twentytwo-priority normal">Open</div>
          <div>
            <strong>Mobile dropdown menu issue</strong>
            <p>Customer reports that the mobile menu dropdown does not close correctly.</p>
            <small>JavaScript · Navigation · Mobile</small>
          </div>
          <time>17:25</time>
        </article>
      </div>

      <div class="vb-filter-twentytwo-empty" data-vb-filter-twentytwo-empty>
        <strong>No tickets found.</strong>
        <p>Try searching for billing, API, urgent, plugin, checkout, email, login, or mobile.</p>
      </div>
    </main>
  </div>
</div>

<style>
.vb-filter-twentytwo-demo,
.vb-filter-twentytwo-demo * {
  box-sizing: border-box;
}

.vb-filter-twentytwo-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(248, 113, 113, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(99, 102, 241, 0.20), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(254, 205, 211, 0.52);
  box-shadow: 0 24px 70px rgba(136, 19, 55, 0.10);
}

.vb-filter-twentytwo-inbox {
  display: grid;
  grid-template-columns: 300px minmax(0, 1fr);
  max-width: 1120px;
  margin: 0 auto;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.14);
}

.vb-filter-twentytwo-sidebar {
  padding: 28px;
  background: #111827;
}

.vb-filter-twentytwo-sidebar > span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(248, 113, 113, 0.16);
  color: #fecaca !important;
  -webkit-text-fill-color: #fecaca !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-twentytwo-sidebar h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 4vw, 52px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-twentytwo-sidebar p {
  margin: 0 0 22px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-filter-twentytwo-statuses {
  display: grid;
  gap: 8px;
  margin-bottom: 18px;
}

.vb-filter-twentytwo-statuses button {
  min-height: 44px;
  padding: 10px 13px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 14px;
  background: rgba(255,255,255,0.08);
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 13px;
  font-weight: 900;
  text-align: left;
  cursor: pointer;
}

.vb-filter-twentytwo-statuses button.is-active,
.vb-filter-twentytwo-statuses button:hover {
  background: linear-gradient(135deg, #ef4444, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-twentytwo-countbox {
  padding: 16px;
  border-radius: 20px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-filter-twentytwo-countbox small {
  display: block;
  margin-bottom: 6px;
  color: #fecaca !important;
  -webkit-text-fill-color: #fecaca !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-twentytwo-countbox strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  font-weight: 950;
}

.vb-filter-twentytwo-main {
  padding: 24px;
  background: #f8fafc;
}

.vb-filter-twentytwo-searchbar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  margin-bottom: 14px;
  padding: 12px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-filter-twentytwo-searchbar input {
  width: 100%;
  min-height: 50px;
  padding: 0 15px;
  border: 1px solid rgba(148, 163, 184, 0.26);
  border-radius: 16px;
  outline: 0;
  background: #f8fafc;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-twentytwo-searchbar button {
  min-height: 50px;
  padding: 0 16px;
  border: 0;
  border-radius: 16px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-twentytwo-list {
  display: grid;
  gap: 10px;
}

.vb-filter-twentytwo-list article {
  display: grid;
  grid-template-columns: 78px minmax(0, 1fr) 58px;
  gap: 14px;
  align-items: center;
  padding: 16px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 10px 28px rgba(15, 23, 42, 0.05);
}

.vb-filter-twentytwo-list article.is-hidden {
  display: none;
}

.vb-filter-twentytwo-priority {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 38px;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 950;
}

.vb-filter-twentytwo-priority.high {
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
}

.vb-filter-twentytwo-priority.normal {
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
}

.vb-filter-twentytwo-priority.wait {
  background: #fef3c7;
  color: #b45309 !important;
  -webkit-text-fill-color: #b45309 !important;
}

.vb-filter-twentytwo-priority.done {
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
}

.vb-filter-twentytwo-list strong {
  display: block;
  margin-bottom: 5px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 17px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-filter-twentytwo-list p {
  margin: 0 0 7px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-filter-twentytwo-list small {
  color: #6366f1 !important;
  -webkit-text-fill-color: #6366f1 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-filter-twentytwo-list time {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-align: right;
}

.vb-filter-twentytwo-empty {
  display: none;
  margin-top: 14px;
  padding: 20px;
  border-radius: 20px;
  background: #fff1f2;
  border: 1px solid rgba(251, 113, 133, 0.32);
}

.vb-filter-twentytwo-empty.is-visible {
  display: block;
}

.vb-filter-twentytwo-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-twentytwo-empty p {
  margin: 0 !important;
  color: #9f1239 !important;
  -webkit-text-fill-color: #9f1239 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 940px) {
  .vb-filter-twentytwo-inbox {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-filter-twentytwo-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-twentytwo-sidebar,
  .vb-filter-twentytwo-main {
    padding: 22px;
  }

  .vb-filter-twentytwo-sidebar h3 {
    font-size: 38px !important;
  }

  .vb-filter-twentytwo-searchbar {
    grid-template-columns: 1fr;
  }

  .vb-filter-twentytwo-list article {
    grid-template-columns: 1fr;
  }

  .vb-filter-twentytwo-list time {
    text-align: left;
  }
}
</style>

<script>
(function () {
  const inbox = document.querySelector("[data-vb-filter-twentytwo]");
  if (!inbox) return;

  const input = inbox.querySelector("[data-vb-filter-twentytwo-input]");
  const buttons = inbox.querySelectorAll("[data-ticket-status]");
  const reset = inbox.querySelector("[data-vb-filter-twentytwo-reset]");
  const count = inbox.querySelector("[data-vb-filter-twentytwo-count]");
  const empty = inbox.querySelector("[data-vb-filter-twentytwo-empty]");
  const tickets = Array.from(inbox.querySelectorAll("[data-ticket-card]"));

  let activeStatus = "all";

  function updateTickets() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    tickets.forEach(function (ticket) {
      const status = ticket.getAttribute("data-ticket-card");
      const text = ticket.getAttribute("data-ticket-text").toLowerCase();
      const fullText = ticket.textContent.toLowerCase();

      const statusMatch = activeStatus === "all" || status === activeStatus;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = statusMatch && searchMatch;

      ticket.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 ticket" : visible + " tickets";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeStatus = button.getAttribute("data-ticket-status");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateTickets();
    });
  });

  input.addEventListener("input", updateTickets);

  reset.addEventListener("click", function () {
    activeStatus = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-ticket-status") === "all");
    });

    input.focus();
    updateTickets();
  });

  updateTickets();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const inbox = document.querySelector("[data-vb-filter-twentytwo]");
  if (!inbox) return;

  const input = inbox.querySelector("[data-vb-filter-twentytwo-input]");
  const buttons = inbox.querySelectorAll("[data-ticket-status]");
  const reset = inbox.querySelector("[data-vb-filter-twentytwo-reset]");
  const count = inbox.querySelector("[data-vb-filter-twentytwo-count]");
  const empty = inbox.querySelector("[data-vb-filter-twentytwo-empty]");
  const tickets = Array.from(inbox.querySelectorAll("[data-ticket-card]"));

  let activeStatus = "all";

  function updateTickets() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    tickets.forEach(function (ticket) {
      const status = ticket.getAttribute("data-ticket-card");
      const text = ticket.getAttribute("data-ticket-text").toLowerCase();
      const fullText = ticket.textContent.toLowerCase();

      const statusMatch = activeStatus === "all" || status === activeStatus;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = statusMatch && searchMatch;

      ticket.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 ticket" : visible + " tickets";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeStatus = button.getAttribute("data-ticket-status");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateTickets();
    });
  });

  input.addEventListener("input", updateTickets);

  reset.addEventListener("click", function () {
    activeStatus = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-ticket-status") === "all");
    });

    input.focus();
    updateTickets();
  });

  updateTickets();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-twentytwo-demo"&gt;
  &lt;div class="vb-filter-twentytwo-inbox" data-vb-filter-twentytwo&gt;
    &lt;aside class="vb-filter-twentytwo-sidebar"&gt;
      &lt;span&gt;Example 22&lt;/span&gt;
      &lt;h3&gt;Help Desk Ticket Inbox Filter&lt;/h3&gt;
      &lt;p&gt;Filter support tickets by status, priority, customer, product, or keyword.&lt;/p&gt;

      &lt;div class="vb-filter-twentytwo-statuses"&gt;
        &lt;button type="button" class="is-active" data-ticket-status="all"&gt;All Tickets&lt;/button&gt;
        &lt;button type="button" data-ticket-status="open"&gt;Open&lt;/button&gt;
        &lt;button type="button" data-ticket-status="pending"&gt;Pending&lt;/button&gt;
        &lt;button type="button" data-ticket-status="solved"&gt;Solved&lt;/button&gt;
        &lt;button type="button" data-ticket-status="urgent"&gt;Urgent&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-twentytwo-countbox"&gt;
        &lt;small&gt;Visible tickets&lt;/small&gt;
        &lt;strong data-vb-filter-twentytwo-count&gt;9 tickets&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/aside&gt;

    &lt;main class="vb-filter-twentytwo-main"&gt;
      &lt;div class="vb-filter-twentytwo-searchbar"&gt;
        &lt;input type="search" placeholder="Search billing, login, urgent, plugin, API..." data-vb-filter-twentytwo-input&gt;
        &lt;button type="button" data-vb-filter-twentytwo-reset&gt;Reset&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-twentytwo-list"&gt;
        &lt;article data-ticket-card="urgent" data-ticket-text="urgent login issue account locked password anna"&gt;
          &lt;div class="vb-filter-twentytwo-priority high"&gt;High&lt;/div&gt;
          &lt;div&gt;
            &lt;strong&gt;Account locked after login attempts&lt;/strong&gt;
            &lt;p&gt;Anna needs help restoring access after multiple failed password attempts.&lt;/p&gt;
            &lt;small&gt;Login · Account · Urgent&lt;/small&gt;
          &lt;/div&gt;
          &lt;time&gt;09:12&lt;/time&gt;
        &lt;/article&gt;

        &lt;article data-ticket-card="open" data-ticket-text="open billing invoice vat payment mark"&gt;
          &lt;div class="vb-filter-twentytwo-priority normal"&gt;Open&lt;/div&gt;
          &lt;div&gt;
            &lt;strong&gt;Invoice VAT number update&lt;/strong&gt;
            &lt;p&gt;Mark requested an updated invoice with company VAT details.&lt;/p&gt;
            &lt;small&gt;Billing · Invoice · Payment&lt;/small&gt;
          &lt;/div&gt;
          &lt;time&gt;10:45&lt;/time&gt;
        &lt;/article&gt;

        &lt;article data-ticket-card="pending" data-ticket-text="pending api webhook integration customer reply"&gt;
          &lt;div class="vb-filter-twentytwo-priority wait"&gt;Pending&lt;/div&gt;
          &lt;div&gt;
            &lt;strong&gt;Webhook endpoint verification&lt;/strong&gt;
            &lt;p&gt;Waiting for the customer to confirm their production API endpoint.&lt;/p&gt;
            &lt;small&gt;API · Webhook · Integration&lt;/small&gt;
          &lt;/div&gt;
          &lt;time&gt;11:20&lt;/time&gt;
        &lt;/article&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-twentytwo-empty" data-vb-filter-twentytwo-empty&gt;
        &lt;strong&gt;No tickets found.&lt;/strong&gt;
        &lt;p&gt;Try searching for billing, API, urgent, plugin, checkout, email, login, or mobile.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/main&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-twentytwo-demo,
.vb-filter-twentytwo-demo * {
  box-sizing: border-box;
}

/* Copy the full CSS from the live preview block above. */</pre>



<p class="wp-block-paragraph">This help desk ticket inbox filter is useful for SaaS dashboards, support portals, customer service inboxes, CRM tools, admin panels, project support systems, and ticket management interfaces.</p>



<h2 class="wp-block-heading">23. Real Estate Listing Search Filter</h2>



<p class="wp-block-paragraph"><strong>A real estate listing search filter</strong> helps users find properties by location, property type, price level, number of rooms, or keyword. This pattern is useful for real estate websites, apartment rental pages, property marketplaces, agency websites, accommodation platforms, and investment listing pages.</p>



<p class="wp-block-paragraph">This example uses a property portal style layout with a large search header, property type filters, listing cards, price labels, location details, and a no-results message. It is designed to feel like a real estate search interface rather than a generic content grid.</p>



<ul class="wp-block-list">
<li>Real estate listing search layout</li>
<li>Filters by property type and keyword</li>
<li>Property cards with price, rooms, and location</li>
<li>Searches city, type, features, and description</li>
<li>Useful for property portals, rental pages, and agency websites</li>
</ul>



<div class="vb-filter-twentythree-demo">
  <div class="vb-filter-twentythree-property" data-vb-filter-twentythree>
    <header class="vb-filter-twentythree-hero">
      <div>
        <span>Example 23</span>
        <h3>Real Estate Listing Search Filter</h3>
        <p>Search apartments, houses, studios, and commercial spaces by city, feature, or property type.</p>
      </div>

      <div class="vb-filter-twentythree-resultbox">
        <small>Matching listings</small>
        <strong data-vb-filter-twentythree-count>8 properties</strong>
      </div>
    </header>

    <div class="vb-filter-twentythree-searchbar">
      <input type="search" placeholder="Search Tallinn, balcony, house, studio, office..." data-vb-filter-twentythree-input>

      <div class="vb-filter-twentythree-types">
        <button type="button" class="is-active" data-property-type="all">All</button>
        <button type="button" data-property-type="apartment">Apartment</button>
        <button type="button" data-property-type="house">House</button>
        <button type="button" data-property-type="studio">Studio</button>
        <button type="button" data-property-type="commercial">Commercial</button>
      </div>

      <button type="button" class="vb-filter-twentythree-reset" data-vb-filter-twentythree-reset>Reset</button>
    </div>

    <div class="vb-filter-twentythree-grid">
      <article data-property-card="apartment" data-property-text="tallinn apartment balcony city center two rooms modern">
        <div class="vb-filter-twentythree-photo apartment-one">
          <strong>€149,000</strong>
        </div>
        <div class="vb-filter-twentythree-info">
          <small>Apartment · Tallinn</small>
          <h4>City Center Apartment</h4>
          <p>Modern two-room apartment with balcony, bright kitchen, and central location.</p>
          <div><span>2 rooms</span><span>54 m²</span><span>Balcony</span></div>
        </div>
      </article>

      <article data-property-card="house" data-property-text="tartu house garden family garage quiet area">
        <div class="vb-filter-twentythree-photo house-one">
          <strong>€269,000</strong>
        </div>
        <div class="vb-filter-twentythree-info">
          <small>House · Tartu</small>
          <h4>Family House with Garden</h4>
          <p>Detached family home with green garden, garage, and quiet residential street.</p>
          <div><span>5 rooms</span><span>146 m²</span><span>Garage</span></div>
        </div>
      </article>

      <article data-property-card="studio" data-property-text="pärnu studio small apartment rental seaside compact">
        <div class="vb-filter-twentythree-photo studio-one">
          <strong>€89,000</strong>
        </div>
        <div class="vb-filter-twentythree-info">
          <small>Studio · Pärnu</small>
          <h4>Compact Seaside Studio</h4>
          <p>Small studio apartment near the beach, suitable for rental or summer living.</p>
          <div><span>1 room</span><span>28 m²</span><span>Seaside</span></div>
        </div>
      </article>

      <article data-property-card="commercial" data-property-text="tallinn commercial office space business parking">
        <div class="vb-filter-twentythree-photo commercial-one">
          <strong>€1,950/mo</strong>
        </div>
        <div class="vb-filter-twentythree-info">
          <small>Commercial · Tallinn</small>
          <h4>Modern Office Space</h4>
          <p>Flexible office space with meeting rooms, parking, and easy business access.</p>
          <div><span>Office</span><span>120 m²</span><span>Parking</span></div>
        </div>
      </article>

      <article data-property-card="apartment" data-property-text="riga apartment renovated old town elevator furnished">
        <div class="vb-filter-twentythree-photo apartment-two">
          <strong>€132,000</strong>
        </div>
        <div class="vb-filter-twentythree-info">
          <small>Apartment · Riga</small>
          <h4>Renovated Old Town Flat</h4>
          <p>Renovated apartment with elevator access, furnished rooms, and old town views.</p>
          <div><span>3 rooms</span><span>68 m²</span><span>Elevator</span></div>
        </div>
      </article>

      <article data-property-card="house" data-property-text="vilnius house new build terrace energy efficient">
        <div class="vb-filter-twentythree-photo house-two">
          <strong>€315,000</strong>
        </div>
        <div class="vb-filter-twentythree-info">
          <small>House · Vilnius</small>
          <h4>New Build Terrace House</h4>
          <p>Energy-efficient new build house with terrace, open kitchen, and private yard.</p>
          <div><span>4 rooms</span><span>132 m²</span><span>Terrace</span></div>
        </div>
      </article>

      <article data-property-card="studio" data-property-text="helsinki studio city rental furnished compact metro">
        <div class="vb-filter-twentythree-photo studio-two">
          <strong>€1,050/mo</strong>
        </div>
        <div class="vb-filter-twentythree-info">
          <small>Studio · Helsinki</small>
          <h4>Furnished Metro Studio</h4>
          <p>Compact rental studio near metro station, furnished and ready for move-in.</p>
          <div><span>1 room</span><span>31 m²</span><span>Metro</span></div>
        </div>
      </article>

      <article data-property-card="commercial" data-property-text="tartu commercial retail shop street front warehouse">
        <div class="vb-filter-twentythree-photo commercial-two">
          <strong>€2,400/mo</strong>
        </div>
        <div class="vb-filter-twentythree-info">
          <small>Commercial · Tartu</small>
          <h4>Street Front Retail Unit</h4>
          <p>Retail space with large windows, storage room, and visible street entrance.</p>
          <div><span>Retail</span><span>96 m²</span><span>Storage</span></div>
        </div>
      </article>
    </div>

    <div class="vb-filter-twentythree-empty" data-vb-filter-twentythree-empty>
      <strong>No properties found.</strong>
      <p>Try searching for Tallinn, balcony, house, studio, office, parking, garden, or commercial.</p>
    </div>
  </div>
</div>

<style>
.vb-filter-twentythree-demo,
.vb-filter-twentythree-demo * {
  box-sizing: border-box;
}

.vb-filter-twentythree-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(20, 184, 166, 0.22), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(245, 158, 11, 0.20), transparent 34%),
    linear-gradient(135deg, #ecfeff 0%, #fffbeb 52%, #ffffff 100%) !important;
  border: 1px solid rgba(153, 246, 228, 0.52);
  box-shadow: 0 24px 70px rgba(15, 118, 110, 0.12);
}

.vb-filter-twentythree-property {
  max-width: 1160px;
  margin: 0 auto;
  padding: 30px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-twentythree-hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 210px;
  gap: 24px;
  align-items: end;
  margin-bottom: 20px;
}

.vb-filter-twentythree-hero span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-twentythree-hero h3 {
  margin: 0 0 12px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-twentythree-hero p {
  max-width: 760px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-twentythree-resultbox {
  padding: 18px;
  border-radius: 24px;
  background: #0f172a;
}

.vb-filter-twentythree-resultbox small {
  display: block;
  margin-bottom: 7px;
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-twentythree-resultbox strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 21px;
  font-weight: 950;
}

.vb-filter-twentythree-searchbar {
  display: grid;
  grid-template-columns: minmax(260px, 0.85fr) minmax(0, 1.15fr) auto;
  gap: 10px;
  align-items: center;
  margin-bottom: 18px;
  padding: 14px;
  border-radius: 24px;
  background: #f8fafc;
}

.vb-filter-twentythree-searchbar input {
  width: 100%;
  min-height: 52px;
  padding: 0 15px;
  border: 1px solid rgba(148, 163, 184, 0.28);
  border-radius: 16px;
  outline: 0;
  background: #ffffff;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-twentythree-types {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-filter-twentythree-types button,
.vb-filter-twentythree-reset {
  min-height: 42px;
  padding: 9px 13px;
  border: 0;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-twentythree-types button {
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  box-shadow: 0 8px 20px rgba(15, 23, 42, 0.05);
}

.vb-filter-twentythree-types button.is-active,
.vb-filter-twentythree-types button:hover {
  background: linear-gradient(135deg, #14b8a6, #f59e0b);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-twentythree-reset {
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-twentythree-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-filter-twentythree-grid article {
  overflow: hidden;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb-filter-twentythree-grid article.is-hidden {
  display: none;
}

.vb-filter-twentythree-photo {
  position: relative;
  min-height: 160px;
  background:
    radial-gradient(circle at 30% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #14b8a6, #0f766e) !important;
}

.vb-filter-twentythree-photo.house-one {
  background:
    radial-gradient(circle at 30% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #92400e, #f59e0b) !important;
}

.vb-filter-twentythree-photo.studio-one {
  background:
    radial-gradient(circle at 30% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #2563eb, #06b6d4) !important;
}

.vb-filter-twentythree-photo.commercial-one {
  background:
    radial-gradient(circle at 30% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #111827, #64748b) !important;
}

.vb-filter-twentythree-photo.apartment-two {
  background:
    radial-gradient(circle at 30% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #7c3aed, #ec4899) !important;
}

.vb-filter-twentythree-photo.house-two {
  background:
    radial-gradient(circle at 30% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #16a34a, #84cc16) !important;
}

.vb-filter-twentythree-photo.studio-two {
  background:
    radial-gradient(circle at 30% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #0284c7, #4f46e5) !important;
}

.vb-filter-twentythree-photo.commercial-two {
  background:
    radial-gradient(circle at 30% 22%, rgba(255,255,255,0.38), transparent 32%),
    linear-gradient(135deg, #be123c, #f97316) !important;
}

.vb-filter-twentythree-photo strong {
  position: absolute;
  left: 14px;
  bottom: 14px;
  padding: 8px 11px;
  border-radius: 999px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-filter-twentythree-info {
  padding: 18px;
}

.vb-filter-twentythree-info small {
  display: inline-flex;
  margin-bottom: 10px;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-filter-twentythree-info h4 {
  margin: 0 0 8px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 20px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-twentythree-info p {
  margin: 0 0 14px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-filter-twentythree-info div {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.vb-filter-twentythree-info div span {
  padding: 6px 8px;
  border-radius: 999px;
  background: #f1f5f9;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 11px;
  font-weight: 900;
}

.vb-filter-twentythree-empty {
  display: none;
  margin-top: 16px;
  padding: 22px;
  border-radius: 22px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.34);
}

.vb-filter-twentythree-empty.is-visible {
  display: block;
}

.vb-filter-twentythree-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-twentythree-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 1040px) {
  .vb-filter-twentythree-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-filter-twentythree-hero,
  .vb-filter-twentythree-searchbar {
    grid-template-columns: 1fr;
  }

  .vb-filter-twentythree-resultbox {
    width: fit-content;
  }

  .vb-filter-twentythree-reset {
    width: fit-content;
  }
}

@media (max-width: 640px) {
  .vb-filter-twentythree-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-twentythree-property {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-twentythree-hero h3 {
    font-size: 38px !important;
  }

  .vb-filter-twentythree-types {
    display: grid;
    grid-template-columns: 1fr;
  }

  .vb-filter-twentythree-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const property = document.querySelector("[data-vb-filter-twentythree]");
  if (!property) return;

  const input = property.querySelector("[data-vb-filter-twentythree-input]");
  const buttons = property.querySelectorAll("[data-property-type]");
  const reset = property.querySelector("[data-vb-filter-twentythree-reset]");
  const count = property.querySelector("[data-vb-filter-twentythree-count]");
  const empty = property.querySelector("[data-vb-filter-twentythree-empty]");
  const listings = Array.from(property.querySelectorAll("[data-property-card]"));

  let activeType = "all";

  function updateListings() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    listings.forEach(function (listing) {
      const type = listing.getAttribute("data-property-card");
      const text = listing.getAttribute("data-property-text").toLowerCase();
      const fullText = listing.textContent.toLowerCase();

      const typeMatch = activeType === "all" || type === activeType;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = typeMatch && searchMatch;

      listing.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 property" : visible + " properties";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeType = button.getAttribute("data-property-type");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateListings();
    });
  });

  input.addEventListener("input", updateListings);

  reset.addEventListener("click", function () {
    activeType = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-property-type") === "all");
    });

    input.focus();
    updateListings();
  });

  updateListings();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const property = document.querySelector("[data-vb-filter-twentythree]");
  if (!property) return;

  const input = property.querySelector("[data-vb-filter-twentythree-input]");
  const buttons = property.querySelectorAll("[data-property-type]");
  const reset = property.querySelector("[data-vb-filter-twentythree-reset]");
  const count = property.querySelector("[data-vb-filter-twentythree-count]");
  const empty = property.querySelector("[data-vb-filter-twentythree-empty]");
  const listings = Array.from(property.querySelectorAll("[data-property-card]"));

  let activeType = "all";

  function updateListings() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    listings.forEach(function (listing) {
      const type = listing.getAttribute("data-property-card");
      const text = listing.getAttribute("data-property-text").toLowerCase();
      const fullText = listing.textContent.toLowerCase();

      const typeMatch = activeType === "all" || type === activeType;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = typeMatch && searchMatch;

      listing.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 property" : visible + " properties";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeType = button.getAttribute("data-property-type");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateListings();
    });
  });

  input.addEventListener("input", updateListings);

  reset.addEventListener("click", function () {
    activeType = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-property-type") === "all");
    });

    input.focus();
    updateListings();
  });

  updateListings();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-twentythree-demo"&gt;
  &lt;div class="vb-filter-twentythree-property" data-vb-filter-twentythree&gt;
    &lt;header class="vb-filter-twentythree-hero"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 23&lt;/span&gt;
        &lt;h3&gt;Real Estate Listing Search Filter&lt;/h3&gt;
        &lt;p&gt;Search apartments, houses, studios, and commercial spaces by city, feature, or property type.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-twentythree-resultbox"&gt;
        &lt;small&gt;Matching listings&lt;/small&gt;
        &lt;strong data-vb-filter-twentythree-count&gt;8 properties&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/header&gt;

    &lt;div class="vb-filter-twentythree-searchbar"&gt;
      &lt;input type="search" placeholder="Search Tallinn, balcony, house, studio, office..." data-vb-filter-twentythree-input&gt;

      &lt;div class="vb-filter-twentythree-types"&gt;
        &lt;button type="button" class="is-active" data-property-type="all"&gt;All&lt;/button&gt;
        &lt;button type="button" data-property-type="apartment"&gt;Apartment&lt;/button&gt;
        &lt;button type="button" data-property-type="house"&gt;House&lt;/button&gt;
        &lt;button type="button" data-property-type="studio"&gt;Studio&lt;/button&gt;
        &lt;button type="button" data-property-type="commercial"&gt;Commercial&lt;/button&gt;
      &lt;/div&gt;

      &lt;button type="button" class="vb-filter-twentythree-reset" data-vb-filter-twentythree-reset&gt;Reset&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-twentythree-grid"&gt;
      &lt;article data-property-card="apartment" data-property-text="tallinn apartment balcony city center two rooms modern"&gt;
        &lt;div class="vb-filter-twentythree-photo apartment-one"&gt;
          &lt;strong&gt;€149,000&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div class="vb-filter-twentythree-info"&gt;
          &lt;small&gt;Apartment · Tallinn&lt;/small&gt;
          &lt;h4&gt;City Center Apartment&lt;/h4&gt;
          &lt;p&gt;Modern two-room apartment with balcony, bright kitchen, and central location.&lt;/p&gt;
          &lt;div&gt;&lt;span&gt;2 rooms&lt;/span&gt;&lt;span&gt;54 m²&lt;/span&gt;&lt;span&gt;Balcony&lt;/span&gt;&lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-property-card="house" data-property-text="tartu house garden family garage quiet area"&gt;
        &lt;div class="vb-filter-twentythree-photo house-one"&gt;
          &lt;strong&gt;€269,000&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div class="vb-filter-twentythree-info"&gt;
          &lt;small&gt;House · Tartu&lt;/small&gt;
          &lt;h4&gt;Family House with Garden&lt;/h4&gt;
          &lt;p&gt;Detached family home with green garden, garage, and quiet residential street.&lt;/p&gt;
          &lt;div&gt;&lt;span&gt;5 rooms&lt;/span&gt;&lt;span&gt;146 m²&lt;/span&gt;&lt;span&gt;Garage&lt;/span&gt;&lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-property-card="studio" data-property-text="pärnu studio small apartment rental seaside compact"&gt;
        &lt;div class="vb-filter-twentythree-photo studio-one"&gt;
          &lt;strong&gt;€89,000&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div class="vb-filter-twentythree-info"&gt;
          &lt;small&gt;Studio · Pärnu&lt;/small&gt;
          &lt;h4&gt;Compact Seaside Studio&lt;/h4&gt;
          &lt;p&gt;Small studio apartment near the beach, suitable for rental or summer living.&lt;/p&gt;
          &lt;div&gt;&lt;span&gt;1 room&lt;/span&gt;&lt;span&gt;28 m²&lt;/span&gt;&lt;span&gt;Seaside&lt;/span&gt;&lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-property-card="commercial" data-property-text="tallinn commercial office space business parking"&gt;
        &lt;div class="vb-filter-twentythree-photo commercial-one"&gt;
          &lt;strong&gt;€1,950/mo&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div class="vb-filter-twentythree-info"&gt;
          &lt;small&gt;Commercial · Tallinn&lt;/small&gt;
          &lt;h4&gt;Modern Office Space&lt;/h4&gt;
          &lt;p&gt;Flexible office space with meeting rooms, parking, and easy business access.&lt;/p&gt;
          &lt;div&gt;&lt;span&gt;Office&lt;/span&gt;&lt;span&gt;120 m²&lt;/span&gt;&lt;span&gt;Parking&lt;/span&gt;&lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-twentythree-empty" data-vb-filter-twentythree-empty&gt;
      &lt;strong&gt;No properties found.&lt;/strong&gt;
      &lt;p&gt;Try searching for Tallinn, balcony, house, studio, office, parking, garden, or commercial.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">/* Use the full CSS from the live preview block above for this real estate listing filter. */</pre>



<p class="wp-block-paragraph">This real estate listing search filter is useful for property portals, rental websites, apartment listing pages, real estate agency websites, accommodation platforms, commercial property directories, and investment listing sections.</p>



<h2 class="wp-block-heading">24. Event Schedule Agenda Filter</h2>



<p class="wp-block-paragraph"><strong>An event schedule agenda filter</strong> helps visitors find conference sessions, workshops, talks, networking blocks, webinars, and event activities by topic, speaker, room, time, or keyword. This layout is useful for event websites, conference landing pages, webinar platforms, workshop schedules, festival pages, and business agendas.</p>



<p class="wp-block-paragraph">This example uses an agenda-style layout with session times on the left, category filters at the top, speaker labels, room names, and hidden agenda rows when filters do not match. It feels like a professional event schedule instead of a basic card filter.</p>



<ul class="wp-block-list">
<li>Event agenda search layout</li>
<li>Filters sessions by topic and keyword</li>
<li>Time-based schedule rows</li>
<li>Speaker, room, and category details</li>
<li>Useful for conferences, workshops, webinars, and event websites</li>
</ul>



<div class="vb-filter-twentyfour-demo">
  <div class="vb-filter-twentyfour-agenda" data-vb-filter-twentyfour>
    <div class="vb-filter-twentyfour-top">
      <div>
        <span>Example 24</span>
        <h3>Event Schedule Agenda Filter</h3>
        <p>Search sessions by topic, speaker, room, time, or event category.</p>
      </div>

      <div class="vb-filter-twentyfour-count">
        <small>Visible sessions</small>
        <strong data-vb-filter-twentyfour-count>9 sessions</strong>
      </div>
    </div>

    <div class="vb-filter-twentyfour-controls">
      <input type="search" placeholder="Search keynote, design, AI, room A, workshop..." data-vb-filter-twentyfour-input>

      <div class="vb-filter-twentyfour-tags">
        <button type="button" class="is-active" data-session-type="all">All</button>
        <button type="button" data-session-type="keynote">Keynote</button>
        <button type="button" data-session-type="workshop">Workshop</button>
        <button type="button" data-session-type="panel">Panel</button>
        <button type="button" data-session-type="networking">Networking</button>
      </div>

      <button type="button" class="vb-filter-twentyfour-reset" data-vb-filter-twentyfour-reset>Reset</button>
    </div>

    <div class="vb-filter-twentyfour-list">
      <article data-session-card="keynote" data-session-text="keynote opening future web design room main hall anna">
        <time>09:00</time>
        <div class="vb-filter-twentyfour-line"></div>
        <div class="vb-filter-twentyfour-session">
          <small>Keynote · Main Hall</small>
          <h4>The Future of Web Interfaces</h4>
          <p>Opening keynote about modern UI, AI-assisted design, and future website experiences.</p>
          <span>Speaker: Anna Reed</span>
        </div>
      </article>

      <article data-session-card="workshop" data-session-text="workshop javascript filters room a coding practical">
        <time>10:15</time>
        <div class="vb-filter-twentyfour-line"></div>
        <div class="vb-filter-twentyfour-session">
          <small>Workshop · Room A</small>
          <h4>Build JavaScript Search Filters</h4>
          <p>Hands-on workshop for building live search filters, reset buttons, and result counters.</p>
          <span>Speaker: Mark Stone</span>
        </div>
      </article>

      <article data-session-card="panel" data-session-text="panel seo content ai search engines room b">
        <time>11:30</time>
        <div class="vb-filter-twentyfour-line"></div>
        <div class="vb-filter-twentyfour-session">
          <small>Panel · Room B</small>
          <h4>SEO Content in the AI Search Era</h4>
          <p>Panel discussion about structured content, internal links, schema, and search intent.</p>
          <span>Panel Lead: Laura West</span>
        </div>
      </article>

      <article data-session-card="networking" data-session-text="networking coffee break lounge partners clients">
        <time>12:30</time>
        <div class="vb-filter-twentyfour-line"></div>
        <div class="vb-filter-twentyfour-session">
          <small>Networking · Lounge</small>
          <h4>Partner Coffee Break</h4>
          <p>Informal networking session for teams, partners, agencies, clients, and speakers.</p>
          <span>Hosted by Event Team</span>
        </div>
      </article>

      <article data-session-card="workshop" data-session-text="workshop css layout cards grid responsive room c">
        <time>13:15</time>
        <div class="vb-filter-twentyfour-line"></div>
        <div class="vb-filter-twentyfour-session">
          <small>Workshop · Room C</small>
          <h4>Responsive CSS Layout Lab</h4>
          <p>Practical layout session covering CSS Grid, Flexbox, cards, spacing, and responsive sections.</p>
          <span>Speaker: Daniel Fox</span>
        </div>
      </article>

      <article data-session-card="keynote" data-session-text="keynote ai automation product growth main hall">
        <time>14:30</time>
        <div class="vb-filter-twentyfour-line"></div>
        <div class="vb-filter-twentyfour-session">
          <small>Keynote · Main Hall</small>
          <h4>AI Automation for Product Growth</h4>
          <p>How automation, smart workflows, and AI tools can improve product teams and digital businesses.</p>
          <span>Speaker: Nina Cole</span>
        </div>
      </article>

      <article data-session-card="panel" data-session-text="panel ecommerce ux checkout conversion room b">
        <time>15:45</time>
        <div class="vb-filter-twentyfour-line"></div>
        <div class="vb-filter-twentyfour-session">
          <small>Panel · Room B</small>
          <h4>Ecommerce UX and Checkout Conversion</h4>
          <p>Discussion about product pages, checkout forms, trust signals, and conversion-focused design.</p>
          <span>Panel Lead: Tom Blake</span>
        </div>
      </article>

      <article data-session-card="workshop" data-session-text="workshop accessibility aria keyboard focus room a">
        <time>16:45</time>
        <div class="vb-filter-twentyfour-line"></div>
        <div class="vb-filter-twentyfour-session">
          <small>Workshop · Room A</small>
          <h4>Accessible JavaScript Components</h4>
          <p>Build interactive components with keyboard support, focus handling, and better labels.</p>
          <span>Speaker: Sara Lane</span>
        </div>
      </article>

      <article data-session-card="networking" data-session-text="networking closing meetup community main hall">
        <time>18:00</time>
        <div class="vb-filter-twentyfour-line"></div>
        <div class="vb-filter-twentyfour-session">
          <small>Networking · Main Hall</small>
          <h4>Closing Meetup</h4>
          <p>Final networking block for speakers, attendees, sponsors, and community members.</p>
          <span>Hosted by Event Team</span>
        </div>
      </article>
    </div>

    <div class="vb-filter-twentyfour-empty" data-vb-filter-twentyfour-empty>
      <strong>No sessions found.</strong>
      <p>Try searching for keynote, workshop, AI, SEO, Room A, networking, accessibility, or ecommerce.</p>
    </div>
  </div>
</div>

<style>
.vb-filter-twentyfour-demo,
.vb-filter-twentyfour-demo * {
  box-sizing: border-box;
}

.vb-filter-twentyfour-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(99, 102, 241, 0.22), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(236, 72, 153, 0.18), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #fdf2f8 52%, #ffffff 100%) !important;
  border: 1px solid rgba(199, 210, 254, 0.52);
  box-shadow: 0 24px 70px rgba(67, 56, 202, 0.12);
}

.vb-filter-twentyfour-agenda {
  max-width: 1040px;
  margin: 0 auto;
  padding: 32px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-twentyfour-top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 190px;
  gap: 24px;
  align-items: end;
  margin-bottom: 20px;
}

.vb-filter-twentyfour-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #e0e7ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-twentyfour-top h3 {
  margin: 0 0 12px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-twentyfour-top p {
  max-width: 720px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-twentyfour-count {
  padding: 18px;
  border-radius: 24px;
  background: #111827;
}

.vb-filter-twentyfour-count small {
  display: block;
  margin-bottom: 7px;
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-twentyfour-count strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 21px;
  font-weight: 950;
}

.vb-filter-twentyfour-controls {
  display: grid;
  grid-template-columns: minmax(260px, 0.85fr) minmax(0, 1.15fr) auto;
  gap: 10px;
  align-items: center;
  margin-bottom: 26px;
  padding: 14px;
  border-radius: 24px;
  background: #f8fafc;
}

.vb-filter-twentyfour-controls input {
  width: 100%;
  min-height: 52px;
  padding: 0 15px;
  border: 1px solid rgba(148, 163, 184, 0.28);
  border-radius: 16px;
  outline: 0;
  background: #ffffff;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-twentyfour-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-filter-twentyfour-tags button,
.vb-filter-twentyfour-reset {
  min-height: 42px;
  padding: 9px 13px;
  border: 0;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-twentyfour-tags button {
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  box-shadow: 0 8px 20px rgba(15, 23, 42, 0.05);
}

.vb-filter-twentyfour-tags button.is-active,
.vb-filter-twentyfour-tags button:hover {
  background: linear-gradient(135deg, #6366f1, #ec4899);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-twentyfour-reset {
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-twentyfour-list {
  position: relative;
  display: grid;
  gap: 16px;
}

.vb-filter-twentyfour-list article {
  display: grid;
  grid-template-columns: 76px 34px minmax(0, 1fr);
  gap: 14px;
  align-items: start;
}

.vb-filter-twentyfour-list article.is-hidden {
  display: none;
}

.vb-filter-twentyfour-list time {
  padding-top: 15px;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 17px;
  font-weight: 950;
  text-align: right;
}

.vb-filter-twentyfour-line {
  position: relative;
  min-height: 100%;
}

.vb-filter-twentyfour-line::before {
  content: "";
  position: absolute;
  top: 44px;
  bottom: -16px;
  left: 15px;
  width: 4px;
  border-radius: 999px;
  background: #e0e7ff;
}

.vb-filter-twentyfour-line::after {
  content: "";
  position: absolute;
  top: 14px;
  left: 3px;
  width: 28px;
  height: 28px;
  border-radius: 999px;
  background: linear-gradient(135deg, #6366f1, #ec4899);
  border: 6px solid #ffffff;
  box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.14);
}

.vb-filter-twentyfour-session {
  padding: 20px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.07);
}

.vb-filter-twentyfour-session small {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #fce7f3;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-twentyfour-session h4 {
  margin: 0 0 9px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-twentyfour-session p {
  margin: 0 0 12px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-filter-twentyfour-session span {
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-filter-twentyfour-empty {
  display: none;
  margin-top: 16px;
  padding: 22px;
  border-radius: 22px;
  background: #fff1f2;
  border: 1px solid rgba(251, 113, 133, 0.32);
}

.vb-filter-twentyfour-empty.is-visible {
  display: block;
}

.vb-filter-twentyfour-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-twentyfour-empty p {
  margin: 0 !important;
  color: #9f1239 !important;
  -webkit-text-fill-color: #9f1239 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 920px) {
  .vb-filter-twentyfour-top,
  .vb-filter-twentyfour-controls {
    grid-template-columns: 1fr;
  }

  .vb-filter-twentyfour-count,
  .vb-filter-twentyfour-reset {
    width: fit-content;
  }
}

@media (max-width: 640px) {
  .vb-filter-twentyfour-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-twentyfour-agenda {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-twentyfour-top h3 {
    font-size: 38px !important;
  }

  .vb-filter-twentyfour-tags {
    display: grid;
    grid-template-columns: 1fr;
  }

  .vb-filter-twentyfour-list article {
    grid-template-columns: 34px minmax(0, 1fr);
  }

  .vb-filter-twentyfour-list time {
    grid-column: 2;
    padding-top: 0;
    text-align: left;
  }

  .vb-filter-twentyfour-line {
    grid-column: 1;
    grid-row: 1 / span 2;
  }

  .vb-filter-twentyfour-session {
    grid-column: 2;
  }
}
</style>

<script>
(function () {
  const agenda = document.querySelector("[data-vb-filter-twentyfour]");
  if (!agenda) return;

  const input = agenda.querySelector("[data-vb-filter-twentyfour-input]");
  const buttons = agenda.querySelectorAll("[data-session-type]");
  const reset = agenda.querySelector("[data-vb-filter-twentyfour-reset]");
  const count = agenda.querySelector("[data-vb-filter-twentyfour-count]");
  const empty = agenda.querySelector("[data-vb-filter-twentyfour-empty]");
  const sessions = Array.from(agenda.querySelectorAll("[data-session-card]"));

  let activeType = "all";

  function updateSessions() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    sessions.forEach(function (session) {
      const type = session.getAttribute("data-session-card");
      const text = session.getAttribute("data-session-text").toLowerCase();
      const fullText = session.textContent.toLowerCase();

      const typeMatch = activeType === "all" || type === activeType;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = typeMatch && searchMatch;

      session.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 session" : visible + " sessions";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeType = button.getAttribute("data-session-type");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateSessions();
    });
  });

  input.addEventListener("input", updateSessions);

  reset.addEventListener("click", function () {
    activeType = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-session-type") === "all");
    });

    input.focus();
    updateSessions();
  });

  updateSessions();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const agenda = document.querySelector("[data-vb-filter-twentyfour]");
  if (!agenda) return;

  const input = agenda.querySelector("[data-vb-filter-twentyfour-input]");
  const buttons = agenda.querySelectorAll("[data-session-type]");
  const reset = agenda.querySelector("[data-vb-filter-twentyfour-reset]");
  const count = agenda.querySelector("[data-vb-filter-twentyfour-count]");
  const empty = agenda.querySelector("[data-vb-filter-twentyfour-empty]");
  const sessions = Array.from(agenda.querySelectorAll("[data-session-card]"));

  let activeType = "all";

  function updateSessions() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    sessions.forEach(function (session) {
      const type = session.getAttribute("data-session-card");
      const text = session.getAttribute("data-session-text").toLowerCase();
      const fullText = session.textContent.toLowerCase();

      const typeMatch = activeType === "all" || type === activeType;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = typeMatch && searchMatch;

      session.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 session" : visible + " sessions";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeType = button.getAttribute("data-session-type");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateSessions();
    });
  });

  input.addEventListener("input", updateSessions);

  reset.addEventListener("click", function () {
    activeType = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-session-type") === "all");
    });

    input.focus();
    updateSessions();
  });

  updateSessions();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-twentyfour-demo"&gt;
  &lt;div class="vb-filter-twentyfour-agenda" data-vb-filter-twentyfour&gt;
    &lt;div class="vb-filter-twentyfour-top"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 24&lt;/span&gt;
        &lt;h3&gt;Event Schedule Agenda Filter&lt;/h3&gt;
        &lt;p&gt;Search sessions by topic, speaker, room, time, or event category.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-twentyfour-count"&gt;
        &lt;small&gt;Visible sessions&lt;/small&gt;
        &lt;strong data-vb-filter-twentyfour-count&gt;9 sessions&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-twentyfour-controls"&gt;
      &lt;input type="search" placeholder="Search keynote, design, AI, room A, workshop..." data-vb-filter-twentyfour-input&gt;

      &lt;div class="vb-filter-twentyfour-tags"&gt;
        &lt;button type="button" class="is-active" data-session-type="all"&gt;All&lt;/button&gt;
        &lt;button type="button" data-session-type="keynote"&gt;Keynote&lt;/button&gt;
        &lt;button type="button" data-session-type="workshop"&gt;Workshop&lt;/button&gt;
        &lt;button type="button" data-session-type="panel"&gt;Panel&lt;/button&gt;
        &lt;button type="button" data-session-type="networking"&gt;Networking&lt;/button&gt;
      &lt;/div&gt;

      &lt;button type="button" class="vb-filter-twentyfour-reset" data-vb-filter-twentyfour-reset&gt;Reset&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-twentyfour-list"&gt;
      &lt;article data-session-card="keynote" data-session-text="keynote opening future web design room main hall anna"&gt;
        &lt;time&gt;09:00&lt;/time&gt;
        &lt;div class="vb-filter-twentyfour-line"&gt;&lt;/div&gt;
        &lt;div class="vb-filter-twentyfour-session"&gt;
          &lt;small&gt;Keynote · Main Hall&lt;/small&gt;
          &lt;h4&gt;The Future of Web Interfaces&lt;/h4&gt;
          &lt;p&gt;Opening keynote about modern UI, AI-assisted design, and future website experiences.&lt;/p&gt;
          &lt;span&gt;Speaker: Anna Reed&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-session-card="workshop" data-session-text="workshop javascript filters room a coding practical"&gt;
        &lt;time&gt;10:15&lt;/time&gt;
        &lt;div class="vb-filter-twentyfour-line"&gt;&lt;/div&gt;
        &lt;div class="vb-filter-twentyfour-session"&gt;
          &lt;small&gt;Workshop · Room A&lt;/small&gt;
          &lt;h4&gt;Build JavaScript Search Filters&lt;/h4&gt;
          &lt;p&gt;Hands-on workshop for building live search filters, reset buttons, and result counters.&lt;/p&gt;
          &lt;span&gt;Speaker: Mark Stone&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-session-card="panel" data-session-text="panel seo content ai search engines room b"&gt;
        &lt;time&gt;11:30&lt;/time&gt;
        &lt;div class="vb-filter-twentyfour-line"&gt;&lt;/div&gt;
        &lt;div class="vb-filter-twentyfour-session"&gt;
          &lt;small&gt;Panel · Room B&lt;/small&gt;
          &lt;h4&gt;SEO Content in the AI Search Era&lt;/h4&gt;
          &lt;p&gt;Panel discussion about structured content, internal links, schema, and search intent.&lt;/p&gt;
          &lt;span&gt;Panel Lead: Laura West&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-twentyfour-empty" data-vb-filter-twentyfour-empty&gt;
      &lt;strong&gt;No sessions found.&lt;/strong&gt;
      &lt;p&gt;Try searching for keynote, workshop, AI, SEO, Room A, networking, accessibility, or ecommerce.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">/* Use the full CSS from the live preview block above for this event schedule agenda filter. */</pre>



<p class="wp-block-paragraph">This event schedule agenda filter is useful for conference websites, workshop pages, webinar schedules, business event agendas, festival programs, speaker schedules, and professional event landing pages.</p>



<h2 class="wp-block-heading">25. Analytics Dashboard Report Filter</h2>



<p class="wp-block-paragraph"><strong>An analytics dashboard report filter</strong> helps users search reports, metrics, charts, and performance widgets by topic, status, channel, or keyword. This layout is useful for admin dashboards, SaaS analytics pages, marketing reports, SEO dashboards, sales platforms, and business intelligence interfaces.</p>



<p class="wp-block-paragraph">This example uses a dashboard-style layout with a metric header, report category buttons, searchable report panels, trend labels, and a no-results state. It is designed to feel like a professional analytics screen rather than a basic card grid.</p>



<ul class="wp-block-list">
<li>Dashboard report search filter</li>
<li>Filters analytics cards by category and keyword</li>
<li>Metric-style report panels</li>
<li>Searches channel, topic, status, and description</li>
<li>Useful for SaaS dashboards, analytics tools, and reporting interfaces</li>
</ul>



<div class="vb-filter-twentyfive-demo">
  <div class="vb-filter-twentyfive-dashboard" data-vb-filter-twentyfive>
    <div class="vb-filter-twentyfive-top">
      <div>
        <span>Example 25</span>
        <h3>Analytics Dashboard Report Filter</h3>
        <p>Search reports by channel, metric, status, campaign, or dashboard keyword.</p>
      </div>

      <div class="vb-filter-twentyfive-total">
        <small>Visible reports</small>
        <strong data-vb-filter-twentyfive-count>9 reports</strong>
      </div>
    </div>

    <div class="vb-filter-twentyfive-toolbar">
      <input type="search" placeholder="Search traffic, revenue, SEO, email, conversion..." data-vb-filter-twentyfive-input>

      <div class="vb-filter-twentyfive-tabs">
        <button type="button" class="is-active" data-report-type="all">All</button>
        <button type="button" data-report-type="traffic">Traffic</button>
        <button type="button" data-report-type="sales">Sales</button>
        <button type="button" data-report-type="marketing">Marketing</button>
        <button type="button" data-report-type="seo">SEO</button>
      </div>

      <button type="button" class="vb-filter-twentyfive-reset" data-vb-filter-twentyfive-reset>Reset</button>
    </div>

    <div class="vb-filter-twentyfive-grid">
      <article data-report-card="traffic" data-report-text="traffic visitors sessions source website overview growth">
        <small>Traffic</small>
        <h4>Website Sessions</h4>
        <strong>128K</strong>
        <p>Tracks total visits, new users, returning visitors, and traffic source movement.</p>
        <span>+18.4%</span>
      </article>

      <article data-report-card="sales" data-report-text="sales revenue ecommerce orders checkout conversion">
        <small>Sales</small>
        <h4>Monthly Revenue</h4>
        <strong>€48.7K</strong>
        <p>Compares revenue, orders, average cart value, and checkout performance.</p>
        <span>+12.1%</span>
      </article>

      <article data-report-card="marketing" data-report-text="marketing email campaign newsletter open rate clicks">
        <small>Marketing</small>
        <h4>Email Campaigns</h4>
        <strong>42.6%</strong>
        <p>Measures newsletter opens, click-through rate, segments, and campaign response.</p>
        <span>+7.8%</span>
      </article>

      <article data-report-card="seo" data-report-text="seo organic traffic ranking keywords search impressions">
        <small>SEO</small>
        <h4>Organic Keywords</h4>
        <strong>3,842</strong>
        <p>Tracks ranking keywords, impressions, organic clicks, and search visibility.</p>
        <span>+22.9%</span>
      </article>

      <article data-report-card="traffic" data-report-text="traffic referral social direct paid source channels">
        <small>Traffic</small>
        <h4>Channel Sources</h4>
        <strong>7</strong>
        <p>Breaks down direct, referral, social, paid, email, and organic traffic channels.</p>
        <span>+5.3%</span>
      </article>

      <article data-report-card="sales" data-report-text="sales conversion checkout funnel abandoned cart">
        <small>Sales</small>
        <h4>Checkout Funnel</h4>
        <strong>6.8%</strong>
        <p>Shows checkout steps, abandoned carts, successful orders, and conversion leaks.</p>
        <span>-2.4%</span>
      </article>

      <article data-report-card="marketing" data-report-text="marketing ads paid campaign cost cpc roas performance">
        <small>Marketing</small>
        <h4>Paid Ads ROAS</h4>
        <strong>4.2x</strong>
        <p>Reviews ad spend, campaign revenue, CPC, impressions, and return on ad spend.</p>
        <span>+9.6%</span>
      </article>

      <article data-report-card="seo" data-report-text="seo pages content blog internal links schema audit">
        <small>SEO</small>
        <h4>Content Audit</h4>
        <strong>86%</strong>
        <p>Checks blog performance, internal links, schema coverage, and content quality signals.</p>
        <span>+14.0%</span>
      </article>

      <article data-report-card="traffic" data-report-text="traffic mobile desktop device browser page speed">
        <small>Traffic</small>
        <h4>Device Breakdown</h4>
        <strong>64%</strong>
        <p>Compares mobile, desktop, tablet, browser behavior, and page speed differences.</p>
        <span>+3.1%</span>
      </article>
    </div>

    <div class="vb-filter-twentyfive-empty" data-vb-filter-twentyfive-empty>
      <strong>No reports found.</strong>
      <p>Try searching for traffic, sales, SEO, email, revenue, checkout, campaign, or keywords.</p>
    </div>
  </div>
</div>

<style>
.vb-filter-twentyfive-demo,
.vb-filter-twentyfive-demo * {
  box-sizing: border-box;
}

.vb-filter-twentyfive-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(34, 197, 94, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(59, 130, 246, 0.20), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #eff6ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(187, 247, 208, 0.52);
  box-shadow: 0 24px 70px rgba(22, 101, 52, 0.10);
}

.vb-filter-twentyfive-dashboard {
  max-width: 1140px;
  margin: 0 auto;
  padding: 30px;
  border-radius: 30px;
  background: #0f172a;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
}

.vb-filter-twentyfive-top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 190px;
  gap: 24px;
  align-items: end;
  margin-bottom: 20px;
}

.vb-filter-twentyfive-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.16);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-twentyfive-top h3 {
  margin: 0 0 12px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-twentyfive-top p {
  max-width: 760px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-twentyfive-total {
  padding: 18px;
  border-radius: 24px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-filter-twentyfive-total small {
  display: block;
  margin-bottom: 7px;
  color: #93c5fd !important;
  -webkit-text-fill-color: #93c5fd !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-twentyfive-total strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 21px;
  font-weight: 950;
}

.vb-filter-twentyfive-toolbar {
  display: grid;
  grid-template-columns: minmax(260px, 0.85fr) minmax(0, 1.15fr) auto;
  gap: 10px;
  align-items: center;
  margin-bottom: 18px;
  padding: 14px;
  border-radius: 24px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-filter-twentyfive-toolbar input {
  width: 100%;
  min-height: 52px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 16px;
  outline: 0;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-twentyfive-toolbar input::placeholder {
  color: rgba(255,255,255,0.58);
  -webkit-text-fill-color: rgba(255,255,255,0.58);
}

.vb-filter-twentyfive-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-filter-twentyfive-tabs button,
.vb-filter-twentyfive-reset {
  min-height: 42px;
  padding: 9px 13px;
  border: 0;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-twentyfive-tabs button {
  background: rgba(255,255,255,0.08);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-filter-twentyfive-tabs button.is-active,
.vb-filter-twentyfive-tabs button:hover {
  background: linear-gradient(135deg, #22c55e, #3b82f6);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-twentyfive-reset {
  background: #ffffff;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
}

.vb-filter-twentyfive-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.vb-filter-twentyfive-grid article {
  position: relative;
  overflow: hidden;
  min-height: 230px;
  padding: 22px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 90% 14%, rgba(34,197,94,0.16), transparent 32%),
    linear-gradient(135deg, rgba(255,255,255,0.98), rgba(248,250,252,0.98)) !important;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 18px 44px rgba(2, 6, 23, 0.20);
}

.vb-filter-twentyfive-grid article.is-hidden {
  display: none;
}

.vb-filter-twentyfive-grid small {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-twentyfive-grid h4 {
  margin: 0 0 10px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-twentyfive-grid article > strong {
  display: block;
  margin-bottom: 10px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 44px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.07em;
}

.vb-filter-twentyfive-grid p {
  margin: 0 0 18px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-filter-twentyfive-grid span {
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: #eff6ff;
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-filter-twentyfive-empty {
  display: none;
  margin-top: 16px;
  padding: 22px;
  border-radius: 22px;
  background: rgba(251, 146, 60, 0.12);
  border: 1px solid rgba(251, 146, 60, 0.24);
}

.vb-filter-twentyfive-empty.is-visible {
  display: block;
}

.vb-filter-twentyfive-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-twentyfive-empty p {
  margin: 0 !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb-filter-twentyfive-top,
  .vb-filter-twentyfive-toolbar {
    grid-template-columns: 1fr;
  }

  .vb-filter-twentyfive-total,
  .vb-filter-twentyfive-reset {
    width: fit-content;
  }

  .vb-filter-twentyfive-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-filter-twentyfive-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-twentyfive-dashboard {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-twentyfive-top h3 {
    font-size: 38px !important;
  }

  .vb-filter-twentyfive-tabs {
    display: grid;
    grid-template-columns: 1fr;
  }

  .vb-filter-twentyfive-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const dashboard = document.querySelector("[data-vb-filter-twentyfive]");
  if (!dashboard) return;

  const input = dashboard.querySelector("[data-vb-filter-twentyfive-input]");
  const buttons = dashboard.querySelectorAll("[data-report-type]");
  const reset = dashboard.querySelector("[data-vb-filter-twentyfive-reset]");
  const count = dashboard.querySelector("[data-vb-filter-twentyfive-count]");
  const empty = dashboard.querySelector("[data-vb-filter-twentyfive-empty]");
  const reports = Array.from(dashboard.querySelectorAll("[data-report-card]"));

  let activeType = "all";

  function updateReports() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    reports.forEach(function (report) {
      const type = report.getAttribute("data-report-card");
      const text = report.getAttribute("data-report-text").toLowerCase();
      const fullText = report.textContent.toLowerCase();

      const typeMatch = activeType === "all" || type === activeType;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = typeMatch && searchMatch;

      report.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 report" : visible + " reports";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeType = button.getAttribute("data-report-type");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateReports();
    });
  });

  input.addEventListener("input", updateReports);

  reset.addEventListener("click", function () {
    activeType = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-report-type") === "all");
    });

    input.focus();
    updateReports();
  });

  updateReports();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dashboard = document.querySelector("[data-vb-filter-twentyfive]");
  if (!dashboard) return;

  const input = dashboard.querySelector("[data-vb-filter-twentyfive-input]");
  const buttons = dashboard.querySelectorAll("[data-report-type]");
  const reset = dashboard.querySelector("[data-vb-filter-twentyfive-reset]");
  const count = dashboard.querySelector("[data-vb-filter-twentyfive-count]");
  const empty = dashboard.querySelector("[data-vb-filter-twentyfive-empty]");
  const reports = Array.from(dashboard.querySelectorAll("[data-report-card]"));

  let activeType = "all";

  function updateReports() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    reports.forEach(function (report) {
      const type = report.getAttribute("data-report-card");
      const text = report.getAttribute("data-report-text").toLowerCase();
      const fullText = report.textContent.toLowerCase();

      const typeMatch = activeType === "all" || type === activeType;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = typeMatch && searchMatch;

      report.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 report" : visible + " reports";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeType = button.getAttribute("data-report-type");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateReports();
    });
  });

  input.addEventListener("input", updateReports);

  reset.addEventListener("click", function () {
    activeType = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-report-type") === "all");
    });

    input.focus();
    updateReports();
  });

  updateReports();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-twentyfive-demo"&gt;
  &lt;div class="vb-filter-twentyfive-dashboard" data-vb-filter-twentyfive&gt;
    &lt;div class="vb-filter-twentyfive-top"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 25&lt;/span&gt;
        &lt;h3&gt;Analytics Dashboard Report Filter&lt;/h3&gt;
        &lt;p&gt;Search reports by channel, metric, status, campaign, or dashboard keyword.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-twentyfive-total"&gt;
        &lt;small&gt;Visible reports&lt;/small&gt;
        &lt;strong data-vb-filter-twentyfive-count&gt;9 reports&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-twentyfive-toolbar"&gt;
      &lt;input type="search" placeholder="Search traffic, revenue, SEO, email, conversion..." data-vb-filter-twentyfive-input&gt;

      &lt;div class="vb-filter-twentyfive-tabs"&gt;
        &lt;button type="button" class="is-active" data-report-type="all"&gt;All&lt;/button&gt;
        &lt;button type="button" data-report-type="traffic"&gt;Traffic&lt;/button&gt;
        &lt;button type="button" data-report-type="sales"&gt;Sales&lt;/button&gt;
        &lt;button type="button" data-report-type="marketing"&gt;Marketing&lt;/button&gt;
        &lt;button type="button" data-report-type="seo"&gt;SEO&lt;/button&gt;
      &lt;/div&gt;

      &lt;button type="button" class="vb-filter-twentyfive-reset" data-vb-filter-twentyfive-reset&gt;Reset&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-twentyfive-grid"&gt;
      &lt;article data-report-card="traffic" data-report-text="traffic visitors sessions source website overview growth"&gt;
        &lt;small&gt;Traffic&lt;/small&gt;
        &lt;h4&gt;Website Sessions&lt;/h4&gt;
        &lt;strong&gt;128K&lt;/strong&gt;
        &lt;p&gt;Tracks total visits, new users, returning visitors, and traffic source movement.&lt;/p&gt;
        &lt;span&gt;+18.4%&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-report-card="sales" data-report-text="sales revenue ecommerce orders checkout conversion"&gt;
        &lt;small&gt;Sales&lt;/small&gt;
        &lt;h4&gt;Monthly Revenue&lt;/h4&gt;
        &lt;strong&gt;€48.7K&lt;/strong&gt;
        &lt;p&gt;Compares revenue, orders, average cart value, and checkout performance.&lt;/p&gt;
        &lt;span&gt;+12.1%&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-report-card="marketing" data-report-text="marketing email campaign newsletter open rate clicks"&gt;
        &lt;small&gt;Marketing&lt;/small&gt;
        &lt;h4&gt;Email Campaigns&lt;/h4&gt;
        &lt;strong&gt;42.6%&lt;/strong&gt;
        &lt;p&gt;Measures newsletter opens, click-through rate, segments, and campaign response.&lt;/p&gt;
        &lt;span&gt;+7.8%&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-report-card="seo" data-report-text="seo organic traffic ranking keywords search impressions"&gt;
        &lt;small&gt;SEO&lt;/small&gt;
        &lt;h4&gt;Organic Keywords&lt;/h4&gt;
        &lt;strong&gt;3,842&lt;/strong&gt;
        &lt;p&gt;Tracks ranking keywords, impressions, organic clicks, and search visibility.&lt;/p&gt;
        &lt;span&gt;+22.9%&lt;/span&gt;
      &lt;/article&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-twentyfive-empty" data-vb-filter-twentyfive-empty&gt;
      &lt;strong&gt;No reports found.&lt;/strong&gt;
      &lt;p&gt;Try searching for traffic, sales, SEO, email, revenue, checkout, campaign, or keywords.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">/* Use the full CSS from the live preview block above for this analytics dashboard report filter. */</pre>



<p class="wp-block-paragraph">This analytics dashboard search filter is useful for SaaS dashboards, SEO dashboards, marketing reports, admin panels, ecommerce analytics, sales tracking screens, and business intelligence interfaces.</p>



<h2 class="wp-block-heading">26. Restaurant Menu Search Filter</h2>



<p class="wp-block-paragraph"><strong>A restaurant menu search filter</strong> helps visitors find meals by category, ingredient, diet type, price, or keyword. This pattern is useful for restaurant websites, cafe menus, food delivery pages, catering menus, hotel dining pages, recipe collections, and ordering interfaces.</p>



<p class="wp-block-paragraph">This example uses a menu-board layout with a featured restaurant panel, category filters, menu rows, ingredient descriptions, price labels, and a no-results message. It feels like a digital restaurant menu instead of a generic search grid.</p>



<ul class="wp-block-list">
<li>Restaurant menu search layout</li>
<li>Filters dishes by category and keyword</li>
<li>Menu rows with ingredients and prices</li>
<li>Searches meal name, diet type, and description</li>
<li>Useful for restaurants, cafes, food delivery pages, and catering websites</li>
</ul>



<div class="vb-filter-twentysix-demo">
  <div class="vb-filter-twentysix-menu" data-vb-filter-twentysix>
    <section class="vb-filter-twentysix-board">
      <span>Example 26</span>
      <h3>Restaurant Menu Search Filter</h3>
      <p>Search menu items by dish name, ingredient, diet type, category, or flavor.</p>

      <div class="vb-filter-twentysix-board-bottom">
        <small>Available dishes</small>
        <strong data-vb-filter-twentysix-count>10 dishes</strong>
      </div>
    </section>

    <section class="vb-filter-twentysix-listarea">
      <div class="vb-filter-twentysix-controls">
        <input type="search" placeholder="Search pasta, vegan, chicken, dessert, spicy..." data-vb-filter-twentysix-input>

        <div class="vb-filter-twentysix-cats">
          <button type="button" class="is-active" data-menu-category="all">All</button>
          <button type="button" data-menu-category="starter">Starters</button>
          <button type="button" data-menu-category="main">Mains</button>
          <button type="button" data-menu-category="vegan">Vegan</button>
          <button type="button" data-menu-category="dessert">Desserts</button>
        </div>

        <button type="button" class="vb-filter-twentysix-reset" data-vb-filter-twentysix-reset>Reset</button>
      </div>

      <div class="vb-filter-twentysix-items">
        <article data-menu-card="starter" data-menu-text="starter bruschetta tomato basil garlic bread italian">
          <div>
            <small>Starter</small>
            <h4>Tomato Basil Bruschetta</h4>
            <p>Toasted bread with fresh tomatoes, basil, garlic, olive oil, and sea salt.</p>
          </div>
          <strong>€8</strong>
        </article>

        <article data-menu-card="main" data-menu-text="main chicken grilled herb potatoes sauce protein">
          <div>
            <small>Main</small>
            <h4>Herb Grilled Chicken</h4>
            <p>Grilled chicken breast with roasted potatoes, herbs, and creamy pepper sauce.</p>
          </div>
          <strong>€18</strong>
        </article>

        <article data-menu-card="vegan" data-menu-text="vegan bowl quinoa avocado chickpeas vegetables healthy">
          <div>
            <small>Vegan</small>
            <h4>Green Quinoa Bowl</h4>
            <p>Quinoa, avocado, chickpeas, roasted vegetables, lemon dressing, and seeds.</p>
          </div>
          <strong>€14</strong>
        </article>

        <article data-menu-card="main" data-menu-text="main pasta tomato parmesan italian basil vegetarian">
          <div>
            <small>Main</small>
            <h4>Classic Tomato Pasta</h4>
            <p>Fresh pasta with tomato sauce, parmesan, garlic, basil, and olive oil.</p>
          </div>
          <strong>€15</strong>
        </article>

        <article data-menu-card="dessert" data-menu-text="dessert chocolate cake cream cocoa sweet">
          <div>
            <small>Dessert</small>
            <h4>Warm Chocolate Cake</h4>
            <p>Soft chocolate cake with cocoa center, cream, berries, and vanilla sauce.</p>
          </div>
          <strong>€9</strong>
        </article>

        <article data-menu-card="starter" data-menu-text="starter soup pumpkin spicy cream seeds autumn">
          <div>
            <small>Starter</small>
            <h4>Spicy Pumpkin Soup</h4>
            <p>Warm pumpkin soup with chili oil, roasted seeds, cream, and fresh herbs.</p>
          </div>
          <strong>€7</strong>
        </article>

        <article data-menu-card="vegan" data-menu-text="vegan burger plant based spicy sauce salad">
          <div>
            <small>Vegan</small>
            <h4>Plant-Based Burger</h4>
            <p>Vegan patty with salad, tomato, pickles, spicy sauce, and toasted bun.</p>
          </div>
          <strong>€16</strong>
        </article>

        <article data-menu-card="main" data-menu-text="main salmon fish lemon butter vegetables dinner">
          <div>
            <small>Main</small>
            <h4>Lemon Butter Salmon</h4>
            <p>Pan-seared salmon with lemon butter, seasonal vegetables, and herb rice.</p>
          </div>
          <strong>€22</strong>
        </article>

        <article data-menu-card="dessert" data-menu-text="dessert cheesecake strawberry cream sweet cold">
          <div>
            <small>Dessert</small>
            <h4>Strawberry Cheesecake</h4>
            <p>Creamy cheesecake with strawberry sauce, biscuit base, and fresh berries.</p>
          </div>
          <strong>€8</strong>
        </article>

        <article data-menu-card="starter" data-menu-text="starter salad greek feta cucumber olives fresh">
          <div>
            <small>Starter</small>
            <h4>Fresh Greek Salad</h4>
            <p>Cucumber, tomato, olives, feta cheese, red onion, oregano, and olive oil.</p>
          </div>
          <strong>€10</strong>
        </article>
      </div>

      <div class="vb-filter-twentysix-empty" data-vb-filter-twentysix-empty>
        <strong>No menu items found.</strong>
        <p>Try searching for pasta, vegan, chicken, dessert, spicy, salmon, salad, or chocolate.</p>
      </div>
    </section>
  </div>
</div>

<style>
.vb-filter-twentysix-demo,
.vb-filter-twentysix-demo * {
  box-sizing: border-box;
}

.vb-filter-twentysix-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(249, 115, 22, 0.22), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(34, 197, 94, 0.18), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #f0fdf4 52%, #ffffff 100%) !important;
  border: 1px solid rgba(254, 215, 170, 0.52);
  box-shadow: 0 24px 70px rgba(154, 52, 18, 0.10);
}

.vb-filter-twentysix-menu {
  display: grid;
  grid-template-columns: 340px minmax(0, 1fr);
  gap: 18px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-filter-twentysix-board {
  position: relative;
  overflow: hidden;
  min-height: 650px;
  padding: 30px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 70% 24%, rgba(255,255,255,0.22), transparent 28%),
    linear-gradient(135deg, #431407, #9a3412 55%, #166534) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.22);
}

.vb-filter-twentysix-board::after {
  content: "";
  position: absolute;
  right: -76px;
  bottom: -76px;
  width: 260px;
  height: 260px;
  border-radius: 50%;
  border: 40px solid rgba(255,255,255,0.12);
}

.vb-filter-twentysix-board > span {
  position: relative;
  z-index: 2;
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-twentysix-board h3 {
  position: relative;
  z-index: 2;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 4vw, 58px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-twentysix-board p {
  position: relative;
  z-index: 2;
  margin: 0 !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-twentysix-board-bottom {
  position: absolute;
  z-index: 2;
  left: 26px;
  right: 26px;
  bottom: 26px;
  padding: 20px;
  border-radius: 24px;
  background: rgba(15, 23, 42, 0.72);
  border: 1px solid rgba(255,255,255,0.16);
  backdrop-filter: blur(14px);
}

.vb-filter-twentysix-board-bottom small {
  display: block;
  margin-bottom: 6px;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-twentysix-board-bottom strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  font-weight: 950;
}

.vb-filter-twentysix-listarea {
  padding: 24px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-twentysix-controls {
  display: grid;
  grid-template-columns: minmax(240px, 0.9fr) minmax(0, 1.1fr) auto;
  gap: 10px;
  align-items: center;
  margin-bottom: 16px;
  padding: 12px;
  border-radius: 22px;
  background: #f8fafc;
}

.vb-filter-twentysix-controls input {
  width: 100%;
  min-height: 50px;
  padding: 0 15px;
  border: 1px solid rgba(148, 163, 184, 0.26);
  border-radius: 16px;
  outline: 0;
  background: #ffffff;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-twentysix-cats {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-filter-twentysix-cats button,
.vb-filter-twentysix-reset {
  min-height: 40px;
  padding: 9px 12px;
  border: 0;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-twentysix-cats button {
  background: #fff7ed;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
}

.vb-filter-twentysix-cats button.is-active,
.vb-filter-twentysix-cats button:hover {
  background: linear-gradient(135deg, #f97316, #16a34a);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-twentysix-reset {
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-twentysix-items {
  display: grid;
  gap: 10px;
}

.vb-filter-twentysix-items article {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 70px;
  gap: 14px;
  align-items: center;
  padding: 17px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px dashed rgba(154, 52, 18, 0.28);
  box-shadow: 0 12px 28px rgba(15, 23, 42, 0.05);
}

.vb-filter-twentysix-items article.is-hidden {
  display: none;
}

.vb-filter-twentysix-items small {
  display: inline-flex;
  margin-bottom: 7px;
  color: #16a34a !important;
  -webkit-text-fill-color: #16a34a !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-filter-twentysix-items h4 {
  margin: 0 0 7px !important;
  color: #431407 !important;
  -webkit-text-fill-color: #431407 !important;
  font-size: 20px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-twentysix-items p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 13px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-filter-twentysix-items article > strong {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  border-radius: 999px;
  background: #fff7ed;
  color: #ea580c !important;
  -webkit-text-fill-color: #ea580c !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-filter-twentysix-empty {
  display: none;
  margin-top: 14px;
  padding: 20px;
  border-radius: 20px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.34);
}

.vb-filter-twentysix-empty.is-visible {
  display: block;
}

.vb-filter-twentysix-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-twentysix-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb-filter-twentysix-menu {
    grid-template-columns: 1fr;
  }

  .vb-filter-twentysix-board {
    min-height: 400px;
  }

  .vb-filter-twentysix-controls {
    grid-template-columns: 1fr;
  }

  .vb-filter-twentysix-reset {
    width: fit-content;
  }
}

@media (max-width: 640px) {
  .vb-filter-twentysix-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-twentysix-board,
  .vb-filter-twentysix-listarea {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-twentysix-board h3 {
    font-size: 38px !important;
  }

  .vb-filter-twentysix-cats {
    display: grid;
    grid-template-columns: 1fr;
  }

  .vb-filter-twentysix-items article {
    grid-template-columns: 1fr;
  }

  .vb-filter-twentysix-items article > strong {
    width: fit-content;
    padding: 0 16px;
  }
}
</style>

<script>
(function () {
  const menu = document.querySelector("[data-vb-filter-twentysix]");
  if (!menu) return;

  const input = menu.querySelector("[data-vb-filter-twentysix-input]");
  const buttons = menu.querySelectorAll("[data-menu-category]");
  const reset = menu.querySelector("[data-vb-filter-twentysix-reset]");
  const count = menu.querySelector("[data-vb-filter-twentysix-count]");
  const empty = menu.querySelector("[data-vb-filter-twentysix-empty]");
  const dishes = Array.from(menu.querySelectorAll("[data-menu-card]"));

  let activeCategory = "all";

  function updateMenu() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    dishes.forEach(function (dish) {
      const category = dish.getAttribute("data-menu-card");
      const text = dish.getAttribute("data-menu-text").toLowerCase();
      const fullText = dish.textContent.toLowerCase();

      const categoryMatch = activeCategory === "all" || category === activeCategory;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = categoryMatch && searchMatch;

      dish.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 dish" : visible + " dishes";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeCategory = button.getAttribute("data-menu-category");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateMenu();
    });
  });

  input.addEventListener("input", updateMenu);

  reset.addEventListener("click", function () {
    activeCategory = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-menu-category") === "all");
    });

    input.focus();
    updateMenu();
  });

  updateMenu();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const menu = document.querySelector("[data-vb-filter-twentysix]");
  if (!menu) return;

  const input = menu.querySelector("[data-vb-filter-twentysix-input]");
  const buttons = menu.querySelectorAll("[data-menu-category]");
  const reset = menu.querySelector("[data-vb-filter-twentysix-reset]");
  const count = menu.querySelector("[data-vb-filter-twentysix-count]");
  const empty = menu.querySelector("[data-vb-filter-twentysix-empty]");
  const dishes = Array.from(menu.querySelectorAll("[data-menu-card]"));

  let activeCategory = "all";

  function updateMenu() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    dishes.forEach(function (dish) {
      const category = dish.getAttribute("data-menu-card");
      const text = dish.getAttribute("data-menu-text").toLowerCase();
      const fullText = dish.textContent.toLowerCase();

      const categoryMatch = activeCategory === "all" || category === activeCategory;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = categoryMatch && searchMatch;

      dish.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 dish" : visible + " dishes";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeCategory = button.getAttribute("data-menu-category");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateMenu();
    });
  });

  input.addEventListener("input", updateMenu);

  reset.addEventListener("click", function () {
    activeCategory = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-menu-category") === "all");
    });

    input.focus();
    updateMenu();
  });

  updateMenu();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-twentysix-demo"&gt;
  &lt;div class="vb-filter-twentysix-menu" data-vb-filter-twentysix&gt;
    &lt;section class="vb-filter-twentysix-board"&gt;
      &lt;span&gt;Example 26&lt;/span&gt;
      &lt;h3&gt;Restaurant Menu Search Filter&lt;/h3&gt;
      &lt;p&gt;Search menu items by dish name, ingredient, diet type, category, or flavor.&lt;/p&gt;

      &lt;div class="vb-filter-twentysix-board-bottom"&gt;
        &lt;small&gt;Available dishes&lt;/small&gt;
        &lt;strong data-vb-filter-twentysix-count&gt;10 dishes&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/section&gt;

    &lt;section class="vb-filter-twentysix-listarea"&gt;
      &lt;div class="vb-filter-twentysix-controls"&gt;
        &lt;input type="search" placeholder="Search pasta, vegan, chicken, dessert, spicy..." data-vb-filter-twentysix-input&gt;

        &lt;div class="vb-filter-twentysix-cats"&gt;
          &lt;button type="button" class="is-active" data-menu-category="all"&gt;All&lt;/button&gt;
          &lt;button type="button" data-menu-category="starter"&gt;Starters&lt;/button&gt;
          &lt;button type="button" data-menu-category="main"&gt;Mains&lt;/button&gt;
          &lt;button type="button" data-menu-category="vegan"&gt;Vegan&lt;/button&gt;
          &lt;button type="button" data-menu-category="dessert"&gt;Desserts&lt;/button&gt;
        &lt;/div&gt;

        &lt;button type="button" class="vb-filter-twentysix-reset" data-vb-filter-twentysix-reset&gt;Reset&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-twentysix-items"&gt;
        &lt;article data-menu-card="starter" data-menu-text="starter bruschetta tomato basil garlic bread italian"&gt;
          &lt;div&gt;
            &lt;small&gt;Starter&lt;/small&gt;
            &lt;h4&gt;Tomato Basil Bruschetta&lt;/h4&gt;
            &lt;p&gt;Toasted bread with fresh tomatoes, basil, garlic, olive oil, and sea salt.&lt;/p&gt;
          &lt;/div&gt;
          &lt;strong&gt;€8&lt;/strong&gt;
        &lt;/article&gt;

        &lt;article data-menu-card="main" data-menu-text="main chicken grilled herb potatoes sauce protein"&gt;
          &lt;div&gt;
            &lt;small&gt;Main&lt;/small&gt;
            &lt;h4&gt;Herb Grilled Chicken&lt;/h4&gt;
            &lt;p&gt;Grilled chicken breast with roasted potatoes, herbs, and creamy pepper sauce.&lt;/p&gt;
          &lt;/div&gt;
          &lt;strong&gt;€18&lt;/strong&gt;
        &lt;/article&gt;

        &lt;article data-menu-card="vegan" data-menu-text="vegan bowl quinoa avocado chickpeas vegetables healthy"&gt;
          &lt;div&gt;
            &lt;small&gt;Vegan&lt;/small&gt;
            &lt;h4&gt;Green Quinoa Bowl&lt;/h4&gt;
            &lt;p&gt;Quinoa, avocado, chickpeas, roasted vegetables, lemon dressing, and seeds.&lt;/p&gt;
          &lt;/div&gt;
          &lt;strong&gt;€14&lt;/strong&gt;
        &lt;/article&gt;

        &lt;article data-menu-card="main" data-menu-text="main pasta tomato parmesan italian basil vegetarian"&gt;
          &lt;div&gt;
            &lt;small&gt;Main&lt;/small&gt;
            &lt;h4&gt;Classic Tomato Pasta&lt;/h4&gt;
            &lt;p&gt;Fresh pasta with tomato sauce, parmesan, garlic, basil, and olive oil.&lt;/p&gt;
          &lt;/div&gt;
          &lt;strong&gt;€15&lt;/strong&gt;
        &lt;/article&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-twentysix-empty" data-vb-filter-twentysix-empty&gt;
        &lt;strong&gt;No menu items found.&lt;/strong&gt;
        &lt;p&gt;Try searching for pasta, vegan, chicken, dessert, spicy, salmon, salad, or chocolate.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/section&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">/* Use the full CSS from the live preview block above for this restaurant menu search filter. */</pre>



<p class="wp-block-paragraph">This restaurant menu search filter is useful for restaurant websites, cafe menus, online ordering pages, food delivery interfaces, hotel dining pages, catering websites, and recipe-style food collections.</p>



<h2 class="wp-block-heading">27. Job Board Search Filter</h2>



<p class="wp-block-paragraph"><strong>A job board search filter</strong> helps visitors search open roles by department, location, work type, seniority, or keyword. This layout is useful for career pages, startup hiring pages, recruitment websites, HR platforms, remote job boards, and company hiring sections.</p>



<p class="wp-block-paragraph">This example uses a professional job board layout with a left filter panel, job result rows, department labels, salary ranges, location tags, and a live result count. Users can search jobs and filter by department at the same time.</p>



<ul class="wp-block-list">
<li>Job board search layout</li>
<li>Filters roles by department and keyword</li>
<li>Searches title, location, salary, and work type</li>
<li>Professional career page design</li>
<li>Useful for career pages, hiring portals, and remote job boards</li>
</ul>



<div class="vb-filter-twentyseven-demo">
  <div class="vb-filter-twentyseven-jobs" data-vb-filter-twentyseven>
    <aside class="vb-filter-twentyseven-sidebar">
      <span>Example 27</span>
      <h3>Job Board Search Filter</h3>
      <p>Search open roles by department, location, remote option, salary, or skill keyword.</p>

      <div class="vb-filter-twentyseven-search">
        <label for="vb-filter-twentyseven-input">Search jobs</label>
        <input id="vb-filter-twentyseven-input" type="search" placeholder="Search developer, remote, design, Tallinn..." data-vb-filter-twentyseven-input>
      </div>

      <div class="vb-filter-twentyseven-departments">
        <button type="button" class="is-active" data-job-dept="all">All Roles</button>
        <button type="button" data-job-dept="engineering">Engineering</button>
        <button type="button" data-job-dept="design">Design</button>
        <button type="button" data-job-dept="marketing">Marketing</button>
        <button type="button" data-job-dept="support">Support</button>
      </div>

      <div class="vb-filter-twentyseven-summary">
        <small>Matching roles</small>
        <strong data-vb-filter-twentyseven-count>8 jobs</strong>
        <button type="button" data-vb-filter-twentyseven-reset>Reset filters</button>
      </div>
    </aside>

    <main class="vb-filter-twentyseven-results">
      <article data-job-card="engineering" data-job-text="frontend developer engineering remote react javascript tallinn senior">
        <div>
          <small>Engineering</small>
          <h4>Senior Frontend Developer</h4>
          <p>Build modern JavaScript interfaces, reusable UI components, and fast product dashboards.</p>
          <div><span>Remote</span><span>Tallinn</span><span>€4,500–€6,200</span></div>
        </div>
        <a href="#">Apply</a>
      </article>

      <article data-job-card="design" data-job-text="product designer design figma ux ui hybrid riga mid level">
        <div>
          <small>Design</small>
          <h4>Product Designer</h4>
          <p>Design user flows, dashboards, onboarding screens, and conversion-focused product layouts.</p>
          <div><span>Hybrid</span><span>Riga</span><span>€3,200–€4,800</span></div>
        </div>
        <a href="#">Apply</a>
      </article>

      <article data-job-card="marketing" data-job-text="seo content strategist marketing remote keywords blog analytics">
        <div>
          <small>Marketing</small>
          <h4>SEO Content Strategist</h4>
          <p>Plan content clusters, keyword strategy, internal linking, and long-form article growth.</p>
          <div><span>Remote</span><span>Europe</span><span>€2,800–€4,200</span></div>
        </div>
        <a href="#">Apply</a>
      </article>

      <article data-job-card="support" data-job-text="technical support specialist wordpress plugin customers helsinki">
        <div>
          <small>Support</small>
          <h4>Technical Support Specialist</h4>
          <p>Help customers with setup questions, WordPress plugin issues, and troubleshooting tickets.</p>
          <div><span>On-site</span><span>Helsinki</span><span>€2,600–€3,600</span></div>
        </div>
        <a href="#">Apply</a>
      </article>

      <article data-job-card="engineering" data-job-text="backend developer engineering node api database remote berlin">
        <div>
          <small>Engineering</small>
          <h4>Backend API Developer</h4>
          <p>Create secure APIs, database models, webhook handlers, and scalable backend services.</p>
          <div><span>Remote</span><span>Berlin</span><span>€4,200–€6,000</span></div>
        </div>
        <a href="#">Apply</a>
      </article>

      <article data-job-card="design" data-job-text="brand designer design visual identity social campaigns office">
        <div>
          <small>Design</small>
          <h4>Brand Designer</h4>
          <p>Create visual identity systems, social graphics, campaign assets, and website visuals.</p>
          <div><span>Office</span><span>Tallinn</span><span>€2,900–€4,100</span></div>
        </div>
        <a href="#">Apply</a>
      </article>

      <article data-job-card="marketing" data-job-text="growth marketer ads funnel conversion analytics remote">
        <div>
          <small>Marketing</small>
          <h4>Growth Marketer</h4>
          <p>Run paid campaigns, analyze conversion funnels, test landing pages, and improve acquisition.</p>
          <div><span>Remote</span><span>Europe</span><span>€3,300–€5,200</span></div>
        </div>
        <a href="#">Apply</a>
      </article>

      <article data-job-card="support" data-job-text="customer success support onboarding accounts crm remote">
        <div>
          <small>Support</small>
          <h4>Customer Success Manager</h4>
          <p>Guide new customers through onboarding, account setup, product adoption, and renewals.</p>
          <div><span>Hybrid</span><span>Stockholm</span><span>€3,100–€4,600</span></div>
        </div>
        <a href="#">Apply</a>
      </article>

      <div class="vb-filter-twentyseven-empty" data-vb-filter-twentyseven-empty>
        <strong>No jobs found.</strong>
        <p>Try searching for frontend, remote, SEO, support, design, backend, Tallinn, or marketing.</p>
      </div>
    </main>
  </div>
</div>

<style>
.vb-filter-twentyseven-demo,
.vb-filter-twentyseven-demo * {
  box-sizing: border-box;
}

.vb-filter-twentyseven-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(37, 99, 235, 0.20), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(16, 185, 129, 0.18), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 52%, #ffffff 100%) !important;
  border: 1px solid rgba(191, 219, 254, 0.58);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.10);
}

.vb-filter-twentyseven-jobs {
  display: grid;
  grid-template-columns: 330px minmax(0, 1fr);
  gap: 18px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-filter-twentyseven-sidebar {
  align-self: start;
  padding: 28px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 80% 12%, rgba(255,255,255,0.13), transparent 28%),
    linear-gradient(135deg, #1e3a8a, #064e3b) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.24);
}

.vb-filter-twentyseven-sidebar > span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-twentyseven-sidebar h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 4vw, 56px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-twentyseven-sidebar p {
  margin: 0 0 22px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-twentyseven-search {
  margin-bottom: 14px;
}

.vb-filter-twentyseven-search label {
  display: block;
  margin-bottom: 8px;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-twentyseven-search input {
  width: 100%;
  min-height: 54px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 18px;
  outline: 0;
  background: rgba(255,255,255,0.11);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-twentyseven-search input::placeholder {
  color: rgba(255,255,255,0.62);
  -webkit-text-fill-color: rgba(255,255,255,0.62);
}

.vb-filter-twentyseven-departments {
  display: grid;
  gap: 8px;
  margin-bottom: 14px;
}

.vb-filter-twentyseven-departments button {
  min-height: 44px;
  padding: 10px 13px;
  border: 1px solid rgba(255,255,255,0.13);
  border-radius: 14px;
  background: rgba(255,255,255,0.09);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 13px;
  font-weight: 900;
  text-align: left;
  cursor: pointer;
}

.vb-filter-twentyseven-departments button.is-active,
.vb-filter-twentyseven-departments button:hover {
  background: #ffffff;
  color: #1e40af !important;
  -webkit-text-fill-color: #1e40af !important;
}

.vb-filter-twentyseven-summary {
  display: grid;
  gap: 9px;
  padding: 16px;
  border-radius: 20px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-filter-twentyseven-summary small {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-twentyseven-summary strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 21px;
  font-weight: 950;
}

.vb-filter-twentyseven-summary button {
  min-height: 40px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #065f46 !important;
  -webkit-text-fill-color: #065f46 !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-twentyseven-results {
  display: grid;
  gap: 12px;
}

.vb-filter-twentyseven-results article {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 94px;
  gap: 18px;
  align-items: center;
  padding: 22px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb-filter-twentyseven-results article.is-hidden {
  display: none;
}

.vb-filter-twentyseven-results small {
  display: inline-flex;
  margin-bottom: 9px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #eff6ff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-twentyseven-results h4 {
  margin: 0 0 8px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 23px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-twentyseven-results p {
  margin: 0 0 13px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-filter-twentyseven-results div div {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
}

.vb-filter-twentyseven-results div div span {
  padding: 6px 9px;
  border-radius: 999px;
  background: #f1f5f9;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 12px;
  font-weight: 900;
}

.vb-filter-twentyseven-results article a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #10b981);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none;
}

.vb-filter-twentyseven-empty {
  display: none;
  padding: 22px;
  border-radius: 22px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.34);
}

.vb-filter-twentyseven-empty.is-visible {
  display: block;
}

.vb-filter-twentyseven-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-twentyseven-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 940px) {
  .vb-filter-twentyseven-jobs {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-filter-twentyseven-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-twentyseven-sidebar {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-twentyseven-sidebar h3 {
    font-size: 38px !important;
  }

  .vb-filter-twentyseven-results article {
    grid-template-columns: 1fr;
  }

  .vb-filter-twentyseven-results article a {
    width: fit-content;
    padding: 0 18px;
  }
}
</style>

<script>
(function () {
  const jobs = document.querySelector("[data-vb-filter-twentyseven]");
  if (!jobs) return;

  const input = jobs.querySelector("[data-vb-filter-twentyseven-input]");
  const buttons = jobs.querySelectorAll("[data-job-dept]");
  const reset = jobs.querySelector("[data-vb-filter-twentyseven-reset]");
  const count = jobs.querySelector("[data-vb-filter-twentyseven-count]");
  const empty = jobs.querySelector("[data-vb-filter-twentyseven-empty]");
  const cards = Array.from(jobs.querySelectorAll("[data-job-card]"));

  let activeDept = "all";

  function updateJobs() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    cards.forEach(function (card) {
      const dept = card.getAttribute("data-job-card");
      const text = card.getAttribute("data-job-text").toLowerCase();
      const fullText = card.textContent.toLowerCase();

      const deptMatch = activeDept === "all" || dept === activeDept;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = deptMatch && searchMatch;

      card.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 job" : visible + " jobs";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeDept = button.getAttribute("data-job-dept");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateJobs();
    });
  });

  input.addEventListener("input", updateJobs);

  reset.addEventListener("click", function () {
    activeDept = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-job-dept") === "all");
    });

    input.focus();
    updateJobs();
  });

  updateJobs();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const jobs = document.querySelector("[data-vb-filter-twentyseven]");
  if (!jobs) return;

  const input = jobs.querySelector("[data-vb-filter-twentyseven-input]");
  const buttons = jobs.querySelectorAll("[data-job-dept]");
  const reset = jobs.querySelector("[data-vb-filter-twentyseven-reset]");
  const count = jobs.querySelector("[data-vb-filter-twentyseven-count]");
  const empty = jobs.querySelector("[data-vb-filter-twentyseven-empty]");
  const cards = Array.from(jobs.querySelectorAll("[data-job-card]"));

  let activeDept = "all";

  function updateJobs() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    cards.forEach(function (card) {
      const dept = card.getAttribute("data-job-card");
      const text = card.getAttribute("data-job-text").toLowerCase();
      const fullText = card.textContent.toLowerCase();

      const deptMatch = activeDept === "all" || dept === activeDept;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = deptMatch && searchMatch;

      card.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 job" : visible + " jobs";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeDept = button.getAttribute("data-job-dept");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateJobs();
    });
  });

  input.addEventListener("input", updateJobs);

  reset.addEventListener("click", function () {
    activeDept = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-job-dept") === "all");
    });

    input.focus();
    updateJobs();
  });

  updateJobs();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-twentyseven-demo"&gt;
  &lt;div class="vb-filter-twentyseven-jobs" data-vb-filter-twentyseven&gt;
    &lt;aside class="vb-filter-twentyseven-sidebar"&gt;
      &lt;span&gt;Example 27&lt;/span&gt;
      &lt;h3&gt;Job Board Search Filter&lt;/h3&gt;
      &lt;p&gt;Search open roles by department, location, remote option, salary, or skill keyword.&lt;/p&gt;

      &lt;div class="vb-filter-twentyseven-search"&gt;
        &lt;label for="vb-filter-twentyseven-input"&gt;Search jobs&lt;/label&gt;
        &lt;input id="vb-filter-twentyseven-input" type="search" placeholder="Search developer, remote, design, Tallinn..." data-vb-filter-twentyseven-input&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-twentyseven-departments"&gt;
        &lt;button type="button" class="is-active" data-job-dept="all"&gt;All Roles&lt;/button&gt;
        &lt;button type="button" data-job-dept="engineering"&gt;Engineering&lt;/button&gt;
        &lt;button type="button" data-job-dept="design"&gt;Design&lt;/button&gt;
        &lt;button type="button" data-job-dept="marketing"&gt;Marketing&lt;/button&gt;
        &lt;button type="button" data-job-dept="support"&gt;Support&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-twentyseven-summary"&gt;
        &lt;small&gt;Matching roles&lt;/small&gt;
        &lt;strong data-vb-filter-twentyseven-count&gt;8 jobs&lt;/strong&gt;
        &lt;button type="button" data-vb-filter-twentyseven-reset&gt;Reset filters&lt;/button&gt;
      &lt;/div&gt;
    &lt;/aside&gt;

    &lt;main class="vb-filter-twentyseven-results"&gt;
      &lt;article data-job-card="engineering" data-job-text="frontend developer engineering remote react javascript tallinn senior"&gt;
        &lt;div&gt;
          &lt;small&gt;Engineering&lt;/small&gt;
          &lt;h4&gt;Senior Frontend Developer&lt;/h4&gt;
          &lt;p&gt;Build modern JavaScript interfaces, reusable UI components, and fast product dashboards.&lt;/p&gt;
          &lt;div&gt;&lt;span&gt;Remote&lt;/span&gt;&lt;span&gt;Tallinn&lt;/span&gt;&lt;span&gt;€4,500–€6,200&lt;/span&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;a href="#"&gt;Apply&lt;/a&gt;
      &lt;/article&gt;

      &lt;article data-job-card="design" data-job-text="product designer design figma ux ui hybrid riga mid level"&gt;
        &lt;div&gt;
          &lt;small&gt;Design&lt;/small&gt;
          &lt;h4&gt;Product Designer&lt;/h4&gt;
          &lt;p&gt;Design user flows, dashboards, onboarding screens, and conversion-focused product layouts.&lt;/p&gt;
          &lt;div&gt;&lt;span&gt;Hybrid&lt;/span&gt;&lt;span&gt;Riga&lt;/span&gt;&lt;span&gt;€3,200–€4,800&lt;/span&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;a href="#"&gt;Apply&lt;/a&gt;
      &lt;/article&gt;

      &lt;article data-job-card="marketing" data-job-text="seo content strategist marketing remote keywords blog analytics"&gt;
        &lt;div&gt;
          &lt;small&gt;Marketing&lt;/small&gt;
          &lt;h4&gt;SEO Content Strategist&lt;/h4&gt;
          &lt;p&gt;Plan content clusters, keyword strategy, internal linking, and long-form article growth.&lt;/p&gt;
          &lt;div&gt;&lt;span&gt;Remote&lt;/span&gt;&lt;span&gt;Europe&lt;/span&gt;&lt;span&gt;€2,800–€4,200&lt;/span&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;a href="#"&gt;Apply&lt;/a&gt;
      &lt;/article&gt;

      &lt;article data-job-card="support" data-job-text="technical support specialist wordpress plugin customers helsinki"&gt;
        &lt;div&gt;
          &lt;small&gt;Support&lt;/small&gt;
          &lt;h4&gt;Technical Support Specialist&lt;/h4&gt;
          &lt;p&gt;Help customers with setup questions, WordPress plugin issues, and troubleshooting tickets.&lt;/p&gt;
          &lt;div&gt;&lt;span&gt;On-site&lt;/span&gt;&lt;span&gt;Helsinki&lt;/span&gt;&lt;span&gt;€2,600–€3,600&lt;/span&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;a href="#"&gt;Apply&lt;/a&gt;
      &lt;/article&gt;

      &lt;article data-job-card="engineering" data-job-text="backend developer engineering node api database remote berlin"&gt;
        &lt;div&gt;
          &lt;small&gt;Engineering&lt;/small&gt;
          &lt;h4&gt;Backend API Developer&lt;/h4&gt;
          &lt;p&gt;Create secure APIs, database models, webhook handlers, and scalable backend services.&lt;/p&gt;
          &lt;div&gt;&lt;span&gt;Remote&lt;/span&gt;&lt;span&gt;Berlin&lt;/span&gt;&lt;span&gt;€4,200–€6,000&lt;/span&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;a href="#"&gt;Apply&lt;/a&gt;
      &lt;/article&gt;

      &lt;article data-job-card="design" data-job-text="brand designer design visual identity social campaigns office"&gt;
        &lt;div&gt;
          &lt;small&gt;Design&lt;/small&gt;
          &lt;h4&gt;Brand Designer&lt;/h4&gt;
          &lt;p&gt;Create visual identity systems, social graphics, campaign assets, and website visuals.&lt;/p&gt;
          &lt;div&gt;&lt;span&gt;Office&lt;/span&gt;&lt;span&gt;Tallinn&lt;/span&gt;&lt;span&gt;€2,900–€4,100&lt;/span&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;a href="#"&gt;Apply&lt;/a&gt;
      &lt;/article&gt;

      &lt;article data-job-card="marketing" data-job-text="growth marketer ads funnel conversion analytics remote"&gt;
        &lt;div&gt;
          &lt;small&gt;Marketing&lt;/small&gt;
          &lt;h4&gt;Growth Marketer&lt;/h4&gt;
          &lt;p&gt;Run paid campaigns, analyze conversion funnels, test landing pages, and improve acquisition.&lt;/p&gt;
          &lt;div&gt;&lt;span&gt;Remote&lt;/span&gt;&lt;span&gt;Europe&lt;/span&gt;&lt;span&gt;€3,300–€5,200&lt;/span&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;a href="#"&gt;Apply&lt;/a&gt;
      &lt;/article&gt;

      &lt;article data-job-card="support" data-job-text="customer success support onboarding accounts crm remote"&gt;
        &lt;div&gt;
          &lt;small&gt;Support&lt;/small&gt;
          &lt;h4&gt;Customer Success Manager&lt;/h4&gt;
          &lt;p&gt;Guide new customers through onboarding, account setup, product adoption, and renewals.&lt;/p&gt;
          &lt;div&gt;&lt;span&gt;Hybrid&lt;/span&gt;&lt;span&gt;Stockholm&lt;/span&gt;&lt;span&gt;€3,100–€4,600&lt;/span&gt;&lt;/div&gt;
        &lt;/div&gt;
        &lt;a href="#"&gt;Apply&lt;/a&gt;
      &lt;/article&gt;

      &lt;div class="vb-filter-twentyseven-empty" data-vb-filter-twentyseven-empty&gt;
        &lt;strong&gt;No jobs found.&lt;/strong&gt;
        &lt;p&gt;Try searching for frontend, remote, SEO, support, design, backend, Tallinn, or marketing.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/main&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-twentyseven-demo,
.vb-filter-twentyseven-demo * {
  box-sizing: border-box;
}

.vb-filter-twentyseven-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(37, 99, 235, 0.20), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(16, 185, 129, 0.18), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 52%, #ffffff 100%) !important;
  border: 1px solid rgba(191, 219, 254, 0.58);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.10);
}

.vb-filter-twentyseven-jobs {
  display: grid;
  grid-template-columns: 330px minmax(0, 1fr);
  gap: 18px;
  max-width: 1120px;
  margin: 0 auto;
}

.vb-filter-twentyseven-sidebar {
  align-self: start;
  padding: 28px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 80% 12%, rgba(255,255,255,0.13), transparent 28%),
    linear-gradient(135deg, #1e3a8a, #064e3b) !important;
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.24);
}

.vb-filter-twentyseven-sidebar > span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-twentyseven-sidebar h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 4vw, 56px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-twentyseven-sidebar p {
  margin: 0 0 22px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-twentyseven-search {
  margin-bottom: 14px;
}

.vb-filter-twentyseven-search label {
  display: block;
  margin-bottom: 8px;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-twentyseven-search input {
  width: 100%;
  min-height: 54px;
  padding: 0 15px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 18px;
  outline: 0;
  background: rgba(255,255,255,0.11);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-twentyseven-search input::placeholder {
  color: rgba(255,255,255,0.62);
  -webkit-text-fill-color: rgba(255,255,255,0.62);
}

.vb-filter-twentyseven-departments {
  display: grid;
  gap: 8px;
  margin-bottom: 14px;
}

.vb-filter-twentyseven-departments button {
  min-height: 44px;
  padding: 10px 13px;
  border: 1px solid rgba(255,255,255,0.13);
  border-radius: 14px;
  background: rgba(255,255,255,0.09);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 13px;
  font-weight: 900;
  text-align: left;
  cursor: pointer;
}

.vb-filter-twentyseven-departments button.is-active,
.vb-filter-twentyseven-departments button:hover {
  background: #ffffff;
  color: #1e40af !important;
  -webkit-text-fill-color: #1e40af !important;
}

.vb-filter-twentyseven-summary {
  display: grid;
  gap: 9px;
  padding: 16px;
  border-radius: 20px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-filter-twentyseven-summary small {
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-twentyseven-summary strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 21px;
  font-weight: 950;
}

.vb-filter-twentyseven-summary button {
  min-height: 40px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #065f46 !important;
  -webkit-text-fill-color: #065f46 !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-twentyseven-results {
  display: grid;
  gap: 12px;
}

.vb-filter-twentyseven-results article {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 94px;
  gap: 18px;
  align-items: center;
  padding: 22px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb-filter-twentyseven-results article.is-hidden {
  display: none;
}

.vb-filter-twentyseven-results small {
  display: inline-flex;
  margin-bottom: 9px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #eff6ff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-twentyseven-results h4 {
  margin: 0 0 8px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 23px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-twentyseven-results p {
  margin: 0 0 13px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-filter-twentyseven-results div div {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
}

.vb-filter-twentyseven-results div div span {
  padding: 6px 9px;
  border-radius: 999px;
  background: #f1f5f9;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 12px;
  font-weight: 900;
}

.vb-filter-twentyseven-results article a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #10b981);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none;
}

.vb-filter-twentyseven-empty {
  display: none;
  padding: 22px;
  border-radius: 22px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.34);
}

.vb-filter-twentyseven-empty.is-visible {
  display: block;
}

.vb-filter-twentyseven-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-twentyseven-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 940px) {
  .vb-filter-twentyseven-jobs {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-filter-twentyseven-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-twentyseven-sidebar {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-twentyseven-sidebar h3 {
    font-size: 38px !important;
  }

  .vb-filter-twentyseven-results article {
    grid-template-columns: 1fr;
  }

  .vb-filter-twentyseven-results article a {
    width: fit-content;
    padding: 0 18px;
  }
}</pre>



<p class="wp-block-paragraph">This job board search filter is useful for company career pages, remote job boards, hiring sections, HR platforms, startup recruitment pages, and professional job listing interfaces.</p>



<h2 class="wp-block-heading">28. FAQ Knowledge Base Search Filter</h2>



<p class="wp-block-paragraph"><strong>A FAQ knowledge base search filter</strong> helps users find answers by topic, product area, question, or support keyword. This layout is useful for help centers, SaaS support pages, plugin documentation, onboarding sections, customer support portals, and product FAQ pages.</p>



<p class="wp-block-paragraph">This example uses an accordion-style knowledge base layout. Users can filter questions by topic, search inside question text and answers, and expand each answer independently.</p>



<ul class="wp-block-list">
<li>FAQ knowledge base search layout</li>
<li>Filters questions by topic and keyword</li>
<li>Expandable accordion answers</li>
<li>Searches question text and answer content</li>
<li>Useful for help centers, product FAQs, and support portals</li>
</ul>



<div class="vb-filter-twentyeight-demo">
  <div class="vb-filter-twentyeight-kb" data-vb-filter-twentyeight>
    <header class="vb-filter-twentyeight-header">
      <span>Example 28</span>
      <h3>FAQ Knowledge Base Search Filter</h3>
      <p>Search support questions by product area, billing topic, setup issue, or help keyword.</p>
    </header>

    <div class="vb-filter-twentyeight-layout">
      <aside class="vb-filter-twentyeight-menu">
        <button type="button" class="is-active" data-faq-topic="all">All Questions</button>
        <button type="button" data-faq-topic="setup">Setup</button>
        <button type="button" data-faq-topic="billing">Billing</button>
        <button type="button" data-faq-topic="account">Account</button>
        <button type="button" data-faq-topic="technical">Technical</button>

        <div class="vb-filter-twentyeight-countbox">
          <small>Visible answers</small>
          <strong data-vb-filter-twentyeight-count>8 FAQs</strong>
        </div>
      </aside>

      <main class="vb-filter-twentyeight-content">
        <div class="vb-filter-twentyeight-search">
          <input type="search" placeholder="Search invoice, setup, password, API, license..." data-vb-filter-twentyeight-input>
          <button type="button" data-vb-filter-twentyeight-reset>Reset</button>
        </div>

        <div class="vb-filter-twentyeight-list">
          <section data-faq-card="setup" data-faq-text="setup install plugin website wordpress getting started">
            <button type="button" data-faq-toggle>
              <span>Setup</span>
              <strong>How do I install the plugin?</strong>
            </button>
            <div class="vb-filter-twentyeight-answer">
              <p>Upload the plugin ZIP file, activate it in WordPress, open the settings page, and follow the setup checklist.</p>
            </div>
          </section>

          <section data-faq-card="billing" data-faq-text="billing invoice receipt payment vat company details">
            <button type="button" data-faq-toggle>
              <span>Billing</span>
              <strong>Where can I find my invoice?</strong>
            </button>
            <div class="vb-filter-twentyeight-answer">
              <p>You can find invoices in the billing area. Update company details before downloading the final invoice copy.</p>
            </div>
          </section>

          <section data-faq-card="account" data-faq-text="account password reset login email access">
            <button type="button" data-faq-toggle>
              <span>Account</span>
              <strong>How do I reset my password?</strong>
            </button>
            <div class="vb-filter-twentyeight-answer">
              <p>Use the password reset link on the login page. A secure reset email will be sent to your account address.</p>
            </div>
          </section>

          <section data-faq-card="technical" data-faq-text="technical api webhook endpoint integration token">
            <button type="button" data-faq-toggle>
              <span>Technical</span>
              <strong>How do webhooks work?</strong>
            </button>
            <div class="vb-filter-twentyeight-answer">
              <p>Webhooks send event payloads to your endpoint when important actions happen, such as orders or account updates.</p>
            </div>
          </section>

          <section data-faq-card="setup" data-faq-text="setup shortcode embed page gutenberg block">
            <button type="button" data-faq-toggle>
              <span>Setup</span>
              <strong>Can I use a shortcode?</strong>
            </button>
            <div class="vb-filter-twentyeight-answer">
              <p>Yes. Add the shortcode to a page, post, or Gutenberg block where you want the frontend component to appear.</p>
            </div>
          </section>

          <section data-faq-card="billing" data-faq-text="billing subscription cancel plan renewal license">
            <button type="button" data-faq-toggle>
              <span>Billing</span>
              <strong>Can I cancel my subscription?</strong>
            </button>
            <div class="vb-filter-twentyeight-answer">
              <p>Yes. You can cancel renewal from your billing dashboard. Your license remains active until the paid period ends.</p>
            </div>
          </section>

          <section data-faq-card="account" data-faq-text="account email change profile settings user">
            <button type="button" data-faq-toggle>
              <span>Account</span>
              <strong>Can I change my account email?</strong>
            </button>
            <div class="vb-filter-twentyeight-answer">
              <p>Open profile settings, update the email field, and confirm the change from the verification email.</p>
            </div>
          </section>

          <section data-faq-card="technical" data-faq-text="technical cache css javascript not loading conflict">
            <button type="button" data-faq-toggle>
              <span>Technical</span>
              <strong>Why is my CSS not loading?</strong>
            </button>
            <div class="vb-filter-twentyeight-answer">
              <p>Clear cache, check the file path, confirm the stylesheet is enqueued, and inspect the browser console for 404 errors.</p>
            </div>
          </section>
        </div>

        <div class="vb-filter-twentyeight-empty" data-vb-filter-twentyeight-empty>
          <strong>No FAQ answers found.</strong>
          <p>Try searching for setup, invoice, password, webhook, shortcode, subscription, email, or CSS.</p>
        </div>
      </main>
    </div>
  </div>
</div>

<style>
.vb-filter-twentyeight-demo,
.vb-filter-twentyeight-demo * {
  box-sizing: border-box;
}

.vb-filter-twentyeight-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(168, 85, 247, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(14, 165, 233, 0.20), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #f0f9ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(221, 214, 254, 0.58);
  box-shadow: 0 24px 70px rgba(88, 28, 135, 0.10);
}

.vb-filter-twentyeight-kb {
  max-width: 1080px;
  margin: 0 auto;
  padding: 30px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-twentyeight-header {
  max-width: 780px;
  margin-bottom: 24px;
}

.vb-filter-twentyeight-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-twentyeight-header h3 {
  margin: 0 0 12px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-twentyeight-header p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-twentyeight-layout {
  display: grid;
  grid-template-columns: 250px minmax(0, 1fr);
  gap: 16px;
}

.vb-filter-twentyeight-menu {
  align-self: start;
  display: grid;
  gap: 8px;
  padding: 16px;
  border-radius: 24px;
  background: #111827;
}

.vb-filter-twentyeight-menu button {
  min-height: 42px;
  padding: 9px 12px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 14px;
  background: rgba(255,255,255,0.08);
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 13px;
  font-weight: 900;
  text-align: left;
  cursor: pointer;
}

.vb-filter-twentyeight-menu button.is-active,
.vb-filter-twentyeight-menu button:hover {
  background: linear-gradient(135deg, #a855f7, #0ea5e9);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-twentyeight-countbox {
  margin-top: 8px;
  padding: 14px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
}

.vb-filter-twentyeight-countbox small {
  display: block;
  margin-bottom: 6px;
  color: #d8b4fe !important;
  -webkit-text-fill-color: #d8b4fe !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-twentyeight-countbox strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 19px;
  font-weight: 950;
}

.vb-filter-twentyeight-search {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  margin-bottom: 12px;
  padding: 12px;
  border-radius: 22px;
  background: #f8fafc;
}

.vb-filter-twentyeight-search input {
  width: 100%;
  min-height: 50px;
  padding: 0 15px;
  border: 1px solid rgba(148, 163, 184, 0.26);
  border-radius: 16px;
  outline: 0;
  background: #ffffff;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-twentyeight-search button {
  min-height: 50px;
  padding: 0 16px;
  border: 0;
  border-radius: 16px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-twentyeight-list {
  display: grid;
  gap: 10px;
}

.vb-filter-twentyeight-list section {
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 12px 28px rgba(15, 23, 42, 0.05);
  overflow: hidden;
}

.vb-filter-twentyeight-list section.is-hidden {
  display: none;
}

.vb-filter-twentyeight-list section > button {
  display: grid;
  grid-template-columns: 94px minmax(0, 1fr);
  gap: 14px;
  align-items: center;
  width: 100%;
  padding: 18px;
  border: 0;
  background: transparent;
  text-align: left;
  cursor: pointer;
}

.vb-filter-twentyeight-list section > button span {
  display: inline-flex;
  justify-content: center;
  padding: 7px 9px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-twentyeight-list section > button strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
}

.vb-filter-twentyeight-answer {
  display: none;
  padding: 0 18px 18px 126px;
}

.vb-filter-twentyeight-list section.is-open .vb-filter-twentyeight-answer {
  display: block;
}

.vb-filter-twentyeight-answer p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-filter-twentyeight-empty {
  display: none;
  margin-top: 14px;
  padding: 20px;
  border-radius: 20px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.34);
}

.vb-filter-twentyeight-empty.is-visible {
  display: block;
}

.vb-filter-twentyeight-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-twentyeight-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 860px) {
  .vb-filter-twentyeight-layout {
    grid-template-columns: 1fr;
  }

  .vb-filter-twentyeight-menu {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-filter-twentyeight-countbox {
    grid-column: 1 / -1;
  }
}

@media (max-width: 640px) {
  .vb-filter-twentyeight-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-twentyeight-kb {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-twentyeight-header h3 {
    font-size: 38px !important;
  }

  .vb-filter-twentyeight-menu,
  .vb-filter-twentyeight-search,
  .vb-filter-twentyeight-list section > button {
    grid-template-columns: 1fr;
  }

  .vb-filter-twentyeight-answer {
    padding: 0 18px 18px;
  }
}
</style>

<script>
(function () {
  const kb = document.querySelector("[data-vb-filter-twentyeight]");
  if (!kb) return;

  const input = kb.querySelector("[data-vb-filter-twentyeight-input]");
  const buttons = kb.querySelectorAll("[data-faq-topic]");
  const reset = kb.querySelector("[data-vb-filter-twentyeight-reset]");
  const count = kb.querySelector("[data-vb-filter-twentyeight-count]");
  const empty = kb.querySelector("[data-vb-filter-twentyeight-empty]");
  const faqs = Array.from(kb.querySelectorAll("[data-faq-card]"));
  const toggles = kb.querySelectorAll("[data-faq-toggle]");

  let activeTopic = "all";

  function updateFaqs() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    faqs.forEach(function (faq) {
      const topic = faq.getAttribute("data-faq-card");
      const text = faq.getAttribute("data-faq-text").toLowerCase();
      const fullText = faq.textContent.toLowerCase();

      const topicMatch = activeTopic === "all" || topic === activeTopic;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = topicMatch && searchMatch;

      faq.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 FAQ" : visible + " FAQs";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeTopic = button.getAttribute("data-faq-topic");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateFaqs();
    });
  });

  toggles.forEach(function (toggle) {
    toggle.addEventListener("click", function () {
      toggle.closest("[data-faq-card]").classList.toggle("is-open");
    });
  });

  input.addEventListener("input", updateFaqs);

  reset.addEventListener("click", function () {
    activeTopic = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-faq-topic") === "all");
    });

    input.focus();
    updateFaqs();
  });

  updateFaqs();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const kb = document.querySelector("[data-vb-filter-twentyeight]");
  if (!kb) return;

  const input = kb.querySelector("[data-vb-filter-twentyeight-input]");
  const buttons = kb.querySelectorAll("[data-faq-topic]");
  const reset = kb.querySelector("[data-vb-filter-twentyeight-reset]");
  const count = kb.querySelector("[data-vb-filter-twentyeight-count]");
  const empty = kb.querySelector("[data-vb-filter-twentyeight-empty]");
  const faqs = Array.from(kb.querySelectorAll("[data-faq-card]"));
  const toggles = kb.querySelectorAll("[data-faq-toggle]");

  let activeTopic = "all";

  function updateFaqs() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    faqs.forEach(function (faq) {
      const topic = faq.getAttribute("data-faq-card");
      const text = faq.getAttribute("data-faq-text").toLowerCase();
      const fullText = faq.textContent.toLowerCase();

      const topicMatch = activeTopic === "all" || topic === activeTopic;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = topicMatch && searchMatch;

      faq.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 FAQ" : visible + " FAQs";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeTopic = button.getAttribute("data-faq-topic");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateFaqs();
    });
  });

  toggles.forEach(function (toggle) {
    toggle.addEventListener("click", function () {
      toggle.closest("[data-faq-card]").classList.toggle("is-open");
    });
  });

  input.addEventListener("input", updateFaqs);

  reset.addEventListener("click", function () {
    activeTopic = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-faq-topic") === "all");
    });

    input.focus();
    updateFaqs();
  });

  updateFaqs();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-twentyeight-demo"&gt;
  &lt;div class="vb-filter-twentyeight-kb" data-vb-filter-twentyeight&gt;
    &lt;header class="vb-filter-twentyeight-header"&gt;
      &lt;span&gt;Example 28&lt;/span&gt;
      &lt;h3&gt;FAQ Knowledge Base Search Filter&lt;/h3&gt;
      &lt;p&gt;Search support questions by product area, billing topic, setup issue, or help keyword.&lt;/p&gt;
    &lt;/header&gt;

    &lt;div class="vb-filter-twentyeight-layout"&gt;
      &lt;aside class="vb-filter-twentyeight-menu"&gt;
        &lt;button type="button" class="is-active" data-faq-topic="all"&gt;All Questions&lt;/button&gt;
        &lt;button type="button" data-faq-topic="setup"&gt;Setup&lt;/button&gt;
        &lt;button type="button" data-faq-topic="billing"&gt;Billing&lt;/button&gt;
        &lt;button type="button" data-faq-topic="account"&gt;Account&lt;/button&gt;
        &lt;button type="button" data-faq-topic="technical"&gt;Technical&lt;/button&gt;

        &lt;div class="vb-filter-twentyeight-countbox"&gt;
          &lt;small&gt;Visible answers&lt;/small&gt;
          &lt;strong data-vb-filter-twentyeight-count&gt;8 FAQs&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/aside&gt;

      &lt;main class="vb-filter-twentyeight-content"&gt;
        &lt;div class="vb-filter-twentyeight-search"&gt;
          &lt;input type="search" placeholder="Search invoice, setup, password, API, license..." data-vb-filter-twentyeight-input&gt;
          &lt;button type="button" data-vb-filter-twentyeight-reset&gt;Reset&lt;/button&gt;
        &lt;/div&gt;

        &lt;div class="vb-filter-twentyeight-list"&gt;
          &lt;section data-faq-card="setup" data-faq-text="setup install plugin website wordpress getting started"&gt;
            &lt;button type="button" data-faq-toggle&gt;
              &lt;span&gt;Setup&lt;/span&gt;
              &lt;strong&gt;How do I install the plugin?&lt;/strong&gt;
            &lt;/button&gt;
            &lt;div class="vb-filter-twentyeight-answer"&gt;
              &lt;p&gt;Upload the plugin ZIP file, activate it in WordPress, open the settings page, and follow the setup checklist.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/section&gt;

          &lt;section data-faq-card="billing" data-faq-text="billing invoice receipt payment vat company details"&gt;
            &lt;button type="button" data-faq-toggle&gt;
              &lt;span&gt;Billing&lt;/span&gt;
              &lt;strong&gt;Where can I find my invoice?&lt;/strong&gt;
            &lt;/button&gt;
            &lt;div class="vb-filter-twentyeight-answer"&gt;
              &lt;p&gt;You can find invoices in the billing area. Update company details before downloading the final invoice copy.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/section&gt;

          &lt;section data-faq-card="account" data-faq-text="account password reset login email access"&gt;
            &lt;button type="button" data-faq-toggle&gt;
              &lt;span&gt;Account&lt;/span&gt;
              &lt;strong&gt;How do I reset my password?&lt;/strong&gt;
            &lt;/button&gt;
            &lt;div class="vb-filter-twentyeight-answer"&gt;
              &lt;p&gt;Use the password reset link on the login page. A secure reset email will be sent to your account address.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/section&gt;

          &lt;section data-faq-card="technical" data-faq-text="technical api webhook endpoint integration token"&gt;
            &lt;button type="button" data-faq-toggle&gt;
              &lt;span&gt;Technical&lt;/span&gt;
              &lt;strong&gt;How do webhooks work?&lt;/strong&gt;
            &lt;/button&gt;
            &lt;div class="vb-filter-twentyeight-answer"&gt;
              &lt;p&gt;Webhooks send event payloads to your endpoint when important actions happen, such as orders or account updates.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/section&gt;

          &lt;section data-faq-card="setup" data-faq-text="setup shortcode embed page gutenberg block"&gt;
            &lt;button type="button" data-faq-toggle&gt;
              &lt;span&gt;Setup&lt;/span&gt;
              &lt;strong&gt;Can I use a shortcode?&lt;/strong&gt;
            &lt;/button&gt;
            &lt;div class="vb-filter-twentyeight-answer"&gt;
              &lt;p&gt;Yes. Add the shortcode to a page, post, or Gutenberg block where you want the frontend component to appear.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/section&gt;

          &lt;section data-faq-card="billing" data-faq-text="billing subscription cancel plan renewal license"&gt;
            &lt;button type="button" data-faq-toggle&gt;
              &lt;span&gt;Billing&lt;/span&gt;
              &lt;strong&gt;Can I cancel my subscription?&lt;/strong&gt;
            &lt;/button&gt;
            &lt;div class="vb-filter-twentyeight-answer"&gt;
              &lt;p&gt;Yes. You can cancel renewal from your billing dashboard. Your license remains active until the paid period ends.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/section&gt;

          &lt;section data-faq-card="account" data-faq-text="account email change profile settings user"&gt;
            &lt;button type="button" data-faq-toggle&gt;
              &lt;span&gt;Account&lt;/span&gt;
              &lt;strong&gt;Can I change my account email?&lt;/strong&gt;
            &lt;/button&gt;
            &lt;div class="vb-filter-twentyeight-answer"&gt;
              &lt;p&gt;Open profile settings, update the email field, and confirm the change from the verification email.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/section&gt;

          &lt;section data-faq-card="technical" data-faq-text="technical cache css javascript not loading conflict"&gt;
            &lt;button type="button" data-faq-toggle&gt;
              &lt;span&gt;Technical&lt;/span&gt;
              &lt;strong&gt;Why is my CSS not loading?&lt;/strong&gt;
            &lt;/button&gt;
            &lt;div class="vb-filter-twentyeight-answer"&gt;
              &lt;p&gt;Clear cache, check the file path, confirm the stylesheet is enqueued, and inspect the browser console for 404 errors.&lt;/p&gt;
            &lt;/div&gt;
          &lt;/section&gt;
        &lt;/div&gt;

        &lt;div class="vb-filter-twentyeight-empty" data-vb-filter-twentyeight-empty&gt;
          &lt;strong&gt;No FAQ answers found.&lt;/strong&gt;
          &lt;p&gt;Try searching for setup, invoice, password, webhook, shortcode, subscription, email, or CSS.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/main&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-twentyeight-demo,
.vb-filter-twentyeight-demo * {
  box-sizing: border-box;
}

.vb-filter-twentyeight-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(168, 85, 247, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(14, 165, 233, 0.20), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #f0f9ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(221, 214, 254, 0.58);
  box-shadow: 0 24px 70px rgba(88, 28, 135, 0.10);
}

.vb-filter-twentyeight-kb {
  max-width: 1080px;
  margin: 0 auto;
  padding: 30px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-twentyeight-header {
  max-width: 780px;
  margin-bottom: 24px;
}

.vb-filter-twentyeight-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-twentyeight-header h3 {
  margin: 0 0 12px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-twentyeight-header p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-twentyeight-layout {
  display: grid;
  grid-template-columns: 250px minmax(0, 1fr);
  gap: 16px;
}

.vb-filter-twentyeight-menu {
  align-self: start;
  display: grid;
  gap: 8px;
  padding: 16px;
  border-radius: 24px;
  background: #111827;
}

.vb-filter-twentyeight-menu button {
  min-height: 42px;
  padding: 9px 12px;
  border: 1px solid rgba(255,255,255,0.12);
  border-radius: 14px;
  background: rgba(255,255,255,0.08);
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 13px;
  font-weight: 900;
  text-align: left;
  cursor: pointer;
}

.vb-filter-twentyeight-menu button.is-active,
.vb-filter-twentyeight-menu button:hover {
  background: linear-gradient(135deg, #a855f7, #0ea5e9);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-twentyeight-countbox {
  margin-top: 8px;
  padding: 14px;
  border-radius: 18px;
  background: rgba(255,255,255,0.08);
}

.vb-filter-twentyeight-countbox small {
  display: block;
  margin-bottom: 6px;
  color: #d8b4fe !important;
  -webkit-text-fill-color: #d8b4fe !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-twentyeight-countbox strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 19px;
  font-weight: 950;
}

.vb-filter-twentyeight-search {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 10px;
  margin-bottom: 12px;
  padding: 12px;
  border-radius: 22px;
  background: #f8fafc;
}

.vb-filter-twentyeight-search input {
  width: 100%;
  min-height: 50px;
  padding: 0 15px;
  border: 1px solid rgba(148, 163, 184, 0.26);
  border-radius: 16px;
  outline: 0;
  background: #ffffff;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-twentyeight-search button {
  min-height: 50px;
  padding: 0 16px;
  border: 0;
  border-radius: 16px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-twentyeight-list {
  display: grid;
  gap: 10px;
}

.vb-filter-twentyeight-list section {
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 12px 28px rgba(15, 23, 42, 0.05);
  overflow: hidden;
}

.vb-filter-twentyeight-list section.is-hidden {
  display: none;
}

.vb-filter-twentyeight-list section > button {
  display: grid;
  grid-template-columns: 94px minmax(0, 1fr);
  gap: 14px;
  align-items: center;
  width: 100%;
  padding: 18px;
  border: 0;
  background: transparent;
  text-align: left;
  cursor: pointer;
}

.vb-filter-twentyeight-list section > button span {
  display: inline-flex;
  justify-content: center;
  padding: 7px 9px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-twentyeight-list section > button strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
}

.vb-filter-twentyeight-answer {
  display: none;
  padding: 0 18px 18px 126px;
}

.vb-filter-twentyeight-list section.is-open .vb-filter-twentyeight-answer {
  display: block;
}

.vb-filter-twentyeight-answer p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-filter-twentyeight-empty {
  display: none;
  margin-top: 14px;
  padding: 20px;
  border-radius: 20px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.34);
}

.vb-filter-twentyeight-empty.is-visible {
  display: block;
}

.vb-filter-twentyeight-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-twentyeight-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 860px) {
  .vb-filter-twentyeight-layout {
    grid-template-columns: 1fr;
  }

  .vb-filter-twentyeight-menu {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-filter-twentyeight-countbox {
    grid-column: 1 / -1;
  }
}

@media (max-width: 640px) {
  .vb-filter-twentyeight-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-twentyeight-kb {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-twentyeight-header h3 {
    font-size: 38px !important;
  }

  .vb-filter-twentyeight-menu,
  .vb-filter-twentyeight-search,
  .vb-filter-twentyeight-list section > button {
    grid-template-columns: 1fr;
  }

  .vb-filter-twentyeight-answer {
    padding: 0 18px 18px;
  }
}</pre>



<p class="wp-block-paragraph">This FAQ knowledge base search filter is useful for support centers, SaaS help pages, product FAQs, plugin documentation, onboarding resources, customer support portals, and searchable help sections.</p>



<h2 class="wp-block-heading">29. Team Directory Search Filter</h2>



<p class="wp-block-paragraph"><strong>A team directory search filter</strong> helps visitors find team members by role, department, location, skill, or keyword. This layout is useful for agency websites, company team pages, employee directories, SaaS about pages, startup websites, and internal staff dashboards.</p>



<p class="wp-block-paragraph">This example uses a modern people directory layout with profile cards, department filters, skill tags, location labels, and a live result count. Users can search names, roles, departments, locations, and skills.</p>



<ul class="wp-block-list">
<li>Team directory search layout</li>
<li>Filters people by department and keyword</li>
<li>Profile cards with role, location, and skills</li>
<li>Searches name, title, department, and skill text</li>
<li>Useful for team pages, employee directories, and company websites</li>
</ul>



<div class="vb-filter-twentynine-demo">
  <div class="vb-filter-twentynine-team" data-vb-filter-twentynine>
    <header class="vb-filter-twentynine-header">
      <div>
        <span>Example 29</span>
        <h3>Team Directory Search Filter</h3>
        <p>Search team members by department, role, location, skill, or keyword.</p>
      </div>

      <div class="vb-filter-twentynine-countbox">
        <small>Visible members</small>
        <strong data-vb-filter-twentynine-count>8 members</strong>
      </div>
    </header>

    <div class="vb-filter-twentynine-controls">
      <input type="search" placeholder="Search designer, developer, Tallinn, SEO..." data-vb-filter-twentynine-input>

      <div class="vb-filter-twentynine-tabs">
        <button type="button" class="is-active" data-member-dept="all">All</button>
        <button type="button" data-member-dept="design">Design</button>
        <button type="button" data-member-dept="development">Development</button>
        <button type="button" data-member-dept="marketing">Marketing</button>
        <button type="button" data-member-dept="operations">Operations</button>
      </div>

      <button type="button" class="vb-filter-twentynine-reset" data-vb-filter-twentynine-reset>Reset</button>
    </div>

    <div class="vb-filter-twentynine-grid">
      <article data-member-card="design" data-member-text="mia product designer design figma ux ui tallinn">
        <div class="vb-filter-twentynine-avatar avatar-one">M</div>
        <small>Design · Tallinn</small>
        <h4>Mia Carter</h4>
        <p>Product designer focused on SaaS dashboards, onboarding screens, and design systems.</p>
        <div><span>Figma</span><span>UX</span><span>UI</span></div>
      </article>

      <article data-member-card="development" data-member-text="leo frontend developer javascript react css berlin">
        <div class="vb-filter-twentynine-avatar avatar-two">L</div>
        <small>Development · Berlin</small>
        <h4>Leo Martin</h4>
        <p>Frontend developer building JavaScript interfaces, reusable components, and responsive layouts.</p>
        <div><span>JavaScript</span><span>React</span><span>CSS</span></div>
      </article>

      <article data-member-card="marketing" data-member-text="sofia seo strategist marketing content keywords lisbon">
        <div class="vb-filter-twentynine-avatar avatar-three">S</div>
        <small>Marketing · Lisbon</small>
        <h4>Sofia Lane</h4>
        <p>SEO strategist planning content clusters, internal links, keyword maps, and organic growth.</p>
        <div><span>SEO</span><span>Content</span><span>Analytics</span></div>
      </article>

      <article data-member-card="operations" data-member-text="noah operations manager process systems support stockholm">
        <div class="vb-filter-twentynine-avatar avatar-four">N</div>
        <small>Operations · Stockholm</small>
        <h4>Noah Brooks</h4>
        <p>Operations manager improving delivery workflows, support systems, and team processes.</p>
        <div><span>Process</span><span>Support</span><span>Systems</span></div>
      </article>

      <article data-member-card="development" data-member-text="ava backend developer api database node remote">
        <div class="vb-filter-twentynine-avatar avatar-five">A</div>
        <small>Development · Remote</small>
        <h4>Ava Wilson</h4>
        <p>Backend developer creating APIs, database structures, webhooks, and automation logic.</p>
        <div><span>API</span><span>Node</span><span>Database</span></div>
      </article>

      <article data-member-card="design" data-member-text="emil brand designer visual identity graphics riga">
        <div class="vb-filter-twentynine-avatar avatar-six">E</div>
        <small>Design · Riga</small>
        <h4>Emil Stone</h4>
        <p>Brand designer creating visual identity systems, campaign assets, and website graphics.</p>
        <div><span>Branding</span><span>Visuals</span><span>Graphics</span></div>
      </article>

      <article data-member-card="marketing" data-member-text="lena growth marketer ads funnels conversion paris">
        <div class="vb-filter-twentynine-avatar avatar-seven">L</div>
        <small>Marketing · Paris</small>
        <h4>Lena Fox</h4>
        <p>Growth marketer testing campaigns, landing pages, funnels, and conversion experiments.</p>
        <div><span>Ads</span><span>Funnels</span><span>CRO</span></div>
      </article>

      <article data-member-card="operations" data-member-text="ivan project coordinator operations clients delivery tallinn">
        <div class="vb-filter-twentynine-avatar avatar-eight">I</div>
        <small>Operations · Tallinn</small>
        <h4>Ivan Reed</h4>
        <p>Project coordinator managing client timelines, delivery checklists, and production tasks.</p>
        <div><span>Clients</span><span>Delivery</span><span>Planning</span></div>
      </article>
    </div>

    <div class="vb-filter-twentynine-empty" data-vb-filter-twentynine-empty>
      <strong>No team members found.</strong>
      <p>Try searching for designer, developer, SEO, Tallinn, API, marketing, support, or Figma.</p>
    </div>
  </div>
</div>

<style>
.vb-filter-twentynine-demo,
.vb-filter-twentynine-demo * {
  box-sizing: border-box;
}

.vb-filter-twentynine-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(236, 72, 153, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(99, 102, 241, 0.20), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(251, 207, 232, 0.58);
  box-shadow: 0 24px 70px rgba(157, 23, 77, 0.10);
}

.vb-filter-twentynine-team {
  max-width: 1140px;
  margin: 0 auto;
  padding: 30px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-twentynine-header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 190px;
  gap: 24px;
  align-items: end;
  margin-bottom: 20px;
}

.vb-filter-twentynine-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fce7f3;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-twentynine-header h3 {
  margin: 0 0 12px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-twentynine-header p {
  max-width: 720px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-twentynine-countbox {
  padding: 18px;
  border-radius: 24px;
  background: #111827;
}

.vb-filter-twentynine-countbox small {
  display: block;
  margin-bottom: 7px;
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-twentynine-countbox strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 21px;
  font-weight: 950;
}

.vb-filter-twentynine-controls {
  display: grid;
  grid-template-columns: minmax(260px, 0.85fr) minmax(0, 1.15fr) auto;
  gap: 10px;
  align-items: center;
  margin-bottom: 18px;
  padding: 14px;
  border-radius: 24px;
  background: #f8fafc;
}

.vb-filter-twentynine-controls input {
  width: 100%;
  min-height: 52px;
  padding: 0 15px;
  border: 1px solid rgba(148, 163, 184, 0.28);
  border-radius: 16px;
  outline: 0;
  background: #ffffff;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-twentynine-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-filter-twentynine-tabs button,
.vb-filter-twentynine-reset {
  min-height: 42px;
  padding: 9px 13px;
  border: 0;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-twentynine-tabs button {
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  box-shadow: 0 8px 20px rgba(15, 23, 42, 0.05);
}

.vb-filter-twentynine-tabs button.is-active,
.vb-filter-twentynine-tabs button:hover {
  background: linear-gradient(135deg, #ec4899, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-twentynine-reset {
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-twentynine-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-filter-twentynine-grid article {
  padding: 20px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb-filter-twentynine-grid article.is-hidden {
  display: none;
}

.vb-filter-twentynine-avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 72px;
  height: 72px;
  margin-bottom: 14px;
  border-radius: 24px;
  background: linear-gradient(135deg, #ec4899, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 28px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(99, 102, 241, 0.22);
}

.vb-filter-twentynine-avatar.avatar-two {
  background: linear-gradient(135deg, #2563eb, #06b6d4);
}

.vb-filter-twentynine-avatar.avatar-three {
  background: linear-gradient(135deg, #16a34a, #84cc16);
}

.vb-filter-twentynine-avatar.avatar-four {
  background: linear-gradient(135deg, #f97316, #dc2626);
}

.vb-filter-twentynine-avatar.avatar-five {
  background: linear-gradient(135deg, #0f766e, #14b8a6);
}

.vb-filter-twentynine-avatar.avatar-six {
  background: linear-gradient(135deg, #7c3aed, #d946ef);
}

.vb-filter-twentynine-avatar.avatar-seven {
  background: linear-gradient(135deg, #f59e0b, #ec4899);
}

.vb-filter-twentynine-avatar.avatar-eight {
  background: linear-gradient(135deg, #334155, #6366f1);
}

.vb-filter-twentynine-grid small {
  display: inline-flex;
  margin-bottom: 9px;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-filter-twentynine-grid h4 {
  margin: 0 0 8px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-twentynine-grid p {
  margin: 0 0 14px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-filter-twentynine-grid article div:last-child {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.vb-filter-twentynine-grid article div:last-child span {
  padding: 6px 8px;
  border-radius: 999px;
  background: #f1f5f9;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 11px;
  font-weight: 900;
}

.vb-filter-twentynine-empty {
  display: none;
  margin-top: 16px;
  padding: 22px;
  border-radius: 22px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.34);
}

.vb-filter-twentynine-empty.is-visible {
  display: block;
}

.vb-filter-twentynine-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-twentynine-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 1040px) {
  .vb-filter-twentynine-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-filter-twentynine-header,
  .vb-filter-twentynine-controls {
    grid-template-columns: 1fr;
  }

  .vb-filter-twentynine-countbox,
  .vb-filter-twentynine-reset {
    width: fit-content;
  }
}

@media (max-width: 640px) {
  .vb-filter-twentynine-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-twentynine-team {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-twentynine-header h3 {
    font-size: 38px !important;
  }

  .vb-filter-twentynine-tabs {
    display: grid;
    grid-template-columns: 1fr;
  }

  .vb-filter-twentynine-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const team = document.querySelector("[data-vb-filter-twentynine]");
  if (!team) return;

  const input = team.querySelector("[data-vb-filter-twentynine-input]");
  const buttons = team.querySelectorAll("[data-member-dept]");
  const reset = team.querySelector("[data-vb-filter-twentynine-reset]");
  const count = team.querySelector("[data-vb-filter-twentynine-count]");
  const empty = team.querySelector("[data-vb-filter-twentynine-empty]");
  const members = Array.from(team.querySelectorAll("[data-member-card]"));

  let activeDept = "all";

  function updateMembers() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    members.forEach(function (member) {
      const dept = member.getAttribute("data-member-card");
      const text = member.getAttribute("data-member-text").toLowerCase();
      const fullText = member.textContent.toLowerCase();

      const deptMatch = activeDept === "all" || dept === activeDept;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = deptMatch && searchMatch;

      member.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 member" : visible + " members";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeDept = button.getAttribute("data-member-dept");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateMembers();
    });
  });

  input.addEventListener("input", updateMembers);

  reset.addEventListener("click", function () {
    activeDept = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-member-dept") === "all");
    });

    input.focus();
    updateMembers();
  });

  updateMembers();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const team = document.querySelector("[data-vb-filter-twentynine]");
  if (!team) return;

  const input = team.querySelector("[data-vb-filter-twentynine-input]");
  const buttons = team.querySelectorAll("[data-member-dept]");
  const reset = team.querySelector("[data-vb-filter-twentynine-reset]");
  const count = team.querySelector("[data-vb-filter-twentynine-count]");
  const empty = team.querySelector("[data-vb-filter-twentynine-empty]");
  const members = Array.from(team.querySelectorAll("[data-member-card]"));

  let activeDept = "all";

  function updateMembers() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    members.forEach(function (member) {
      const dept = member.getAttribute("data-member-card");
      const text = member.getAttribute("data-member-text").toLowerCase();
      const fullText = member.textContent.toLowerCase();

      const deptMatch = activeDept === "all" || dept === activeDept;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = deptMatch && searchMatch;

      member.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 member" : visible + " members";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeDept = button.getAttribute("data-member-dept");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateMembers();
    });
  });

  input.addEventListener("input", updateMembers);

  reset.addEventListener("click", function () {
    activeDept = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-member-dept") === "all");
    });

    input.focus();
    updateMembers();
  });

  updateMembers();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-twentynine-demo"&gt;
  &lt;div class="vb-filter-twentynine-team" data-vb-filter-twentynine&gt;
    &lt;header class="vb-filter-twentynine-header"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 29&lt;/span&gt;
        &lt;h3&gt;Team Directory Search Filter&lt;/h3&gt;
        &lt;p&gt;Search team members by department, role, location, skill, or keyword.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-twentynine-countbox"&gt;
        &lt;small&gt;Visible members&lt;/small&gt;
        &lt;strong data-vb-filter-twentynine-count&gt;8 members&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/header&gt;

    &lt;div class="vb-filter-twentynine-controls"&gt;
      &lt;input type="search" placeholder="Search designer, developer, Tallinn, SEO..." data-vb-filter-twentynine-input&gt;

      &lt;div class="vb-filter-twentynine-tabs"&gt;
        &lt;button type="button" class="is-active" data-member-dept="all"&gt;All&lt;/button&gt;
        &lt;button type="button" data-member-dept="design"&gt;Design&lt;/button&gt;
        &lt;button type="button" data-member-dept="development"&gt;Development&lt;/button&gt;
        &lt;button type="button" data-member-dept="marketing"&gt;Marketing&lt;/button&gt;
        &lt;button type="button" data-member-dept="operations"&gt;Operations&lt;/button&gt;
      &lt;/div&gt;

      &lt;button type="button" class="vb-filter-twentynine-reset" data-vb-filter-twentynine-reset&gt;Reset&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-twentynine-grid"&gt;
      &lt;article data-member-card="design" data-member-text="mia product designer design figma ux ui tallinn"&gt;
        &lt;div class="vb-filter-twentynine-avatar avatar-one"&gt;M&lt;/div&gt;
        &lt;small&gt;Design · Tallinn&lt;/small&gt;
        &lt;h4&gt;Mia Carter&lt;/h4&gt;
        &lt;p&gt;Product designer focused on SaaS dashboards, onboarding screens, and design systems.&lt;/p&gt;
        &lt;div&gt;&lt;span&gt;Figma&lt;/span&gt;&lt;span&gt;UX&lt;/span&gt;&lt;span&gt;UI&lt;/span&gt;&lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-member-card="development" data-member-text="leo frontend developer javascript react css berlin"&gt;
        &lt;div class="vb-filter-twentynine-avatar avatar-two"&gt;L&lt;/div&gt;
        &lt;small&gt;Development · Berlin&lt;/small&gt;
        &lt;h4&gt;Leo Martin&lt;/h4&gt;
        &lt;p&gt;Frontend developer building JavaScript interfaces, reusable components, and responsive layouts.&lt;/p&gt;
        &lt;div&gt;&lt;span&gt;JavaScript&lt;/span&gt;&lt;span&gt;React&lt;/span&gt;&lt;span&gt;CSS&lt;/span&gt;&lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-member-card="marketing" data-member-text="sofia seo strategist marketing content keywords lisbon"&gt;
        &lt;div class="vb-filter-twentynine-avatar avatar-three"&gt;S&lt;/div&gt;
        &lt;small&gt;Marketing · Lisbon&lt;/small&gt;
        &lt;h4&gt;Sofia Lane&lt;/h4&gt;
        &lt;p&gt;SEO strategist planning content clusters, internal links, keyword maps, and organic growth.&lt;/p&gt;
        &lt;div&gt;&lt;span&gt;SEO&lt;/span&gt;&lt;span&gt;Content&lt;/span&gt;&lt;span&gt;Analytics&lt;/span&gt;&lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-member-card="operations" data-member-text="noah operations manager process systems support stockholm"&gt;
        &lt;div class="vb-filter-twentynine-avatar avatar-four"&gt;N&lt;/div&gt;
        &lt;small&gt;Operations · Stockholm&lt;/small&gt;
        &lt;h4&gt;Noah Brooks&lt;/h4&gt;
        &lt;p&gt;Operations manager improving delivery workflows, support systems, and team processes.&lt;/p&gt;
        &lt;div&gt;&lt;span&gt;Process&lt;/span&gt;&lt;span&gt;Support&lt;/span&gt;&lt;span&gt;Systems&lt;/span&gt;&lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-member-card="development" data-member-text="ava backend developer api database node remote"&gt;
        &lt;div class="vb-filter-twentynine-avatar avatar-five"&gt;A&lt;/div&gt;
        &lt;small&gt;Development · Remote&lt;/small&gt;
        &lt;h4&gt;Ava Wilson&lt;/h4&gt;
        &lt;p&gt;Backend developer creating APIs, database structures, webhooks, and automation logic.&lt;/p&gt;
        &lt;div&gt;&lt;span&gt;API&lt;/span&gt;&lt;span&gt;Node&lt;/span&gt;&lt;span&gt;Database&lt;/span&gt;&lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-member-card="design" data-member-text="emil brand designer visual identity graphics riga"&gt;
        &lt;div class="vb-filter-twentynine-avatar avatar-six"&gt;E&lt;/div&gt;
        &lt;small&gt;Design · Riga&lt;/small&gt;
        &lt;h4&gt;Emil Stone&lt;/h4&gt;
        &lt;p&gt;Brand designer creating visual identity systems, campaign assets, and website graphics.&lt;/p&gt;
        &lt;div&gt;&lt;span&gt;Branding&lt;/span&gt;&lt;span&gt;Visuals&lt;/span&gt;&lt;span&gt;Graphics&lt;/span&gt;&lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-member-card="marketing" data-member-text="lena growth marketer ads funnels conversion paris"&gt;
        &lt;div class="vb-filter-twentynine-avatar avatar-seven"&gt;L&lt;/div&gt;
        &lt;small&gt;Marketing · Paris&lt;/small&gt;
        &lt;h4&gt;Lena Fox&lt;/h4&gt;
        &lt;p&gt;Growth marketer testing campaigns, landing pages, funnels, and conversion experiments.&lt;/p&gt;
        &lt;div&gt;&lt;span&gt;Ads&lt;/span&gt;&lt;span&gt;Funnels&lt;/span&gt;&lt;span&gt;CRO&lt;/span&gt;&lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-member-card="operations" data-member-text="ivan project coordinator operations clients delivery tallinn"&gt;
        &lt;div class="vb-filter-twentynine-avatar avatar-eight"&gt;I&lt;/div&gt;
        &lt;small&gt;Operations · Tallinn&lt;/small&gt;
        &lt;h4&gt;Ivan Reed&lt;/h4&gt;
        &lt;p&gt;Project coordinator managing client timelines, delivery checklists, and production tasks.&lt;/p&gt;
        &lt;div&gt;&lt;span&gt;Clients&lt;/span&gt;&lt;span&gt;Delivery&lt;/span&gt;&lt;span&gt;Planning&lt;/span&gt;&lt;/div&gt;
      &lt;/article&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-twentynine-empty" data-vb-filter-twentynine-empty&gt;
      &lt;strong&gt;No team members found.&lt;/strong&gt;
      &lt;p&gt;Try searching for designer, developer, SEO, Tallinn, API, marketing, support, or Figma.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-twentynine-demo,
.vb-filter-twentynine-demo * {
  box-sizing: border-box;
}

.vb-filter-twentynine-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(236, 72, 153, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(99, 102, 241, 0.20), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(251, 207, 232, 0.58);
  box-shadow: 0 24px 70px rgba(157, 23, 77, 0.10);
}

.vb-filter-twentynine-team {
  max-width: 1140px;
  margin: 0 auto;
  padding: 30px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
}

.vb-filter-twentynine-header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 190px;
  gap: 24px;
  align-items: end;
  margin-bottom: 20px;
}

.vb-filter-twentynine-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fce7f3;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-twentynine-header h3 {
  margin: 0 0 12px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.075em;
}

.vb-filter-twentynine-header p {
  max-width: 720px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-twentynine-countbox {
  padding: 18px;
  border-radius: 24px;
  background: #111827;
}

.vb-filter-twentynine-countbox small {
  display: block;
  margin-bottom: 7px;
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-filter-twentynine-countbox strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 21px;
  font-weight: 950;
}

.vb-filter-twentynine-controls {
  display: grid;
  grid-template-columns: minmax(260px, 0.85fr) minmax(0, 1.15fr) auto;
  gap: 10px;
  align-items: center;
  margin-bottom: 18px;
  padding: 14px;
  border-radius: 24px;
  background: #f8fafc;
}

.vb-filter-twentynine-controls input {
  width: 100%;
  min-height: 52px;
  padding: 0 15px;
  border: 1px solid rgba(148, 163, 184, 0.28);
  border-radius: 16px;
  outline: 0;
  background: #ffffff;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-twentynine-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-filter-twentynine-tabs button,
.vb-filter-twentynine-reset {
  min-height: 42px;
  padding: 9px 13px;
  border: 0;
  border-radius: 999px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-twentynine-tabs button {
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  box-shadow: 0 8px 20px rgba(15, 23, 42, 0.05);
}

.vb-filter-twentynine-tabs button.is-active,
.vb-filter-twentynine-tabs button:hover {
  background: linear-gradient(135deg, #ec4899, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-twentynine-reset {
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-twentynine-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-filter-twentynine-grid article {
  padding: 20px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb-filter-twentynine-grid article.is-hidden {
  display: none;
}

.vb-filter-twentynine-avatar {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 72px;
  height: 72px;
  margin-bottom: 14px;
  border-radius: 24px;
  background: linear-gradient(135deg, #ec4899, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 28px;
  font-weight: 950;
  box-shadow: 0 16px 34px rgba(99, 102, 241, 0.22);
}

.vb-filter-twentynine-avatar.avatar-two {
  background: linear-gradient(135deg, #2563eb, #06b6d4);
}

.vb-filter-twentynine-avatar.avatar-three {
  background: linear-gradient(135deg, #16a34a, #84cc16);
}

.vb-filter-twentynine-avatar.avatar-four {
  background: linear-gradient(135deg, #f97316, #dc2626);
}

.vb-filter-twentynine-avatar.avatar-five {
  background: linear-gradient(135deg, #0f766e, #14b8a6);
}

.vb-filter-twentynine-avatar.avatar-six {
  background: linear-gradient(135deg, #7c3aed, #d946ef);
}

.vb-filter-twentynine-avatar.avatar-seven {
  background: linear-gradient(135deg, #f59e0b, #ec4899);
}

.vb-filter-twentynine-avatar.avatar-eight {
  background: linear-gradient(135deg, #334155, #6366f1);
}

.vb-filter-twentynine-grid small {
  display: inline-flex;
  margin-bottom: 9px;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-filter-twentynine-grid h4 {
  margin: 0 0 8px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-filter-twentynine-grid p {
  margin: 0 0 14px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-filter-twentynine-grid article div:last-child {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.vb-filter-twentynine-grid article div:last-child span {
  padding: 6px 8px;
  border-radius: 999px;
  background: #f1f5f9;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 11px;
  font-weight: 900;
}

.vb-filter-twentynine-empty {
  display: none;
  margin-top: 16px;
  padding: 22px;
  border-radius: 22px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.34);
}

.vb-filter-twentynine-empty.is-visible {
  display: block;
}

.vb-filter-twentynine-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-twentynine-empty p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 1040px) {
  .vb-filter-twentynine-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-filter-twentynine-header,
  .vb-filter-twentynine-controls {
    grid-template-columns: 1fr;
  }

  .vb-filter-twentynine-countbox,
  .vb-filter-twentynine-reset {
    width: fit-content;
  }
}

@media (max-width: 640px) {
  .vb-filter-twentynine-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-twentynine-team {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-twentynine-header h3 {
    font-size: 38px !important;
  }

  .vb-filter-twentynine-tabs {
    display: grid;
    grid-template-columns: 1fr;
  }

  .vb-filter-twentynine-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This team directory search filter is useful for agency team pages, SaaS company websites, startup about pages, employee directories, staff dashboards, consultant directories, and people-based content sections.</p>



<h2 class="wp-block-heading">30. Complete Responsive Search Filter Section</h2>



<p class="wp-block-paragraph"><strong>A complete responsive search filter section</strong> combines search input, category buttons, result cards, a result counter, reset behavior, and a no-results state into one polished interface. This is a strong final example because it can be adapted to portfolios, products, blog posts, resources, tools, templates, services, and content libraries.</p>



<p class="wp-block-paragraph">This example uses a balanced responsive layout with modern cards, strong mobile behavior, full keyword filtering, category filtering, and a clean empty state. It is designed as a reusable search filter component for real website projects.</p>



<ul class="wp-block-list">
<li>Complete responsive search filter layout</li>
<li>Search input, category buttons, reset button, and result counter</li>
<li>Reusable card system for many website sections</li>
<li>Mobile-friendly layout</li>
<li>Useful for portfolios, resource libraries, tools, services, templates, and product sections</li>
</ul>



<div class="vb-filter-thirty-demo">
  <div class="vb-filter-thirty-section" data-vb-filter-thirty>
    <header class="vb-filter-thirty-hero">
      <span>Example 30</span>
      <h3>Complete Responsive Search Filter Section</h3>
      <p>Search and filter reusable website resources by category, keyword, topic, or content type.</p>
    </header>

    <div class="vb-filter-thirty-toolbar">
      <input type="search" placeholder="Search templates, components, guides, tools..." data-vb-filter-thirty-input>

      <div class="vb-filter-thirty-buttons">
        <button type="button" class="is-active" data-resource-type="all">All</button>
        <button type="button" data-resource-type="template">Templates</button>
        <button type="button" data-resource-type="component">Components</button>
        <button type="button" data-resource-type="guide">Guides</button>
        <button type="button" data-resource-type="tool">Tools</button>
      </div>

      <div class="vb-filter-thirty-meta">
        <strong data-vb-filter-thirty-count>8 resources</strong>
        <button type="button" data-vb-filter-thirty-reset>Reset</button>
      </div>
    </div>

    <div class="vb-filter-thirty-grid">
      <article data-resource-card="template" data-resource-text="template landing page hero pricing responsive business">
        <small>Template</small>
        <h4>Landing Page Template</h4>
        <p>A complete landing page layout with hero section, feature cards, pricing, FAQ, and CTA area.</p>
        <span>HTML + CSS</span>
      </article>

      <article data-resource-card="component" data-resource-text="component javascript modal popup dialog overlay ui">
        <small>Component</small>
        <h4>JavaScript Modal UI</h4>
        <p>Reusable popup component with open, close, overlay click, and keyboard-friendly structure.</p>
        <span>JavaScript</span>
      </article>

      <article data-resource-card="guide" data-resource-text="guide seo internal linking article structure blog">
        <small>Guide</small>
        <h4>SEO Article Structure</h4>
        <p>Guide for writing better headings, internal links, examples, FAQ sections, and metadata.</p>
        <span>SEO</span>
      </article>

      <article data-resource-card="tool" data-resource-text="tool color palette generator ui design gradients">
        <small>Tool</small>
        <h4>UI Color Palette Tool</h4>
        <p>A small helper tool for planning gradients, backgrounds, contrast, and reusable UI colors.</p>
        <span>Design</span>
      </article>

      <article data-resource-card="component" data-resource-text="component search filter cards table directory javascript">
        <small>Component</small>
        <h4>Search Filter Component</h4>
        <p>Reusable live search pattern for cards, tables, directories, products, posts, and listings.</p>
        <span>JavaScript</span>
      </article>

      <article data-resource-card="template" data-resource-text="template dashboard admin analytics cards sidebar">
        <small>Template</small>
        <h4>Dashboard UI Template</h4>
        <p>Admin dashboard layout with sidebar navigation, analytics cards, tables, and action panels.</p>
        <span>Dashboard</span>
      </article>

      <article data-resource-card="guide" data-resource-text="guide accessibility keyboard aria focus javascript components">
        <small>Guide</small>
        <h4>Accessible Components Guide</h4>
        <p>Accessibility guide for focus states, ARIA labels, keyboard navigation, and semantic markup.</p>
        <span>A11y</span>
      </article>

      <article data-resource-card="tool" data-resource-text="tool css shadow generator cards buttons layout">
        <small>Tool</small>
        <h4>CSS Shadow Generator</h4>
        <p>Generate clean card shadows, button shadows, layered panels, and soft interface depth.</p>
        <span>CSS Tool</span>
      </article>
    </div>

    <div class="vb-filter-thirty-empty" data-vb-filter-thirty-empty>
      <strong>No resources found.</strong>
      <p>Try searching for templates, JavaScript, SEO, dashboard, modal, accessibility, CSS, or tools.</p>
    </div>
  </div>
</div>

<style>
.vb-filter-thirty-demo,
.vb-filter-thirty-demo * {
  box-sizing: border-box;
}

.vb-filter-thirty-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(59, 130, 246, 0.22), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(236, 72, 153, 0.18), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #fdf2f8 52%, #ffffff 100%) !important;
  border: 1px solid rgba(191, 219, 254, 0.58);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.10);
}

.vb-filter-thirty-section {
  max-width: 1120px;
  margin: 0 auto;
  padding: 30px;
  border-radius: 30px;
  background: #0f172a;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
}

.vb-filter-thirty-hero {
  max-width: 800px;
  margin-bottom: 22px;
}

.vb-filter-thirty-hero span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(59, 130, 246, 0.16);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-thirty-hero h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 5vw, 72px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-filter-thirty-hero p {
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-thirty-toolbar {
  display: grid;
  grid-template-columns: minmax(260px, 0.85fr) minmax(0, 1.15fr) 170px;
  gap: 12px;
  align-items: center;
  margin-bottom: 18px;
  padding: 14px;
  border-radius: 24px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-filter-thirty-toolbar input {
  width: 100%;
  min-height: 54px;
  padding: 0 16px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 17px;
  outline: 0;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-thirty-toolbar input::placeholder {
  color: rgba(255,255,255,0.58);
  -webkit-text-fill-color: rgba(255,255,255,0.58);
}

.vb-filter-thirty-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-filter-thirty-buttons button {
  min-height: 42px;
  padding: 9px 13px;
  border: 1px solid rgba(255,255,255,0.11);
  border-radius: 999px;
  background: rgba(255,255,255,0.08);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-thirty-buttons button.is-active,
.vb-filter-thirty-buttons button:hover {
  background: linear-gradient(135deg, #3b82f6, #ec4899);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-thirty-meta {
  display: grid;
  gap: 8px;
}

.vb-filter-thirty-meta strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  text-align: center;
}

.vb-filter-thirty-meta button {
  min-height: 38px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-thirty-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-filter-thirty-grid article {
  min-height: 245px;
  padding: 22px;
  border-radius: 26px;
  background:
    radial-gradient(circle at 86% 16%, rgba(59,130,246,0.16), transparent 32%),
    linear-gradient(135deg, rgba(255,255,255,0.98), rgba(248,250,252,0.98)) !important;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 18px 44px rgba(2, 6, 23, 0.20);
}

.vb-filter-thirty-grid article.is-hidden {
  display: none;
}

.vb-filter-thirty-grid small {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-thirty-grid h4 {
  margin: 0 0 10px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.05em;
}

.vb-filter-thirty-grid p {
  margin: 0 0 16px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-filter-thirty-grid span {
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: #fdf2f8;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-filter-thirty-empty {
  display: none;
  margin-top: 16px;
  padding: 22px;
  border-radius: 22px;
  background: rgba(251, 146, 60, 0.12);
  border: 1px solid rgba(251, 146, 60, 0.24);
}

.vb-filter-thirty-empty.is-visible {
  display: block;
}

.vb-filter-thirty-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-thirty-empty p {
  margin: 0 !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 1040px) {
  .vb-filter-thirty-toolbar {
    grid-template-columns: 1fr;
  }

  .vb-filter-thirty-meta {
    max-width: 180px;
  }

  .vb-filter-thirty-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-filter-thirty-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-thirty-section {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-thirty-hero h3 {
    font-size: 38px !important;
  }

  .vb-filter-thirty-buttons {
    display: grid;
    grid-template-columns: 1fr;
  }

  .vb-filter-thirty-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const section = document.querySelector("[data-vb-filter-thirty]");
  if (!section) return;

  const input = section.querySelector("[data-vb-filter-thirty-input]");
  const buttons = section.querySelectorAll("[data-resource-type]");
  const reset = section.querySelector("[data-vb-filter-thirty-reset]");
  const count = section.querySelector("[data-vb-filter-thirty-count]");
  const empty = section.querySelector("[data-vb-filter-thirty-empty]");
  const resources = Array.from(section.querySelectorAll("[data-resource-card]"));

  let activeType = "all";

  function updateResources() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    resources.forEach(function (resource) {
      const type = resource.getAttribute("data-resource-card");
      const text = resource.getAttribute("data-resource-text").toLowerCase();
      const fullText = resource.textContent.toLowerCase();

      const typeMatch = activeType === "all" || type === activeType;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = typeMatch && searchMatch;

      resource.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 resource" : visible + " resources";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeType = button.getAttribute("data-resource-type");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateResources();
    });
  });

  input.addEventListener("input", updateResources);

  reset.addEventListener("click", function () {
    activeType = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-resource-type") === "all");
    });

    input.focus();
    updateResources();
  });

  updateResources();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const section = document.querySelector("[data-vb-filter-thirty]");
  if (!section) return;

  const input = section.querySelector("[data-vb-filter-thirty-input]");
  const buttons = section.querySelectorAll("[data-resource-type]");
  const reset = section.querySelector("[data-vb-filter-thirty-reset]");
  const count = section.querySelector("[data-vb-filter-thirty-count]");
  const empty = section.querySelector("[data-vb-filter-thirty-empty]");
  const resources = Array.from(section.querySelectorAll("[data-resource-card]"));

  let activeType = "all";

  function updateResources() {
    const query = input.value.trim().toLowerCase();
    let visible = 0;

    resources.forEach(function (resource) {
      const type = resource.getAttribute("data-resource-card");
      const text = resource.getAttribute("data-resource-text").toLowerCase();
      const fullText = resource.textContent.toLowerCase();

      const typeMatch = activeType === "all" || type === activeType;
      const searchMatch = text.includes(query) || fullText.includes(query);
      const shouldShow = typeMatch && searchMatch;

      resource.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visible += 1;
      }
    });

    count.textContent = visible === 1 ? "1 resource" : visible + " resources";
    empty.classList.toggle("is-visible", visible === 0);
  }

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeType = button.getAttribute("data-resource-type");

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      updateResources();
    });
  });

  input.addEventListener("input", updateResources);

  reset.addEventListener("click", function () {
    activeType = "all";
    input.value = "";

    buttons.forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-resource-type") === "all");
    });

    input.focus();
    updateResources();
  });

  updateResources();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-filter-thirty-demo"&gt;
  &lt;div class="vb-filter-thirty-section" data-vb-filter-thirty&gt;
    &lt;header class="vb-filter-thirty-hero"&gt;
      &lt;span&gt;Example 30&lt;/span&gt;
      &lt;h3&gt;Complete Responsive Search Filter Section&lt;/h3&gt;
      &lt;p&gt;Search and filter reusable website resources by category, keyword, topic, or content type.&lt;/p&gt;
    &lt;/header&gt;

    &lt;div class="vb-filter-thirty-toolbar"&gt;
      &lt;input type="search" placeholder="Search templates, components, guides, tools..." data-vb-filter-thirty-input&gt;

      &lt;div class="vb-filter-thirty-buttons"&gt;
        &lt;button type="button" class="is-active" data-resource-type="all"&gt;All&lt;/button&gt;
        &lt;button type="button" data-resource-type="template"&gt;Templates&lt;/button&gt;
        &lt;button type="button" data-resource-type="component"&gt;Components&lt;/button&gt;
        &lt;button type="button" data-resource-type="guide"&gt;Guides&lt;/button&gt;
        &lt;button type="button" data-resource-type="tool"&gt;Tools&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-filter-thirty-meta"&gt;
        &lt;strong data-vb-filter-thirty-count&gt;8 resources&lt;/strong&gt;
        &lt;button type="button" data-vb-filter-thirty-reset&gt;Reset&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-thirty-grid"&gt;
      &lt;article data-resource-card="template" data-resource-text="template landing page hero pricing responsive business"&gt;
        &lt;small&gt;Template&lt;/small&gt;
        &lt;h4&gt;Landing Page Template&lt;/h4&gt;
        &lt;p&gt;A complete landing page layout with hero section, feature cards, pricing, FAQ, and CTA area.&lt;/p&gt;
        &lt;span&gt;HTML + CSS&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-resource-card="component" data-resource-text="component javascript modal popup dialog overlay ui"&gt;
        &lt;small&gt;Component&lt;/small&gt;
        &lt;h4&gt;JavaScript Modal UI&lt;/h4&gt;
        &lt;p&gt;Reusable popup component with open, close, overlay click, and keyboard-friendly structure.&lt;/p&gt;
        &lt;span&gt;JavaScript&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-resource-card="guide" data-resource-text="guide seo internal linking article structure blog"&gt;
        &lt;small&gt;Guide&lt;/small&gt;
        &lt;h4&gt;SEO Article Structure&lt;/h4&gt;
        &lt;p&gt;Guide for writing better headings, internal links, examples, FAQ sections, and metadata.&lt;/p&gt;
        &lt;span&gt;SEO&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-resource-card="tool" data-resource-text="tool color palette generator ui design gradients"&gt;
        &lt;small&gt;Tool&lt;/small&gt;
        &lt;h4&gt;UI Color Palette Tool&lt;/h4&gt;
        &lt;p&gt;A small helper tool for planning gradients, backgrounds, contrast, and reusable UI colors.&lt;/p&gt;
        &lt;span&gt;Design&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-resource-card="component" data-resource-text="component search filter cards table directory javascript"&gt;
        &lt;small&gt;Component&lt;/small&gt;
        &lt;h4&gt;Search Filter Component&lt;/h4&gt;
        &lt;p&gt;Reusable live search pattern for cards, tables, directories, products, posts, and listings.&lt;/p&gt;
        &lt;span&gt;JavaScript&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-resource-card="template" data-resource-text="template dashboard admin analytics cards sidebar"&gt;
        &lt;small&gt;Template&lt;/small&gt;
        &lt;h4&gt;Dashboard UI Template&lt;/h4&gt;
        &lt;p&gt;Admin dashboard layout with sidebar navigation, analytics cards, tables, and action panels.&lt;/p&gt;
        &lt;span&gt;Dashboard&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-resource-card="guide" data-resource-text="guide accessibility keyboard aria focus javascript components"&gt;
        &lt;small&gt;Guide&lt;/small&gt;
        &lt;h4&gt;Accessible Components Guide&lt;/h4&gt;
        &lt;p&gt;Accessibility guide for focus states, ARIA labels, keyboard navigation, and semantic markup.&lt;/p&gt;
        &lt;span&gt;A11y&lt;/span&gt;
      &lt;/article&gt;

      &lt;article data-resource-card="tool" data-resource-text="tool css shadow generator cards buttons layout"&gt;
        &lt;small&gt;Tool&lt;/small&gt;
        &lt;h4&gt;CSS Shadow Generator&lt;/h4&gt;
        &lt;p&gt;Generate clean card shadows, button shadows, layered panels, and soft interface depth.&lt;/p&gt;
        &lt;span&gt;CSS Tool&lt;/span&gt;
      &lt;/article&gt;
    &lt;/div&gt;

    &lt;div class="vb-filter-thirty-empty" data-vb-filter-thirty-empty&gt;
      &lt;strong&gt;No resources found.&lt;/strong&gt;
      &lt;p&gt;Try searching for templates, JavaScript, SEO, dashboard, modal, accessibility, CSS, or tools.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-filter-thirty-demo,
.vb-filter-thirty-demo * {
  box-sizing: border-box;
}

.vb-filter-thirty-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 16%, rgba(59, 130, 246, 0.22), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(236, 72, 153, 0.18), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #fdf2f8 52%, #ffffff 100%) !important;
  border: 1px solid rgba(191, 219, 254, 0.58);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.10);
}

.vb-filter-thirty-section {
  max-width: 1120px;
  margin: 0 auto;
  padding: 30px;
  border-radius: 30px;
  background: #0f172a;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 30px 90px rgba(15, 23, 42, 0.28);
}

.vb-filter-thirty-hero {
  max-width: 800px;
  margin-bottom: 22px;
}

.vb-filter-thirty-hero span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(59, 130, 246, 0.16);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-filter-thirty-hero h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 5vw, 72px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-filter-thirty-hero p {
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-filter-thirty-toolbar {
  display: grid;
  grid-template-columns: minmax(260px, 0.85fr) minmax(0, 1.15fr) 170px;
  gap: 12px;
  align-items: center;
  margin-bottom: 18px;
  padding: 14px;
  border-radius: 24px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-filter-thirty-toolbar input {
  width: 100%;
  min-height: 54px;
  padding: 0 16px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 17px;
  outline: 0;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 800;
}

.vb-filter-thirty-toolbar input::placeholder {
  color: rgba(255,255,255,0.58);
  -webkit-text-fill-color: rgba(255,255,255,0.58);
}

.vb-filter-thirty-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-filter-thirty-buttons button {
  min-height: 42px;
  padding: 9px 13px;
  border: 1px solid rgba(255,255,255,0.11);
  border-radius: 999px;
  background: rgba(255,255,255,0.08);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-thirty-buttons button.is-active,
.vb-filter-thirty-buttons button:hover {
  background: linear-gradient(135deg, #3b82f6, #ec4899);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-filter-thirty-meta {
  display: grid;
  gap: 8px;
}

.vb-filter-thirty-meta strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  text-align: center;
}

.vb-filter-thirty-meta button {
  min-height: 38px;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-filter-thirty-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-filter-thirty-grid article {
  min-height: 245px;
  padding: 22px;
  border-radius: 26px;
  background:
    radial-gradient(circle at 86% 16%, rgba(59,130,246,0.16), transparent 32%),
    linear-gradient(135deg, rgba(255,255,255,0.98), rgba(248,250,252,0.98)) !important;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 18px 44px rgba(2, 6, 23, 0.20);
}

.vb-filter-thirty-grid article.is-hidden {
  display: none;
}

.vb-filter-thirty-grid small {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-filter-thirty-grid h4 {
  margin: 0 0 10px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.05em;
}

.vb-filter-thirty-grid p {
  margin: 0 0 16px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-filter-thirty-grid span {
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: #fdf2f8;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-filter-thirty-empty {
  display: none;
  margin-top: 16px;
  padding: 22px;
  border-radius: 22px;
  background: rgba(251, 146, 60, 0.12);
  border: 1px solid rgba(251, 146, 60, 0.24);
}

.vb-filter-thirty-empty.is-visible {
  display: block;
}

.vb-filter-thirty-empty strong {
  display: block;
  margin-bottom: 7px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-filter-thirty-empty p {
  margin: 0 !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 1040px) {
  .vb-filter-thirty-toolbar {
    grid-template-columns: 1fr;
  }

  .vb-filter-thirty-meta {
    max-width: 180px;
  }

  .vb-filter-thirty-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-filter-thirty-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-filter-thirty-section {
    padding: 22px;
    border-radius: 22px;
  }

  .vb-filter-thirty-hero h3 {
    font-size: 38px !important;
  }

  .vb-filter-thirty-buttons {
    display: grid;
    grid-template-columns: 1fr;
  }

  .vb-filter-thirty-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This complete responsive search filter section is useful for resource libraries, service sections, portfolio grids, tool directories, template collections, product highlights, blog resource hubs, and reusable content filtering systems.</p>



<div class="vb24-js-filter-mid-ad" id="javascript-search-filter-bottom-ad">
  <div class="vb24-js-filter-mid-ad-content">
    <span>Recommended WordPress Hosting</span>
    <h2>Need faster hosting for JavaScript search filters?</h2>
    <p>Interactive components like live search filters, product filters, dropdowns, sliders, modals, dashboards, and responsive UI sections work best on fast WordPress hosting. A performance-focused setup can improve page speed, user experience, Core Web Vitals, and SEO.</p>
    <a href="https://kinsta.com?kaid=XTNLJLKTCJHP" target="_blank" rel="sponsored nofollow noopener">Explore Kinsta Hosting</a>
  </div>

  <div class="vb24-js-filter-mid-ad-image">
    <a href="https://kinsta.com?kaid=XTNLJLKTCJHP" target="_blank" rel="sponsored nofollow noopener">
      <img decoding="async" src="https://veebilehed24.ee/wp-content/uploads/2026/03/300x250-wp-dark-2-months-free-hosting.webp" width="300" height="250" alt="Kinsta managed WordPress hosting for fast JavaScript search filter websites" loading="lazy">
    </a>
  </div>
</div>

<style>
.vb24-js-filter-mid-ad,
.vb24-js-filter-mid-ad * {
  box-sizing: border-box;
}

.vb24-js-filter-mid-ad {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 28px;
  align-items: center;
  margin: 46px 0;
  padding: 30px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 14% 18%, rgba(16, 185, 129, 0.22), transparent 30%),
    radial-gradient(circle at 86% 20%, rgba(6, 182, 212, 0.22), transparent 32%),
    linear-gradient(135deg, #0f172a 0%, #020617 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 26px 80px rgba(15, 23, 42, 0.22);
  overflow: hidden;
}

.vb24-js-filter-mid-ad-content span {
  display: inline-flex;
  margin-bottom: 13px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(16, 185, 129, 0.16);
  border: 1px solid rgba(167, 243, 208, 0.24);
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 12px;
  font-weight: 900;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb24-js-filter-mid-ad-content h2 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 4vw, 54px) !important;
  line-height: 1.05 !important;
  font-weight: 950 !important;
  letter-spacing: -0.065em;
}

.vb24-js-filter-mid-ad-content p {
  max-width: 760px;
  margin: 0 0 24px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb24-js-filter-mid-ad-content a {
  display: inline-flex;
  min-height: 48px;
  align-items: center;
  justify-content: center;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #10b981, #06b6d4, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 900;
  text-decoration: none !important;
  box-shadow: 0 16px 36px rgba(14, 165, 233, 0.28);
}

.vb24-js-filter-mid-ad-image {
  display: flex;
  justify-content: center;
}

.vb24-js-filter-mid-ad-image a {
  display: block;
  line-height: 0;
}

.vb24-js-filter-mid-ad-image img {
  display: block;
  width: 300px;
  max-width: 100%;
  height: auto;
  border-radius: 20px;
  box-shadow: 0 22px 60px rgba(0, 0, 0, 0.28);
}

@media (max-width: 900px) {
  .vb24-js-filter-mid-ad {
    grid-template-columns: 1fr;
  }

  .vb24-js-filter-mid-ad-image {
    justify-content: flex-start;
  }
}

@media (max-width: 640px) {
  .vb24-js-filter-mid-ad {
    padding: 22px;
    border-radius: 24px;
  }

  .vb24-js-filter-mid-ad-content a {
    width: 100%;
  }
}
</style>



<h2 class="wp-block-heading" id="javascript-search-filter-best-practices">JavaScript Search Filter Best Practices</h2>



<p class="wp-block-paragraph">JavaScript search filters are easy to start, but they need careful structure to feel professional. A good filter should be fast, predictable, readable, responsive, and clear when no results match. Whether you are filtering cards, tables, products, posts, FAQs, directories, dashboards, or resource libraries, the user should always understand what is being filtered and which controls are active.</p>



<p class="wp-block-paragraph">The most important rule is to keep the filter logic understandable. Use clear data attributes, readable class names, obvious active states, and a reset option when more than one control can affect the results. If the page has many items, add a live result count and a helpful empty state so users are never left with a blank section.</p>



<div class="vb24-js-filter-practice-grid">
  <article>
    <span>01</span>
    <h3>Use scoped JavaScript</h3>
    <p>Scope your query selectors to the current filter component so multiple filters can work on the same page without conflicts.</p>
  </article>

  <article>
    <span>02</span>
    <h3>Use data attributes</h3>
    <p>Store searchable categories, tags, status values, prices, or keywords in data attributes to keep the filtering logic clean.</p>
  </article>

  <article>
    <span>03</span>
    <h3>Show active filters</h3>
    <p>Highlight selected category buttons, chips, tabs, or dropdown options so users know exactly what is controlling the results.</p>
  </article>

  <article>
    <span>04</span>
    <h3>Add an empty state</h3>
    <p>When no cards or rows match the search, show a useful message instead of leaving the interface looking broken.</p>
  </article>

  <article>
    <span>05</span>
    <h3>Keep mobile controls usable</h3>
    <p>Search inputs, filter buttons, reset buttons, and filter chips should be easy to tap and read on small screens.</p>
  </article>

  <article>
    <span>06</span>
    <h3>Keep filters fast</h3>
    <p>For small and medium sections, simple client-side filtering works well. For very large datasets, consider pagination or server-side filtering.</p>
  </article>
</div>

<style>
.vb24-js-filter-practice-grid,
.vb24-js-filter-practice-grid * {
  box-sizing: border-box;
}

.vb24-js-filter-practice-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  margin: 26px 0 34px;
}

.vb24-js-filter-practice-grid article {
  padding: 22px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 18% 14%, rgba(16, 185, 129, 0.12), transparent 32%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.08);
}

.vb24-js-filter-practice-grid span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  margin-bottom: 14px;
  border-radius: 14px;
  background: linear-gradient(135deg, #10b981, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb24-js-filter-practice-grid h3 {
  margin: 0 0 10px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 20px !important;
  line-height: 1.2 !important;
  font-weight: 900 !important;
  letter-spacing: -0.03em;
}

.vb24-js-filter-practice-grid p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 900px) {
  .vb24-js-filter-practice-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-js-filter-practice-grid {
    grid-template-columns: 1fr;
  }

  .vb24-js-filter-practice-grid article {
    padding: 20px;
    border-radius: 20px;
  }
}
</style>



<p class="wp-block-paragraph">For real websites, search filters should match the page goal. A product filter should help shoppers compare products faster. A blog filter should help readers find articles by topic. A dashboard filter should reduce scanning time. A FAQ filter should answer support questions quickly. The design should look polished, but the main purpose is always clarity and speed.</p>



<ul class="wp-block-list">
  <li><strong>Use clear placeholder text</strong> so visitors know what they can search for.</li>
  <li><strong>Normalize search text</strong> with lowercase comparisons to avoid case-sensitive mismatches.</li>
  <li><strong>Use one hidden class</strong> consistently for cards, rows, items, and sections.</li>
  <li><strong>Update result counts</strong> when filtering large lists, product grids, directories, or dashboards.</li>
  <li><strong>Add reset behavior</strong> so users can quickly return to the full list.</li>
  <li><strong>Avoid over-filtering</strong> with too many controls if the section only has a small number of items.</li>
  <li><strong>Test partial keywords</strong> such as product names, categories, tags, locations, and common typos.</li>
  <li><strong>Keep visible code organized</strong> when publishing tutorial examples in WordPress or Gutenberg.</li>
</ul>



<h2 class="wp-block-heading" id="responsive-filter-design-tips">Responsive Filter Design Tips</h2>



<p class="wp-block-paragraph">Responsive filter design matters because search interfaces often contain several controls in a small space. A desktop layout may use a sidebar, horizontal tabs, a product grid, or a wide toolbar. On mobile, those controls usually need to stack, wrap, or become full-width tap targets so the filter remains easy to use.</p>



<p class="wp-block-paragraph">When designing responsive JavaScript filters, keep the search input close to the results, make buttons large enough to tap, avoid tiny chips, and test long labels. A filter that works well on desktop can become frustrating on mobile if category buttons are too small or the result grid becomes cramped.</p>



<div class="vb24-js-filter-responsive-box">
  <div>
    <span>Desktop</span>
    <h3>Use toolbars or sidebars</h3>
    <p>Desktop filters can use wide search bars, category tabs, table controls, filter sidebars, product grids, and multi-column result layouts.</p>
  </div>

  <div>
    <span>Tablet</span>
    <h3>Allow controls to wrap</h3>
    <p>Tablet layouts need flexible controls. Let buttons wrap, reduce grid columns, and keep the search input readable.</p>
  </div>

  <div>
    <span>Mobile</span>
    <h3>Stack controls vertically</h3>
    <p>Mobile filters should use full-width inputs, large buttons, simple spacing, and single-column result cards when needed.</p>
  </div>
</div>

<style>
.vb24-js-filter-responsive-box,
.vb24-js-filter-responsive-box * {
  box-sizing: border-box;
}

.vb24-js-filter-responsive-box {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  margin: 26px 0 34px;
  padding: 24px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 15% 18%, rgba(16, 185, 129, 0.16), transparent 34%),
    radial-gradient(circle at 85% 20%, rgba(6, 182, 212, 0.16), transparent 34%),
    linear-gradient(135deg, #0f172a, #111827) !important;
  border: 1px solid rgba(148, 163, 184, 0.18);
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.18);
}

.vb24-js-filter-responsive-box div {
  padding: 22px;
  border-radius: 22px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb24-js-filter-responsive-box span {
  display: inline-flex;
  margin-bottom: 13px;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(16, 185, 129, 0.18);
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 12px;
  font-weight: 900;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb24-js-filter-responsive-box h3 {
  margin: 0 0 10px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px !important;
  line-height: 1.15 !important;
  font-weight: 900 !important;
  letter-spacing: -0.04em;
}

.vb24-js-filter-responsive-box p {
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 15px;
  line-height: 1.7;
}

@media (max-width: 900px) {
  .vb24-js-filter-responsive-box {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb24-js-filter-responsive-box {
    padding: 18px;
    border-radius: 24px;
  }

  .vb24-js-filter-responsive-box div {
    padding: 18px;
    border-radius: 18px;
  }
}
</style>



<ul class="wp-block-list">
  <li><strong>Use full-width search fields on mobile</strong> so typing feels comfortable.</li>
  <li><strong>Stack filter buttons</strong> when labels become too narrow or hard to tap.</li>
  <li><strong>Reduce grid columns</strong> from four columns to two columns, then one column on small screens.</li>
  <li><strong>Keep reset buttons visible</strong> when multiple filters can be active.</li>
  <li><strong>Avoid horizontal overflow</strong> unless the pattern is intentionally scrollable, such as a table.</li>
  <li><strong>Use readable empty states</strong> so mobile users understand why results disappeared.</li>
</ul>



<h2 class="wp-block-heading" id="common-javascript-filter-mistakes">Common JavaScript Filter Mistakes</h2>



<p class="wp-block-paragraph">Many JavaScript filter problems come from unclear structure. The UI may look good at first, but it can break when users type unexpected keywords, click multiple filters, reset the view, or use the page on mobile. A strong filter should handle common user behavior without confusing the visitor.</p>



<div class="vb24-js-filter-mistakes">
  <article>
    <h3>No empty state</h3>
    <p>If no results match, the section should explain what happened. A blank grid looks broken.</p>
  </article>

  <article>
    <h3>Unclear active filters</h3>
    <p>Users should always see which category, tag, tab, or dropdown option is active.</p>
  </article>

  <article>
    <h3>Weak mobile layout</h3>
    <p>Small buttons, cramped cards, and narrow search fields make filters harder to use on phones.</p>
  </article>

  <article>
    <h3>Overcomplicated logic</h3>
    <p>Do not add too many filter rules if the content only needs simple keyword or category filtering.</p>
  </article>

  <article>
    <h3>Global selectors</h3>
    <p>Using document-wide selectors can cause conflicts when several filter examples exist on one page.</p>
  </article>

  <article>
    <h3>No reset option</h3>
    <p>When multiple filters are active, users need a fast way to return to the original full list.</p>
  </article>
</div>

<style>
.vb24-js-filter-mistakes,
.vb24-js-filter-mistakes * {
  box-sizing: border-box;
}

.vb24-js-filter-mistakes {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  margin: 26px 0 36px;
}

.vb24-js-filter-mistakes article {
  padding: 22px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 16% 16%, rgba(251, 146, 60, 0.12), transparent 34%),
    linear-gradient(135deg, #ffffff, #fff7ed) !important;
  border: 1px solid rgba(253, 186, 116, 0.34);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.07);
}

.vb24-js-filter-mistakes h3 {
  margin: 0 0 10px !important;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 20px !important;
  line-height: 1.2 !important;
  font-weight: 950 !important;
  letter-spacing: -0.03em;
}

.vb24-js-filter-mistakes p {
  margin: 0 !important;
  color: #7c2d12 !important;
  -webkit-text-fill-color: #7c2d12 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 900px) {
  .vb24-js-filter-mistakes {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-js-filter-mistakes {
    grid-template-columns: 1fr;
  }

  .vb24-js-filter-mistakes article {
    padding: 20px;
    border-radius: 20px;
  }
}
</style>



<p class="wp-block-paragraph">Another common mistake is treating JavaScript filtering as a replacement for good content structure. Filters can improve usability, but they do not fix weak titles, unclear categories, poor product data, or messy content. Strong filtering starts with well-organized HTML, meaningful labels, and useful text to search inside each item.</p>



<h2 class="wp-block-heading" id="javascript-search-filter-faq">JavaScript Search Filter FAQ</h2>



<div class="vb24-js-filter-faq">
  <details>
    <summary>What is a JavaScript search filter?</summary>
    <div>
      <p>A JavaScript search filter is an interactive feature that shows or hides items based on a keyword, category, tag, status, or selected option. It can filter cards, table rows, product grids, blog posts, FAQ items, directories, dashboards, and other visible content without reloading the page.</p>
    </div>
  </details>

  <details>
    <summary>Can I use these JavaScript filter examples in WordPress?</summary>
    <div>
      <p>Yes. You can paste the HTML, CSS, and JavaScript into a Gutenberg HTML block, custom theme template, shortcode output, or plugin file. For real projects, keep class names unique and avoid placing the same script multiple times on the same page unless the code is scoped correctly.</p>
    </div>
  </details>

  <details>
    <summary>Should product filtering be client-side or server-side?</summary>
    <div>
      <p>Small product grids can use client-side JavaScript filtering. Large ecommerce catalogs usually need server-side filtering, database queries, pagination, or AJAX because loading thousands of products into one page can hurt performance.</p>
    </div>
  </details>

  <details>
    <summary>How do I show a no-results message?</summary>
    <div>
      <p>Count how many items remain visible after filtering. If the count is zero, add a visible class to an empty-state element. If one or more items match, hide the empty-state element again.</p>
    </div>
  </details>

  <details>
    <summary>Can JavaScript filters work with dropdown menus?</summary>
    <div>
      <p>Yes. A dropdown can control a filter value, while the JavaScript compares that value with cards, rows, products, or posts. You can combine search inputs, dropdowns, buttons, checkboxes, tags, and reset controls in one filtering interface.</p>
    </div>
  </details>

  <details>
    <summary>Do JavaScript search filters help SEO?</summary>
    <div>
      <p>Search filters mainly improve user experience. For SEO, important content should still exist in the HTML and be easy to access. Filters can make long pages more usable, but they should not hide critical content that users or search engines need to understand.</p>
    </div>
  </details>
</div>

<style>
.vb24-js-filter-faq,
.vb24-js-filter-faq * {
  box-sizing: border-box;
}

.vb24-js-filter-faq {
  display: grid;
  gap: 12px;
  margin: 26px 0 42px;
}

.vb24-js-filter-faq details {
  overflow: hidden;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.07);
}

.vb24-js-filter-faq summary {
  position: relative;
  display: block;
  padding: 19px 58px 19px 20px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 17px;
  line-height: 1.35;
  font-weight: 900;
  cursor: pointer;
  list-style: none;
}

.vb24-js-filter-faq summary::-webkit-details-marker {
  display: none;
}

.vb24-js-filter-faq summary::after {
  content: "+";
  position: absolute;
  top: 50%;
  right: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  line-height: 1;
  font-weight: 900;
  transform: translateY(-50%);
}

.vb24-js-filter-faq details[open] summary::after {
  content: "−";
}

.vb24-js-filter-faq details > div {
  padding: 0 20px 20px;
}

.vb24-js-filter-faq p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.7;
}
</style>



<h2 class="wp-block-heading" id="javascript-search-filter-conclusion">Conclusion</h2>



<p class="wp-block-paragraph">JavaScript search filters are one of the most practical interactive patterns for modern websites. They can improve product browsing, blog archives, FAQ sections, resource libraries, dashboards, support centers, directories, portfolios, pricing comparisons, event schedules, team pages, and many other content-heavy interfaces.</p>



<p class="wp-block-paragraph">The key is to keep the filter clear. Use a visible search input, readable filter buttons, helpful active states, a reset option, dynamic result counts, and a useful no-results message. When the layout is responsive and the JavaScript is scoped properly, the same pattern can be adapted to many real website projects.</p>



<p class="wp-block-paragraph">You can start with one of these 30 JavaScript search filter examples and customize the HTML, CSS, and JavaScript for your own WordPress post, product section, portfolio grid, directory, dashboard, or resource library.</p>



<div class="vb24-js-filter-back-links">
  <a href="#javascript-search-filter-examples">Back to JavaScript Search Filter Examples</a>
  <a href="#what-is-a-javascript-search-filter">Back to Search Filter Basics</a>
  <a href="#javascript-search-filter-faq">Back to FAQ</a>
</div>

<style>
.vb24-js-filter-back-links {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 26px 0 42px;
}

.vb24-js-filter-back-links a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 46px;
  padding: 12px 17px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 850;
  text-decoration: none !important;
}

.vb24-js-filter-back-links a::after {
  content: "↑";
  margin-left: 8px;
}

@media (max-width: 640px) {
  .vb24-js-filter-back-links a {
    width: 100%;
  }
}
</style>



<h2 class="wp-block-heading" id="related-javascript-and-css-guides">Related JavaScript and CSS Guides</h2>



<p class="wp-block-paragraph">Continue with these related JavaScript and CSS guides. These internal links connect search filters with dropdowns, sliders, modals, form validation, navigation menus, cards, accordions, tabs, pricing sections, banners, footers, testimonials, hero sections, and responsive layouts.</p>



<div class="vb24-js-filter-related">
  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-dropdown-menu-examples/">
    <span>JavaScript</span>
    <h3>30 JavaScript Dropdown Menu Examples</h3>
    <p>Custom select menus, navigation dropdowns, profile menus, searchable dropdowns, and responsive UI components.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-slider-examples/">
    <span>JavaScript</span>
    <h3>30 JavaScript Slider Examples</h3>
    <p>Image sliders, content carousels, product sliders, hero sliders, and responsive UI slider examples.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-form-validation-examples/">
    <span>JavaScript</span>
    <h3>30 JavaScript Form Validation Examples</h3>
    <p>Input validation, signup forms, checkout forms, error states, password checks, and form UI examples.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-modal-examples/">
    <span>JavaScript</span>
    <h3>30 JavaScript Modal Examples</h3>
    <p>Responsive modal windows, dialogs, popups, overlays, confirmation boxes, and interaction patterns.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-navigation-menus/">
    <span>CSS</span>
    <h3>25 Modern CSS Navigation Menus</h3>
    <p>Responsive navbars, dropdown menus, mega menus, hamburger menus, and complete website headers.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-forms/">
    <span>CSS</span>
    <h3>30 Modern CSS Forms</h3>
    <p>Contact forms, login forms, checkout forms, booking forms, lead forms, and modern input layouts.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-tabs/">
    <span>CSS</span>
    <h3>30 Modern CSS Tabs</h3>
    <p>Responsive tab UI, product tabs, dashboard tabs, content tabs, and accessible tab examples.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-accordions/">
    <span>CSS</span>
    <h3>30 Modern CSS Accordions</h3>
    <p>FAQ accordions, product toggles, content expanders, mobile sections, and collapsible UI patterns.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-banners/">
    <span>CSS</span>
    <h3>30 Modern CSS Banners</h3>
    <p>Promo banners, alert bars, CTA banners, announcement bars, sale banners, and notification sections.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-footers/">
    <span>CSS</span>
    <h3>30 Modern CSS Footers</h3>
    <p>Responsive footer layouts, newsletter footers, SaaS footers, ecommerce footers, and link sections.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-testimonials/">
    <span>CSS</span>
    <h3>30 Modern CSS Testimonials</h3>
    <p>Review cards, quote sections, social proof blocks, customer stories, and trust-building UI examples.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-pricing-tables/">
    <span>CSS</span>
    <h3>30 Modern CSS Pricing Tables</h3>
    <p>Responsive pricing sections, SaaS pricing cards, comparison tables, featured plans, and plan selectors.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-website-hero-sections/">
    <span>CSS</span>
    <h3>30 Modern Website Hero Sections</h3>
    <p>Responsive hero layouts, landing page headers, SaaS heroes, ecommerce heroes, and CTA sections.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/25-modern-css-cards-for-websites-html-css-examples/">
    <span>CSS</span>
    <h3>25 Modern CSS Cards</h3>
    <p>Product cards, blog cards, feature cards, pricing cards, profile cards, and responsive card layouts.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-layouts/">
    <span>CSS</span>
    <h3>25 Modern CSS Layouts</h3>
    <p>Grid layouts, flexbox layouts, dashboard layouts, bento grids, responsive sections, and container queries.</p>
  </a>
</div>

<style>
.vb24-js-filter-related,
.vb24-js-filter-related * {
  box-sizing: border-box;
}

.vb24-js-filter-related {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  margin: 26px 0 46px;
}

.vb24-js-filter-related a {
  display: block;
  padding: 22px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 16% 14%, rgba(16, 185, 129, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.08);
  text-decoration: none !important;
  transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}

.vb24-js-filter-related a:hover {
  transform: translateY(-3px);
  border-color: rgba(16, 185, 129, 0.52);
  box-shadow: 0 22px 54px rgba(15, 23, 42, 0.12);
}

.vb24-js-filter-related span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #d1fae5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb24-js-filter-related h3 {
  margin: 0 0 10px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.18 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb24-js-filter-related p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 760px) {
  .vb24-js-filter-related {
    grid-template-columns: 1fr;
  }

  .vb24-js-filter-related a {
    padding: 20px;
    border-radius: 20px;
  }
}
</style>
]]></content:encoded>
					
					<wfw:commentRss>https://veebilehed24.ee/en/blog/javascript/javascript-search-filter-examples/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>30 JavaScript Image Gallery Examples – Responsive Galleries, Filters &#038; Lightbox UI</title>
		<link>https://veebilehed24.ee/en/blog/javascript/javascript-image-gallery-examples/</link>
					<comments>https://veebilehed24.ee/en/blog/javascript/javascript-image-gallery-examples/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Wed, 10 Jun 2026 06:45:39 +0000</pubDate>
				<category><![CDATA[Javascript]]></category>
		<guid isPermaLink="false">https://veebilehed24.ee/?p=1697</guid>

					<description><![CDATA[JavaScript image galleries are useful interactive UI components for portfolio websites, photography pages, ecommerce product collections, real estate listings, travel blogs, agency case studies, interior design projects, product showcases, event albums, and content-heavy landing pages. A good gallery does more than display images — it helps users browse, filter, preview, search, open, compare, select, and [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">JavaScript image galleries are useful interactive UI components for portfolio websites, photography pages, ecommerce product collections, real estate listings, travel blogs, agency case studies, interior design projects, product showcases, event albums, and content-heavy landing pages. A good gallery does more than display images — it helps users browse, filter, preview, search, open, compare, select, and explore visual content in a clear and responsive way.</p>



<p class="wp-block-paragraph">In this guide, you will find 30 JavaScript image gallery examples for real website projects, including responsive image grids, filterable galleries, searchable galleries, lightbox galleries, keyboard-controlled viewers, masonry galleries, lazy loading galleries, infinite scroll galleries, sortable galleries, favorites, selectable galleries, thumbnail navigation, product image galleries, zoom galleries, before-and-after comparison galleries, drag-and-drop galleries, upload preview galleries, tag-based galleries, paginated galleries, accessible gallery modals, and complete responsive gallery sections.</p>



<p class="wp-block-paragraph">This post focuses on JavaScript image gallery logic, dynamic rendering, gallery state management, filtering, searching, sorting, image preview handling, modal/lightbox behavior, keyboard navigation, lazy loading, localStorage, drag-and-drop events, responsive gallery layouts, and copy-paste-ready HTML, CSS, and JavaScript examples. For related UI components, you can also explore our <a href="https://veebilehed24.ee/en/blog/javascript/javascript-slider-examples/">JavaScript slider examples</a>, <a href="https://veebilehed24.ee/en/blog/javascript/javascript-search-filter-examples/">JavaScript search filter examples</a>, <a href="https://veebilehed24.ee/en/blog/javascript/javascript-modal-examples/">JavaScript modal examples</a>, and <a href="https://veebilehed24.ee/en/blog/javascript/javascript-dropdown-menu-examples/">JavaScript dropdown menu examples</a>.</p>



<div class="vb24-js-gallery-jump-box">
  <a class="vb24-js-gallery-jump-button" href="#javascript-image-gallery-examples">View All 30 JavaScript Image Gallery Examples</a>
</div>

<style>
.vb24-js-gallery-jump-box {
  margin: 28px 0 36px;
}

.vb24-js-gallery-jump-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 14px 22px;
  border-radius: 999px;
  background: linear-gradient(135deg, #0ea5e9, #6366f1 52%, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 850;
  line-height: 1.2;
  text-decoration: none !important;
  box-shadow: 0 16px 38px rgba(99, 102, 241, 0.30);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-js-gallery-jump-button::after {
  content: "↓";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.18);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  line-height: 1;
}

.vb24-js-gallery-jump-button:hover {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transform: translateY(-2px);
  filter: saturate(1.08);
  box-shadow: 0 20px 46px rgba(99, 102, 241, 0.38);
}

@media (max-width: 640px) {
  .vb24-js-gallery-jump-button {
    width: 100%;
    padding: 14px 16px;
    font-size: 14px;
  }
}
</style>



<div class="toc-affiliate-wrap vb24-js-gallery-toc-wrap">

  <div class="toc-left vb24-js-gallery-toc-left">

    <div class="vb24-js-gallery-toc-kicker">On this page</div>

    <h2>Table of Contents</h2>

    <ul class="vl24-toc vb24-js-gallery-toc">
      <li><a href="#what-is-a-javascript-image-gallery">What Is a JavaScript Image Gallery?</a></li>
      <li><a href="#why-image-galleries-matter">Why Image Galleries Matter</a></li>
      <li><a href="#javascript-image-gallery-types">JavaScript Image Gallery Types</a></li>
      <li><a href="#what-should-a-good-image-gallery-include">What Should a Good Image Gallery Include?</a></li>
      <li><a class="vb24-featured-toc-link" href="#javascript-image-gallery-examples">30 JavaScript Image Gallery Examples</a></li>
      <li><a href="#javascript-image-gallery-best-practices">JavaScript Image Gallery Best Practices</a></li>
      <li><a href="#responsive-image-gallery-design-tips">Responsive Image Gallery Design Tips</a></li>
      <li><a href="#common-javascript-image-gallery-mistakes">Common JavaScript Image Gallery Mistakes</a></li>
      <li><a href="#javascript-image-gallery-faq">JavaScript Image Gallery FAQ</a></li>
      <li><a href="#javascript-image-gallery-conclusion">Conclusion</a></li>
      <li><a href="#related-javascript-and-css-guides">Related JavaScript and CSS Guides</a></li>
    </ul>

  </div>

  <div class="toc-right vb24-js-gallery-toc-right">

    <a class="vb24-entityschema-ad-card" href="https://veebilehed24.ee/en/shop/entityschema-pro/" target="_blank" rel="sponsored noopener">
      <span class="vb24-entityschema-ad-badge">WordPress SEO Plugin</span>

      <div class="vb24-entityschema-ad-image">
        <img decoding="async" src="https://veebilehed24.ee/wp-content/uploads/2026/03/entityschema-cover-600x400.webp" width="300" height="200" alt="EntitySchema Pro WordPress structured data and entity SEO plugin" loading="lazy">
      </div>

      <div class="vb24-entityschema-ad-content">
        <h3>EntitySchema Pro</h3>
        <p>Build a real entity-based structured data system for WordPress, modern SEO, and AI-readable websites.</p>

        <div class="vb24-entityschema-ad-price">
          <div class="vb24-entityschema-ad-price-left">
            <span class="vb24-entityschema-ad-price-label">Sale price</span>
            <span class="vb24-entityschema-ad-old-price">89€</span>
          </div>

          <strong class="vb24-entityschema-ad-sale-price">29€</strong>

          <span class="vb24-entityschema-ad-save">Save 60€</span>
        </div>

        <span class="vb24-entityschema-ad-button">View Plugin</span>
      </div>
    </a>

  </div>

</div>

<style>
.vb24-js-gallery-toc-wrap {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 26px;
  align-items: stretch;
  margin: 34px 0 44px;
}

.vb24-js-gallery-toc-left,
.vb24-js-gallery-toc-right {
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 28px;
  background: linear-gradient(135deg, #0f172a 0%, #1e3a8a 48%, #581c87 100%);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.18);
}

.vb24-js-gallery-toc-left {
  padding: 28px 30px 30px;
}

.vb24-js-gallery-toc-kicker {
  margin-bottom: 10px;
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 13px;
  font-weight: 850;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb24-js-gallery-toc-left h2 {
  margin: 0 0 22px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px !important;
  line-height: 1.15 !important;
  font-weight: 850 !important;
}

.vb24-js-gallery-toc {
  display: grid !important;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px !important;
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb24-js-gallery-toc li {
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb24-js-gallery-toc li::before {
  display: none !important;
  content: none !important;
}

.vb24-js-gallery-toc a {
  display: flex;
  align-items: center;
  min-height: 54px;
  padding: 13px 15px;
  border: 1px solid rgba(148, 163, 184, 0.18);
  border-radius: 15px;
  background: rgba(255, 255, 255, 0.065);
  color: #f3f4f6 !important;
  -webkit-text-fill-color: #f3f4f6 !important;
  font-size: 15px;
  font-weight: 750;
  line-height: 1.35;
  text-decoration: none !important;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.05);
  transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease;
}

.vb24-js-gallery-toc a:hover {
  transform: translateY(-2px);
  border-color: rgba(56, 189, 248, 0.68);
  background: rgba(14, 165, 233, 0.16);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb24-js-gallery-toc .vb24-featured-toc-link {
  border-color: rgba(56, 189, 248, 0.78);
  background: linear-gradient(135deg, rgba(14, 165, 233, 0.34), rgba(99, 102, 241, 0.28), rgba(168, 85, 247, 0.26));
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb24-js-gallery-toc-right {
  display: flex;
  align-items: stretch;
  justify-content: center;
  padding: 16px;
  overflow: hidden;
}

.vb24-entityschema-ad-card,
.vb24-entityschema-ad-card * {
  box-sizing: border-box;
}

.vb24-entityschema-ad-card {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  min-height: 100%;
  padding: 12px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(34, 211, 238, 0.28), transparent 34%),
    radial-gradient(circle at 86% 14%, rgba(236, 72, 153, 0.24), transparent 36%),
    linear-gradient(135deg, #111827 0%, #312e81 52%, #701a75 100%) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  overflow: hidden;
  box-shadow: 0 20px 56px rgba(2, 6, 23, 0.32);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-entityschema-ad-card:hover {
  transform: translateY(-3px);
  filter: saturate(1.08);
  box-shadow: 0 26px 70px rgba(2, 6, 23, 0.42);
}

.vb24-entityschema-ad-badge {
  position: absolute;
  z-index: 3;
  top: 18px;
  left: 18px;
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.70);
  border: 1px solid rgba(255,255,255,0.22);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb24-entityschema-ad-image {
  overflow: hidden;
  border-radius: 17px;
  border: 1px solid rgba(255,255,255,0.16);
  background: rgba(255,255,255,0.08);
}

.vb24-entityschema-ad-image img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 17px;
}

.vb24-entityschema-ad-content {
  padding: 15px 8px 4px;
}

.vb24-entityschema-ad-content h3 {
  margin: 0 0 8px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 23px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb24-entityschema-ad-content p {
  margin: 0 0 14px !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 13px;
  line-height: 1.5;
  font-weight: 650;
}

.vb24-entityschema-ad-price {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin: 0 0 12px;
  padding: 11px 12px;
  border-radius: 16px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.16);
}

.vb24-entityschema-ad-price-left {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.vb24-entityschema-ad-price-label {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 11px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb24-entityschema-ad-old-price {
  color: rgba(255,255,255,0.62) !important;
  -webkit-text-fill-color: rgba(255,255,255,0.62) !important;
  font-size: 15px;
  line-height: 1;
  font-weight: 850;
  text-decoration: line-through;
  text-decoration-thickness: 2px;
  text-decoration-color: rgba(248, 113, 113, 0.95);
}

.vb24-entityschema-ad-sale-price {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 31px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb24-entityschema-ad-save {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 28px;
  padding: 6px 9px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.18);
  border: 1px solid rgba(74, 222, 128, 0.34);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 11px;
  font-weight: 950;
  white-space: nowrap;
}

.vb24-entityschema-ad-button {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 43px;
  padding: 12px 14px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22d3ee, #2563eb 55%, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
  box-shadow: 0 14px 34px rgba(37, 99, 235, 0.30);
}

@media (max-width: 900px) {
  .vb24-js-gallery-toc-wrap {
    grid-template-columns: 1fr;
  }

  .vb24-js-gallery-toc-right {
    justify-content: flex-start;
    max-width: 360px;
  }
}

@media (max-width: 640px) {
  .vb24-js-gallery-toc-left {
    padding: 22px 18px;
    border-radius: 22px;
  }

  .vb24-js-gallery-toc-left h2 {
    font-size: 26px !important;
  }

  .vb24-js-gallery-toc {
    grid-template-columns: 1fr;
  }

  .vb24-js-gallery-toc a {
    min-height: 48px;
    font-size: 14px;
  }

  .vb24-js-gallery-toc-right {
    max-width: 100%;
    border-radius: 22px;
  }
}
</style>



<h2 class="wp-block-heading" id="what-is-a-javascript-image-gallery">What Is a JavaScript Image Gallery?</h2>



<p class="wp-block-paragraph">A JavaScript image gallery is an interactive website component that displays a collection of images and lets users browse them in a more useful way than a static image grid. It can include filters, search, sorting, lightbox previews, keyboard navigation, lazy loading, pagination, favorites, image selection, thumbnail switching, zoom effects, drag-and-drop ordering, or dynamic rendering from a JavaScript data array.</p>



<p class="wp-block-paragraph">The main purpose of a JavaScript image gallery is to make visual content easier to explore. Instead of placing many images on a page without structure, a gallery can organize images by category, tag, product type, project, location, style, date, or user interaction. This helps visitors find the right image faster and gives the website a more polished, app-like experience.</p>



<p class="wp-block-paragraph">A JavaScript gallery can be very simple or highly advanced. A basic version may render a responsive grid and open a larger preview when an image is clicked. A more advanced version may support live search, animated filters, keyboard-controlled lightbox navigation, lazy loading, infinite scroll, localStorage favorites, image upload previews, before-and-after comparison sliders, accessible focus trapping, and reusable gallery data structures.</p>



<h2 class="wp-block-heading" id="why-image-galleries-matter">Why Image Galleries Matter</h2>



<p class="wp-block-paragraph">Image galleries matter because visual content is often one of the most important parts of a website. A portfolio page needs to show work clearly. An ecommerce page needs to help users inspect products. A real estate website needs to present rooms and exterior views. A travel blog needs to organize destinations. A case study page needs to show project results. A gallery turns these images into a usable interface instead of a long, unstructured image list.</p>



<ul class="wp-block-list">
  <li><strong>They improve browsing</strong> by helping users move through many images without feeling lost.</li>
  <li><strong>They support better visual storytelling</strong> by grouping images into categories, projects, tags, or collections.</li>
  <li><strong>They improve ecommerce pages</strong> by allowing product image switching, zooming, thumbnails, and variant previews.</li>
  <li><strong>They make portfolio pages stronger</strong> by letting visitors filter work by service, industry, style, or project type.</li>
  <li><strong>They improve performance</strong> when combined with lazy loading, pagination, load more buttons, or infinite scroll logic.</li>
  <li><strong>They create better interaction</strong> through lightboxes, keyboard navigation, hover previews, selection states, and fullscreen viewers.</li>
</ul>



<p class="wp-block-paragraph">JavaScript image galleries should be built carefully. A gallery should not only look good, but also load efficiently, work on mobile screens, keep image controls easy to understand, support keyboard users where needed, and avoid heavy scripts that slow down the page. The best gallery examples combine clean UI design with useful JavaScript behavior.</p>



<h2 class="wp-block-heading" id="javascript-image-gallery-types">JavaScript Image Gallery Types</h2>



<p class="wp-block-paragraph">There are many different types of JavaScript image galleries. Some galleries are designed for portfolios, while others are made for ecommerce products, photography albums, blog image collections, real estate listings, dashboards, upload interfaces, comparison sections, or full-screen viewing experiences.</p>



<p class="wp-block-paragraph">The right image gallery depends on the content and user goal. A product gallery should make image switching and zooming easy. A portfolio gallery should support filtering and project discovery. A photography gallery may need fullscreen viewing and keyboard navigation. A large media archive may need search, tags, sorting, pagination, or lazy loading.</p>



<ul class="wp-block-list">
  <li><strong>Responsive image grid galleries</strong> display images in a flexible layout that adapts to desktop, tablet, and mobile screens.</li>
  <li><strong>Filterable image galleries</strong> let users show images by category, such as products, interiors, travel, architecture, events, or portfolio type.</li>
  <li><strong>Searchable image galleries</strong> update the visible images as users type keywords, tags, titles, or descriptions.</li>
  <li><strong>Lightbox image galleries</strong> open a larger image preview in an overlay without leaving the page.</li>
  <li><strong>Keyboard-controlled galleries</strong> let users move through images with arrow keys and close the viewer with Escape.</li>
  <li><strong>Masonry image galleries</strong> create a Pinterest-style layout with mixed image heights and balanced columns.</li>
  <li><strong>Lazy loading galleries</strong> load images only when they are close to the viewport, improving performance on image-heavy pages.</li>
  <li><strong>Infinite scroll galleries</strong> load more images automatically as the visitor scrolls down the page.</li>
  <li><strong>Product image galleries</strong> use thumbnails, variant buttons, zoom, and main image switching for ecommerce product pages.</li>
  <li><strong>Interactive comparison galleries</strong> use sliders, drag handles, or layered images to compare before-and-after visuals.</li>
</ul>



<p class="wp-block-paragraph">This guide focuses on JavaScript image gallery examples, so every demo is designed around a different JavaScript feature or UI behavior. The examples are not just color variations. Each one uses a different gallery idea, different interaction model, different data structure, different user action, or different image browsing pattern.</p>



<h2 class="wp-block-heading" id="what-should-a-good-image-gallery-include">What Should a Good Image Gallery Include?</h2>



<p class="wp-block-paragraph">A good JavaScript image gallery should be fast, responsive, accessible, easy to browse, and visually clear. Users should quickly understand how to open images, move between images, filter content, search the gallery, return to the grid, and continue browsing without confusion.</p>



<div class="vb24-js-gallery-checklist">
  <div class="vb24-js-gallery-check-item">
    <h3>Clear browsing logic</h3>
    <p>The gallery should make it obvious how users can view images, open previews, move between items, and return to the main grid.</p>
  </div>

  <div class="vb24-js-gallery-check-item">
    <h3>Useful JavaScript behavior</h3>
    <p>The JavaScript should add real functionality, such as filtering, search, sorting, lightbox navigation, lazy loading, or image selection.</p>
  </div>

  <div class="vb24-js-gallery-check-item">
    <h3>Responsive image layout</h3>
    <p>The gallery should work on wide desktop screens, tablets, and phones without broken cards, oversized images, or unreadable controls.</p>
  </div>

  <div class="vb24-js-gallery-check-item">
    <h3>Performance-friendly loading</h3>
    <p>Large galleries should avoid loading too much at once by using lazy loading, pagination, load more buttons, or infinite scroll patterns.</p>
  </div>
</div>

<style>
.vb24-js-gallery-checklist {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 30px;
}

.vb24-js-gallery-check-item {
  padding: 20px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 22px;
  background:
    radial-gradient(circle at 18% 10%, rgba(14, 165, 233, 0.10), transparent 32%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb24-js-gallery-check-item h3 {
  margin: 0 0 10px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 850;
}

.vb24-js-gallery-check-item p {
  margin: 0;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb24-js-gallery-checklist {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-js-gallery-checklist {
    grid-template-columns: 1fr;
  }

  .vb24-js-gallery-check-item {
    padding: 18px;
    border-radius: 20px;
  }
}
</style>



<p class="wp-block-paragraph">Before building a gallery, decide what the user should be able to do with the images. Should they only browse? Should they filter by category? Should they search by keyword? Should they open a lightbox? Should they use keyboard navigation? Should images load only when visible? Should selected images stay saved? Should the gallery render from a reusable data array?</p>



<ul class="wp-block-list">
  <li><strong>Use descriptive image data</strong> such as title, category, tags, date, description, and image URL when the gallery needs filtering or search.</li>
  <li><strong>Keep JavaScript scoped</strong> so one gallery does not accidentally control another gallery on the same page.</li>
  <li><strong>Use responsive CSS</strong> so the gallery adapts naturally to different screen sizes.</li>
  <li><strong>Provide clear active states</strong> for filters, selected images, thumbnails, tabs, and current lightbox items.</li>
  <li><strong>Handle empty states</strong> when no images match the current search or selected filter.</li>
  <li><strong>Optimize image loading</strong> with lazy loading, smaller thumbnails, pagination, or load more logic for large galleries.</li>
  <li><strong>Support keyboard actions</strong> for lightboxes, modals, and interactive viewers where users need next, previous, close, or focus handling.</li>
  <li><strong>Use clear alt text</strong> so gallery images remain useful for accessibility and SEO.</li>
  <li><strong>Avoid layout shifts</strong> by giving images stable dimensions or using well-structured gallery cards.</li>
  <li><strong>Keep animations purposeful</strong> so filtering, opening, zooming, and transitions feel smooth without making the gallery hard to use.</li>
</ul>



<p class="wp-block-paragraph">You can combine JavaScript image galleries with many other website UI patterns. Portfolio galleries work well inside <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-layouts/">modern CSS layouts</a>, product image galleries can be paired with <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-pricing-tables/">pricing sections</a> or ecommerce cards, visual case studies can use <a href="https://veebilehed24.ee/en/blog/css-effects/modern-website-hero-sections/">modern hero sections</a>, and gallery contact flows can connect to <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-forms/">modern CSS forms</a>.</p>



<h2 class="wp-block-heading" id="javascript-image-gallery-examples">30 JavaScript Image Gallery Examples</h2>



<p class="wp-block-paragraph">Now let’s look at 30 JavaScript image gallery examples for real website projects. Each example uses a different gallery layout, JavaScript behavior, user interaction, image browsing pattern, visual style, and responsive approach. You will find dynamic rendering, filters, search, sorting, lightboxes, keyboard navigation, masonry logic, lazy loading, infinite scroll, localStorage favorites, selectable images, thumbnail navigation, product gallery behavior, zoom effects, before-and-after comparison, drag-and-drop ordering, upload previews, tag chips, pagination, accessibility improvements, and a complete responsive gallery system with visible JavaScript, HTML, and CSS code.</p>



<h2 class="wp-block-heading">1. Responsive Image Grid Gallery</h2>



<p class="wp-block-paragraph"><strong>A responsive image grid gallery</strong> is a strong starting point for portfolio pages, agency work sections, photography websites, product showcases, blog image collections, and modern landing pages. Instead of hardcoding every image card in HTML, this example uses JavaScript to render the gallery from a reusable image data array.</p>



<p class="wp-block-paragraph">This makes the gallery easier to maintain because image titles, categories, descriptions, and URLs are stored in one JavaScript array. The layout is fully responsive, the cards have a professional editorial style, and every image is generated dynamically when the page loads.</p>



<ul class="wp-block-list">
<li>Responsive JavaScript image gallery</li>
<li>Dynamic rendering from an image data array</li>
<li>Professional card-based gallery layout</li>
<li>Image title, category, and description support</li>
<li>Fully responsive desktop, tablet, and mobile design</li>
</ul>



<div class="vb-gallery-one-demo">
  <div class="vb-gallery-one-shell">
    <div class="vb-gallery-one-head">
      <span>Example 01</span>
      <h3>Responsive Image Grid Gallery</h3>
      <p>A dynamic JavaScript image gallery that renders all gallery cards from a reusable data array.</p>
    </div>

    <div class="vb-gallery-one-grid" data-vb-gallery-one-grid></div>
  </div>
</div>

<style>
.vb-gallery-one-demo,
.vb-gallery-one-demo * {
  box-sizing: border-box;
}

.vb-gallery-one-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: clamp(26px, 4vw, 42px);
  background:
    radial-gradient(circle at 10% 10%, rgba(14, 165, 233, 0.16), transparent 34%),
    radial-gradient(circle at 90% 12%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-gallery-one-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-one-head {
  display: grid;
  gap: 12px;
  max-width: 780px;
  margin-bottom: 26px;
}

.vb-gallery-one-head span {
  display: inline-flex;
  width: fit-content;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-one-head h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.065em;
}

.vb-gallery-one-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-one-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
}

.vb-gallery-one-card {
  position: relative;
  overflow: hidden;
  min-width: 0;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.10);
  transition: transform 0.24s ease, box-shadow 0.24s ease, border-color 0.24s ease;
}

.vb-gallery-one-card:hover {
  transform: translateY(-6px);
  border-color: rgba(37, 99, 235, 0.34);
  box-shadow: 0 26px 70px rgba(15, 23, 42, 0.16);
}

.vb-gallery-one-image-wrap {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: #e2e8f0;
}

.vb-gallery-one-image-wrap img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.36s ease, filter 0.36s ease;
}

.vb-gallery-one-card:hover .vb-gallery-one-image-wrap img {
  transform: scale(1.08);
  filter: saturate(1.08) contrast(1.04);
}

.vb-gallery-one-badge {
  position: absolute;
  left: 14px;
  top: 14px;
  z-index: 2;
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.74);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb-gallery-one-body {
  display: grid;
  gap: 9px;
  padding: 18px;
}

.vb-gallery-one-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px !important;
  line-height: 1.18 !important;
  font-weight: 900 !important;
  letter-spacing: -0.035em;
}

.vb-gallery-one-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 600;
}

.vb-gallery-one-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 4px;
  padding-top: 13px;
  border-top: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-gallery-one-meta small {
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 12px;
  font-weight: 900;
}

.vb-gallery-one-meta strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 12px;
  font-weight: 900;
}

@media (max-width: 980px) {
  .vb-gallery-one-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-gallery-one-demo {
    padding: 16px;
    border-radius: 26px;
  }

  .vb-gallery-one-head h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-one-grid {
    grid-template-columns: 1fr;
  }

  .vb-gallery-one-card {
    border-radius: 22px;
  }
}
</style>

<script>
(function () {
  const grid = document.querySelector("[data-vb-gallery-one-grid]");
  if (!grid) return;

  const galleryItems = [
    {
      title: "Mountain Workspace",
      category: "Workspace",
      description: "A calm desk setup with natural light, mountain view, and clean creative atmosphere.",
      image: "https://picsum.photos/seed/gallery-one-workspace/900/700",
      year: "2026"
    },
    {
      title: "Modern Interior",
      category: "Interior",
      description: "A warm modern room layout with layered materials, soft lighting, and elegant details.",
      image: "https://picsum.photos/seed/gallery-one-interior/900/700",
      year: "2026"
    },
    {
      title: "Urban Architecture",
      category: "Architecture",
      description: "A structured city scene with strong lines, glass surfaces, and modern building forms.",
      image: "https://picsum.photos/seed/gallery-one-architecture/900/700",
      year: "2026"
    },
    {
      title: "Product Detail",
      category: "Product",
      description: "A close-up product composition designed for ecommerce and landing page galleries.",
      image: "https://picsum.photos/seed/gallery-one-product/900/700",
      year: "2026"
    },
    {
      title: "Travel Moment",
      category: "Travel",
      description: "A bright visual story for travel blogs, destination guides, and editorial galleries.",
      image: "https://picsum.photos/seed/gallery-one-travel/900/700",
      year: "2026"
    },
    {
      title: "Creative Studio",
      category: "Studio",
      description: "A professional creative workspace suitable for agency portfolios and case study pages.",
      image: "https://picsum.photos/seed/gallery-one-studio/900/700",
      year: "2026"
    }
  ];

  function createGalleryCard(item, index) {
    return `
      <article class="vb-gallery-one-card">
        <div class="vb-gallery-one-image-wrap">
          <span class="vb-gallery-one-badge">${item.category}</span>
          <img decoding="async" src="${item.image}" alt="${item.title}" loading="lazy">
        </div>

        <div class="vb-gallery-one-body">
          <h4>${item.title}</h4>
          <p>${item.description}</p>

          <div class="vb-gallery-one-meta">
            <small>Image ${String(index + 1).padStart(2, "0")}</small>
            <strong>${item.year}</strong>
          </div>
        </div>
      </article>
    `;
  }

  function renderGallery(items) {
    grid.innerHTML = items.map(createGalleryCard).join("");
  }

  renderGallery(galleryItems);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const grid = document.querySelector("[data-vb-gallery-one-grid]");
  if (!grid) return;

  const galleryItems = [
    {
      title: "Mountain Workspace",
      category: "Workspace",
      description: "A calm desk setup with natural light, mountain view, and clean creative atmosphere.",
      image: "https://picsum.photos/seed/gallery-one-workspace/900/700",
      year: "2026"
    },
    {
      title: "Modern Interior",
      category: "Interior",
      description: "A warm modern room layout with layered materials, soft lighting, and elegant details.",
      image: "https://picsum.photos/seed/gallery-one-interior/900/700",
      year: "2026"
    },
    {
      title: "Urban Architecture",
      category: "Architecture",
      description: "A structured city scene with strong lines, glass surfaces, and modern building forms.",
      image: "https://picsum.photos/seed/gallery-one-architecture/900/700",
      year: "2026"
    },
    {
      title: "Product Detail",
      category: "Product",
      description: "A close-up product composition designed for ecommerce and landing page galleries.",
      image: "https://picsum.photos/seed/gallery-one-product/900/700",
      year: "2026"
    },
    {
      title: "Travel Moment",
      category: "Travel",
      description: "A bright visual story for travel blogs, destination guides, and editorial galleries.",
      image: "https://picsum.photos/seed/gallery-one-travel/900/700",
      year: "2026"
    },
    {
      title: "Creative Studio",
      category: "Studio",
      description: "A professional creative workspace suitable for agency portfolios and case study pages.",
      image: "https://picsum.photos/seed/gallery-one-studio/900/700",
      year: "2026"
    }
  ];

  function createGalleryCard(item, index) {
    return `
      &lt;article class="vb-gallery-one-card"&gt;
        &lt;div class="vb-gallery-one-image-wrap"&gt;
          &lt;span class="vb-gallery-one-badge"&gt;${item.category}&lt;/span&gt;
          &lt;img src="${item.image}" alt="${item.title}" loading="lazy"&gt;
        &lt;/div&gt;

        &lt;div class="vb-gallery-one-body"&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
          &lt;p&gt;${item.description}&lt;/p&gt;

          &lt;div class="vb-gallery-one-meta"&gt;
            &lt;small&gt;Image ${String(index + 1).padStart(2, "0")}&lt;/small&gt;
            &lt;strong&gt;${item.year}&lt;/strong&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    `;
  }

  function renderGallery(items) {
    grid.innerHTML = items.map(createGalleryCard).join("");
  }

  renderGallery(galleryItems);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-one-demo"&gt;
  &lt;div class="vb-gallery-one-shell"&gt;
    &lt;div class="vb-gallery-one-head"&gt;
      &lt;span&gt;Example 01&lt;/span&gt;
      &lt;h3&gt;Responsive Image Grid Gallery&lt;/h3&gt;
      &lt;p&gt;A dynamic JavaScript image gallery that renders all gallery cards from a reusable data array.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-one-grid" data-vb-gallery-one-grid&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-one-demo,
.vb-gallery-one-demo * {
  box-sizing: border-box;
}

.vb-gallery-one-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: clamp(26px, 4vw, 42px);
  background:
    radial-gradient(circle at 10% 10%, rgba(14, 165, 233, 0.16), transparent 34%),
    radial-gradient(circle at 90% 12%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-gallery-one-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-one-head {
  display: grid;
  gap: 12px;
  max-width: 780px;
  margin-bottom: 26px;
}

.vb-gallery-one-head span {
  display: inline-flex;
  width: fit-content;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-one-head h3 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.065em;
}

.vb-gallery-one-head p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-one-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 18px;
}

.vb-gallery-one-card {
  position: relative;
  overflow: hidden;
  min-width: 0;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 18px 46px rgba(15, 23, 42, 0.10);
  transition: transform 0.24s ease, box-shadow 0.24s ease, border-color 0.24s ease;
}

.vb-gallery-one-card:hover {
  transform: translateY(-6px);
  border-color: rgba(37, 99, 235, 0.34);
  box-shadow: 0 26px 70px rgba(15, 23, 42, 0.16);
}

.vb-gallery-one-image-wrap {
  position: relative;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: #e2e8f0;
}

.vb-gallery-one-image-wrap img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.36s ease, filter 0.36s ease;
}

.vb-gallery-one-card:hover .vb-gallery-one-image-wrap img {
  transform: scale(1.08);
  filter: saturate(1.08) contrast(1.04);
}

.vb-gallery-one-badge {
  position: absolute;
  left: 14px;
  top: 14px;
  z-index: 2;
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.74);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb-gallery-one-body {
  display: grid;
  gap: 9px;
  padding: 18px;
}

.vb-gallery-one-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px !important;
  line-height: 1.18 !important;
  font-weight: 900 !important;
  letter-spacing: -0.035em;
}

.vb-gallery-one-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 600;
}

.vb-gallery-one-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: 4px;
  padding-top: 13px;
  border-top: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-gallery-one-meta small {
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 12px;
  font-weight: 900;
}

.vb-gallery-one-meta strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 12px;
  font-weight: 900;
}

@media (max-width: 980px) {
  .vb-gallery-one-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-gallery-one-demo {
    padding: 16px;
    border-radius: 26px;
  }

  .vb-gallery-one-head h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-one-grid {
    grid-template-columns: 1fr;
  }

  .vb-gallery-one-card {
    border-radius: 22px;
  }
}</pre>



<p class="wp-block-paragraph">This responsive image grid gallery is useful for portfolio pages, image-heavy landing pages, agency project sections, photography previews, product showcases, and visual blog layouts where the image data should be easy to update from JavaScript.</p>



<h2 class="wp-block-heading">2. Filterable Image Gallery</h2>



<p class="wp-block-paragraph"><strong>A filterable image gallery</strong> helps users browse a larger image collection by category. It is useful for portfolios, ecommerce collections, real estate galleries, travel websites, restaurant galleries, interior design projects, event albums, and agency case studies.</p>



<p class="wp-block-paragraph">This example uses JavaScript category buttons to filter gallery cards by type. The active filter state updates instantly, the result count changes dynamically, and an empty-state message appears when no images match the selected category. The gallery is designed with a dark editorial layout so it looks visually different from the first example.</p>



<ul class="wp-block-list">
<li>Filterable JavaScript image gallery</li>
<li>Category button filtering</li>
<li>Active filter state</li>
<li>Dynamic result counter</li>
<li>Empty-state handling</li>
</ul>



<div class="vb-gallery-two-demo">
  <div class="vb-gallery-two-shell">
    <div class="vb-gallery-two-top">
      <div>
        <span>Example 02</span>
        <h3>Filterable Image Gallery</h3>
        <p>Filter a visual collection by category with JavaScript and update the gallery instantly.</p>
      </div>

      <strong data-vb-gallery-two-count>0 images</strong>
    </div>

    <div class="vb-gallery-two-filters" data-vb-gallery-two-filters>
      <button type="button" class="is-active" data-filter="all">All</button>
      <button type="button" data-filter="interior">Interior</button>
      <button type="button" data-filter="product">Product</button>
      <button type="button" data-filter="travel">Travel</button>
      <button type="button" data-filter="architecture">Architecture</button>
    </div>

    <div class="vb-gallery-two-grid" data-vb-gallery-two-grid></div>

    <div class="vb-gallery-two-empty" data-vb-gallery-two-empty hidden>
      <h4>No images found</h4>
      <p>Try another gallery category to view more images.</p>
    </div>
  </div>
</div>

<style>
.vb-gallery-two-demo,
.vb-gallery-two-demo * {
  box-sizing: border-box;
}

.vb-gallery-two-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 12px 44px 12px 44px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 211, 238, 0.18), transparent 34%),
    radial-gradient(circle at 88% 10%, rgba(168, 85, 247, 0.22), transparent 36%),
    linear-gradient(135deg, #020617 0%, #111827 48%, #312e81 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 28px 90px rgba(2, 6, 23, 0.32);
}

.vb-gallery-two-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-two-top {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 22px;
  margin-bottom: 24px;
}

.vb-gallery-two-top span {
  display: inline-flex;
  margin-bottom: 13px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(14, 165, 233, 0.16);
  border: 1px solid rgba(125, 211, 252, 0.24);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-two-top h3 {
  max-width: 720px;
  margin: 0 0 12px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-two-top p {
  max-width: 680px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-gallery-two-top strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-two-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 22px;
}

.vb-gallery-two-filters button {
  appearance: none;
  border: 1px solid rgba(148, 163, 184, 0.28);
  border-radius: 999px;
  background: rgba(255,255,255,0.07);
  color: #e2e8f0 !important;
  -webkit-text-fill-color: #e2e8f0 !important;
  padding: 11px 15px;
  font-size: 13px;
  line-height: 1;
  font-weight: 900;
  cursor: pointer;
  transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease;
}

.vb-gallery-two-filters button:hover {
  transform: translateY(-2px);
  border-color: rgba(34, 211, 238, 0.58);
  background: rgba(34, 211, 238, 0.14);
}

.vb-gallery-two-filters button.is-active {
  border-color: rgba(34, 211, 238, 0.80);
  background: linear-gradient(135deg, #0891b2, #4f46e5);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 14px 34px rgba(79, 70, 229, 0.30);
}

.vb-gallery-two-grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-two-card {
  position: relative;
  grid-column: span 4;
  min-height: 310px;
  overflow: hidden;
  border-radius: 26px;
  background: #0f172a;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 18px 46px rgba(2, 6, 23, 0.28);
}

.vb-gallery-two-card:nth-child(5n + 1) {
  grid-column: span 5;
}

.vb-gallery-two-card:nth-child(5n + 2) {
  grid-column: span 7;
}

.vb-gallery-two-card img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.38s ease, filter 0.38s ease;
}

.vb-gallery-two-card:hover img {
  transform: scale(1.08);
  filter: saturate(1.12) contrast(1.05);
}

.vb-gallery-two-card::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(2, 6, 23, 0.04), rgba(2, 6, 23, 0.86)),
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%);
  z-index: 1;
}

.vb-gallery-two-content {
  position: absolute;
  z-index: 2;
  left: 18px;
  right: 18px;
  bottom: 18px;
  display: grid;
  gap: 9px;
}

.vb-gallery-two-content span {
  display: inline-flex;
  width: fit-content;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.66);
  border: 1px solid rgba(255,255,255,0.16);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb-gallery-two-content h4 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(22px, 3vw, 32px) !important;
  line-height: 1.02 !important;
  font-weight: 950 !important;
  letter-spacing: -0.055em;
}

.vb-gallery-two-content p {
  max-width: 560px;
  margin: 0 !important;
  color: #e2e8f0 !important;
  -webkit-text-fill-color: #e2e8f0 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-gallery-two-empty {
  margin-top: 18px;
  padding: 24px;
  border-radius: 24px;
  background: rgba(255,255,255,0.08);
  border: 1px dashed rgba(148, 163, 184, 0.38);
  text-align: center;
}

.vb-gallery-two-empty h4 {
  margin: 0 0 8px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px !important;
  font-weight: 950 !important;
}

.vb-gallery-two-empty p {
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 15px;
  line-height: 1.6;
}

@media (max-width: 980px) {
  .vb-gallery-two-top {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-two-card,
  .vb-gallery-two-card:nth-child(5n + 1),
  .vb-gallery-two-card:nth-child(5n + 2) {
    grid-column: span 6;
  }
}

@media (max-width: 640px) {
  .vb-gallery-two-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-two-top h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-two-filters {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-two-filters button {
    width: 100%;
  }

  .vb-gallery-two-card,
  .vb-gallery-two-card:nth-child(5n + 1),
  .vb-gallery-two-card:nth-child(5n + 2) {
    grid-column: span 12;
    min-height: 280px;
  }
}
</style>

<script>
(function () {
  const grid = document.querySelector("[data-vb-gallery-two-grid]");
  const filters = document.querySelector("[data-vb-gallery-two-filters]");
  const count = document.querySelector("[data-vb-gallery-two-count]");
  const empty = document.querySelector("[data-vb-gallery-two-empty]");

  if (!grid || !filters || !count || !empty) return;

  const galleryItems = [
    {
      title: "Soft Living Room",
      category: "interior",
      label: "Interior",
      description: "A warm interior image for home design, furniture, and architecture websites.",
      image: "https://picsum.photos/seed/gallery-two-interior-one/1000/700"
    },
    {
      title: "Minimal Product Shot",
      category: "product",
      label: "Product",
      description: "A clean product-focused image for ecommerce galleries and landing pages.",
      image: "https://picsum.photos/seed/gallery-two-product-one/1000/700"
    },
    {
      title: "Coastal Escape",
      category: "travel",
      label: "Travel",
      description: "A bright travel image for destination guides, travel blogs, and booking pages.",
      image: "https://picsum.photos/seed/gallery-two-travel-one/1000/700"
    },
    {
      title: "Glass Building Lines",
      category: "architecture",
      label: "Architecture",
      description: "A modern architecture image with strong structure and city atmosphere.",
      image: "https://picsum.photos/seed/gallery-two-architecture-one/1000/700"
    },
    {
      title: "Nordic Kitchen",
      category: "interior",
      label: "Interior",
      description: "A calm interior gallery item for design studios and renovation portfolios.",
      image: "https://picsum.photos/seed/gallery-two-interior-two/1000/700"
    },
    {
      title: "Premium Package",
      category: "product",
      label: "Product",
      description: "A polished product image suitable for brand galleries and shop sections.",
      image: "https://picsum.photos/seed/gallery-two-product-two/1000/700"
    },
    {
      title: "Mountain Route",
      category: "travel",
      label: "Travel",
      description: "A travel story image for adventure websites and editorial image collections.",
      image: "https://picsum.photos/seed/gallery-two-travel-two/1000/700"
    },
    {
      title: "Concrete Facade",
      category: "architecture",
      label: "Architecture",
      description: "A bold architectural gallery image for project showcases and case studies.",
      image: "https://picsum.photos/seed/gallery-two-architecture-two/1000/700"
    }
  ];

  function createCard(item) {
    return `
      <article class="vb-gallery-two-card">
        <img decoding="async" src="${item.image}" alt="${item.title}" loading="lazy">

        <div class="vb-gallery-two-content">
          <span>${item.label}</span>
          <h4>${item.title}</h4>
          <p>${item.description}</p>
        </div>
      </article>
    `;
  }

  function updateCount(number) {
    count.textContent = number === 1 ? "1 image" : number + " images";
  }

  function renderGallery(filterValue) {
    const visibleItems = filterValue === "all"
      ? galleryItems
      : galleryItems.filter(function (item) {
          return item.category === filterValue;
        });

    grid.innerHTML = visibleItems.map(createCard).join("");
    updateCount(visibleItems.length);
    empty.hidden = visibleItems.length !== 0;
  }

  filters.addEventListener("click", function (event) {
    const button = event.target.closest("button[data-filter]");
    if (!button) return;

    const filterValue = button.getAttribute("data-filter");

    filters.querySelectorAll("button").forEach(function (filterButton) {
      filterButton.classList.remove("is-active");
    });

    button.classList.add("is-active");
    renderGallery(filterValue);
  });

  renderGallery("all");
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const grid = document.querySelector("[data-vb-gallery-two-grid]");
  const filters = document.querySelector("[data-vb-gallery-two-filters]");
  const count = document.querySelector("[data-vb-gallery-two-count]");
  const empty = document.querySelector("[data-vb-gallery-two-empty]");

  if (!grid || !filters || !count || !empty) return;

  const galleryItems = [
    {
      title: "Soft Living Room",
      category: "interior",
      label: "Interior",
      description: "A warm interior image for home design, furniture, and architecture websites.",
      image: "https://picsum.photos/seed/gallery-two-interior-one/1000/700"
    },
    {
      title: "Minimal Product Shot",
      category: "product",
      label: "Product",
      description: "A clean product-focused image for ecommerce galleries and landing pages.",
      image: "https://picsum.photos/seed/gallery-two-product-one/1000/700"
    },
    {
      title: "Coastal Escape",
      category: "travel",
      label: "Travel",
      description: "A bright travel image for destination guides, travel blogs, and booking pages.",
      image: "https://picsum.photos/seed/gallery-two-travel-one/1000/700"
    },
    {
      title: "Glass Building Lines",
      category: "architecture",
      label: "Architecture",
      description: "A modern architecture image with strong structure and city atmosphere.",
      image: "https://picsum.photos/seed/gallery-two-architecture-one/1000/700"
    },
    {
      title: "Nordic Kitchen",
      category: "interior",
      label: "Interior",
      description: "A calm interior gallery item for design studios and renovation portfolios.",
      image: "https://picsum.photos/seed/gallery-two-interior-two/1000/700"
    },
    {
      title: "Premium Package",
      category: "product",
      label: "Product",
      description: "A polished product image suitable for brand galleries and shop sections.",
      image: "https://picsum.photos/seed/gallery-two-product-two/1000/700"
    },
    {
      title: "Mountain Route",
      category: "travel",
      label: "Travel",
      description: "A travel story image for adventure websites and editorial image collections.",
      image: "https://picsum.photos/seed/gallery-two-travel-two/1000/700"
    },
    {
      title: "Concrete Facade",
      category: "architecture",
      label: "Architecture",
      description: "A bold architectural gallery image for project showcases and case studies.",
      image: "https://picsum.photos/seed/gallery-two-architecture-two/1000/700"
    }
  ];

  function createCard(item) {
    return `
      &lt;article class="vb-gallery-two-card"&gt;
        &lt;img src="${item.image}" alt="${item.title}" loading="lazy"&gt;

        &lt;div class="vb-gallery-two-content"&gt;
          &lt;span&gt;${item.label}&lt;/span&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
          &lt;p&gt;${item.description}&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    `;
  }

  function updateCount(number) {
    count.textContent = number === 1 ? "1 image" : number + " images";
  }

  function renderGallery(filterValue) {
    const visibleItems = filterValue === "all"
      ? galleryItems
      : galleryItems.filter(function (item) {
          return item.category === filterValue;
        });

    grid.innerHTML = visibleItems.map(createCard).join("");
    updateCount(visibleItems.length);
    empty.hidden = visibleItems.length !== 0;
  }

  filters.addEventListener("click", function (event) {
    const button = event.target.closest("button[data-filter]");
    if (!button) return;

    const filterValue = button.getAttribute("data-filter");

    filters.querySelectorAll("button").forEach(function (filterButton) {
      filterButton.classList.remove("is-active");
    });

    button.classList.add("is-active");
    renderGallery(filterValue);
  });

  renderGallery("all");
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-two-demo"&gt;
  &lt;div class="vb-gallery-two-shell"&gt;
    &lt;div class="vb-gallery-two-top"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 02&lt;/span&gt;
        &lt;h3&gt;Filterable Image Gallery&lt;/h3&gt;
        &lt;p&gt;Filter a visual collection by category with JavaScript and update the gallery instantly.&lt;/p&gt;
      &lt;/div&gt;

      &lt;strong data-vb-gallery-two-count&gt;0 images&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-two-filters" data-vb-gallery-two-filters&gt;
      &lt;button type="button" class="is-active" data-filter="all"&gt;All&lt;/button&gt;
      &lt;button type="button" data-filter="interior"&gt;Interior&lt;/button&gt;
      &lt;button type="button" data-filter="product"&gt;Product&lt;/button&gt;
      &lt;button type="button" data-filter="travel"&gt;Travel&lt;/button&gt;
      &lt;button type="button" data-filter="architecture"&gt;Architecture&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-two-grid" data-vb-gallery-two-grid&gt;&lt;/div&gt;

    &lt;div class="vb-gallery-two-empty" data-vb-gallery-two-empty hidden&gt;
      &lt;h4&gt;No images found&lt;/h4&gt;
      &lt;p&gt;Try another gallery category to view more images.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-two-demo,
.vb-gallery-two-demo * {
  box-sizing: border-box;
}

.vb-gallery-two-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 12px 44px 12px 44px;
  background:
    radial-gradient(circle at 12% 16%, rgba(34, 211, 238, 0.18), transparent 34%),
    radial-gradient(circle at 88% 10%, rgba(168, 85, 247, 0.22), transparent 36%),
    linear-gradient(135deg, #020617 0%, #111827 48%, #312e81 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 28px 90px rgba(2, 6, 23, 0.32);
}

.vb-gallery-two-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-two-top {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 22px;
  margin-bottom: 24px;
}

.vb-gallery-two-top span {
  display: inline-flex;
  margin-bottom: 13px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(14, 165, 233, 0.16);
  border: 1px solid rgba(125, 211, 252, 0.24);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-two-top h3 {
  max-width: 720px;
  margin: 0 0 12px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-two-top p {
  max-width: 680px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-gallery-two-top strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-two-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 22px;
}

.vb-gallery-two-filters button {
  appearance: none;
  border: 1px solid rgba(148, 163, 184, 0.28);
  border-radius: 999px;
  background: rgba(255,255,255,0.07);
  color: #e2e8f0 !important;
  -webkit-text-fill-color: #e2e8f0 !important;
  padding: 11px 15px;
  font-size: 13px;
  line-height: 1;
  font-weight: 900;
  cursor: pointer;
  transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease;
}

.vb-gallery-two-filters button:hover {
  transform: translateY(-2px);
  border-color: rgba(34, 211, 238, 0.58);
  background: rgba(34, 211, 238, 0.14);
}

.vb-gallery-two-filters button.is-active {
  border-color: rgba(34, 211, 238, 0.80);
  background: linear-gradient(135deg, #0891b2, #4f46e5);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 14px 34px rgba(79, 70, 229, 0.30);
}

.vb-gallery-two-grid {
  display: grid;
  grid-template-columns: repeat(12, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-two-card {
  position: relative;
  grid-column: span 4;
  min-height: 310px;
  overflow: hidden;
  border-radius: 26px;
  background: #0f172a;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 18px 46px rgba(2, 6, 23, 0.28);
}

.vb-gallery-two-card:nth-child(5n + 1) {
  grid-column: span 5;
}

.vb-gallery-two-card:nth-child(5n + 2) {
  grid-column: span 7;
}

.vb-gallery-two-card img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.38s ease, filter 0.38s ease;
}

.vb-gallery-two-card:hover img {
  transform: scale(1.08);
  filter: saturate(1.12) contrast(1.05);
}

.vb-gallery-two-card::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(2, 6, 23, 0.04), rgba(2, 6, 23, 0.86)),
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%);
  z-index: 1;
}

.vb-gallery-two-content {
  position: absolute;
  z-index: 2;
  left: 18px;
  right: 18px;
  bottom: 18px;
  display: grid;
  gap: 9px;
}

.vb-gallery-two-content span {
  display: inline-flex;
  width: fit-content;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.66);
  border: 1px solid rgba(255,255,255,0.16);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb-gallery-two-content h4 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(22px, 3vw, 32px) !important;
  line-height: 1.02 !important;
  font-weight: 950 !important;
  letter-spacing: -0.055em;
}

.vb-gallery-two-content p {
  max-width: 560px;
  margin: 0 !important;
  color: #e2e8f0 !important;
  -webkit-text-fill-color: #e2e8f0 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-gallery-two-empty {
  margin-top: 18px;
  padding: 24px;
  border-radius: 24px;
  background: rgba(255,255,255,0.08);
  border: 1px dashed rgba(148, 163, 184, 0.38);
  text-align: center;
}

.vb-gallery-two-empty h4 {
  margin: 0 0 8px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px !important;
  font-weight: 950 !important;
}

.vb-gallery-two-empty p {
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 15px;
  line-height: 1.6;
}

@media (max-width: 980px) {
  .vb-gallery-two-top {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-two-card,
  .vb-gallery-two-card:nth-child(5n + 1),
  .vb-gallery-two-card:nth-child(5n + 2) {
    grid-column: span 6;
  }
}

@media (max-width: 640px) {
  .vb-gallery-two-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-two-top h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-two-filters {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-two-filters button {
    width: 100%;
  }

  .vb-gallery-two-card,
  .vb-gallery-two-card:nth-child(5n + 1),
  .vb-gallery-two-card:nth-child(5n + 2) {
    grid-column: span 12;
    min-height: 280px;
  }
}</pre>



<p class="wp-block-paragraph">This filterable image gallery is useful for portfolio websites, product collections, interior design projects, travel galleries, architecture showcases, restaurant image sections, event albums, and agency case studies where users need to browse images by category.</p>



<h2 class="wp-block-heading">3. Searchable Image Gallery</h2>



<p class="wp-block-paragraph"><strong>A searchable image gallery</strong> is useful when a website has many images and users need to find specific visuals quickly. This pattern works well for portfolio archives, product collections, real estate galleries, travel galleries, content libraries, design inspiration pages, and media-heavy websites.</p>



<p class="wp-block-paragraph">This example uses JavaScript live search logic. Users can search by image title, category, location, or tag. The gallery updates instantly while typing, the visible result counter changes dynamically, and a clear empty state appears when no images match the search query.</p>



<ul class="wp-block-list">
<li>Searchable JavaScript image gallery</li>
<li>Live search while typing</li>
<li>Search by title, category, location, and tags</li>
<li>Dynamic result counter</li>
<li>Empty-state message when no results match</li>
</ul>



<div class="vb-gallery-three-demo">
  <div class="vb-gallery-three-shell">
    <div class="vb-gallery-three-hero">
      <div class="vb-gallery-three-copy">
        <span>Example 03</span>
        <h3>Searchable Image Gallery</h3>
        <p>Search a visual gallery by title, category, location, and tags using vanilla JavaScript.</p>
      </div>

      <div class="vb-gallery-three-search-card">
        <label for="vb-gallery-three-search">Search gallery</label>
        <div class="vb-gallery-three-search-wrap">
          <input id="vb-gallery-three-search" type="search" placeholder="Try product, city, nature, interior..." data-vb-gallery-three-search>
          <button type="button" data-vb-gallery-three-clear>Clear</button>
        </div>
        <strong data-vb-gallery-three-count>0 results</strong>
      </div>
    </div>

    <div class="vb-gallery-three-grid" data-vb-gallery-three-grid></div>

    <div class="vb-gallery-three-empty" data-vb-gallery-three-empty hidden>
      <strong>No matching images</strong>
      <p>Try a different keyword, category, location, or tag.</p>
    </div>
  </div>
</div>

<style>
.vb-gallery-three-demo,
.vb-gallery-three-demo * {
  box-sizing: border-box;
}

.vb-gallery-three-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 14% 16%, rgba(16, 185, 129, 0.16), transparent 34%),
    radial-gradient(circle at 88% 12%, rgba(14, 165, 233, 0.18), transparent 36%),
    linear-gradient(135deg, #ecfdf5 0%, #f0f9ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.24);
  box-shadow: 0 28px 80px rgba(15, 118, 110, 0.11);
}

.vb-gallery-three-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-three-hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(320px, 430px);
  gap: 22px;
  align-items: stretch;
  margin-bottom: 24px;
}

.vb-gallery-three-copy {
  min-width: 0;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.08);
}

.vb-gallery-three-copy span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-three-copy h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-three-copy p {
  max-width: 700px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-three-search-card {
  display: grid;
  align-content: center;
  gap: 13px;
  min-width: 0;
  padding: clamp(20px, 3vw, 28px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 18% 12%, rgba(255,255,255,0.20), transparent 34%),
    linear-gradient(135deg, #0f766e, #0284c7) !important;
  box-shadow: 0 22px 64px rgba(14, 116, 144, 0.22);
}

.vb-gallery-three-search-card label {
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-gallery-three-search-wrap {
  display: flex;
  gap: 10px;
  padding: 8px;
  border-radius: 20px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.20);
}

.vb-gallery-three-search-wrap input {
  min-width: 0;
  flex: 1;
  border: 0;
  outline: 0;
  border-radius: 15px;
  background: #ffffff;
  color: #0f172a;
  padding: 13px 14px;
  font-size: 15px;
  font-weight: 700;
}

.vb-gallery-three-search-wrap input::placeholder {
  color: #94a3b8;
}

.vb-gallery-three-search-wrap button {
  appearance: none;
  border: 0;
  border-radius: 15px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 12px 15px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-gallery-three-search-card strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 900;
}

.vb-gallery-three-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-three-card {
  min-width: 0;
  overflow: hidden;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.09);
}

.vb-gallery-three-image {
  position: relative;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  background: #e2e8f0;
}

.vb-gallery-three-image img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.36s ease;
}

.vb-gallery-three-card:hover img {
  transform: scale(1.08);
}

.vb-gallery-three-image span {
  position: absolute;
  left: 12px;
  bottom: 12px;
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.72);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb-gallery-three-body {
  display: grid;
  gap: 8px;
  padding: 15px;
}

.vb-gallery-three-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.15 !important;
  font-weight: 900 !important;
  letter-spacing: -0.035em;
}

.vb-gallery-three-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-gallery-three-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 3px;
}

.vb-gallery-three-tags small {
  display: inline-flex;
  padding: 5px 8px;
  border-radius: 999px;
  background: #f1f5f9;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 11px;
  font-weight: 850;
}

.vb-gallery-three-empty {
  margin-top: 18px;
  padding: 26px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px dashed rgba(20, 184, 166, 0.45);
  text-align: center;
}

.vb-gallery-three-empty strong {
  display: block;
  margin-bottom: 8px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 22px;
  font-weight: 950;
}

.vb-gallery-three-empty p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 15px;
  line-height: 1.6;
}

@media (max-width: 1050px) {
  .vb-gallery-three-hero {
    grid-template-columns: 1fr;
  }

  .vb-gallery-three-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 760px) {
  .vb-gallery-three-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-three-search-wrap {
    flex-direction: column;
  }

  .vb-gallery-three-search-wrap button {
    width: 100%;
  }
}

@media (max-width: 520px) {
  .vb-gallery-three-demo {
    padding: 16px;
    border-radius: 26px;
  }

  .vb-gallery-three-copy h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-three-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const searchInput = document.querySelector("[data-vb-gallery-three-search]");
  const clearButton = document.querySelector("[data-vb-gallery-three-clear]");
  const grid = document.querySelector("[data-vb-gallery-three-grid]");
  const count = document.querySelector("[data-vb-gallery-three-count]");
  const empty = document.querySelector("[data-vb-gallery-three-empty]");

  if (!searchInput || !clearButton || !grid || !count || !empty) return;

  const galleryItems = [
    {
      title: "City Glass Tower",
      category: "Architecture",
      location: "New York",
      tags: ["city", "building", "glass"],
      image: "https://picsum.photos/seed/gallery-three-city/900/900"
    },
    {
      title: "Green Product Box",
      category: "Product",
      location: "Studio",
      tags: ["product", "package", "brand"],
      image: "https://picsum.photos/seed/gallery-three-product/900/900"
    },
    {
      title: "Forest Cabin",
      category: "Nature",
      location: "Finland",
      tags: ["nature", "forest", "cabin"],
      image: "https://picsum.photos/seed/gallery-three-forest/900/900"
    },
    {
      title: "Minimal Kitchen",
      category: "Interior",
      location: "Stockholm",
      tags: ["interior", "kitchen", "minimal"],
      image: "https://picsum.photos/seed/gallery-three-kitchen/900/900"
    },
    {
      title: "Desert Road",
      category: "Travel",
      location: "Arizona",
      tags: ["travel", "road", "desert"],
      image: "https://picsum.photos/seed/gallery-three-road/900/900"
    },
    {
      title: "Creative Desk",
      category: "Workspace",
      location: "Berlin",
      tags: ["workspace", "desk", "creative"],
      image: "https://picsum.photos/seed/gallery-three-desk/900/900"
    },
    {
      title: "Hotel Lounge",
      category: "Interior",
      location: "Paris",
      tags: ["hotel", "lounge", "design"],
      image: "https://picsum.photos/seed/gallery-three-lounge/900/900"
    },
    {
      title: "Coastal View",
      category: "Travel",
      location: "Portugal",
      tags: ["coast", "ocean", "travel"],
      image: "https://picsum.photos/seed/gallery-three-coast/900/900"
    }
  ];

  function createSearchText(item) {
    return [
      item.title,
      item.category,
      item.location,
      item.tags.join(" ")
    ].join(" ").toLowerCase();
  }

  function createCard(item) {
    return `
      <article class="vb-gallery-three-card">
        <div class="vb-gallery-three-image">
          <img decoding="async" src="${item.image}" alt="${item.title}" loading="lazy">
          <span>${item.category}</span>
        </div>

        <div class="vb-gallery-three-body">
          <h4>${item.title}</h4>
          <p>${item.location}</p>

          <div class="vb-gallery-three-tags">
            ${item.tags.map(function (tag) {
              return `<small>#${tag}</small>`;
            }).join("")}
          </div>
        </div>
      </article>
    `;
  }

  function updateCount(number) {
    count.textContent = number === 1 ? "1 result" : number + " results";
  }

  function renderGallery(query) {
    const normalizedQuery = query.trim().toLowerCase();

    const visibleItems = galleryItems.filter(function (item) {
      return createSearchText(item).includes(normalizedQuery);
    });

    grid.innerHTML = visibleItems.map(createCard).join("");
    updateCount(visibleItems.length);
    empty.hidden = visibleItems.length !== 0;
  }

  searchInput.addEventListener("input", function () {
    renderGallery(searchInput.value);
  });

  clearButton.addEventListener("click", function () {
    searchInput.value = "";
    searchInput.focus();
    renderGallery("");
  });

  renderGallery("");
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const searchInput = document.querySelector("[data-vb-gallery-three-search]");
  const clearButton = document.querySelector("[data-vb-gallery-three-clear]");
  const grid = document.querySelector("[data-vb-gallery-three-grid]");
  const count = document.querySelector("[data-vb-gallery-three-count]");
  const empty = document.querySelector("[data-vb-gallery-three-empty]");

  if (!searchInput || !clearButton || !grid || !count || !empty) return;

  const galleryItems = [
    {
      title: "City Glass Tower",
      category: "Architecture",
      location: "New York",
      tags: ["city", "building", "glass"],
      image: "https://picsum.photos/seed/gallery-three-city/900/900"
    },
    {
      title: "Green Product Box",
      category: "Product",
      location: "Studio",
      tags: ["product", "package", "brand"],
      image: "https://picsum.photos/seed/gallery-three-product/900/900"
    },
    {
      title: "Forest Cabin",
      category: "Nature",
      location: "Finland",
      tags: ["nature", "forest", "cabin"],
      image: "https://picsum.photos/seed/gallery-three-forest/900/900"
    },
    {
      title: "Minimal Kitchen",
      category: "Interior",
      location: "Stockholm",
      tags: ["interior", "kitchen", "minimal"],
      image: "https://picsum.photos/seed/gallery-three-kitchen/900/900"
    },
    {
      title: "Desert Road",
      category: "Travel",
      location: "Arizona",
      tags: ["travel", "road", "desert"],
      image: "https://picsum.photos/seed/gallery-three-road/900/900"
    },
    {
      title: "Creative Desk",
      category: "Workspace",
      location: "Berlin",
      tags: ["workspace", "desk", "creative"],
      image: "https://picsum.photos/seed/gallery-three-desk/900/900"
    },
    {
      title: "Hotel Lounge",
      category: "Interior",
      location: "Paris",
      tags: ["hotel", "lounge", "design"],
      image: "https://picsum.photos/seed/gallery-three-lounge/900/900"
    },
    {
      title: "Coastal View",
      category: "Travel",
      location: "Portugal",
      tags: ["coast", "ocean", "travel"],
      image: "https://picsum.photos/seed/gallery-three-coast/900/900"
    }
  ];

  function createSearchText(item) {
    return [
      item.title,
      item.category,
      item.location,
      item.tags.join(" ")
    ].join(" ").toLowerCase();
  }

  function createCard(item) {
    return `
      &lt;article class="vb-gallery-three-card"&gt;
        &lt;div class="vb-gallery-three-image"&gt;
          &lt;img src="${item.image}" alt="${item.title}" loading="lazy"&gt;
          &lt;span&gt;${item.category}&lt;/span&gt;
        &lt;/div&gt;

        &lt;div class="vb-gallery-three-body"&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
          &lt;p&gt;${item.location}&lt;/p&gt;

          &lt;div class="vb-gallery-three-tags"&gt;
            ${item.tags.map(function (tag) {
              return `&lt;small&gt;#${tag}&lt;/small&gt;`;
            }).join("")}
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    `;
  }

  function updateCount(number) {
    count.textContent = number === 1 ? "1 result" : number + " results";
  }

  function renderGallery(query) {
    const normalizedQuery = query.trim().toLowerCase();

    const visibleItems = galleryItems.filter(function (item) {
      return createSearchText(item).includes(normalizedQuery);
    });

    grid.innerHTML = visibleItems.map(createCard).join("");
    updateCount(visibleItems.length);
    empty.hidden = visibleItems.length !== 0;
  }

  searchInput.addEventListener("input", function () {
    renderGallery(searchInput.value);
  });

  clearButton.addEventListener("click", function () {
    searchInput.value = "";
    searchInput.focus();
    renderGallery("");
  });

  renderGallery("");
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-three-demo"&gt;
  &lt;div class="vb-gallery-three-shell"&gt;
    &lt;div class="vb-gallery-three-hero"&gt;
      &lt;div class="vb-gallery-three-copy"&gt;
        &lt;span&gt;Example 03&lt;/span&gt;
        &lt;h3&gt;Searchable Image Gallery&lt;/h3&gt;
        &lt;p&gt;Search a visual gallery by title, category, location, and tags using vanilla JavaScript.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-gallery-three-search-card"&gt;
        &lt;label for="vb-gallery-three-search"&gt;Search gallery&lt;/label&gt;
        &lt;div class="vb-gallery-three-search-wrap"&gt;
          &lt;input id="vb-gallery-three-search" type="search" placeholder="Try product, city, nature, interior..." data-vb-gallery-three-search&gt;
          &lt;button type="button" data-vb-gallery-three-clear&gt;Clear&lt;/button&gt;
        &lt;/div&gt;
        &lt;strong data-vb-gallery-three-count&gt;0 results&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-three-grid" data-vb-gallery-three-grid&gt;&lt;/div&gt;

    &lt;div class="vb-gallery-three-empty" data-vb-gallery-three-empty hidden&gt;
      &lt;strong&gt;No matching images&lt;/strong&gt;
      &lt;p&gt;Try a different keyword, category, location, or tag.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-three-demo,
.vb-gallery-three-demo * {
  box-sizing: border-box;
}

.vb-gallery-three-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 40px;
  background:
    radial-gradient(circle at 14% 16%, rgba(16, 185, 129, 0.16), transparent 34%),
    radial-gradient(circle at 88% 12%, rgba(14, 165, 233, 0.18), transparent 36%),
    linear-gradient(135deg, #ecfdf5 0%, #f0f9ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.24);
  box-shadow: 0 28px 80px rgba(15, 118, 110, 0.11);
}

.vb-gallery-three-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-three-hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(320px, 430px);
  gap: 22px;
  align-items: stretch;
  margin-bottom: 24px;
}

.vb-gallery-three-copy {
  min-width: 0;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.08);
}

.vb-gallery-three-copy span {
  display: inline-flex;
  margin-bottom: 15px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ccfbf1;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-three-copy h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-three-copy p {
  max-width: 700px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-three-search-card {
  display: grid;
  align-content: center;
  gap: 13px;
  min-width: 0;
  padding: clamp(20px, 3vw, 28px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 18% 12%, rgba(255,255,255,0.20), transparent 34%),
    linear-gradient(135deg, #0f766e, #0284c7) !important;
  box-shadow: 0 22px 64px rgba(14, 116, 144, 0.22);
}

.vb-gallery-three-search-card label {
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-gallery-three-search-wrap {
  display: flex;
  gap: 10px;
  padding: 8px;
  border-radius: 20px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.20);
}

.vb-gallery-three-search-wrap input {
  min-width: 0;
  flex: 1;
  border: 0;
  outline: 0;
  border-radius: 15px;
  background: #ffffff;
  color: #0f172a;
  padding: 13px 14px;
  font-size: 15px;
  font-weight: 700;
}

.vb-gallery-three-search-wrap input::placeholder {
  color: #94a3b8;
}

.vb-gallery-three-search-wrap button {
  appearance: none;
  border: 0;
  border-radius: 15px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 12px 15px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-gallery-three-search-card strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 900;
}

.vb-gallery-three-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-three-card {
  min-width: 0;
  overflow: hidden;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.09);
}

.vb-gallery-three-image {
  position: relative;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  background: #e2e8f0;
}

.vb-gallery-three-image img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.36s ease;
}

.vb-gallery-three-card:hover img {
  transform: scale(1.08);
}

.vb-gallery-three-image span {
  position: absolute;
  left: 12px;
  bottom: 12px;
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.72);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb-gallery-three-body {
  display: grid;
  gap: 8px;
  padding: 15px;
}

.vb-gallery-three-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.15 !important;
  font-weight: 900 !important;
  letter-spacing: -0.035em;
}

.vb-gallery-three-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-gallery-three-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 3px;
}

.vb-gallery-three-tags small {
  display: inline-flex;
  padding: 5px 8px;
  border-radius: 999px;
  background: #f1f5f9;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 11px;
  font-weight: 850;
}

.vb-gallery-three-empty {
  margin-top: 18px;
  padding: 26px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px dashed rgba(20, 184, 166, 0.45);
  text-align: center;
}

.vb-gallery-three-empty strong {
  display: block;
  margin-bottom: 8px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 22px;
  font-weight: 950;
}

.vb-gallery-three-empty p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 15px;
  line-height: 1.6;
}

@media (max-width: 1050px) {
  .vb-gallery-three-hero {
    grid-template-columns: 1fr;
  }

  .vb-gallery-three-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 760px) {
  .vb-gallery-three-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-three-search-wrap {
    flex-direction: column;
  }

  .vb-gallery-three-search-wrap button {
    width: 100%;
  }
}

@media (max-width: 520px) {
  .vb-gallery-three-demo {
    padding: 16px;
    border-radius: 26px;
  }

  .vb-gallery-three-copy h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-three-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This searchable image gallery is useful for media libraries, portfolio archives, product image collections, travel galleries, real estate image sections, content directories, and any visual page where users need to quickly find images by keyword.</p>



<h2 class="wp-block-heading">4. Lightbox Image Gallery</h2>



<p class="wp-block-paragraph"><strong>A lightbox image gallery</strong> lets users open a larger image preview without leaving the page. It is useful for photography websites, product galleries, portfolio pages, case studies, real estate listings, event albums, restaurant galleries, and visual landing pages.</p>



<p class="wp-block-paragraph">This example uses JavaScript to open a custom lightbox modal when an image card is clicked. The selected image, title, category, and description are injected into the lightbox dynamically. Users can close the lightbox by clicking the close button, clicking the dark backdrop, or pressing the Escape key.</p>



<ul class="wp-block-list">
<li>Custom JavaScript lightbox gallery</li>
<li>Dynamic image, title, category, and description injection</li>
<li>Backdrop click close</li>
<li>Escape key close</li>
<li>Responsive large image preview</li>
</ul>



<div class="vb-gallery-four-demo">
  <div class="vb-gallery-four-shell" data-vb-gallery-four>
    <div class="vb-gallery-four-top">
      <span>Example 04</span>
      <h3>Lightbox Image Gallery</h3>
      <p>Open large image previews in a custom JavaScript lightbox modal with title, category, and description.</p>
    </div>

    <div class="vb-gallery-four-grid">
      <button type="button" class="vb-gallery-four-card" data-title="Editorial Workspace" data-category="Workspace" data-description="A polished workspace gallery image for agency portfolios and creative websites." data-image="https://picsum.photos/seed/gallery-four-workspace/1200/850">
        <img decoding="async" src="https://picsum.photos/seed/gallery-four-workspace/700/520" alt="Editorial Workspace" loading="lazy">
        <span>Workspace</span>
        <strong>Editorial Workspace</strong>
      </button>

      <button type="button" class="vb-gallery-four-card" data-title="Modern Product Display" data-category="Product" data-description="A clean product gallery preview for ecommerce, SaaS, and product launch pages." data-image="https://picsum.photos/seed/gallery-four-product/1200/850">
        <img decoding="async" src="https://picsum.photos/seed/gallery-four-product/700/520" alt="Modern Product Display" loading="lazy">
        <span>Product</span>
        <strong>Modern Product Display</strong>
      </button>

      <button type="button" class="vb-gallery-four-card" data-title="Hotel Interior Detail" data-category="Interior" data-description="A warm interior image suitable for hospitality, renovation, and design portfolios." data-image="https://picsum.photos/seed/gallery-four-interior/1200/850">
        <img decoding="async" src="https://picsum.photos/seed/gallery-four-interior/700/520" alt="Hotel Interior Detail" loading="lazy">
        <span>Interior</span>
        <strong>Hotel Interior Detail</strong>
      </button>

      <button type="button" class="vb-gallery-four-card" data-title="Mountain Travel Scene" data-category="Travel" data-description="A cinematic travel gallery image for destination pages and adventure blogs." data-image="https://picsum.photos/seed/gallery-four-travel/1200/850">
        <img decoding="async" src="https://picsum.photos/seed/gallery-four-travel/700/520" alt="Mountain Travel Scene" loading="lazy">
        <span>Travel</span>
        <strong>Mountain Travel Scene</strong>
      </button>
    </div>

    <div class="vb-gallery-four-lightbox" data-vb-gallery-four-lightbox hidden>
      <div class="vb-gallery-four-backdrop" data-vb-gallery-four-close></div>

      <div class="vb-gallery-four-modal" role="dialog" aria-modal="true" aria-label="Image preview">
        <button type="button" class="vb-gallery-four-close" data-vb-gallery-four-close>Close</button>

        <div class="vb-gallery-four-preview">
          <img decoding="async" src="" alt="" data-vb-gallery-four-image>
        </div>

        <div class="vb-gallery-four-info">
          <span data-vb-gallery-four-category></span>
          <h4 data-vb-gallery-four-title></h4>
          <p data-vb-gallery-four-description></p>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-gallery-four-demo,
.vb-gallery-four-demo * {
  box-sizing: border-box;
}

.vb-gallery-four-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 18px 56px 18px 56px;
  background:
    radial-gradient(circle at 16% 18%, rgba(244, 63, 94, 0.18), transparent 34%),
    radial-gradient(circle at 86% 14%, rgba(251, 146, 60, 0.20), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #fff7ed 52%, #ffffff 100%) !important;
  border: 1px solid rgba(251, 113, 133, 0.24);
  box-shadow: 0 28px 80px rgba(159, 18, 57, 0.10);
}

.vb-gallery-four-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-four-top {
  max-width: 760px;
  margin-bottom: 24px;
}

.vb-gallery-four-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-four-top h3 {
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-four-top p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-four-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-four-card {
  appearance: none;
  position: relative;
  display: block;
  min-width: 0;
  min-height: 370px;
  overflow: hidden;
  padding: 0;
  border: 0;
  border-radius: 30px;
  background: #111827;
  cursor: pointer;
  text-align: left;
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.15);
}

.vb-gallery-four-card:nth-child(even) {
  transform: translateY(24px);
}

.vb-gallery-four-card img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.42s ease, filter 0.42s ease;
}

.vb-gallery-four-card:hover img {
  transform: scale(1.1);
  filter: saturate(1.10) contrast(1.06);
}

.vb-gallery-four-card::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(17, 24, 39, 0.02), rgba(17, 24, 39, 0.88)),
    radial-gradient(circle at 20% 18%, rgba(255,255,255,0.18), transparent 34%);
}

.vb-gallery-four-card span,
.vb-gallery-four-card strong {
  position: absolute;
  z-index: 2;
  left: 18px;
  right: 18px;
}

.vb-gallery-four-card span {
  bottom: 74px;
  display: inline-flex;
  width: fit-content;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.15);
  border: 1px solid rgba(255,255,255,0.18);
  color: #ffe4e6 !important;
  -webkit-text-fill-color: #ffe4e6 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb-gallery-four-card strong {
  bottom: 20px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-gallery-four-lightbox {
  position: fixed;
  inset: 0;
  z-index: 99999;
  display: grid;
  place-items: center;
  padding: clamp(16px, 4vw, 34px);
}

.vb-gallery-four-lightbox[hidden] {
  display: none;
}

.vb-gallery-four-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(2, 6, 23, 0.78);
  backdrop-filter: blur(14px);
}

.vb-gallery-four-modal {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(280px, 0.8fr);
  width: min(1040px, 100%);
  max-height: min(760px, 92vh);
  overflow: hidden;
  border-radius: 34px;
  background: #ffffff;
  box-shadow: 0 30px 100px rgba(2, 6, 23, 0.46);
}

.vb-gallery-four-close {
  position: absolute;
  z-index: 3;
  top: 16px;
  right: 16px;
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.82);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 10px 13px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-gallery-four-preview {
  min-height: 520px;
  background: #111827;
}

.vb-gallery-four-preview img {
  display: block;
  width: 100%;
  height: 100%;
  min-height: 520px;
  object-fit: cover;
}

.vb-gallery-four-info {
  display: grid;
  align-content: center;
  gap: 13px;
  padding: clamp(24px, 4vw, 36px);
}

.vb-gallery-four-info span {
  display: inline-flex;
  width: fit-content;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-gallery-four-info h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(30px, 4vw, 48px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.065em;
}

.vb-gallery-four-info p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 980px) {
  .vb-gallery-four-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-four-card:nth-child(even) {
    transform: none;
  }

  .vb-gallery-four-card {
    min-height: 320px;
  }

  .vb-gallery-four-modal {
    grid-template-columns: 1fr;
    overflow: auto;
  }

  .vb-gallery-four-preview,
  .vb-gallery-four-preview img {
    min-height: 360px;
  }
}

@media (max-width: 560px) {
  .vb-gallery-four-demo {
    padding: 16px;
    border-radius: 26px;
  }

  .vb-gallery-four-top h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-four-grid {
    grid-template-columns: 1fr;
  }

  .vb-gallery-four-card {
    min-height: 290px;
    border-radius: 24px;
  }

  .vb-gallery-four-lightbox {
    padding: 12px;
  }

  .vb-gallery-four-modal {
    border-radius: 24px;
  }

  .vb-gallery-four-preview,
  .vb-gallery-four-preview img {
    min-height: 280px;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-four]");
  if (!gallery) return;

  const cards = gallery.querySelectorAll(".vb-gallery-four-card");
  const lightbox = gallery.querySelector("[data-vb-gallery-four-lightbox]");
  const closeButtons = gallery.querySelectorAll("[data-vb-gallery-four-close]");
  const lightboxImage = gallery.querySelector("[data-vb-gallery-four-image]");
  const lightboxTitle = gallery.querySelector("[data-vb-gallery-four-title]");
  const lightboxCategory = gallery.querySelector("[data-vb-gallery-four-category]");
  const lightboxDescription = gallery.querySelector("[data-vb-gallery-four-description]");

  let lastFocusedCard = null;

  function openLightbox(card) {
    lastFocusedCard = card;

    lightboxImage.src = card.getAttribute("data-image");
    lightboxImage.alt = card.getAttribute("data-title");
    lightboxTitle.textContent = card.getAttribute("data-title");
    lightboxCategory.textContent = card.getAttribute("data-category");
    lightboxDescription.textContent = card.getAttribute("data-description");

    lightbox.hidden = false;
    document.body.style.overflow = "hidden";
  }

  function closeLightbox() {
    lightbox.hidden = true;
    lightboxImage.src = "";
    document.body.style.overflow = "";

    if (lastFocusedCard) {
      lastFocusedCard.focus();
    }
  }

  cards.forEach(function (card) {
    card.addEventListener("click", function () {
      openLightbox(card);
    });
  });

  closeButtons.forEach(function (button) {
    button.addEventListener("click", closeLightbox);
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape" && !lightbox.hidden) {
      closeLightbox();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-four]");
  if (!gallery) return;

  const cards = gallery.querySelectorAll(".vb-gallery-four-card");
  const lightbox = gallery.querySelector("[data-vb-gallery-four-lightbox]");
  const closeButtons = gallery.querySelectorAll("[data-vb-gallery-four-close]");
  const lightboxImage = gallery.querySelector("[data-vb-gallery-four-image]");
  const lightboxTitle = gallery.querySelector("[data-vb-gallery-four-title]");
  const lightboxCategory = gallery.querySelector("[data-vb-gallery-four-category]");
  const lightboxDescription = gallery.querySelector("[data-vb-gallery-four-description]");

  let lastFocusedCard = null;

  function openLightbox(card) {
    lastFocusedCard = card;

    lightboxImage.src = card.getAttribute("data-image");
    lightboxImage.alt = card.getAttribute("data-title");
    lightboxTitle.textContent = card.getAttribute("data-title");
    lightboxCategory.textContent = card.getAttribute("data-category");
    lightboxDescription.textContent = card.getAttribute("data-description");

    lightbox.hidden = false;
    document.body.style.overflow = "hidden";
  }

  function closeLightbox() {
    lightbox.hidden = true;
    lightboxImage.src = "";
    document.body.style.overflow = "";

    if (lastFocusedCard) {
      lastFocusedCard.focus();
    }
  }

  cards.forEach(function (card) {
    card.addEventListener("click", function () {
      openLightbox(card);
    });
  });

  closeButtons.forEach(function (button) {
    button.addEventListener("click", closeLightbox);
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape" && !lightbox.hidden) {
      closeLightbox();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-four-demo"&gt;
  &lt;div class="vb-gallery-four-shell" data-vb-gallery-four&gt;
    &lt;div class="vb-gallery-four-top"&gt;
      &lt;span&gt;Example 04&lt;/span&gt;
      &lt;h3&gt;Lightbox Image Gallery&lt;/h3&gt;
      &lt;p&gt;Open large image previews in a custom JavaScript lightbox modal with title, category, and description.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-four-grid"&gt;
      &lt;button type="button" class="vb-gallery-four-card" data-title="Editorial Workspace" data-category="Workspace" data-description="A polished workspace gallery image for agency portfolios and creative websites." data-image="https://picsum.photos/seed/gallery-four-workspace/1200/850"&gt;
        &lt;img src="https://picsum.photos/seed/gallery-four-workspace/700/520" alt="Editorial Workspace" loading="lazy"&gt;
        &lt;span&gt;Workspace&lt;/span&gt;
        &lt;strong&gt;Editorial Workspace&lt;/strong&gt;
      &lt;/button&gt;

      &lt;button type="button" class="vb-gallery-four-card" data-title="Modern Product Display" data-category="Product" data-description="A clean product gallery preview for ecommerce, SaaS, and product launch pages." data-image="https://picsum.photos/seed/gallery-four-product/1200/850"&gt;
        &lt;img src="https://picsum.photos/seed/gallery-four-product/700/520" alt="Modern Product Display" loading="lazy"&gt;
        &lt;span&gt;Product&lt;/span&gt;
        &lt;strong&gt;Modern Product Display&lt;/strong&gt;
      &lt;/button&gt;

      &lt;button type="button" class="vb-gallery-four-card" data-title="Hotel Interior Detail" data-category="Interior" data-description="A warm interior image suitable for hospitality, renovation, and design portfolios." data-image="https://picsum.photos/seed/gallery-four-interior/1200/850"&gt;
        &lt;img src="https://picsum.photos/seed/gallery-four-interior/700/520" alt="Hotel Interior Detail" loading="lazy"&gt;
        &lt;span&gt;Interior&lt;/span&gt;
        &lt;strong&gt;Hotel Interior Detail&lt;/strong&gt;
      &lt;/button&gt;

      &lt;button type="button" class="vb-gallery-four-card" data-title="Mountain Travel Scene" data-category="Travel" data-description="A cinematic travel gallery image for destination pages and adventure blogs." data-image="https://picsum.photos/seed/gallery-four-travel/1200/850"&gt;
        &lt;img src="https://picsum.photos/seed/gallery-four-travel/700/520" alt="Mountain Travel Scene" loading="lazy"&gt;
        &lt;span&gt;Travel&lt;/span&gt;
        &lt;strong&gt;Mountain Travel Scene&lt;/strong&gt;
      &lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-four-lightbox" data-vb-gallery-four-lightbox hidden&gt;
      &lt;div class="vb-gallery-four-backdrop" data-vb-gallery-four-close&gt;&lt;/div&gt;

      &lt;div class="vb-gallery-four-modal" role="dialog" aria-modal="true" aria-label="Image preview"&gt;
        &lt;button type="button" class="vb-gallery-four-close" data-vb-gallery-four-close&gt;Close&lt;/button&gt;

        &lt;div class="vb-gallery-four-preview"&gt;
          &lt;img src="" alt="" data-vb-gallery-four-image&gt;
        &lt;/div&gt;

        &lt;div class="vb-gallery-four-info"&gt;
          &lt;span data-vb-gallery-four-category&gt;&lt;/span&gt;
          &lt;h4 data-vb-gallery-four-title&gt;&lt;/h4&gt;
          &lt;p data-vb-gallery-four-description&gt;&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-four-demo,
.vb-gallery-four-demo * {
  box-sizing: border-box;
}

.vb-gallery-four-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 18px 56px 18px 56px;
  background:
    radial-gradient(circle at 16% 18%, rgba(244, 63, 94, 0.18), transparent 34%),
    radial-gradient(circle at 86% 14%, rgba(251, 146, 60, 0.20), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #fff7ed 52%, #ffffff 100%) !important;
  border: 1px solid rgba(251, 113, 133, 0.24);
  box-shadow: 0 28px 80px rgba(159, 18, 57, 0.10);
}

.vb-gallery-four-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-four-top {
  max-width: 760px;
  margin-bottom: 24px;
}

.vb-gallery-four-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-four-top h3 {
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-four-top p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-four-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-four-card {
  appearance: none;
  position: relative;
  display: block;
  min-width: 0;
  min-height: 370px;
  overflow: hidden;
  padding: 0;
  border: 0;
  border-radius: 30px;
  background: #111827;
  cursor: pointer;
  text-align: left;
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.15);
}

.vb-gallery-four-card:nth-child(even) {
  transform: translateY(24px);
}

.vb-gallery-four-card img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.42s ease, filter 0.42s ease;
}

.vb-gallery-four-card:hover img {
  transform: scale(1.1);
  filter: saturate(1.10) contrast(1.06);
}

.vb-gallery-four-card::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(17, 24, 39, 0.02), rgba(17, 24, 39, 0.88)),
    radial-gradient(circle at 20% 18%, rgba(255,255,255,0.18), transparent 34%);
}

.vb-gallery-four-card span,
.vb-gallery-four-card strong {
  position: absolute;
  z-index: 2;
  left: 18px;
  right: 18px;
}

.vb-gallery-four-card span {
  bottom: 74px;
  display: inline-flex;
  width: fit-content;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.15);
  border: 1px solid rgba(255,255,255,0.18);
  color: #ffe4e6 !important;
  -webkit-text-fill-color: #ffe4e6 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb-gallery-four-card strong {
  bottom: 20px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-gallery-four-lightbox {
  position: fixed;
  inset: 0;
  z-index: 99999;
  display: grid;
  place-items: center;
  padding: clamp(16px, 4vw, 34px);
}

.vb-gallery-four-lightbox[hidden] {
  display: none;
}

.vb-gallery-four-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(2, 6, 23, 0.78);
  backdrop-filter: blur(14px);
}

.vb-gallery-four-modal {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: minmax(0, 1.2fr) minmax(280px, 0.8fr);
  width: min(1040px, 100%);
  max-height: min(760px, 92vh);
  overflow: hidden;
  border-radius: 34px;
  background: #ffffff;
  box-shadow: 0 30px 100px rgba(2, 6, 23, 0.46);
}

.vb-gallery-four-close {
  position: absolute;
  z-index: 3;
  top: 16px;
  right: 16px;
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.82);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 10px 13px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-gallery-four-preview {
  min-height: 520px;
  background: #111827;
}

.vb-gallery-four-preview img {
  display: block;
  width: 100%;
  height: 100%;
  min-height: 520px;
  object-fit: cover;
}

.vb-gallery-four-info {
  display: grid;
  align-content: center;
  gap: 13px;
  padding: clamp(24px, 4vw, 36px);
}

.vb-gallery-four-info span {
  display: inline-flex;
  width: fit-content;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.10em;
  text-transform: uppercase;
}

.vb-gallery-four-info h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(30px, 4vw, 48px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.065em;
}

.vb-gallery-four-info p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 980px) {
  .vb-gallery-four-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-four-card:nth-child(even) {
    transform: none;
  }

  .vb-gallery-four-card {
    min-height: 320px;
  }

  .vb-gallery-four-modal {
    grid-template-columns: 1fr;
    overflow: auto;
  }

  .vb-gallery-four-preview,
  .vb-gallery-four-preview img {
    min-height: 360px;
  }
}

@media (max-width: 560px) {
  .vb-gallery-four-demo {
    padding: 16px;
    border-radius: 26px;
  }

  .vb-gallery-four-top h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-four-grid {
    grid-template-columns: 1fr;
  }

  .vb-gallery-four-card {
    min-height: 290px;
    border-radius: 24px;
  }

  .vb-gallery-four-lightbox {
    padding: 12px;
  }

  .vb-gallery-four-modal {
    border-radius: 24px;
  }

  .vb-gallery-four-preview,
  .vb-gallery-four-preview img {
    min-height: 280px;
  }
}</pre>



<p class="wp-block-paragraph">This lightbox image gallery is useful for photography portfolios, ecommerce image previews, project case studies, real estate photos, restaurant galleries, event albums, and visual landing pages where users need a larger image view without leaving the page.</p>



<h2 class="wp-block-heading">5. Lightbox Gallery with Next and Previous Buttons</h2>



<p class="wp-block-paragraph"><strong>A lightbox gallery with next and previous buttons</strong> is useful when visitors need to move through a full image set without closing the preview after every image. This pattern works well for photography portfolios, product galleries, project case studies, event albums, travel websites, real estate listings, and visual storytelling pages.</p>



<p class="wp-block-paragraph">This example uses JavaScript index tracking. When a user opens an image, the script stores the current image index and updates the lightbox when the Next or Previous button is clicked. The image counter, title, category, and description all update dynamically.</p>



<ul class="wp-block-list">
<li>Lightbox gallery with next and previous controls</li>
<li>Current image index tracking</li>
<li>Dynamic image counter</li>
<li>Reusable gallery data array</li>
<li>Responsive lightbox preview layout</li>
</ul>



<div class="vb-gallery-five-demo">
  <div class="vb-gallery-five-shell" data-vb-gallery-five>
    <div class="vb-gallery-five-header">
      <div>
        <span>Example 05</span>
        <h3>Lightbox Gallery with Next and Previous Buttons</h3>
        <p>Browse a full image set inside a custom JavaScript lightbox without returning to the grid.</p>
      </div>
    </div>

    <div class="vb-gallery-five-grid" data-vb-gallery-five-grid></div>

    <div class="vb-gallery-five-lightbox" data-vb-gallery-five-lightbox hidden>
      <div class="vb-gallery-five-backdrop" data-vb-gallery-five-close></div>

      <div class="vb-gallery-five-modal" role="dialog" aria-modal="true" aria-label="Gallery image viewer">
        <button type="button" class="vb-gallery-five-close" data-vb-gallery-five-close>×</button>

        <div class="vb-gallery-five-image-stage">
          <button type="button" class="vb-gallery-five-nav vb-gallery-five-prev" data-vb-gallery-five-prev aria-label="Previous image">‹</button>
          <img decoding="async" src="" alt="" data-vb-gallery-five-image>
          <button type="button" class="vb-gallery-five-nav vb-gallery-five-next" data-vb-gallery-five-next aria-label="Next image">›</button>
        </div>

        <div class="vb-gallery-five-info">
          <div>
            <span data-vb-gallery-five-category></span>
            <h4 data-vb-gallery-five-title></h4>
            <p data-vb-gallery-five-description></p>
          </div>

          <strong data-vb-gallery-five-counter>1 / 1</strong>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-gallery-five-demo,
.vb-gallery-five-demo * {
  box-sizing: border-box;
}

.vb-gallery-five-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 46px 16px 46px 16px;
  background:
    linear-gradient(135deg, rgba(255, 255, 255, 0.92), rgba(239, 246, 255, 0.94)),
    radial-gradient(circle at 12% 12%, rgba(37, 99, 235, 0.18), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(168, 85, 247, 0.18), transparent 34%) !important;
  border: 1px solid rgba(37, 99, 235, 0.20);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-gallery-five-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-five-header {
  margin-bottom: 24px;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 34px 10px 34px 10px;
  background:
    radial-gradient(circle at 12% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #172554, #312e81 52%, #581c87) !important;
  box-shadow: 0 22px 64px rgba(30, 41, 59, 0.22);
}

.vb-gallery-five-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.18);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-five-header h3 {
  max-width: 850px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-five-header p {
  max-width: 720px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-five-grid {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-five-card {
  position: relative;
  min-width: 0;
  min-height: 240px;
  overflow: hidden;
  padding: 0;
  border: 0;
  border-radius: 28px;
  background: #0f172a;
  cursor: pointer;
  text-align: left;
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.14);
}

.vb-gallery-five-card:nth-child(1),
.vb-gallery-five-card:nth-child(6) {
  grid-column: span 3;
  min-height: 310px;
}

.vb-gallery-five-card:nth-child(2),
.vb-gallery-five-card:nth-child(3),
.vb-gallery-five-card:nth-child(4),
.vb-gallery-five-card:nth-child(5) {
  grid-column: span 3;
}

.vb-gallery-five-card img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.38s ease, filter 0.38s ease;
}

.vb-gallery-five-card:hover img {
  transform: scale(1.08);
  filter: saturate(1.12) contrast(1.05);
}

.vb-gallery-five-card::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(15, 23, 42, 0.02), rgba(15, 23, 42, 0.78));
}

.vb-gallery-five-card-content {
  position: absolute;
  z-index: 2;
  left: 18px;
  right: 18px;
  bottom: 18px;
  display: grid;
  gap: 7px;
}

.vb-gallery-five-card-content span {
  display: inline-flex;
  width: fit-content;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb-gallery-five-card-content strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-gallery-five-lightbox {
  position: fixed;
  inset: 0;
  z-index: 99999;
  display: grid;
  place-items: center;
  padding: clamp(14px, 4vw, 32px);
}

.vb-gallery-five-lightbox[hidden] {
  display: none;
}

.vb-gallery-five-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(2, 6, 23, 0.82);
  backdrop-filter: blur(14px);
}

.vb-gallery-five-modal {
  position: relative;
  z-index: 2;
  width: min(1060px, 100%);
  max-height: 92vh;
  overflow: hidden;
  border-radius: 36px;
  background: #ffffff;
  box-shadow: 0 34px 110px rgba(2, 6, 23, 0.48);
}

.vb-gallery-five-close {
  position: absolute;
  z-index: 5;
  top: 16px;
  right: 16px;
  width: 42px;
  height: 42px;
  border: 0;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.82);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 26px;
  line-height: 1;
  font-weight: 700;
  cursor: pointer;
}

.vb-gallery-five-image-stage {
  position: relative;
  min-height: 560px;
  background: #020617;
}

.vb-gallery-five-image-stage img {
  display: block;
  width: 100%;
  height: 560px;
  object-fit: cover;
}

.vb-gallery-five-nav {
  position: absolute;
  z-index: 4;
  top: 50%;
  transform: translateY(-50%);
  width: 54px;
  height: 54px;
  border: 1px solid rgba(255,255,255,0.24);
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.68);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 42px;
  line-height: 1;
  cursor: pointer;
  backdrop-filter: blur(10px);
}

.vb-gallery-five-prev {
  left: 18px;
}

.vb-gallery-five-next {
  right: 18px;
}

.vb-gallery-five-info {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 18px;
  padding: clamp(20px, 3vw, 30px);
}

.vb-gallery-five-info span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #e0e7ff;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-gallery-five-info h4 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(28px, 4vw, 42px) !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-gallery-five-info p {
  max-width: 680px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-gallery-five-info strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 10px 13px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

@media (max-width: 760px) {
  .vb-gallery-five-grid {
    grid-template-columns: 1fr;
  }

  .vb-gallery-five-card,
  .vb-gallery-five-card:nth-child(1),
  .vb-gallery-five-card:nth-child(6),
  .vb-gallery-five-card:nth-child(2),
  .vb-gallery-five-card:nth-child(3),
  .vb-gallery-five-card:nth-child(4),
  .vb-gallery-five-card:nth-child(5) {
    grid-column: span 1;
    min-height: 270px;
  }

  .vb-gallery-five-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-five-modal {
    border-radius: 24px;
  }

  .vb-gallery-five-image-stage,
  .vb-gallery-five-image-stage img {
    height: 330px;
    min-height: 330px;
  }

  .vb-gallery-five-info {
    flex-direction: column;
  }

  .vb-gallery-five-nav {
    width: 46px;
    height: 46px;
    font-size: 34px;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-five]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-five-grid]");
  const lightbox = gallery.querySelector("[data-vb-gallery-five-lightbox]");
  const closeButtons = gallery.querySelectorAll("[data-vb-gallery-five-close]");
  const prevButton = gallery.querySelector("[data-vb-gallery-five-prev]");
  const nextButton = gallery.querySelector("[data-vb-gallery-five-next]");
  const imageEl = gallery.querySelector("[data-vb-gallery-five-image]");
  const titleEl = gallery.querySelector("[data-vb-gallery-five-title]");
  const categoryEl = gallery.querySelector("[data-vb-gallery-five-category]");
  const descriptionEl = gallery.querySelector("[data-vb-gallery-five-description]");
  const counterEl = gallery.querySelector("[data-vb-gallery-five-counter]");

  const items = [
    {
      title: "Blue Mountain View",
      category: "Landscape",
      description: "A wide landscape image for travel websites, hero galleries, and visual storytelling layouts.",
      thumb: "https://picsum.photos/seed/gallery-five-mountain/800/620",
      image: "https://picsum.photos/seed/gallery-five-mountain/1400/900"
    },
    {
      title: "Premium Studio Desk",
      category: "Workspace",
      description: "A clean workspace image for agency pages, personal brands, and productivity content.",
      thumb: "https://picsum.photos/seed/gallery-five-desk/800/620",
      image: "https://picsum.photos/seed/gallery-five-desk/1400/900"
    },
    {
      title: "Modern Product Scene",
      category: "Product",
      description: "A polished product image for ecommerce collections and launch pages.",
      thumb: "https://picsum.photos/seed/gallery-five-product/800/620",
      image: "https://picsum.photos/seed/gallery-five-product/1400/900"
    },
    {
      title: "Warm Interior Corner",
      category: "Interior",
      description: "A soft interior image for design galleries, renovation case studies, and home decor websites.",
      thumb: "https://picsum.photos/seed/gallery-five-interior/800/620",
      image: "https://picsum.photos/seed/gallery-five-interior/1400/900"
    },
    {
      title: "City Night Lines",
      category: "Architecture",
      description: "A structured city image for architecture portfolios and urban visual collections.",
      thumb: "https://picsum.photos/seed/gallery-five-city/800/620",
      image: "https://picsum.photos/seed/gallery-five-city/1400/900"
    },
    {
      title: "Editorial Travel Detail",
      category: "Travel",
      description: "A travel-focused image for destination guides, blogs, and editorial gallery sections.",
      thumb: "https://picsum.photos/seed/gallery-five-travel/800/620",
      image: "https://picsum.photos/seed/gallery-five-travel/1400/900"
    }
  ];

  let currentIndex = 0;

  function createCard(item, index) {
    return `
      <button type="button" class="vb-gallery-five-card" data-index="${index}">
        <img decoding="async" src="${item.thumb}" alt="${item.title}" loading="lazy">
        <div class="vb-gallery-five-card-content">
          <span>${item.category}</span>
          <strong>${item.title}</strong>
        </div>
      </button>
    `;
  }

  function renderGrid() {
    grid.innerHTML = items.map(createCard).join("");
  }

  function updateLightbox() {
    const item = items[currentIndex];

    imageEl.src = item.image;
    imageEl.alt = item.title;
    titleEl.textContent = item.title;
    categoryEl.textContent = item.category;
    descriptionEl.textContent = item.description;
    counterEl.textContent = currentIndex + 1 + " / " + items.length;
  }

  function openLightbox(index) {
    currentIndex = index;
    updateLightbox();
    lightbox.hidden = false;
    document.body.style.overflow = "hidden";
  }

  function closeLightbox() {
    lightbox.hidden = true;
    imageEl.src = "";
    document.body.style.overflow = "";
  }

  function showPrevious() {
    currentIndex = (currentIndex - 1 + items.length) % items.length;
    updateLightbox();
  }

  function showNext() {
    currentIndex = (currentIndex + 1) % items.length;
    updateLightbox();
  }

  grid.addEventListener("click", function (event) {
    const card = event.target.closest("[data-index]");
    if (!card) return;

    openLightbox(Number(card.getAttribute("data-index")));
  });

  closeButtons.forEach(function (button) {
    button.addEventListener("click", closeLightbox);
  });

  prevButton.addEventListener("click", showPrevious);
  nextButton.addEventListener("click", showNext);

  renderGrid();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-five]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-five-grid]");
  const lightbox = gallery.querySelector("[data-vb-gallery-five-lightbox]");
  const closeButtons = gallery.querySelectorAll("[data-vb-gallery-five-close]");
  const prevButton = gallery.querySelector("[data-vb-gallery-five-prev]");
  const nextButton = gallery.querySelector("[data-vb-gallery-five-next]");
  const imageEl = gallery.querySelector("[data-vb-gallery-five-image]");
  const titleEl = gallery.querySelector("[data-vb-gallery-five-title]");
  const categoryEl = gallery.querySelector("[data-vb-gallery-five-category]");
  const descriptionEl = gallery.querySelector("[data-vb-gallery-five-description]");
  const counterEl = gallery.querySelector("[data-vb-gallery-five-counter]");

  const items = [
    {
      title: "Blue Mountain View",
      category: "Landscape",
      description: "A wide landscape image for travel websites, hero galleries, and visual storytelling layouts.",
      thumb: "https://picsum.photos/seed/gallery-five-mountain/800/620",
      image: "https://picsum.photos/seed/gallery-five-mountain/1400/900"
    },
    {
      title: "Premium Studio Desk",
      category: "Workspace",
      description: "A clean workspace image for agency pages, personal brands, and productivity content.",
      thumb: "https://picsum.photos/seed/gallery-five-desk/800/620",
      image: "https://picsum.photos/seed/gallery-five-desk/1400/900"
    },
    {
      title: "Modern Product Scene",
      category: "Product",
      description: "A polished product image for ecommerce collections and launch pages.",
      thumb: "https://picsum.photos/seed/gallery-five-product/800/620",
      image: "https://picsum.photos/seed/gallery-five-product/1400/900"
    },
    {
      title: "Warm Interior Corner",
      category: "Interior",
      description: "A soft interior image for design galleries, renovation case studies, and home decor websites.",
      thumb: "https://picsum.photos/seed/gallery-five-interior/800/620",
      image: "https://picsum.photos/seed/gallery-five-interior/1400/900"
    },
    {
      title: "City Night Lines",
      category: "Architecture",
      description: "A structured city image for architecture portfolios and urban visual collections.",
      thumb: "https://picsum.photos/seed/gallery-five-city/800/620",
      image: "https://picsum.photos/seed/gallery-five-city/1400/900"
    },
    {
      title: "Editorial Travel Detail",
      category: "Travel",
      description: "A travel-focused image for destination guides, blogs, and editorial gallery sections.",
      thumb: "https://picsum.photos/seed/gallery-five-travel/800/620",
      image: "https://picsum.photos/seed/gallery-five-travel/1400/900"
    }
  ];

  let currentIndex = 0;

  function createCard(item, index) {
    return `
      &lt;button type="button" class="vb-gallery-five-card" data-index="${index}"&gt;
        &lt;img src="${item.thumb}" alt="${item.title}" loading="lazy"&gt;
        &lt;div class="vb-gallery-five-card-content"&gt;
          &lt;span&gt;${item.category}&lt;/span&gt;
          &lt;strong&gt;${item.title}&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/button&gt;
    `;
  }

  function renderGrid() {
    grid.innerHTML = items.map(createCard).join("");
  }

  function updateLightbox() {
    const item = items[currentIndex];

    imageEl.src = item.image;
    imageEl.alt = item.title;
    titleEl.textContent = item.title;
    categoryEl.textContent = item.category;
    descriptionEl.textContent = item.description;
    counterEl.textContent = currentIndex + 1 + " / " + items.length;
  }

  function openLightbox(index) {
    currentIndex = index;
    updateLightbox();
    lightbox.hidden = false;
    document.body.style.overflow = "hidden";
  }

  function closeLightbox() {
    lightbox.hidden = true;
    imageEl.src = "";
    document.body.style.overflow = "";
  }

  function showPrevious() {
    currentIndex = (currentIndex - 1 + items.length) % items.length;
    updateLightbox();
  }

  function showNext() {
    currentIndex = (currentIndex + 1) % items.length;
    updateLightbox();
  }

  grid.addEventListener("click", function (event) {
    const card = event.target.closest("[data-index]");
    if (!card) return;

    openLightbox(Number(card.getAttribute("data-index")));
  });

  closeButtons.forEach(function (button) {
    button.addEventListener("click", closeLightbox);
  });

  prevButton.addEventListener("click", showPrevious);
  nextButton.addEventListener("click", showNext);

  renderGrid();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-five-demo"&gt;
  &lt;div class="vb-gallery-five-shell" data-vb-gallery-five&gt;
    &lt;div class="vb-gallery-five-header"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 05&lt;/span&gt;
        &lt;h3&gt;Lightbox Gallery with Next and Previous Buttons&lt;/h3&gt;
        &lt;p&gt;Browse a full image set inside a custom JavaScript lightbox without returning to the grid.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-five-grid" data-vb-gallery-five-grid&gt;&lt;/div&gt;

    &lt;div class="vb-gallery-five-lightbox" data-vb-gallery-five-lightbox hidden&gt;
      &lt;div class="vb-gallery-five-backdrop" data-vb-gallery-five-close&gt;&lt;/div&gt;

      &lt;div class="vb-gallery-five-modal" role="dialog" aria-modal="true" aria-label="Gallery image viewer"&gt;
        &lt;button type="button" class="vb-gallery-five-close" data-vb-gallery-five-close&gt;×&lt;/button&gt;

        &lt;div class="vb-gallery-five-image-stage"&gt;
          &lt;button type="button" class="vb-gallery-five-nav vb-gallery-five-prev" data-vb-gallery-five-prev aria-label="Previous image"&gt;‹&lt;/button&gt;
          &lt;img src="" alt="" data-vb-gallery-five-image&gt;
          &lt;button type="button" class="vb-gallery-five-nav vb-gallery-five-next" data-vb-gallery-five-next aria-label="Next image"&gt;›&lt;/button&gt;
        &lt;/div&gt;

        &lt;div class="vb-gallery-five-info"&gt;
          &lt;div&gt;
            &lt;span data-vb-gallery-five-category&gt;&lt;/span&gt;
            &lt;h4 data-vb-gallery-five-title&gt;&lt;/h4&gt;
            &lt;p data-vb-gallery-five-description&gt;&lt;/p&gt;
          &lt;/div&gt;

          &lt;strong data-vb-gallery-five-counter&gt;1 / 1&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-five-demo,
.vb-gallery-five-demo * {
  box-sizing: border-box;
}

.vb-gallery-five-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 46px 16px 46px 16px;
  background:
    linear-gradient(135deg, rgba(255, 255, 255, 0.92), rgba(239, 246, 255, 0.94)),
    radial-gradient(circle at 12% 12%, rgba(37, 99, 235, 0.18), transparent 34%),
    radial-gradient(circle at 88% 20%, rgba(168, 85, 247, 0.18), transparent 34%) !important;
  border: 1px solid rgba(37, 99, 235, 0.20);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-gallery-five-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-five-header {
  margin-bottom: 24px;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 34px 10px 34px 10px;
  background:
    radial-gradient(circle at 12% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #172554, #312e81 52%, #581c87) !important;
  box-shadow: 0 22px 64px rgba(30, 41, 59, 0.22);
}

.vb-gallery-five-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.18);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-five-header h3 {
  max-width: 850px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-five-header p {
  max-width: 720px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-five-grid {
  display: grid;
  grid-template-columns: repeat(6, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-five-card {
  position: relative;
  min-width: 0;
  min-height: 240px;
  overflow: hidden;
  padding: 0;
  border: 0;
  border-radius: 28px;
  background: #0f172a;
  cursor: pointer;
  text-align: left;
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.14);
}

.vb-gallery-five-card:nth-child(1),
.vb-gallery-five-card:nth-child(6) {
  grid-column: span 3;
  min-height: 310px;
}

.vb-gallery-five-card:nth-child(2),
.vb-gallery-five-card:nth-child(3),
.vb-gallery-five-card:nth-child(4),
.vb-gallery-five-card:nth-child(5) {
  grid-column: span 3;
}

.vb-gallery-five-card img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.38s ease, filter 0.38s ease;
}

.vb-gallery-five-card:hover img {
  transform: scale(1.08);
  filter: saturate(1.12) contrast(1.05);
}

.vb-gallery-five-card::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(15, 23, 42, 0.02), rgba(15, 23, 42, 0.78));
}

.vb-gallery-five-card-content {
  position: absolute;
  z-index: 2;
  left: 18px;
  right: 18px;
  bottom: 18px;
  display: grid;
  gap: 7px;
}

.vb-gallery-five-card-content span {
  display: inline-flex;
  width: fit-content;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb-gallery-five-card-content strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.055em;
}

.vb-gallery-five-lightbox {
  position: fixed;
  inset: 0;
  z-index: 99999;
  display: grid;
  place-items: center;
  padding: clamp(14px, 4vw, 32px);
}

.vb-gallery-five-lightbox[hidden] {
  display: none;
}

.vb-gallery-five-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(2, 6, 23, 0.82);
  backdrop-filter: blur(14px);
}

.vb-gallery-five-modal {
  position: relative;
  z-index: 2;
  width: min(1060px, 100%);
  max-height: 92vh;
  overflow: hidden;
  border-radius: 36px;
  background: #ffffff;
  box-shadow: 0 34px 110px rgba(2, 6, 23, 0.48);
}

.vb-gallery-five-close {
  position: absolute;
  z-index: 5;
  top: 16px;
  right: 16px;
  width: 42px;
  height: 42px;
  border: 0;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.82);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 26px;
  line-height: 1;
  font-weight: 700;
  cursor: pointer;
}

.vb-gallery-five-image-stage {
  position: relative;
  min-height: 560px;
  background: #020617;
}

.vb-gallery-five-image-stage img {
  display: block;
  width: 100%;
  height: 560px;
  object-fit: cover;
}

.vb-gallery-five-nav {
  position: absolute;
  z-index: 4;
  top: 50%;
  transform: translateY(-50%);
  width: 54px;
  height: 54px;
  border: 1px solid rgba(255,255,255,0.24);
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.68);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 42px;
  line-height: 1;
  cursor: pointer;
  backdrop-filter: blur(10px);
}

.vb-gallery-five-prev {
  left: 18px;
}

.vb-gallery-five-next {
  right: 18px;
}

.vb-gallery-five-info {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 18px;
  padding: clamp(20px, 3vw, 30px);
}

.vb-gallery-five-info span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #e0e7ff;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-gallery-five-info h4 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(28px, 4vw, 42px) !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-gallery-five-info p {
  max-width: 680px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-gallery-five-info strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 10px 13px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

@media (max-width: 760px) {
  .vb-gallery-five-grid {
    grid-template-columns: 1fr;
  }

  .vb-gallery-five-card,
  .vb-gallery-five-card:nth-child(1),
  .vb-gallery-five-card:nth-child(6),
  .vb-gallery-five-card:nth-child(2),
  .vb-gallery-five-card:nth-child(3),
  .vb-gallery-five-card:nth-child(4),
  .vb-gallery-five-card:nth-child(5) {
    grid-column: span 1;
    min-height: 270px;
  }

  .vb-gallery-five-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-five-modal {
    border-radius: 24px;
  }

  .vb-gallery-five-image-stage,
  .vb-gallery-five-image-stage img {
    height: 330px;
    min-height: 330px;
  }

  .vb-gallery-five-info {
    flex-direction: column;
  }

  .vb-gallery-five-nav {
    width: 46px;
    height: 46px;
    font-size: 34px;
  }
}</pre>



<p class="wp-block-paragraph">This lightbox gallery with next and previous buttons is useful for photography collections, product galleries, interior design projects, real estate image sets, travel galleries, event albums, and portfolio pages where users need to browse several images in one focused preview mode.</p>



<h2 class="wp-block-heading">6. Keyboard Controlled Gallery Lightbox</h2>



<p class="wp-block-paragraph"><strong>A keyboard controlled gallery lightbox</strong> improves usability by letting users navigate images without using the mouse. This is especially useful for portfolio galleries, photography websites, media libraries, product previews, documentation pages, and accessible image viewers.</p>



<p class="wp-block-paragraph">This example uses JavaScript keyboard event handling. Users can open the viewer, press the right arrow key for the next image, press the left arrow key for the previous image, and press Escape to close the lightbox. The visible keyboard hint and counter update with the current image.</p>



<ul class="wp-block-list">
<li>Keyboard controlled image lightbox</li>
<li>Left and right arrow navigation</li>
<li>Escape key close behavior</li>
<li>Current image counter</li>
<li>Accessible button-based gallery cards</li>
</ul>



<div class="vb-gallery-six-demo">
  <div class="vb-gallery-six-shell" data-vb-gallery-six>
    <div class="vb-gallery-six-sidebar">
      <span>Example 06</span>
      <h3>Keyboard Controlled Gallery Lightbox</h3>
      <p>Open the gallery and use arrow keys to move between images. Press Escape to close the viewer.</p>

      <div class="vb-gallery-six-keys">
        <kbd>←</kbd>
        <kbd>→</kbd>
        <kbd>Esc</kbd>
      </div>
    </div>

    <div class="vb-gallery-six-grid" data-vb-gallery-six-grid></div>

    <div class="vb-gallery-six-viewer" data-vb-gallery-six-viewer hidden>
      <div class="vb-gallery-six-overlay" data-vb-gallery-six-close></div>

      <div class="vb-gallery-six-panel" role="dialog" aria-modal="true" aria-label="Keyboard controlled gallery viewer">
        <div class="vb-gallery-six-toolbar">
          <span data-vb-gallery-six-counter>1 / 1</span>
          <strong>Use ← → keys to browse</strong>
          <button type="button" data-vb-gallery-six-close>Close</button>
        </div>

        <div class="vb-gallery-six-photo-wrap">
          <button type="button" class="vb-gallery-six-arrow vb-gallery-six-left" data-vb-gallery-six-prev aria-label="Previous image">←</button>
          <img decoding="async" src="" alt="" data-vb-gallery-six-image>
          <button type="button" class="vb-gallery-six-arrow vb-gallery-six-right" data-vb-gallery-six-next aria-label="Next image">→</button>
        </div>

        <div class="vb-gallery-six-caption">
          <span data-vb-gallery-six-category></span>
          <h4 data-vb-gallery-six-title></h4>
          <p data-vb-gallery-six-description></p>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-gallery-six-demo,
.vb-gallery-six-demo * {
  box-sizing: border-box;
}

.vb-gallery-six-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 26px;
  background:
    linear-gradient(90deg, rgba(15, 23, 42, 0.05) 1px, transparent 1px),
    linear-gradient(0deg, rgba(15, 23, 42, 0.05) 1px, transparent 1px),
    linear-gradient(135deg, #fafaf9 0%, #f5f5f4 52%, #ffffff 100%) !important;
  background-size: 30px 30px, 30px 30px, auto !important;
  border: 1px solid rgba(120, 113, 108, 0.18);
  box-shadow: 0 28px 80px rgba(68, 64, 60, 0.10);
}

.vb-gallery-six-shell {
  display: grid;
  grid-template-columns: minmax(260px, 340px) minmax(0, 1fr);
  gap: 18px;
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-six-sidebar {
  display: grid;
  align-content: center;
  min-width: 0;
  padding: clamp(22px, 4vw, 32px);
  border-radius: 24px;
  background:
    radial-gradient(circle at 18% 14%, rgba(255,255,255,0.14), transparent 34%),
    linear-gradient(135deg, #1c1917, #44403c) !important;
  box-shadow: 0 22px 64px rgba(28, 25, 23, 0.20);
}

.vb-gallery-six-sidebar span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-six-sidebar h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 4.8vw, 54px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-six-sidebar p {
  margin: 0 0 22px !important;
  color: #e7e5e4 !important;
  -webkit-text-fill-color: #e7e5e4 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-six-keys {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.vb-gallery-six-keys kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 48px;
  height: 42px;
  padding: 0 13px;
  border-radius: 12px;
  background: #ffffff;
  color: #1c1917;
  font-size: 14px;
  font-weight: 950;
  box-shadow: inset 0 -3px 0 rgba(15, 23, 42, 0.14);
}

.vb-gallery-six-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-gallery-six-tile {
  position: relative;
  min-height: 235px;
  overflow: hidden;
  border: 0;
  border-radius: 24px;
  background: #292524;
  cursor: pointer;
  text-align: left;
  box-shadow: 0 16px 44px rgba(41, 37, 36, 0.14);
}

.vb-gallery-six-tile:nth-child(1),
.vb-gallery-six-tile:nth-child(4) {
  grid-row: span 2;
  min-height: 482px;
}

.vb-gallery-six-tile img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  transition: transform 0.38s ease, filter 0.38s ease;
}

.vb-gallery-six-tile:hover img {
  transform: scale(1.08);
  filter: contrast(1.05) saturate(1.08);
}

.vb-gallery-six-tile::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(28, 25, 23, 0.03), rgba(28, 25, 23, 0.78));
}

.vb-gallery-six-tile strong {
  position: absolute;
  z-index: 2;
  left: 16px;
  right: 16px;
  bottom: 16px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.045em;
}

.vb-gallery-six-viewer {
  position: fixed;
  inset: 0;
  z-index: 99999;
  display: grid;
  place-items: center;
  padding: clamp(12px, 3vw, 28px);
}

.vb-gallery-six-viewer[hidden] {
  display: none;
}

.vb-gallery-six-overlay {
  position: absolute;
  inset: 0;
  background: rgba(12, 10, 9, 0.86);
  backdrop-filter: blur(14px);
}

.vb-gallery-six-panel {
  position: relative;
  z-index: 2;
  width: min(1080px, 100%);
  max-height: 92vh;
  overflow: hidden;
  border-radius: 28px;
  background: #fafaf9;
  box-shadow: 0 34px 110px rgba(0, 0, 0, 0.48);
}

.vb-gallery-six-toolbar {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 12px;
  padding: 14px;
  background: #1c1917;
}

.vb-gallery-six-toolbar span,
.vb-gallery-six-toolbar strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-gallery-six-toolbar strong {
  text-align: center;
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
}

.vb-gallery-six-toolbar button {
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #1c1917;
  padding: 9px 12px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-gallery-six-photo-wrap {
  position: relative;
  height: 560px;
  background: #0c0a09;
}

.vb-gallery-six-photo-wrap img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.vb-gallery-six-arrow {
  position: absolute;
  z-index: 3;
  top: 50%;
  transform: translateY(-50%);
  width: 54px;
  height: 54px;
  border: 1px solid rgba(255,255,255,0.24);
  border-radius: 999px;
  background: rgba(28, 25, 23, 0.72);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  font-weight: 950;
  cursor: pointer;
  backdrop-filter: blur(10px);
}

.vb-gallery-six-left {
  left: 18px;
}

.vb-gallery-six-right {
  right: 18px;
}

.vb-gallery-six-caption {
  padding: clamp(20px, 3vw, 28px);
}

.vb-gallery-six-caption span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-gallery-six-caption h4 {
  margin: 0 0 8px !important;
  color: #1c1917 !important;
  -webkit-text-fill-color: #1c1917 !important;
  font-size: clamp(28px, 4vw, 42px) !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-gallery-six-caption p {
  max-width: 760px;
  margin: 0 !important;
  color: #57534e !important;
  -webkit-text-fill-color: #57534e !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

@media (max-width: 980px) {
  .vb-gallery-six-shell {
    grid-template-columns: 1fr;
  }

  .vb-gallery-six-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-six-tile:nth-child(1),
  .vb-gallery-six-tile:nth-child(4) {
    grid-row: span 1;
    min-height: 260px;
  }
}

@media (max-width: 620px) {
  .vb-gallery-six-demo {
    padding: 16px;
  }

  .vb-gallery-six-sidebar h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-six-grid {
    grid-template-columns: 1fr;
  }

  .vb-gallery-six-tile {
    min-height: 260px;
  }

  .vb-gallery-six-toolbar {
    grid-template-columns: 1fr;
    text-align: center;
  }

  .vb-gallery-six-photo-wrap {
    height: 320px;
  }

  .vb-gallery-six-arrow {
    width: 44px;
    height: 44px;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-six]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-six-grid]");
  const viewer = gallery.querySelector("[data-vb-gallery-six-viewer]");
  const imageEl = gallery.querySelector("[data-vb-gallery-six-image]");
  const titleEl = gallery.querySelector("[data-vb-gallery-six-title]");
  const categoryEl = gallery.querySelector("[data-vb-gallery-six-category]");
  const descriptionEl = gallery.querySelector("[data-vb-gallery-six-description]");
  const counterEl = gallery.querySelector("[data-vb-gallery-six-counter]");
  const closeButtons = gallery.querySelectorAll("[data-vb-gallery-six-close]");
  const prevButton = gallery.querySelector("[data-vb-gallery-six-prev]");
  const nextButton = gallery.querySelector("[data-vb-gallery-six-next]");

  const items = [
    {
      title: "Gallery Keyboard One",
      category: "Portfolio",
      description: "A keyboard-friendly gallery item designed for portfolio image browsing and accessible preview controls.",
      thumb: "https://picsum.photos/seed/gallery-six-one/700/900",
      image: "https://picsum.photos/seed/gallery-six-one/1400/920"
    },
    {
      title: "Gallery Keyboard Two",
      category: "Editorial",
      description: "A visual editorial gallery item where users can navigate with arrow keys inside the viewer.",
      thumb: "https://picsum.photos/seed/gallery-six-two/700/700",
      image: "https://picsum.photos/seed/gallery-six-two/1400/920"
    },
    {
      title: "Gallery Keyboard Three",
      category: "Product",
      description: "A product gallery image preview with keyboard navigation for faster browsing.",
      thumb: "https://picsum.photos/seed/gallery-six-three/700/700",
      image: "https://picsum.photos/seed/gallery-six-three/1400/920"
    },
    {
      title: "Gallery Keyboard Four",
      category: "Travel",
      description: "A travel gallery item that supports keyboard-based movement between large image previews.",
      thumb: "https://picsum.photos/seed/gallery-six-four/700/900",
      image: "https://picsum.photos/seed/gallery-six-four/1400/920"
    },
    {
      title: "Gallery Keyboard Five",
      category: "Interior",
      description: "An interior design gallery item with clear title, category, and description in the lightbox.",
      thumb: "https://picsum.photos/seed/gallery-six-five/700/700",
      image: "https://picsum.photos/seed/gallery-six-five/1400/920"
    }
  ];

  let currentIndex = 0;

  function createTile(item, index) {
    return `
      <button type="button" class="vb-gallery-six-tile" data-index="${index}">
        <img decoding="async" src="${item.thumb}" alt="${item.title}" loading="lazy">
        <strong>${item.title}</strong>
      </button>
    `;
  }

  function renderGrid() {
    grid.innerHTML = items.map(createTile).join("");
  }

  function updateViewer() {
    const item = items[currentIndex];

    imageEl.src = item.image;
    imageEl.alt = item.title;
    titleEl.textContent = item.title;
    categoryEl.textContent = item.category;
    descriptionEl.textContent = item.description;
    counterEl.textContent = currentIndex + 1 + " / " + items.length;
  }

  function openViewer(index) {
    currentIndex = index;
    updateViewer();
    viewer.hidden = false;
    document.body.style.overflow = "hidden";
  }

  function closeViewer() {
    viewer.hidden = true;
    imageEl.src = "";
    document.body.style.overflow = "";
  }

  function showPrevious() {
    currentIndex = (currentIndex - 1 + items.length) % items.length;
    updateViewer();
  }

  function showNext() {
    currentIndex = (currentIndex + 1) % items.length;
    updateViewer();
  }

  grid.addEventListener("click", function (event) {
    const tile = event.target.closest("[data-index]");
    if (!tile) return;
    openViewer(Number(tile.getAttribute("data-index")));
  });

  closeButtons.forEach(function (button) {
    button.addEventListener("click", closeViewer);
  });

  prevButton.addEventListener("click", showPrevious);
  nextButton.addEventListener("click", showNext);

  document.addEventListener("keydown", function (event) {
    if (viewer.hidden) return;

    if (event.key === "Escape") {
      closeViewer();
    }

    if (event.key === "ArrowLeft") {
      showPrevious();
    }

    if (event.key === "ArrowRight") {
      showNext();
    }
  });

  renderGrid();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-six]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-six-grid]");
  const viewer = gallery.querySelector("[data-vb-gallery-six-viewer]");
  const imageEl = gallery.querySelector("[data-vb-gallery-six-image]");
  const titleEl = gallery.querySelector("[data-vb-gallery-six-title]");
  const categoryEl = gallery.querySelector("[data-vb-gallery-six-category]");
  const descriptionEl = gallery.querySelector("[data-vb-gallery-six-description]");
  const counterEl = gallery.querySelector("[data-vb-gallery-six-counter]");
  const closeButtons = gallery.querySelectorAll("[data-vb-gallery-six-close]");
  const prevButton = gallery.querySelector("[data-vb-gallery-six-prev]");
  const nextButton = gallery.querySelector("[data-vb-gallery-six-next]");

  const items = [
    {
      title: "Gallery Keyboard One",
      category: "Portfolio",
      description: "A keyboard-friendly gallery item designed for portfolio image browsing and accessible preview controls.",
      thumb: "https://picsum.photos/seed/gallery-six-one/700/900",
      image: "https://picsum.photos/seed/gallery-six-one/1400/920"
    },
    {
      title: "Gallery Keyboard Two",
      category: "Editorial",
      description: "A visual editorial gallery item where users can navigate with arrow keys inside the viewer.",
      thumb: "https://picsum.photos/seed/gallery-six-two/700/700",
      image: "https://picsum.photos/seed/gallery-six-two/1400/920"
    },
    {
      title: "Gallery Keyboard Three",
      category: "Product",
      description: "A product gallery image preview with keyboard navigation for faster browsing.",
      thumb: "https://picsum.photos/seed/gallery-six-three/700/700",
      image: "https://picsum.photos/seed/gallery-six-three/1400/920"
    },
    {
      title: "Gallery Keyboard Four",
      category: "Travel",
      description: "A travel gallery item that supports keyboard-based movement between large image previews.",
      thumb: "https://picsum.photos/seed/gallery-six-four/700/900",
      image: "https://picsum.photos/seed/gallery-six-four/1400/920"
    },
    {
      title: "Gallery Keyboard Five",
      category: "Interior",
      description: "An interior design gallery item with clear title, category, and description in the lightbox.",
      thumb: "https://picsum.photos/seed/gallery-six-five/700/700",
      image: "https://picsum.photos/seed/gallery-six-five/1400/920"
    }
  ];

  let currentIndex = 0;

  function createTile(item, index) {
    return `
      &lt;button type="button" class="vb-gallery-six-tile" data-index="${index}"&gt;
        &lt;img src="${item.thumb}" alt="${item.title}" loading="lazy"&gt;
        &lt;strong&gt;${item.title}&lt;/strong&gt;
      &lt;/button&gt;
    `;
  }

  function renderGrid() {
    grid.innerHTML = items.map(createTile).join("");
  }

  function updateViewer() {
    const item = items[currentIndex];

    imageEl.src = item.image;
    imageEl.alt = item.title;
    titleEl.textContent = item.title;
    categoryEl.textContent = item.category;
    descriptionEl.textContent = item.description;
    counterEl.textContent = currentIndex + 1 + " / " + items.length;
  }

  function openViewer(index) {
    currentIndex = index;
    updateViewer();
    viewer.hidden = false;
    document.body.style.overflow = "hidden";
  }

  function closeViewer() {
    viewer.hidden = true;
    imageEl.src = "";
    document.body.style.overflow = "";
  }

  function showPrevious() {
    currentIndex = (currentIndex - 1 + items.length) % items.length;
    updateViewer();
  }

  function showNext() {
    currentIndex = (currentIndex + 1) % items.length;
    updateViewer();
  }

  grid.addEventListener("click", function (event) {
    const tile = event.target.closest("[data-index]");
    if (!tile) return;
    openViewer(Number(tile.getAttribute("data-index")));
  });

  closeButtons.forEach(function (button) {
    button.addEventListener("click", closeViewer);
  });

  prevButton.addEventListener("click", showPrevious);
  nextButton.addEventListener("click", showNext);

  document.addEventListener("keydown", function (event) {
    if (viewer.hidden) return;

    if (event.key === "Escape") {
      closeViewer();
    }

    if (event.key === "ArrowLeft") {
      showPrevious();
    }

    if (event.key === "ArrowRight") {
      showNext();
    }
  });

  renderGrid();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-six-demo"&gt;
  &lt;div class="vb-gallery-six-shell" data-vb-gallery-six&gt;
    &lt;div class="vb-gallery-six-sidebar"&gt;
      &lt;span&gt;Example 06&lt;/span&gt;
      &lt;h3&gt;Keyboard Controlled Gallery Lightbox&lt;/h3&gt;
      &lt;p&gt;Open the gallery and use arrow keys to move between images. Press Escape to close the viewer.&lt;/p&gt;

      &lt;div class="vb-gallery-six-keys"&gt;
        &lt;kbd&gt;←&lt;/kbd&gt;
        &lt;kbd&gt;→&lt;/kbd&gt;
        &lt;kbd&gt;Esc&lt;/kbd&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-six-grid" data-vb-gallery-six-grid&gt;&lt;/div&gt;

    &lt;div class="vb-gallery-six-viewer" data-vb-gallery-six-viewer hidden&gt;
      &lt;div class="vb-gallery-six-overlay" data-vb-gallery-six-close&gt;&lt;/div&gt;

      &lt;div class="vb-gallery-six-panel" role="dialog" aria-modal="true" aria-label="Keyboard controlled gallery viewer"&gt;
        &lt;div class="vb-gallery-six-toolbar"&gt;
          &lt;span data-vb-gallery-six-counter&gt;1 / 1&lt;/span&gt;
          &lt;strong&gt;Use ← → keys to browse&lt;/strong&gt;
          &lt;button type="button" data-vb-gallery-six-close&gt;Close&lt;/button&gt;
        &lt;/div&gt;

        &lt;div class="vb-gallery-six-photo-wrap"&gt;
          &lt;button type="button" class="vb-gallery-six-arrow vb-gallery-six-left" data-vb-gallery-six-prev aria-label="Previous image"&gt;←&lt;/button&gt;
          &lt;img src="" alt="" data-vb-gallery-six-image&gt;
          &lt;button type="button" class="vb-gallery-six-arrow vb-gallery-six-right" data-vb-gallery-six-next aria-label="Next image"&gt;→&lt;/button&gt;
        &lt;/div&gt;

        &lt;div class="vb-gallery-six-caption"&gt;
          &lt;span data-vb-gallery-six-category&gt;&lt;/span&gt;
          &lt;h4 data-vb-gallery-six-title&gt;&lt;/h4&gt;
          &lt;p data-vb-gallery-six-description&gt;&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-six-demo,
.vb-gallery-six-demo * {
  box-sizing: border-box;
}

.vb-gallery-six-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 26px;
  background:
    linear-gradient(90deg, rgba(15, 23, 42, 0.05) 1px, transparent 1px),
    linear-gradient(0deg, rgba(15, 23, 42, 0.05) 1px, transparent 1px),
    linear-gradient(135deg, #fafaf9 0%, #f5f5f4 52%, #ffffff 100%) !important;
  background-size: 30px 30px, 30px 30px, auto !important;
  border: 1px solid rgba(120, 113, 108, 0.18);
  box-shadow: 0 28px 80px rgba(68, 64, 60, 0.10);
}

.vb-gallery-six-shell {
  display: grid;
  grid-template-columns: minmax(260px, 340px) minmax(0, 1fr);
  gap: 18px;
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-six-sidebar {
  display: grid;
  align-content: center;
  min-width: 0;
  padding: clamp(22px, 4vw, 32px);
  border-radius: 24px;
  background:
    radial-gradient(circle at 18% 14%, rgba(255,255,255,0.14), transparent 34%),
    linear-gradient(135deg, #1c1917, #44403c) !important;
  box-shadow: 0 22px 64px rgba(28, 25, 23, 0.20);
}

.vb-gallery-six-sidebar span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-six-sidebar h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 4.8vw, 54px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-six-sidebar p {
  margin: 0 0 22px !important;
  color: #e7e5e4 !important;
  -webkit-text-fill-color: #e7e5e4 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-six-keys {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
}

.vb-gallery-six-keys kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 48px;
  height: 42px;
  padding: 0 13px;
  border-radius: 12px;
  background: #ffffff;
  color: #1c1917;
  font-size: 14px;
  font-weight: 950;
  box-shadow: inset 0 -3px 0 rgba(15, 23, 42, 0.14);
}

.vb-gallery-six-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-gallery-six-tile {
  position: relative;
  min-height: 235px;
  overflow: hidden;
  border: 0;
  border-radius: 24px;
  background: #292524;
  cursor: pointer;
  text-align: left;
  box-shadow: 0 16px 44px rgba(41, 37, 36, 0.14);
}

.vb-gallery-six-tile:nth-child(1),
.vb-gallery-six-tile:nth-child(4) {
  grid-row: span 2;
  min-height: 482px;
}

.vb-gallery-six-tile img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  transition: transform 0.38s ease, filter 0.38s ease;
}

.vb-gallery-six-tile:hover img {
  transform: scale(1.08);
  filter: contrast(1.05) saturate(1.08);
}

.vb-gallery-six-tile::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(28, 25, 23, 0.03), rgba(28, 25, 23, 0.78));
}

.vb-gallery-six-tile strong {
  position: absolute;
  z-index: 2;
  left: 16px;
  right: 16px;
  bottom: 16px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  line-height: 1.05;
  font-weight: 950;
  letter-spacing: -0.045em;
}

.vb-gallery-six-viewer {
  position: fixed;
  inset: 0;
  z-index: 99999;
  display: grid;
  place-items: center;
  padding: clamp(12px, 3vw, 28px);
}

.vb-gallery-six-viewer[hidden] {
  display: none;
}

.vb-gallery-six-overlay {
  position: absolute;
  inset: 0;
  background: rgba(12, 10, 9, 0.86);
  backdrop-filter: blur(14px);
}

.vb-gallery-six-panel {
  position: relative;
  z-index: 2;
  width: min(1080px, 100%);
  max-height: 92vh;
  overflow: hidden;
  border-radius: 28px;
  background: #fafaf9;
  box-shadow: 0 34px 110px rgba(0, 0, 0, 0.48);
}

.vb-gallery-six-toolbar {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 12px;
  padding: 14px;
  background: #1c1917;
}

.vb-gallery-six-toolbar span,
.vb-gallery-six-toolbar strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 900;
}

.vb-gallery-six-toolbar strong {
  text-align: center;
  color: #fde68a !important;
  -webkit-text-fill-color: #fde68a !important;
}

.vb-gallery-six-toolbar button {
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #1c1917;
  padding: 9px 12px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-gallery-six-photo-wrap {
  position: relative;
  height: 560px;
  background: #0c0a09;
}

.vb-gallery-six-photo-wrap img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.vb-gallery-six-arrow {
  position: absolute;
  z-index: 3;
  top: 50%;
  transform: translateY(-50%);
  width: 54px;
  height: 54px;
  border: 1px solid rgba(255,255,255,0.24);
  border-radius: 999px;
  background: rgba(28, 25, 23, 0.72);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  font-weight: 950;
  cursor: pointer;
  backdrop-filter: blur(10px);
}

.vb-gallery-six-left {
  left: 18px;
}

.vb-gallery-six-right {
  right: 18px;
}

.vb-gallery-six-caption {
  padding: clamp(20px, 3vw, 28px);
}

.vb-gallery-six-caption span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-gallery-six-caption h4 {
  margin: 0 0 8px !important;
  color: #1c1917 !important;
  -webkit-text-fill-color: #1c1917 !important;
  font-size: clamp(28px, 4vw, 42px) !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-gallery-six-caption p {
  max-width: 760px;
  margin: 0 !important;
  color: #57534e !important;
  -webkit-text-fill-color: #57534e !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

@media (max-width: 980px) {
  .vb-gallery-six-shell {
    grid-template-columns: 1fr;
  }

  .vb-gallery-six-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-six-tile:nth-child(1),
  .vb-gallery-six-tile:nth-child(4) {
    grid-row: span 1;
    min-height: 260px;
  }
}

@media (max-width: 620px) {
  .vb-gallery-six-demo {
    padding: 16px;
  }

  .vb-gallery-six-sidebar h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-six-grid {
    grid-template-columns: 1fr;
  }

  .vb-gallery-six-tile {
    min-height: 260px;
  }

  .vb-gallery-six-toolbar {
    grid-template-columns: 1fr;
    text-align: center;
  }

  .vb-gallery-six-photo-wrap {
    height: 320px;
  }

  .vb-gallery-six-arrow {
    width: 44px;
    height: 44px;
  }
}</pre>



<p class="wp-block-paragraph">This keyboard controlled gallery lightbox is useful for accessible image galleries, photography portfolios, media collections, product previews, editorial pages, and visual interfaces where users should be able to browse images with keyboard controls.</p>



<h2 class="wp-block-heading">7. Masonry Image Gallery</h2>



<p class="wp-block-paragraph"><strong>A masonry image gallery</strong> is useful when images have different heights and should flow into a Pinterest-style layout instead of a strict equal-height grid. This pattern works well for photography galleries, moodboards, portfolio collections, travel blogs, interior inspiration pages, and editorial image layouts.</p>



<p class="wp-block-paragraph">This example uses JavaScript masonry distribution logic. Instead of relying only on CSS columns, JavaScript splits the gallery items into balanced columns and always adds the next card to the shortest column. This creates a more controlled masonry layout and keeps the gallery visually balanced.</p>



<ul class="wp-block-list">
<li>JavaScript masonry gallery layout</li>
<li>Shortest-column distribution logic</li>
<li>Mixed image heights</li>
<li>Dynamic rendering from a data array</li>
<li>Responsive column count for desktop, tablet, and mobile</li>
</ul>



<div class="vb-gallery-seven-demo">
  <div class="vb-gallery-seven-shell" data-vb-gallery-seven>
    <div class="vb-gallery-seven-header">
      <span>Example 07</span>
      <h3>Masonry Image Gallery</h3>
      <p>A JavaScript-powered masonry gallery that balances image cards into the shortest available column.</p>
    </div>

    <div class="vb-gallery-seven-stats">
      <strong data-vb-gallery-seven-count>0 images</strong>
      <button type="button" data-vb-gallery-seven-rebuild>Rebuild Layout</button>
    </div>

    <div class="vb-gallery-seven-columns" data-vb-gallery-seven-columns></div>
  </div>
</div>

<style>
.vb-gallery-seven-demo,
.vb-gallery-seven-demo * {
  box-sizing: border-box;
}

.vb-gallery-seven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(217, 70, 239, 0.16), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(14, 165, 233, 0.16), transparent 36%),
    linear-gradient(135deg, #fdf4ff 0%, #f0f9ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(192, 132, 252, 0.24);
  box-shadow: 0 28px 80px rgba(88, 28, 135, 0.10);
}

.vb-gallery-seven-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-seven-header {
  max-width: 820px;
  margin-bottom: 22px;
}

.vb-gallery-seven-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fae8ff;
  color: #a21caf !important;
  -webkit-text-fill-color: #a21caf !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-seven-header h3 {
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-seven-header p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-seven-stats {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 18px;
  padding: 12px;
  border-radius: 22px;
  background: rgba(255,255,255,0.78);
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.08);
}

.vb-gallery-seven-stats strong {
  display: inline-flex;
  padding: 10px 13px;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-gallery-seven-stats button {
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #d946ef, #0ea5e9);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 12px 16px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 14px 32px rgba(217, 70, 239, 0.24);
}

.vb-gallery-seven-columns {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  align-items: start;
}

.vb-gallery-seven-column {
  display: grid;
  gap: 16px;
  min-width: 0;
}

.vb-gallery-seven-card {
  overflow: hidden;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  animation: vbGallerySevenRise 0.42s ease both;
}

@keyframes vbGallerySevenRise {
  from {
    opacity: 0;
    transform: translateY(14px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.vb-gallery-seven-image {
  position: relative;
  overflow: hidden;
  background: #e5e7eb;
}

.vb-gallery-seven-image img {
  display: block;
  width: 100%;
  height: auto;
  min-height: 180px;
  object-fit: cover;
  transition: transform 0.38s ease, filter 0.38s ease;
}

.vb-gallery-seven-card:hover img {
  transform: scale(1.07);
  filter: saturate(1.1) contrast(1.04);
}

.vb-gallery-seven-image span {
  position: absolute;
  left: 13px;
  top: 13px;
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(17, 24, 39, 0.72);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb-gallery-seven-body {
  display: grid;
  gap: 8px;
  padding: 16px;
}

.vb-gallery-seven-body h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 19px !important;
  line-height: 1.16 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-gallery-seven-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 1050px) {
  .vb-gallery-seven-columns {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 760px) {
  .vb-gallery-seven-columns {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-seven-stats {
    align-items: stretch;
    flex-direction: column;
  }

  .vb-gallery-seven-stats button,
  .vb-gallery-seven-stats strong {
    justify-content: center;
    width: 100%;
  }
}

@media (max-width: 520px) {
  .vb-gallery-seven-demo {
    padding: 16px;
    border-radius: 26px;
  }

  .vb-gallery-seven-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-seven-columns {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-seven]");
  if (!gallery) return;

  const columnsWrap = gallery.querySelector("[data-vb-gallery-seven-columns]");
  const countEl = gallery.querySelector("[data-vb-gallery-seven-count]");
  const rebuildButton = gallery.querySelector("[data-vb-gallery-seven-rebuild]");

  const items = [
    {
      title: "Tall Editorial Shot",
      category: "Editorial",
      description: "A tall gallery card for editorial image layouts and visual story pages.",
      image: "https://picsum.photos/seed/gallery-seven-editorial/720/1040",
      heightScore: 1040
    },
    {
      title: "Compact Product Frame",
      category: "Product",
      description: "A shorter card for ecommerce collections and product-focused galleries.",
      image: "https://picsum.photos/seed/gallery-seven-product/720/620",
      heightScore: 620
    },
    {
      title: "Interior Moodboard",
      category: "Interior",
      description: "A medium-height interior card for inspiration boards and design collections.",
      image: "https://picsum.photos/seed/gallery-seven-interior/720/860",
      heightScore: 860
    },
    {
      title: "Travel Journal Image",
      category: "Travel",
      description: "A tall travel visual for destination galleries and blog collections.",
      image: "https://picsum.photos/seed/gallery-seven-travel/720/980",
      heightScore: 980
    },
    {
      title: "Architecture Detail",
      category: "Architecture",
      description: "A wide-feeling architecture card with a balanced visual ratio.",
      image: "https://picsum.photos/seed/gallery-seven-architecture/720/700",
      heightScore: 700
    },
    {
      title: "Studio Campaign",
      category: "Studio",
      description: "A polished studio image for agency work and brand presentation galleries.",
      image: "https://picsum.photos/seed/gallery-seven-studio/720/900",
      heightScore: 900
    },
    {
      title: "Nature Texture",
      category: "Nature",
      description: "A compact nature card for moodboards and visual inspiration pages.",
      image: "https://picsum.photos/seed/gallery-seven-nature/720/640",
      heightScore: 640
    },
    {
      title: "Creative Workspace",
      category: "Workspace",
      description: "A taller workspace gallery card for portfolio and blog page layouts.",
      image: "https://picsum.photos/seed/gallery-seven-workspace/720/1060",
      heightScore: 1060
    },
    {
      title: "Urban Night Scene",
      category: "Urban",
      description: "A medium gallery card for street photography and city collections.",
      image: "https://picsum.photos/seed/gallery-seven-urban/720/820",
      heightScore: 820
    }
  ];

  function getColumnCount() {
    if (window.matchMedia("(max-width: 520px)").matches) return 1;
    if (window.matchMedia("(max-width: 760px)").matches) return 2;
    if (window.matchMedia("(max-width: 1050px)").matches) return 3;
    return 4;
  }

  function createCard(item, index) {
    return `
      <article class="vb-gallery-seven-card" style="animation-delay: ${index * 45}ms">
        <div class="vb-gallery-seven-image">
          <img decoding="async" src="${item.image}" alt="${item.title}" loading="lazy">
          <span>${item.category}</span>
        </div>

        <div class="vb-gallery-seven-body">
          <h4>${item.title}</h4>
          <p>${item.description}</p>
        </div>
      </article>
    `;
  }

  function distributeItems(itemList, columnCount) {
    const columns = Array.from({ length: columnCount }, function () {
      return {
        height: 0,
        items: []
      };
    });

    itemList.forEach(function (item) {
      const shortestColumn = columns.reduce(function (shortest, column) {
        return column.height < shortest.height ? column : shortest;
      }, columns[0]);

      shortestColumn.items.push(item);
      shortestColumn.height += item.heightScore;
    });

    return columns;
  }

  function renderMasonry() {
    const columnCount = getColumnCount();
    const columns = distributeItems(items, columnCount);

    columnsWrap.innerHTML = columns.map(function (column) {
      return `
        <div class="vb-gallery-seven-column">
          ${column.items.map(createCard).join("")}
        </div>
      `;
    }).join("");

    countEl.textContent = items.length + " masonry images";
  }

  rebuildButton.addEventListener("click", function () {
    renderMasonry();
  });

  window.addEventListener("resize", function () {
    renderMasonry();
  });

  renderMasonry();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-seven]");
  if (!gallery) return;

  const columnsWrap = gallery.querySelector("[data-vb-gallery-seven-columns]");
  const countEl = gallery.querySelector("[data-vb-gallery-seven-count]");
  const rebuildButton = gallery.querySelector("[data-vb-gallery-seven-rebuild]");

  const items = [
    {
      title: "Tall Editorial Shot",
      category: "Editorial",
      description: "A tall gallery card for editorial image layouts and visual story pages.",
      image: "https://picsum.photos/seed/gallery-seven-editorial/720/1040",
      heightScore: 1040
    },
    {
      title: "Compact Product Frame",
      category: "Product",
      description: "A shorter card for ecommerce collections and product-focused galleries.",
      image: "https://picsum.photos/seed/gallery-seven-product/720/620",
      heightScore: 620
    },
    {
      title: "Interior Moodboard",
      category: "Interior",
      description: "A medium-height interior card for inspiration boards and design collections.",
      image: "https://picsum.photos/seed/gallery-seven-interior/720/860",
      heightScore: 860
    },
    {
      title: "Travel Journal Image",
      category: "Travel",
      description: "A tall travel visual for destination galleries and blog collections.",
      image: "https://picsum.photos/seed/gallery-seven-travel/720/980",
      heightScore: 980
    },
    {
      title: "Architecture Detail",
      category: "Architecture",
      description: "A wide-feeling architecture card with a balanced visual ratio.",
      image: "https://picsum.photos/seed/gallery-seven-architecture/720/700",
      heightScore: 700
    },
    {
      title: "Studio Campaign",
      category: "Studio",
      description: "A polished studio image for agency work and brand presentation galleries.",
      image: "https://picsum.photos/seed/gallery-seven-studio/720/900",
      heightScore: 900
    },
    {
      title: "Nature Texture",
      category: "Nature",
      description: "A compact nature card for moodboards and visual inspiration pages.",
      image: "https://picsum.photos/seed/gallery-seven-nature/720/640",
      heightScore: 640
    },
    {
      title: "Creative Workspace",
      category: "Workspace",
      description: "A taller workspace gallery card for portfolio and blog page layouts.",
      image: "https://picsum.photos/seed/gallery-seven-workspace/720/1060",
      heightScore: 1060
    },
    {
      title: "Urban Night Scene",
      category: "Urban",
      description: "A medium gallery card for street photography and city collections.",
      image: "https://picsum.photos/seed/gallery-seven-urban/720/820",
      heightScore: 820
    }
  ];

  function getColumnCount() {
    if (window.matchMedia("(max-width: 520px)").matches) return 1;
    if (window.matchMedia("(max-width: 760px)").matches) return 2;
    if (window.matchMedia("(max-width: 1050px)").matches) return 3;
    return 4;
  }

  function createCard(item, index) {
    return `
      &lt;article class="vb-gallery-seven-card" style="animation-delay: ${index * 45}ms"&gt;
        &lt;div class="vb-gallery-seven-image"&gt;
          &lt;img src="${item.image}" alt="${item.title}" loading="lazy"&gt;
          &lt;span&gt;${item.category}&lt;/span&gt;
        &lt;/div&gt;

        &lt;div class="vb-gallery-seven-body"&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
          &lt;p&gt;${item.description}&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    `;
  }

  function distributeItems(itemList, columnCount) {
    const columns = Array.from({ length: columnCount }, function () {
      return {
        height: 0,
        items: []
      };
    });

    itemList.forEach(function (item) {
      const shortestColumn = columns.reduce(function (shortest, column) {
        return column.height &lt; shortest.height ? column : shortest;
      }, columns[0]);

      shortestColumn.items.push(item);
      shortestColumn.height += item.heightScore;
    });

    return columns;
  }

  function renderMasonry() {
    const columnCount = getColumnCount();
    const columns = distributeItems(items, columnCount);

    columnsWrap.innerHTML = columns.map(function (column) {
      return `
        &lt;div class="vb-gallery-seven-column"&gt;
          ${column.items.map(createCard).join("")}
        &lt;/div&gt;
      `;
    }).join("");

    countEl.textContent = items.length + " masonry images";
  }

  rebuildButton.addEventListener("click", function () {
    renderMasonry();
  });

  window.addEventListener("resize", function () {
    renderMasonry();
  });

  renderMasonry();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-seven-demo"&gt;
  &lt;div class="vb-gallery-seven-shell" data-vb-gallery-seven&gt;
    &lt;div class="vb-gallery-seven-header"&gt;
      &lt;span&gt;Example 07&lt;/span&gt;
      &lt;h3&gt;Masonry Image Gallery&lt;/h3&gt;
      &lt;p&gt;A JavaScript-powered masonry gallery that balances image cards into the shortest available column.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-seven-stats"&gt;
      &lt;strong data-vb-gallery-seven-count&gt;0 images&lt;/strong&gt;
      &lt;button type="button" data-vb-gallery-seven-rebuild&gt;Rebuild Layout&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-seven-columns" data-vb-gallery-seven-columns&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-seven-demo,
.vb-gallery-seven-demo * {
  box-sizing: border-box;
}

.vb-gallery-seven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(217, 70, 239, 0.16), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(14, 165, 233, 0.16), transparent 36%),
    linear-gradient(135deg, #fdf4ff 0%, #f0f9ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(192, 132, 252, 0.24);
  box-shadow: 0 28px 80px rgba(88, 28, 135, 0.10);
}

.vb-gallery-seven-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-seven-header {
  max-width: 820px;
  margin-bottom: 22px;
}

.vb-gallery-seven-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fae8ff;
  color: #a21caf !important;
  -webkit-text-fill-color: #a21caf !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-seven-header h3 {
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-seven-header p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-seven-stats {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 18px;
  padding: 12px;
  border-radius: 22px;
  background: rgba(255,255,255,0.78);
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.08);
}

.vb-gallery-seven-stats strong {
  display: inline-flex;
  padding: 10px 13px;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-gallery-seven-stats button {
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #d946ef, #0ea5e9);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 12px 16px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 14px 32px rgba(217, 70, 239, 0.24);
}

.vb-gallery-seven-columns {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  align-items: start;
}

.vb-gallery-seven-column {
  display: grid;
  gap: 16px;
  min-width: 0;
}

.vb-gallery-seven-card {
  overflow: hidden;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  animation: vbGallerySevenRise 0.42s ease both;
}

@keyframes vbGallerySevenRise {
  from {
    opacity: 0;
    transform: translateY(14px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.vb-gallery-seven-image {
  position: relative;
  overflow: hidden;
  background: #e5e7eb;
}

.vb-gallery-seven-image img {
  display: block;
  width: 100%;
  height: auto;
  min-height: 180px;
  object-fit: cover;
  transition: transform 0.38s ease, filter 0.38s ease;
}

.vb-gallery-seven-card:hover img {
  transform: scale(1.07);
  filter: saturate(1.1) contrast(1.04);
}

.vb-gallery-seven-image span {
  position: absolute;
  left: 13px;
  top: 13px;
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(17, 24, 39, 0.72);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb-gallery-seven-body {
  display: grid;
  gap: 8px;
  padding: 16px;
}

.vb-gallery-seven-body h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 19px !important;
  line-height: 1.16 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-gallery-seven-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 1050px) {
  .vb-gallery-seven-columns {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 760px) {
  .vb-gallery-seven-columns {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-seven-stats {
    align-items: stretch;
    flex-direction: column;
  }

  .vb-gallery-seven-stats button,
  .vb-gallery-seven-stats strong {
    justify-content: center;
    width: 100%;
  }
}

@media (max-width: 520px) {
  .vb-gallery-seven-demo {
    padding: 16px;
    border-radius: 26px;
  }

  .vb-gallery-seven-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-seven-columns {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This masonry image gallery is useful for photography collections, Pinterest-style inspiration boards, portfolio archives, travel image layouts, interior design galleries, moodboards, and editorial pages where images have different heights.</p>



<h2 class="wp-block-heading">8. Lazy Loading Image Gallery</h2>



<p class="wp-block-paragraph"><strong>A lazy loading image gallery</strong> improves performance by loading images only when they are close to the visible viewport. This is useful for large gallery pages, image-heavy blog posts, ecommerce collections, photography portfolios, travel guides, real estate listings, and long landing pages.</p>



<p class="wp-block-paragraph">This example uses the JavaScript IntersectionObserver API. Each image starts with a lightweight placeholder and stores the real image URL in a data attribute. When the image card becomes visible, JavaScript replaces the placeholder with the real image and marks the card as loaded.</p>



<ul class="wp-block-list">
<li>JavaScript lazy loading image gallery</li>
<li>IntersectionObserver-based loading</li>
<li>Image placeholders before loading</li>
<li>Loaded state animation</li>
<li>Performance-friendly for large image galleries</li>
</ul>



<div class="vb-gallery-eight-demo">
  <div class="vb-gallery-eight-shell" data-vb-gallery-eight>
    <div class="vb-gallery-eight-top">
      <div>
        <span>Example 08</span>
        <h3>Lazy Loading Image Gallery</h3>
        <p>Load gallery images only when they approach the viewport using JavaScript IntersectionObserver.</p>
      </div>

      <strong data-vb-gallery-eight-status>Waiting for images</strong>
    </div>

    <div class="vb-gallery-eight-grid">
      <article class="vb-gallery-eight-card">
        <div class="vb-gallery-eight-photo">
          <img decoding="async" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='620'%3E%3Crect width='900' height='620' fill='%23e0f2fe'/%3E%3C/svg%3E" data-src="https://picsum.photos/seed/gallery-eight-one/900/620" alt="Lazy loaded gallery image one">
        </div>
        <div>
          <span>01</span>
          <h4>Deferred Portfolio Image</h4>
          <p>This image loads when the card becomes visible inside the viewport.</p>
        </div>
      </article>

      <article class="vb-gallery-eight-card">
        <div class="vb-gallery-eight-photo">
          <img decoding="async" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='760'%3E%3Crect width='900' height='760' fill='%23ddd6fe'/%3E%3C/svg%3E" data-src="https://picsum.photos/seed/gallery-eight-two/900/760" alt="Lazy loaded gallery image two">
        </div>
        <div>
          <span>02</span>
          <h4>Image Near Viewport</h4>
          <p>IntersectionObserver watches each image and loads it at the right time.</p>
        </div>
      </article>

      <article class="vb-gallery-eight-card">
        <div class="vb-gallery-eight-photo">
          <img decoding="async" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='680'%3E%3Crect width='900' height='680' fill='%23dcfce7'/%3E%3C/svg%3E" data-src="https://picsum.photos/seed/gallery-eight-three/900/680" alt="Lazy loaded gallery image three">
        </div>
        <div>
          <span>03</span>
          <h4>Performance Gallery Card</h4>
          <p>Useful for long galleries where loading every image immediately is not ideal.</p>
        </div>
      </article>

      <article class="vb-gallery-eight-card">
        <div class="vb-gallery-eight-photo">
          <img decoding="async" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='720'%3E%3Crect width='900' height='720' fill='%23ffedd5'/%3E%3C/svg%3E" data-src="https://picsum.photos/seed/gallery-eight-four/900/720" alt="Lazy loaded gallery image four">
        </div>
        <div>
          <span>04</span>
          <h4>Scroll Activated Image</h4>
          <p>The gallery marks each card as loaded after the full image has loaded.</p>
        </div>
      </article>

      <article class="vb-gallery-eight-card">
        <div class="vb-gallery-eight-photo">
          <img decoding="async" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='640'%3E%3Crect width='900' height='640' fill='%23fce7f3'/%3E%3C/svg%3E" data-src="https://picsum.photos/seed/gallery-eight-five/900/640" alt="Lazy loaded gallery image five">
        </div>
        <div>
          <span>05</span>
          <h4>Optimized Visual Section</h4>
          <p>Lazy loading can improve perceived speed on image-heavy website sections.</p>
        </div>
      </article>

      <article class="vb-gallery-eight-card">
        <div class="vb-gallery-eight-photo">
          <img decoding="async" src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='800'%3E%3Crect width='900' height='800' fill='%23ccfbf1'/%3E%3C/svg%3E" data-src="https://picsum.photos/seed/gallery-eight-six/900/800" alt="Lazy loaded gallery image six">
        </div>
        <div>
          <span>06</span>
          <h4>Large Gallery Ready</h4>
          <p>This pattern can be reused for portfolios, catalogs, image archives, and galleries.</p>
        </div>
      </article>
    </div>
  </div>
</div>

<style>
.vb-gallery-eight-demo,
.vb-gallery-eight-demo * {
  box-sizing: border-box;
}

.vb-gallery-eight-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 18px;
  background:
    radial-gradient(circle at 12% 12%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ffffff 54%, #f8fafc 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.20);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-gallery-eight-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-eight-top {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px;
  margin-bottom: 24px;
}

.vb-gallery-eight-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 10px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-eight-top h3 {
  max-width: 760px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-eight-top p {
  max-width: 740px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-eight-top > strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-eight-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-gallery-eight-card {
  overflow: hidden;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.09);
}

.vb-gallery-eight-photo {
  position: relative;
  aspect-ratio: 1.25 / 1;
  overflow: hidden;
  background:
    linear-gradient(90deg, #e2e8f0 0%, #f8fafc 48%, #e2e8f0 100%);
  background-size: 220% 100%;
  animation: vbGalleryEightShimmer 1.4s linear infinite;
}

@keyframes vbGalleryEightShimmer {
  0% {
    background-position: 120% 0;
  }

  100% {
    background-position: -120% 0;
  }
}

.vb-gallery-eight-card.is-loaded .vb-gallery-eight-photo {
  animation: none;
  background: #e2e8f0;
}

.vb-gallery-eight-photo::after {
  content: "Loading image";
  position: absolute;
  left: 16px;
  bottom: 16px;
  z-index: 2;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.72);
  color: #ffffff;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb-gallery-eight-card.is-loaded .vb-gallery-eight-photo::after {
  content: "Loaded";
  background: rgba(22, 163, 74, 0.82);
}

.vb-gallery-eight-photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.22;
  filter: blur(12px);
  transform: scale(1.04);
  transition: opacity 0.42s ease, filter 0.42s ease, transform 0.42s ease;
}

.vb-gallery-eight-card.is-loaded img {
  opacity: 1;
  filter: blur(0);
  transform: scale(1);
}

.vb-gallery-eight-card > div:last-child {
  display: grid;
  gap: 8px;
  padding: 17px;
}

.vb-gallery-eight-card span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #eff6ff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-eight-card h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px !important;
  line-height: 1.16 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-eight-card p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 980px) {
  .vb-gallery-eight-top {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-eight-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .vb-gallery-eight-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-eight-top h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-eight-grid {
    grid-template-columns: 1fr;
  }

  .vb-gallery-eight-top > strong {
    justify-content: center;
    width: 100%;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-eight]");
  if (!gallery) return;

  const images = gallery.querySelectorAll("img[data-src]");
  const statusEl = gallery.querySelector("[data-vb-gallery-eight-status]");
  let loadedCount = 0;

  function updateStatus() {
    statusEl.textContent = loadedCount + " / " + images.length + " images loaded";
  }

  function loadImage(image) {
    const realSource = image.getAttribute("data-src");
    if (!realSource) return;

    image.src = realSource;
    image.removeAttribute("data-src");

    image.addEventListener("load", function () {
      loadedCount += 1;
      image.closest(".vb-gallery-eight-card").classList.add("is-loaded");
      updateStatus();
    }, { once: true });
  }

  if ("IntersectionObserver" in window) {
    const observer = new IntersectionObserver(function (entries, currentObserver) {
      entries.forEach(function (entry) {
        if (!entry.isIntersecting) return;

        loadImage(entry.target);
        currentObserver.unobserve(entry.target);
      });
    }, {
      root: null,
      rootMargin: "160px 0px",
      threshold: 0.1
    });

    images.forEach(function (image) {
      observer.observe(image);
    });
  } else {
    images.forEach(loadImage);
  }

  updateStatus();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-eight]");
  if (!gallery) return;

  const images = gallery.querySelectorAll("img[data-src]");
  const statusEl = gallery.querySelector("[data-vb-gallery-eight-status]");
  let loadedCount = 0;

  function updateStatus() {
    statusEl.textContent = loadedCount + " / " + images.length + " images loaded";
  }

  function loadImage(image) {
    const realSource = image.getAttribute("data-src");
    if (!realSource) return;

    image.src = realSource;
    image.removeAttribute("data-src");

    image.addEventListener("load", function () {
      loadedCount += 1;
      image.closest(".vb-gallery-eight-card").classList.add("is-loaded");
      updateStatus();
    }, { once: true });
  }

  if ("IntersectionObserver" in window) {
    const observer = new IntersectionObserver(function (entries, currentObserver) {
      entries.forEach(function (entry) {
        if (!entry.isIntersecting) return;

        loadImage(entry.target);
        currentObserver.unobserve(entry.target);
      });
    }, {
      root: null,
      rootMargin: "160px 0px",
      threshold: 0.1
    });

    images.forEach(function (image) {
      observer.observe(image);
    });
  } else {
    images.forEach(loadImage);
  }

  updateStatus();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-eight-demo"&gt;
  &lt;div class="vb-gallery-eight-shell" data-vb-gallery-eight&gt;
    &lt;div class="vb-gallery-eight-top"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 08&lt;/span&gt;
        &lt;h3&gt;Lazy Loading Image Gallery&lt;/h3&gt;
        &lt;p&gt;Load gallery images only when they approach the viewport using JavaScript IntersectionObserver.&lt;/p&gt;
      &lt;/div&gt;

      &lt;strong data-vb-gallery-eight-status&gt;Waiting for images&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-eight-grid"&gt;
      &lt;article class="vb-gallery-eight-card"&gt;
        &lt;div class="vb-gallery-eight-photo"&gt;
          &lt;img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='620'%3E%3Crect width='900' height='620' fill='%23e0f2fe'/%3E%3C/svg%3E" data-src="https://picsum.photos/seed/gallery-eight-one/900/620" alt="Lazy loaded gallery image one"&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;01&lt;/span&gt;
          &lt;h4&gt;Deferred Portfolio Image&lt;/h4&gt;
          &lt;p&gt;This image loads when the card becomes visible inside the viewport.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-gallery-eight-card"&gt;
        &lt;div class="vb-gallery-eight-photo"&gt;
          &lt;img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='760'%3E%3Crect width='900' height='760' fill='%23ddd6fe'/%3E%3C/svg%3E" data-src="https://picsum.photos/seed/gallery-eight-two/900/760" alt="Lazy loaded gallery image two"&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;02&lt;/span&gt;
          &lt;h4&gt;Image Near Viewport&lt;/h4&gt;
          &lt;p&gt;IntersectionObserver watches each image and loads it at the right time.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-gallery-eight-card"&gt;
        &lt;div class="vb-gallery-eight-photo"&gt;
          &lt;img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='680'%3E%3Crect width='900' height='680' fill='%23dcfce7'/%3E%3C/svg%3E" data-src="https://picsum.photos/seed/gallery-eight-three/900/680" alt="Lazy loaded gallery image three"&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;03&lt;/span&gt;
          &lt;h4&gt;Performance Gallery Card&lt;/h4&gt;
          &lt;p&gt;Useful for long galleries where loading every image immediately is not ideal.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-gallery-eight-card"&gt;
        &lt;div class="vb-gallery-eight-photo"&gt;
          &lt;img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='720'%3E%3Crect width='900' height='720' fill='%23ffedd5'/%3E%3C/svg%3E" data-src="https://picsum.photos/seed/gallery-eight-four/900/720" alt="Lazy loaded gallery image four"&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;04&lt;/span&gt;
          &lt;h4&gt;Scroll Activated Image&lt;/h4&gt;
          &lt;p&gt;The gallery marks each card as loaded after the full image has loaded.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-gallery-eight-card"&gt;
        &lt;div class="vb-gallery-eight-photo"&gt;
          &lt;img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='640'%3E%3Crect width='900' height='640' fill='%23fce7f3'/%3E%3C/svg%3E" data-src="https://picsum.photos/seed/gallery-eight-five/900/640" alt="Lazy loaded gallery image five"&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;05&lt;/span&gt;
          &lt;h4&gt;Optimized Visual Section&lt;/h4&gt;
          &lt;p&gt;Lazy loading can improve perceived speed on image-heavy website sections.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-gallery-eight-card"&gt;
        &lt;div class="vb-gallery-eight-photo"&gt;
          &lt;img src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='900' height='800'%3E%3Crect width='900' height='800' fill='%23ccfbf1'/%3E%3C/svg%3E" data-src="https://picsum.photos/seed/gallery-eight-six/900/800" alt="Lazy loaded gallery image six"&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;span&gt;06&lt;/span&gt;
          &lt;h4&gt;Large Gallery Ready&lt;/h4&gt;
          &lt;p&gt;This pattern can be reused for portfolios, catalogs, image archives, and galleries.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-eight-demo,
.vb-gallery-eight-demo * {
  box-sizing: border-box;
}

.vb-gallery-eight-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 18px;
  background:
    radial-gradient(circle at 12% 12%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ffffff 54%, #f8fafc 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.20);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-gallery-eight-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-eight-top {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px;
  margin-bottom: 24px;
}

.vb-gallery-eight-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 10px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-eight-top h3 {
  max-width: 760px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-eight-top p {
  max-width: 740px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-eight-top > strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-eight-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-gallery-eight-card {
  overflow: hidden;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.09);
}

.vb-gallery-eight-photo {
  position: relative;
  aspect-ratio: 1.25 / 1;
  overflow: hidden;
  background:
    linear-gradient(90deg, #e2e8f0 0%, #f8fafc 48%, #e2e8f0 100%);
  background-size: 220% 100%;
  animation: vbGalleryEightShimmer 1.4s linear infinite;
}

@keyframes vbGalleryEightShimmer {
  0% {
    background-position: 120% 0;
  }

  100% {
    background-position: -120% 0;
  }
}

.vb-gallery-eight-card.is-loaded .vb-gallery-eight-photo {
  animation: none;
  background: #e2e8f0;
}

.vb-gallery-eight-photo::after {
  content: "Loading image";
  position: absolute;
  left: 16px;
  bottom: 16px;
  z-index: 2;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.72);
  color: #ffffff;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb-gallery-eight-card.is-loaded .vb-gallery-eight-photo::after {
  content: "Loaded";
  background: rgba(22, 163, 74, 0.82);
}

.vb-gallery-eight-photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0.22;
  filter: blur(12px);
  transform: scale(1.04);
  transition: opacity 0.42s ease, filter 0.42s ease, transform 0.42s ease;
}

.vb-gallery-eight-card.is-loaded img {
  opacity: 1;
  filter: blur(0);
  transform: scale(1);
}

.vb-gallery-eight-card > div:last-child {
  display: grid;
  gap: 8px;
  padding: 17px;
}

.vb-gallery-eight-card span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #eff6ff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-eight-card h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px !important;
  line-height: 1.16 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-eight-card p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 980px) {
  .vb-gallery-eight-top {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-eight-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .vb-gallery-eight-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-eight-top h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-eight-grid {
    grid-template-columns: 1fr;
  }

  .vb-gallery-eight-top > strong {
    justify-content: center;
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This lazy loading image gallery is useful for large image collections, portfolio pages, ecommerce category pages, photography archives, travel galleries, real estate listings, and long blog posts where performance matters.</p>



<h2 class="wp-block-heading">9. Infinite Scroll Image Gallery</h2>



<p class="wp-block-paragraph"><strong>An infinite scroll image gallery</strong> loads more images automatically when the visitor reaches the bottom of the gallery. This is useful for portfolio archives, inspiration boards, photography collections, ecommerce galleries, travel pages, media libraries, and long visual browsing experiences.</p>



<p class="wp-block-paragraph">This example uses JavaScript IntersectionObserver logic. A small loader element at the bottom of the gallery is observed, and when it enters the viewport, the next batch of images is rendered automatically. The layout is clean, responsive, and built so every image fills the full card area without unwanted top spacing.</p>



<ul class="wp-block-list">
<li>Infinite scroll JavaScript image gallery</li>
<li>IntersectionObserver load trigger</li>
<li>Batch-based image rendering</li>
<li>Dynamic loaded count</li>
<li>Responsive full-cover image cards</li>
</ul>



<div class="vb-gallery-nine-demo">
  <div class="vb-gallery-nine-shell" data-vb-gallery-nine>
    <div class="vb-gallery-nine-head">
      <div>
        <span>Example 09</span>
        <h3>Infinite Scroll Image Gallery</h3>
        <p>Automatically load more image cards when the visitor reaches the bottom of the gallery.</p>
      </div>

      <strong data-vb-gallery-nine-count>0 images loaded</strong>
    </div>

    <div class="vb-gallery-nine-grid" data-vb-gallery-nine-grid></div>

    <div class="vb-gallery-nine-loader" data-vb-gallery-nine-loader>
      <span></span>
      <p data-vb-gallery-nine-loader-text>Scroll down to load more images</p>
    </div>
  </div>
</div>

<style>
.vb-gallery-nine-demo,
.vb-gallery-nine-demo * {
  box-sizing: border-box;
}

.vb-gallery-nine-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 14% 14%, rgba(14, 165, 233, 0.18), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #ecfeff 0%, #f0fdf4 52%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.22);
  box-shadow: 0 28px 80px rgba(14, 116, 144, 0.10);
}

.vb-gallery-nine-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-nine-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px;
  margin-bottom: 24px;
}

.vb-gallery-nine-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #cffafe;
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-nine-head h3 {
  max-width: 760px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-nine-head p {
  max-width: 720px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-nine-head strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-nine-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-gallery-nine-card {
  position: relative;
  min-height: 340px;
  overflow: hidden;
  border-radius: 28px;
  background: #0f172a;
  border: 1px solid rgba(15, 23, 42, 0.10);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.12);
  animation: vbGalleryNineIn 0.38s ease both;
}

@keyframes vbGalleryNineIn {
  from {
    opacity: 0;
    transform: translateY(18px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.vb-gallery-nine-card img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  min-width: 100%;
  min-height: 100%;
  object-fit: cover;
  object-position: center center;
  border: 0;
  margin: 0;
  padding: 0;
  transition: transform 0.42s ease, filter 0.42s ease;
}

.vb-gallery-nine-card:hover img {
  transform: scale(1.08);
  filter: saturate(1.12) contrast(1.05);
}

.vb-gallery-nine-card::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(15, 23, 42, 0.02), rgba(15, 23, 42, 0.86)),
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.18), transparent 34%);
  z-index: 1;
}

.vb-gallery-nine-content {
  position: absolute;
  z-index: 2;
  left: 18px;
  right: 18px;
  bottom: 18px;
  display: grid;
  gap: 8px;
}

.vb-gallery-nine-content span {
  display: inline-flex;
  width: fit-content;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.18);
  color: #cffafe !important;
  -webkit-text-fill-color: #cffafe !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb-gallery-nine-content h4 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 25px !important;
  line-height: 1.05 !important;
  font-weight: 950 !important;
  letter-spacing: -0.055em;
}

.vb-gallery-nine-content p {
  margin: 0 !important;
  color: #e2e8f0 !important;
  -webkit-text-fill-color: #e2e8f0 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-gallery-nine-loader {
  display: grid;
  place-items: center;
  gap: 12px;
  margin-top: 22px;
  padding: 22px;
  border-radius: 24px;
  background: rgba(255,255,255,0.76);
  border: 1px dashed rgba(14, 165, 233, 0.36);
}

.vb-gallery-nine-loader span {
  width: 34px;
  height: 34px;
  border-radius: 999px;
  border: 4px solid #bae6fd;
  border-top-color: #0891b2;
  animation: vbGalleryNineSpin 0.8s linear infinite;
}

@keyframes vbGalleryNineSpin {
  to {
    transform: rotate(360deg);
  }
}

.vb-gallery-nine-loader p {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 850;
}

@media (max-width: 980px) {
  .vb-gallery-nine-head {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-nine-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-nine-head strong {
    justify-content: center;
    width: 100%;
  }
}

@media (max-width: 620px) {
  .vb-gallery-nine-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-nine-head h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-nine-grid {
    grid-template-columns: 1fr;
  }

  .vb-gallery-nine-card {
    min-height: 300px;
    border-radius: 24px;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-nine]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-nine-grid]");
  const loader = gallery.querySelector("[data-vb-gallery-nine-loader]");
  const loaderText = gallery.querySelector("[data-vb-gallery-nine-loader-text]");
  const countEl = gallery.querySelector("[data-vb-gallery-nine-count]");

  const items = [
    { title: "Infinite Gallery One", category: "Portfolio", description: "A loaded image card for endless visual browsing.", image: "https://picsum.photos/seed/gallery-nine-1/900/700" },
    { title: "Infinite Gallery Two", category: "Travel", description: "A travel-inspired image card loaded in the first batch.", image: "https://picsum.photos/seed/gallery-nine-2/900/700" },
    { title: "Infinite Gallery Three", category: "Interior", description: "A clean interior image card for scroll-based galleries.", image: "https://picsum.photos/seed/gallery-nine-3/900/700" },
    { title: "Infinite Gallery Four", category: "Product", description: "A product-style visual card loaded after scrolling.", image: "https://picsum.photos/seed/gallery-nine-4/900/700" },
    { title: "Infinite Gallery Five", category: "Architecture", description: "A structured architecture card added by JavaScript.", image: "https://picsum.photos/seed/gallery-nine-5/900/700" },
    { title: "Infinite Gallery Six", category: "Nature", description: "A nature card added as part of the next image batch.", image: "https://picsum.photos/seed/gallery-nine-6/900/700" },
    { title: "Infinite Gallery Seven", category: "Studio", description: "A creative studio card for long image collections.", image: "https://picsum.photos/seed/gallery-nine-7/900/700" },
    { title: "Infinite Gallery Eight", category: "Workspace", description: "A workspace card loaded when the observer is triggered.", image: "https://picsum.photos/seed/gallery-nine-8/900/700" },
    { title: "Infinite Gallery Nine", category: "Editorial", description: "An editorial card for media-heavy gallery pages.", image: "https://picsum.photos/seed/gallery-nine-9/900/700" },
    { title: "Infinite Gallery Ten", category: "Lifestyle", description: "A lifestyle card appended without refreshing the page.", image: "https://picsum.photos/seed/gallery-nine-10/900/700" },
    { title: "Infinite Gallery Eleven", category: "Urban", description: "An urban card for automatic scroll loading.", image: "https://picsum.photos/seed/gallery-nine-11/900/700" },
    { title: "Infinite Gallery Twelve", category: "Gallery", description: "The final card in this infinite scroll demo.", image: "https://picsum.photos/seed/gallery-nine-12/900/700" }
  ];

  const batchSize = 3;
  let loadedItems = 0;
  let isLoading = false;

  function createCard(item, index) {
    return `
      <article class="vb-gallery-nine-card" style="animation-delay: ${index * 45}ms">
        <img decoding="async" src="${item.image}" alt="${item.title}" loading="lazy">

        <div class="vb-gallery-nine-content">
          <span>${item.category}</span>
          <h4>${item.title}</h4>
          <p>${item.description}</p>
        </div>
      </article>
    `;
  }

  function updateCount() {
    countEl.textContent = loadedItems + " / " + items.length + " images loaded";
  }

  function loadNextBatch() {
    if (isLoading) return;
    if (loadedItems >= items.length) return;

    isLoading = true;
    loaderText.textContent = "Loading more images...";

    window.setTimeout(function () {
      const nextItems = items.slice(loadedItems, loadedItems + batchSize);
      const markup = nextItems.map(function (item, index) {
        return createCard(item, index);
      }).join("");

      grid.insertAdjacentHTML("beforeend", markup);
      loadedItems += nextItems.length;
      updateCount();

      if (loadedItems >= items.length) {
        loaderText.textContent = "All images loaded";
        loader.querySelector("span").style.display = "none";
      } else {
        loaderText.textContent = "Scroll down to load more images";
      }

      isLoading = false;
    }, 450);
  }

  if ("IntersectionObserver" in window) {
    const observer = new IntersectionObserver(function (entries) {
      entries.forEach(function (entry) {
        if (entry.isIntersecting) {
          loadNextBatch();
        }
      });
    }, {
      root: null,
      rootMargin: "180px 0px",
      threshold: 0.1
    });

    observer.observe(loader);
  }

  loadNextBatch();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-nine]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-nine-grid]");
  const loader = gallery.querySelector("[data-vb-gallery-nine-loader]");
  const loaderText = gallery.querySelector("[data-vb-gallery-nine-loader-text]");
  const countEl = gallery.querySelector("[data-vb-gallery-nine-count]");

  const items = [
    { title: "Infinite Gallery One", category: "Portfolio", description: "A loaded image card for endless visual browsing.", image: "https://picsum.photos/seed/gallery-nine-1/900/700" },
    { title: "Infinite Gallery Two", category: "Travel", description: "A travel-inspired image card loaded in the first batch.", image: "https://picsum.photos/seed/gallery-nine-2/900/700" },
    { title: "Infinite Gallery Three", category: "Interior", description: "A clean interior image card for scroll-based galleries.", image: "https://picsum.photos/seed/gallery-nine-3/900/700" },
    { title: "Infinite Gallery Four", category: "Product", description: "A product-style visual card loaded after scrolling.", image: "https://picsum.photos/seed/gallery-nine-4/900/700" },
    { title: "Infinite Gallery Five", category: "Architecture", description: "A structured architecture card added by JavaScript.", image: "https://picsum.photos/seed/gallery-nine-5/900/700" },
    { title: "Infinite Gallery Six", category: "Nature", description: "A nature card added as part of the next image batch.", image: "https://picsum.photos/seed/gallery-nine-6/900/700" },
    { title: "Infinite Gallery Seven", category: "Studio", description: "A creative studio card for long image collections.", image: "https://picsum.photos/seed/gallery-nine-7/900/700" },
    { title: "Infinite Gallery Eight", category: "Workspace", description: "A workspace card loaded when the observer is triggered.", image: "https://picsum.photos/seed/gallery-nine-8/900/700" },
    { title: "Infinite Gallery Nine", category: "Editorial", description: "An editorial card for media-heavy gallery pages.", image: "https://picsum.photos/seed/gallery-nine-9/900/700" },
    { title: "Infinite Gallery Ten", category: "Lifestyle", description: "A lifestyle card appended without refreshing the page.", image: "https://picsum.photos/seed/gallery-nine-10/900/700" },
    { title: "Infinite Gallery Eleven", category: "Urban", description: "An urban card for automatic scroll loading.", image: "https://picsum.photos/seed/gallery-nine-11/900/700" },
    { title: "Infinite Gallery Twelve", category: "Gallery", description: "The final card in this infinite scroll demo.", image: "https://picsum.photos/seed/gallery-nine-12/900/700" }
  ];

  const batchSize = 3;
  let loadedItems = 0;
  let isLoading = false;

  function createCard(item, index) {
    return `
      &lt;article class="vb-gallery-nine-card" style="animation-delay: ${index * 45}ms"&gt;
        &lt;img src="${item.image}" alt="${item.title}" loading="lazy"&gt;

        &lt;div class="vb-gallery-nine-content"&gt;
          &lt;span&gt;${item.category}&lt;/span&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
          &lt;p&gt;${item.description}&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    `;
  }

  function updateCount() {
    countEl.textContent = loadedItems + " / " + items.length + " images loaded";
  }

  function loadNextBatch() {
    if (isLoading) return;
    if (loadedItems &gt;= items.length) return;

    isLoading = true;
    loaderText.textContent = "Loading more images...";

    window.setTimeout(function () {
      const nextItems = items.slice(loadedItems, loadedItems + batchSize);
      const markup = nextItems.map(function (item, index) {
        return createCard(item, index);
      }).join("");

      grid.insertAdjacentHTML("beforeend", markup);
      loadedItems += nextItems.length;
      updateCount();

      if (loadedItems &gt;= items.length) {
        loaderText.textContent = "All images loaded";
        loader.querySelector("span").style.display = "none";
      } else {
        loaderText.textContent = "Scroll down to load more images";
      }

      isLoading = false;
    }, 450);
  }

  if ("IntersectionObserver" in window) {
    const observer = new IntersectionObserver(function (entries) {
      entries.forEach(function (entry) {
        if (entry.isIntersecting) {
          loadNextBatch();
        }
      });
    }, {
      root: null,
      rootMargin: "180px 0px",
      threshold: 0.1
    });

    observer.observe(loader);
  }

  loadNextBatch();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-nine-demo"&gt;
  &lt;div class="vb-gallery-nine-shell" data-vb-gallery-nine&gt;
    &lt;div class="vb-gallery-nine-head"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 09&lt;/span&gt;
        &lt;h3&gt;Infinite Scroll Image Gallery&lt;/h3&gt;
        &lt;p&gt;Automatically load more image cards when the visitor reaches the bottom of the gallery.&lt;/p&gt;
      &lt;/div&gt;

      &lt;strong data-vb-gallery-nine-count&gt;0 images loaded&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-nine-grid" data-vb-gallery-nine-grid&gt;&lt;/div&gt;

    &lt;div class="vb-gallery-nine-loader" data-vb-gallery-nine-loader&gt;
      &lt;span&gt;&lt;/span&gt;
      &lt;p data-vb-gallery-nine-loader-text&gt;Scroll down to load more images&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-nine-card img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  min-width: 100%;
  min-height: 100%;
  object-fit: cover;
  object-position: center center;
  border: 0;
  margin: 0;
  padding: 0;
}</pre>



<p class="wp-block-paragraph">This infinite scroll image gallery is useful for portfolio archives, image-heavy blogs, ecommerce galleries, photography websites, inspiration boards, travel collections, and visual pages where new images should load automatically as users scroll.</p>



<h2 class="wp-block-heading">10. Load More Image Gallery</h2>



<p class="wp-block-paragraph"><strong>A load more image gallery</strong> gives users control over how many images they want to see. Instead of loading the full gallery immediately, the page shows an initial set of images and reveals more when the user clicks a button.</p>



<p class="wp-block-paragraph">This example uses JavaScript visible count logic. The gallery starts with four images, then adds more in groups of four. The progress bar, visible count, and button state update automatically. This is useful when you want better performance and a more controlled browsing experience than infinite scroll.</p>



<ul class="wp-block-list">
<li>Load more JavaScript image gallery</li>
<li>Visible item count state</li>
<li>Progress bar update</li>
<li>Button hides when all images are visible</li>
<li>Professional full-cover card layout</li>
</ul>



<div class="vb-gallery-ten-demo">
  <div class="vb-gallery-ten-shell" data-vb-gallery-ten>
    <div class="vb-gallery-ten-panel">
      <span>Example 10</span>
      <h3>Load More Image Gallery</h3>
      <p>Reveal more image cards on button click with JavaScript count state and progress feedback.</p>

      <div class="vb-gallery-ten-progress">
        <strong data-vb-gallery-ten-count>Showing 0 of 0</strong>
        <div>
          <span data-vb-gallery-ten-bar></span>
        </div>
      </div>
    </div>

    <div class="vb-gallery-ten-grid" data-vb-gallery-ten-grid></div>

    <div class="vb-gallery-ten-actions">
      <button type="button" data-vb-gallery-ten-button>Load More Images</button>
    </div>
  </div>
</div>

<style>
.vb-gallery-ten-demo,
.vb-gallery-ten-demo * {
  box-sizing: border-box;
}

.vb-gallery-ten-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 48px;
  background:
    radial-gradient(circle at 12% 12%, rgba(249, 115, 22, 0.16), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(236, 72, 153, 0.16), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #fdf2f8 52%, #ffffff 100%) !important;
  border: 1px solid rgba(251, 146, 60, 0.24);
  box-shadow: 0 28px 80px rgba(154, 52, 18, 0.10);
}

.vb-gallery-ten-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-ten-panel {
  margin-bottom: 22px;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 36px;
  background:
    radial-gradient(circle at 16% 12%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #7c2d12, #be123c 52%, #831843) !important;
  box-shadow: 0 24px 70px rgba(124, 45, 18, 0.22);
}

.vb-gallery-ten-panel > span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-ten-panel h3 {
  max-width: 760px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-ten-panel p {
  max-width: 720px;
  margin: 0 0 22px !important;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-ten-progress {
  display: grid;
  gap: 10px;
  max-width: 520px;
}

.vb-gallery-ten-progress strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-gallery-ten-progress div {
  height: 12px;
  overflow: hidden;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
}

.vb-gallery-ten-progress span {
  display: block;
  width: 0%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(135deg, #fbbf24, #fb7185);
  transition: width 0.3s ease;
}

.vb-gallery-ten-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-ten-card {
  position: relative;
  min-height: 300px;
  overflow: hidden;
  border-radius: 28px;
  background: #111827;
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.13);
  animation: vbGalleryTenIn 0.34s ease both;
}

@keyframes vbGalleryTenIn {
  from {
    opacity: 0;
    transform: scale(0.97) translateY(14px);
  }

  to {
    opacity: 1;
    transform: scale(1) translateY(0);
  }
}

.vb-gallery-ten-card img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  min-width: 100%;
  min-height: 100%;
  object-fit: cover;
  object-position: center center;
  border: 0;
  margin: 0;
  padding: 0;
  transition: transform 0.42s ease, filter 0.42s ease;
}

.vb-gallery-ten-card:hover img {
  transform: scale(1.08);
  filter: saturate(1.12) contrast(1.05);
}

.vb-gallery-ten-card::after {
  content: "";
  position: absolute;
  inset: 0;
  background:
    linear-gradient(180deg, rgba(17, 24, 39, 0.02), rgba(17, 24, 39, 0.86)),
    radial-gradient(circle at 18% 18%, rgba(255,255,255,0.16), transparent 34%);
  z-index: 1;
}

.vb-gallery-ten-content {
  position: absolute;
  z-index: 2;
  left: 16px;
  right: 16px;
  bottom: 16px;
  display: grid;
  gap: 7px;
}

.vb-gallery-ten-content span {
  display: inline-flex;
  width: fit-content;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.15);
  border: 1px solid rgba(255,255,255,0.18);
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb-gallery-ten-content h4 {
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px !important;
  line-height: 1.05 !important;
  font-weight: 950 !important;
  letter-spacing: -0.055em;
}

.vb-gallery-ten-actions {
  display: flex;
  justify-content: center;
  margin-top: 22px;
}

.vb-gallery-ten-actions button {
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #f97316, #ec4899);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 14px 22px;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(236, 72, 153, 0.28);
}

.vb-gallery-ten-actions button[hidden] {
  display: none;
}

@media (max-width: 1050px) {
  .vb-gallery-ten-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 760px) {
  .vb-gallery-ten-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-ten-panel h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }
}

@media (max-width: 520px) {
  .vb-gallery-ten-demo {
    padding: 16px;
    border-radius: 26px;
  }

  .vb-gallery-ten-grid {
    grid-template-columns: 1fr;
  }

  .vb-gallery-ten-card {
    min-height: 280px;
    border-radius: 24px;
  }

  .vb-gallery-ten-actions button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-ten]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-ten-grid]");
  const button = gallery.querySelector("[data-vb-gallery-ten-button]");
  const countEl = gallery.querySelector("[data-vb-gallery-ten-count]");
  const barEl = gallery.querySelector("[data-vb-gallery-ten-bar]");

  const items = [
    { title: "Load More One", category: "Portfolio", image: "https://picsum.photos/seed/gallery-ten-1/900/700" },
    { title: "Load More Two", category: "Interior", image: "https://picsum.photos/seed/gallery-ten-2/900/700" },
    { title: "Load More Three", category: "Product", image: "https://picsum.photos/seed/gallery-ten-3/900/700" },
    { title: "Load More Four", category: "Travel", image: "https://picsum.photos/seed/gallery-ten-4/900/700" },
    { title: "Load More Five", category: "Architecture", image: "https://picsum.photos/seed/gallery-ten-5/900/700" },
    { title: "Load More Six", category: "Studio", image: "https://picsum.photos/seed/gallery-ten-6/900/700" },
    { title: "Load More Seven", category: "Nature", image: "https://picsum.photos/seed/gallery-ten-7/900/700" },
    { title: "Load More Eight", category: "Workspace", image: "https://picsum.photos/seed/gallery-ten-8/900/700" },
    { title: "Load More Nine", category: "Editorial", image: "https://picsum.photos/seed/gallery-ten-9/900/700" },
    { title: "Load More Ten", category: "Lifestyle", image: "https://picsum.photos/seed/gallery-ten-10/900/700" },
    { title: "Load More Eleven", category: "Urban", image: "https://picsum.photos/seed/gallery-ten-11/900/700" },
    { title: "Load More Twelve", category: "Gallery", image: "https://picsum.photos/seed/gallery-ten-12/900/700" }
  ];

  const step = 4;
  let visibleCount = 4;

  function createCard(item, index) {
    return `
      <article class="vb-gallery-ten-card" style="animation-delay: ${index * 45}ms">
        <img decoding="async" src="${item.image}" alt="${item.title}" loading="lazy">

        <div class="vb-gallery-ten-content">
          <span>${item.category}</span>
          <h4>${item.title}</h4>
        </div>
      </article>
    `;
  }

  function updateProgress() {
    const percent = Math.round((visibleCount / items.length) * 100);
    countEl.textContent = "Showing " + visibleCount + " of " + items.length + " images";
    barEl.style.width = percent + "%";
    button.hidden = visibleCount >= items.length;
  }

  function renderGallery() {
    const visibleItems = items.slice(0, visibleCount);
    grid.innerHTML = visibleItems.map(createCard).join("");
    updateProgress();
  }

  button.addEventListener("click", function () {
    visibleCount = Math.min(visibleCount + step, items.length);
    renderGallery();
  });

  renderGallery();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-ten]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-ten-grid]");
  const button = gallery.querySelector("[data-vb-gallery-ten-button]");
  const countEl = gallery.querySelector("[data-vb-gallery-ten-count]");
  const barEl = gallery.querySelector("[data-vb-gallery-ten-bar]");

  const items = [
    { title: "Load More One", category: "Portfolio", image: "https://picsum.photos/seed/gallery-ten-1/900/700" },
    { title: "Load More Two", category: "Interior", image: "https://picsum.photos/seed/gallery-ten-2/900/700" },
    { title: "Load More Three", category: "Product", image: "https://picsum.photos/seed/gallery-ten-3/900/700" },
    { title: "Load More Four", category: "Travel", image: "https://picsum.photos/seed/gallery-ten-4/900/700" },
    { title: "Load More Five", category: "Architecture", image: "https://picsum.photos/seed/gallery-ten-5/900/700" },
    { title: "Load More Six", category: "Studio", image: "https://picsum.photos/seed/gallery-ten-6/900/700" },
    { title: "Load More Seven", category: "Nature", image: "https://picsum.photos/seed/gallery-ten-7/900/700" },
    { title: "Load More Eight", category: "Workspace", image: "https://picsum.photos/seed/gallery-ten-8/900/700" },
    { title: "Load More Nine", category: "Editorial", image: "https://picsum.photos/seed/gallery-ten-9/900/700" },
    { title: "Load More Ten", category: "Lifestyle", image: "https://picsum.photos/seed/gallery-ten-10/900/700" },
    { title: "Load More Eleven", category: "Urban", image: "https://picsum.photos/seed/gallery-ten-11/900/700" },
    { title: "Load More Twelve", category: "Gallery", image: "https://picsum.photos/seed/gallery-ten-12/900/700" }
  ];

  const step = 4;
  let visibleCount = 4;

  function createCard(item, index) {
    return `
      &lt;article class="vb-gallery-ten-card" style="animation-delay: ${index * 45}ms"&gt;
        &lt;img src="${item.image}" alt="${item.title}" loading="lazy"&gt;

        &lt;div class="vb-gallery-ten-content"&gt;
          &lt;span&gt;${item.category}&lt;/span&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    `;
  }

  function updateProgress() {
    const percent = Math.round((visibleCount / items.length) * 100);
    countEl.textContent = "Showing " + visibleCount + " of " + items.length + " images";
    barEl.style.width = percent + "%";
    button.hidden = visibleCount &gt;= items.length;
  }

  function renderGallery() {
    const visibleItems = items.slice(0, visibleCount);
    grid.innerHTML = visibleItems.map(createCard).join("");
    updateProgress();
  }

  button.addEventListener("click", function () {
    visibleCount = Math.min(visibleCount + step, items.length);
    renderGallery();
  });

  renderGallery();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-ten-demo"&gt;
  &lt;div class="vb-gallery-ten-shell" data-vb-gallery-ten&gt;
    &lt;div class="vb-gallery-ten-panel"&gt;
      &lt;span&gt;Example 10&lt;/span&gt;
      &lt;h3&gt;Load More Image Gallery&lt;/h3&gt;
      &lt;p&gt;Reveal more image cards on button click with JavaScript count state and progress feedback.&lt;/p&gt;

      &lt;div class="vb-gallery-ten-progress"&gt;
        &lt;strong data-vb-gallery-ten-count&gt;Showing 0 of 0&lt;/strong&gt;
        &lt;div&gt;
          &lt;span data-vb-gallery-ten-bar&gt;&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-ten-grid" data-vb-gallery-ten-grid&gt;&lt;/div&gt;

    &lt;div class="vb-gallery-ten-actions"&gt;
      &lt;button type="button" data-vb-gallery-ten-button&gt;Load More Images&lt;/button&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-ten-card img {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
  min-width: 100%;
  min-height: 100%;
  object-fit: cover;
  object-position: center center;
  border: 0;
  margin: 0;
  padding: 0;
}</pre>



<p class="wp-block-paragraph">This load more image gallery is useful for portfolio pages, ecommerce image grids, travel collections, media libraries, blog galleries, real estate listings, and any visual section where users should control how many images appear at once.</p>



<h2 class="wp-block-heading">11. Sortable Image Gallery</h2>



<p class="wp-block-paragraph"><strong>A sortable image gallery</strong> lets users change the order of images by title, date, popularity, or another custom value. This is useful for portfolio archives, product collections, media libraries, design galleries, real estate listings, case studies, and any image-heavy page where the same gallery data should be displayed in different orders.</p>



<p class="wp-block-paragraph">This example uses JavaScript array sorting and re-rendering. The gallery items are stored in a reusable data array, and each sort button changes how the cards appear. The visual thumbnails are created with CSS only, so the demo does not depend on any external image URLs.</p>



<ul class="wp-block-list">
<li>Sortable JavaScript image gallery</li>
<li>Sort by newest, oldest, title, and most viewed</li>
<li>Dynamic re-rendering from a data array</li>
<li>Active sort button state</li>
<li>CSS-only illustrated image thumbnails</li>
</ul>



<div class="vb-gallery-eleven-demo">
  <div class="vb-gallery-eleven-shell" data-vb-gallery-eleven>
    <div class="vb-gallery-eleven-top">
      <div>
        <span>Example 11</span>
        <h3>Sortable Image Gallery</h3>
        <p>Sort a CSS-illustrated image gallery by newest, oldest, title, or most viewed using JavaScript.</p>
      </div>

      <strong data-vb-gallery-eleven-status>Sorted by newest</strong>
    </div>

    <div class="vb-gallery-eleven-controls" data-vb-gallery-eleven-controls>
      <button type="button" class="is-active" data-sort="newest">Newest</button>
      <button type="button" data-sort="oldest">Oldest</button>
      <button type="button" data-sort="title">Title A-Z</button>
      <button type="button" data-sort="views">Most Viewed</button>
    </div>

    <div class="vb-gallery-eleven-grid" data-vb-gallery-eleven-grid></div>
  </div>
</div>

<style>
.vb-gallery-eleven-demo,
.vb-gallery-eleven-demo * {
  box-sizing: border-box;
}

.vb-gallery-eleven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 14%, rgba(99, 102, 241, 0.16), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(20, 184, 166, 0.16), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #ecfeff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.22);
  box-shadow: 0 28px 80px rgba(67, 56, 202, 0.10);
}

.vb-gallery-eleven-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-eleven-top {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px;
  margin-bottom: 22px;
}

.vb-gallery-eleven-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #e0e7ff;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-eleven-top h3 {
  max-width: 760px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-eleven-top p {
  max-width: 720px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-eleven-top strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-eleven-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 22px;
  padding: 12px;
  border-radius: 24px;
  background: rgba(255,255,255,0.76);
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.08);
}

.vb-gallery-eleven-controls button {
  appearance: none;
  border: 1px solid rgba(99, 102, 241, 0.20);
  border-radius: 999px;
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  padding: 11px 15px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease;
}

.vb-gallery-eleven-controls button:hover {
  transform: translateY(-2px);
  border-color: rgba(99, 102, 241, 0.54);
}

.vb-gallery-eleven-controls button.is-active {
  border-color: rgba(99, 102, 241, 0.88);
  background: linear-gradient(135deg, #4f46e5, #0f766e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 14px 34px rgba(79, 70, 229, 0.26);
}

.vb-gallery-eleven-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-gallery-eleven-card {
  overflow: hidden;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  animation: vbGalleryElevenIn 0.32s ease both;
}

@keyframes vbGalleryElevenIn {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.vb-gallery-eleven-art {
  position: relative;
  height: 240px;
  overflow: hidden;
  background: #0f172a;
}

.vb-gallery-eleven-art::before,
.vb-gallery-eleven-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-eleven-art span {
  position: absolute;
  pointer-events: none;
}

.vb-gallery-eleven-art-aurora {
  background: linear-gradient(135deg, #020617 0%, #1e1b4b 48%, #0f766e 100%);
}

.vb-gallery-eleven-art-aurora::before {
  left: -12%;
  top: 18%;
  width: 124%;
  height: 42%;
  border-radius: 999px;
  background: linear-gradient(90deg, rgba(45,212,191,0), rgba(45,212,191,0.78), rgba(168,85,247,0.62), rgba(45,212,191,0));
  filter: blur(20px);
  transform: rotate(-9deg);
}

.vb-gallery-eleven-art-aurora::after {
  right: 12%;
  top: 18%;
  width: 90px;
  height: 90px;
  border-radius: 999px;
  background: rgba(224, 242, 254, 0.90);
  box-shadow: 0 0 70px rgba(224, 242, 254, 0.62);
}

.vb-gallery-eleven-art-desert {
  background: linear-gradient(180deg, #fed7aa 0%, #fb923c 54%, #7c2d12 100%);
}

.vb-gallery-eleven-art-desert::before {
  left: -10%;
  right: -10%;
  bottom: -34%;
  height: 72%;
  border-radius: 50% 50% 0 0;
  background: #431407;
}

.vb-gallery-eleven-art-desert::after {
  right: 18%;
  top: 16%;
  width: 74px;
  height: 74px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 54px rgba(255,247,237,0.72);
}

.vb-gallery-eleven-art-ocean {
  background: linear-gradient(180deg, #bae6fd 0%, #0284c7 52%, #082f49 100%);
}

.vb-gallery-eleven-art-ocean::before {
  left: -10%;
  right: -10%;
  bottom: 20%;
  height: 28%;
  background:
    radial-gradient(circle at 12% 40%, rgba(255,255,255,0.86), transparent 11%),
    radial-gradient(circle at 34% 55%, rgba(255,255,255,0.62), transparent 12%),
    radial-gradient(circle at 68% 42%, rgba(255,255,255,0.70), transparent 12%),
    linear-gradient(90deg, rgba(255,255,255,0.12), rgba(255,255,255,0.50), rgba(255,255,255,0.12));
  filter: blur(2px);
  transform: rotate(-2deg);
}

.vb-gallery-eleven-art-ocean::after {
  left: 16%;
  top: 18%;
  width: 96px;
  height: 96px;
  border-radius: 50%;
  background: rgba(255,255,255,0.42);
  filter: blur(10px);
}

.vb-gallery-eleven-art-city {
  background: linear-gradient(180deg, #312e81 0%, #111827 66%, #020617 100%);
}

.vb-gallery-eleven-art-city::before {
  left: 10%;
  bottom: 0;
  width: 18%;
  height: 58%;
  background: #020617;
  box-shadow:
    70px -42px 0 #020617,
    142px -12px 0 #020617,
    224px -62px 0 #020617,
    304px -24px 0 #020617;
}

.vb-gallery-eleven-art-city::after {
  inset: 18% 10% auto 10%;
  height: 3px;
  background: repeating-linear-gradient(90deg, rgba(255,255,255,0.82) 0 8px, transparent 8px 24px);
  box-shadow:
    0 34px 0 rgba(255,255,255,0.42),
    0 70px 0 rgba(255,255,255,0.22);
}

.vb-gallery-eleven-art-product {
  background: radial-gradient(circle at 50% 40%, #ffffff 0%, #e0e7ff 34%, #312e81 100%);
}

.vb-gallery-eleven-art-product::before {
  left: 50%;
  top: 50%;
  width: 118px;
  height: 118px;
  border-radius: 32px;
  background: linear-gradient(135deg, #ffffff, #c7d2fe);
  box-shadow: 0 28px 70px rgba(49,46,129,0.32);
  transform: translate(-50%, -50%) rotate(12deg);
}

.vb-gallery-eleven-art-product::after {
  left: 50%;
  top: 50%;
  width: 74px;
  height: 74px;
  border-radius: 22px;
  border: 4px solid rgba(79,70,229,0.46);
  transform: translate(-50%, -50%) rotate(12deg);
}

.vb-gallery-eleven-art-forest {
  background: linear-gradient(180deg, #bbf7d0 0%, #16a34a 54%, #052e16 100%);
}

.vb-gallery-eleven-art-forest::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 44% 100%, transparent 0 25%, #064e3b 0 50%, transparent 0),
    conic-gradient(from 45deg at 72% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-eleven-art-forest::after {
  left: 12%;
  top: 16%;
  width: 70px;
  height: 70px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-eleven-body {
  display: grid;
  gap: 10px;
  padding: 18px;
}

.vb-gallery-eleven-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 21px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-eleven-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-gallery-eleven-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding-top: 10px;
  border-top: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-gallery-eleven-meta small {
  display: inline-flex;
  padding: 6px 9px;
  border-radius: 999px;
  background: #f1f5f9;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 11px;
  font-weight: 900;
}

@media (max-width: 980px) {
  .vb-gallery-eleven-top {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-eleven-top strong {
    justify-content: center;
    width: 100%;
  }

  .vb-gallery-eleven-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .vb-gallery-eleven-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-eleven-top h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-eleven-grid {
    grid-template-columns: 1fr;
  }

  .vb-gallery-eleven-controls {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-eleven-controls button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-eleven]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-eleven-grid]");
  const controls = gallery.querySelector("[data-vb-gallery-eleven-controls]");
  const status = gallery.querySelector("[data-vb-gallery-eleven-status]");

  const items = [
    {
      title: "Aurora Field",
      category: "Landscape",
      year: 2026,
      views: 1280,
      art: "vb-gallery-eleven-art-aurora",
      description: "A CSS-only aurora style thumbnail for a modern gallery card."
    },
    {
      title: "Desert Sun",
      category: "Travel",
      year: 2023,
      views: 940,
      art: "vb-gallery-eleven-art-desert",
      description: "A warm CSS desert illustration for visual browsing sections."
    },
    {
      title: "Ocean Motion",
      category: "Nature",
      year: 2025,
      views: 1760,
      art: "vb-gallery-eleven-art-ocean",
      description: "A CSS ocean scene for image gallery examples without external images."
    },
    {
      title: "City Grid",
      category: "Architecture",
      year: 2024,
      views: 2210,
      art: "vb-gallery-eleven-art-city",
      description: "A CSS city illustration for urban portfolio gallery layouts."
    },
    {
      title: "Product Cube",
      category: "Product",
      year: 2026,
      views: 1510,
      art: "vb-gallery-eleven-art-product",
      description: "A CSS product-style visual for ecommerce gallery sorting."
    },
    {
      title: "Forest Light",
      category: "Nature",
      year: 2022,
      views: 1160,
      art: "vb-gallery-eleven-art-forest",
      description: "A CSS forest scene for a sortable image gallery card."
    }
  ];

  function createCard(item, index) {
    return `
      <article class="vb-gallery-eleven-card" style="animation-delay: ${index * 45}ms">
        <div class="vb-gallery-eleven-art ${item.art}" aria-label="${item.title} illustration" role="img"></div>

        <div class="vb-gallery-eleven-body">
          <h4>${item.title}</h4>
          <p>${item.description}</p>

          <div class="vb-gallery-eleven-meta">
            <small>${item.category}</small>
            <small>${item.year}</small>
            <small>${item.views} views</small>
          </div>
        </div>
      </article>
    `;
  }

  function getSortedItems(sortType) {
    const sortedItems = items.slice();

    if (sortType === "newest") {
      sortedItems.sort(function (a, b) {
        return b.year - a.year;
      });
    }

    if (sortType === "oldest") {
      sortedItems.sort(function (a, b) {
        return a.year - b.year;
      });
    }

    if (sortType === "title") {
      sortedItems.sort(function (a, b) {
        return a.title.localeCompare(b.title);
      });
    }

    if (sortType === "views") {
      sortedItems.sort(function (a, b) {
        return b.views - a.views;
      });
    }

    return sortedItems;
  }

  function renderGallery(sortType) {
    const sortedItems = getSortedItems(sortType);
    grid.innerHTML = sortedItems.map(createCard).join("");

    const label = sortType.replace("-", " ");
    status.textContent = "Sorted by " + label;
  }

  controls.addEventListener("click", function (event) {
    const button = event.target.closest("button[data-sort]");
    if (!button) return;

    controls.querySelectorAll("button").forEach(function (controlButton) {
      controlButton.classList.remove("is-active");
    });

    button.classList.add("is-active");
    renderGallery(button.getAttribute("data-sort"));
  });

  renderGallery("newest");
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-eleven]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-eleven-grid]");
  const controls = gallery.querySelector("[data-vb-gallery-eleven-controls]");
  const status = gallery.querySelector("[data-vb-gallery-eleven-status]");

  const items = [
    {
      title: "Aurora Field",
      category: "Landscape",
      year: 2026,
      views: 1280,
      art: "vb-gallery-eleven-art-aurora",
      description: "A CSS-only aurora style thumbnail for a modern gallery card."
    },
    {
      title: "Desert Sun",
      category: "Travel",
      year: 2023,
      views: 940,
      art: "vb-gallery-eleven-art-desert",
      description: "A warm CSS desert illustration for visual browsing sections."
    },
    {
      title: "Ocean Motion",
      category: "Nature",
      year: 2025,
      views: 1760,
      art: "vb-gallery-eleven-art-ocean",
      description: "A CSS ocean scene for image gallery examples without external images."
    },
    {
      title: "City Grid",
      category: "Architecture",
      year: 2024,
      views: 2210,
      art: "vb-gallery-eleven-art-city",
      description: "A CSS city illustration for urban portfolio gallery layouts."
    },
    {
      title: "Product Cube",
      category: "Product",
      year: 2026,
      views: 1510,
      art: "vb-gallery-eleven-art-product",
      description: "A CSS product-style visual for ecommerce gallery sorting."
    },
    {
      title: "Forest Light",
      category: "Nature",
      year: 2022,
      views: 1160,
      art: "vb-gallery-eleven-art-forest",
      description: "A CSS forest scene for a sortable image gallery card."
    }
  ];

  function createCard(item, index) {
    return `
      &lt;article class="vb-gallery-eleven-card" style="animation-delay: ${index * 45}ms"&gt;
        &lt;div class="vb-gallery-eleven-art ${item.art}" aria-label="${item.title} illustration" role="img"&gt;&lt;/div&gt;

        &lt;div class="vb-gallery-eleven-body"&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
          &lt;p&gt;${item.description}&lt;/p&gt;

          &lt;div class="vb-gallery-eleven-meta"&gt;
            &lt;small&gt;${item.category}&lt;/small&gt;
            &lt;small&gt;${item.year}&lt;/small&gt;
            &lt;small&gt;${item.views} views&lt;/small&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    `;
  }

  function getSortedItems(sortType) {
    const sortedItems = items.slice();

    if (sortType === "newest") {
      sortedItems.sort(function (a, b) {
        return b.year - a.year;
      });
    }

    if (sortType === "oldest") {
      sortedItems.sort(function (a, b) {
        return a.year - b.year;
      });
    }

    if (sortType === "title") {
      sortedItems.sort(function (a, b) {
        return a.title.localeCompare(b.title);
      });
    }

    if (sortType === "views") {
      sortedItems.sort(function (a, b) {
        return b.views - a.views;
      });
    }

    return sortedItems;
  }

  function renderGallery(sortType) {
    const sortedItems = getSortedItems(sortType);
    grid.innerHTML = sortedItems.map(createCard).join("");

    const label = sortType.replace("-", " ");
    status.textContent = "Sorted by " + label;
  }

  controls.addEventListener("click", function (event) {
    const button = event.target.closest("button[data-sort]");
    if (!button) return;

    controls.querySelectorAll("button").forEach(function (controlButton) {
      controlButton.classList.remove("is-active");
    });

    button.classList.add("is-active");
    renderGallery(button.getAttribute("data-sort"));
  });

  renderGallery("newest");
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-eleven-demo"&gt;
  &lt;div class="vb-gallery-eleven-shell" data-vb-gallery-eleven&gt;
    &lt;div class="vb-gallery-eleven-top"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 11&lt;/span&gt;
        &lt;h3&gt;Sortable Image Gallery&lt;/h3&gt;
        &lt;p&gt;Sort a CSS-illustrated image gallery by newest, oldest, title, or most viewed using JavaScript.&lt;/p&gt;
      &lt;/div&gt;

      &lt;strong data-vb-gallery-eleven-status&gt;Sorted by newest&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-eleven-controls" data-vb-gallery-eleven-controls&gt;
      &lt;button type="button" class="is-active" data-sort="newest"&gt;Newest&lt;/button&gt;
      &lt;button type="button" data-sort="oldest"&gt;Oldest&lt;/button&gt;
      &lt;button type="button" data-sort="title"&gt;Title A-Z&lt;/button&gt;
      &lt;button type="button" data-sort="views"&gt;Most Viewed&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-eleven-grid" data-vb-gallery-eleven-grid&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-eleven-demo,
.vb-gallery-eleven-demo * {
  box-sizing: border-box;
}

.vb-gallery-eleven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 14%, rgba(99, 102, 241, 0.16), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(20, 184, 166, 0.16), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #ecfeff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(99, 102, 241, 0.22);
  box-shadow: 0 28px 80px rgba(67, 56, 202, 0.10);
}

.vb-gallery-eleven-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-eleven-top {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 20px;
  margin-bottom: 22px;
}

.vb-gallery-eleven-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #e0e7ff;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-eleven-top h3 {
  max-width: 760px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-eleven-top p {
  max-width: 720px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-eleven-top strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-eleven-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 22px;
  padding: 12px;
  border-radius: 24px;
  background: rgba(255,255,255,0.76);
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.08);
}

.vb-gallery-eleven-controls button {
  appearance: none;
  border: 1px solid rgba(99, 102, 241, 0.20);
  border-radius: 999px;
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  padding: 11px 15px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease;
}

.vb-gallery-eleven-controls button:hover {
  transform: translateY(-2px);
  border-color: rgba(99, 102, 241, 0.54);
}

.vb-gallery-eleven-controls button.is-active {
  border-color: rgba(99, 102, 241, 0.88);
  background: linear-gradient(135deg, #4f46e5, #0f766e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 14px 34px rgba(79, 70, 229, 0.26);
}

.vb-gallery-eleven-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-gallery-eleven-card {
  overflow: hidden;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  animation: vbGalleryElevenIn 0.32s ease both;
}

@keyframes vbGalleryElevenIn {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.vb-gallery-eleven-art {
  position: relative;
  height: 240px;
  overflow: hidden;
  background: #0f172a;
}

.vb-gallery-eleven-art::before,
.vb-gallery-eleven-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-eleven-art span {
  position: absolute;
  pointer-events: none;
}

.vb-gallery-eleven-art-aurora {
  background: linear-gradient(135deg, #020617 0%, #1e1b4b 48%, #0f766e 100%);
}

.vb-gallery-eleven-art-aurora::before {
  left: -12%;
  top: 18%;
  width: 124%;
  height: 42%;
  border-radius: 999px;
  background: linear-gradient(90deg, rgba(45,212,191,0), rgba(45,212,191,0.78), rgba(168,85,247,0.62), rgba(45,212,191,0));
  filter: blur(20px);
  transform: rotate(-9deg);
}

.vb-gallery-eleven-art-aurora::after {
  right: 12%;
  top: 18%;
  width: 90px;
  height: 90px;
  border-radius: 999px;
  background: rgba(224, 242, 254, 0.90);
  box-shadow: 0 0 70px rgba(224, 242, 254, 0.62);
}

.vb-gallery-eleven-art-desert {
  background: linear-gradient(180deg, #fed7aa 0%, #fb923c 54%, #7c2d12 100%);
}

.vb-gallery-eleven-art-desert::before {
  left: -10%;
  right: -10%;
  bottom: -34%;
  height: 72%;
  border-radius: 50% 50% 0 0;
  background: #431407;
}

.vb-gallery-eleven-art-desert::after {
  right: 18%;
  top: 16%;
  width: 74px;
  height: 74px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 54px rgba(255,247,237,0.72);
}

.vb-gallery-eleven-art-ocean {
  background: linear-gradient(180deg, #bae6fd 0%, #0284c7 52%, #082f49 100%);
}

.vb-gallery-eleven-art-ocean::before {
  left: -10%;
  right: -10%;
  bottom: 20%;
  height: 28%;
  background:
    radial-gradient(circle at 12% 40%, rgba(255,255,255,0.86), transparent 11%),
    radial-gradient(circle at 34% 55%, rgba(255,255,255,0.62), transparent 12%),
    radial-gradient(circle at 68% 42%, rgba(255,255,255,0.70), transparent 12%),
    linear-gradient(90deg, rgba(255,255,255,0.12), rgba(255,255,255,0.50), rgba(255,255,255,0.12));
  filter: blur(2px);
  transform: rotate(-2deg);
}

.vb-gallery-eleven-art-ocean::after {
  left: 16%;
  top: 18%;
  width: 96px;
  height: 96px;
  border-radius: 50%;
  background: rgba(255,255,255,0.42);
  filter: blur(10px);
}

.vb-gallery-eleven-art-city {
  background: linear-gradient(180deg, #312e81 0%, #111827 66%, #020617 100%);
}

.vb-gallery-eleven-art-city::before {
  left: 10%;
  bottom: 0;
  width: 18%;
  height: 58%;
  background: #020617;
  box-shadow:
    70px -42px 0 #020617,
    142px -12px 0 #020617,
    224px -62px 0 #020617,
    304px -24px 0 #020617;
}

.vb-gallery-eleven-art-city::after {
  inset: 18% 10% auto 10%;
  height: 3px;
  background: repeating-linear-gradient(90deg, rgba(255,255,255,0.82) 0 8px, transparent 8px 24px);
  box-shadow:
    0 34px 0 rgba(255,255,255,0.42),
    0 70px 0 rgba(255,255,255,0.22);
}

.vb-gallery-eleven-art-product {
  background: radial-gradient(circle at 50% 40%, #ffffff 0%, #e0e7ff 34%, #312e81 100%);
}

.vb-gallery-eleven-art-product::before {
  left: 50%;
  top: 50%;
  width: 118px;
  height: 118px;
  border-radius: 32px;
  background: linear-gradient(135deg, #ffffff, #c7d2fe);
  box-shadow: 0 28px 70px rgba(49,46,129,0.32);
  transform: translate(-50%, -50%) rotate(12deg);
}

.vb-gallery-eleven-art-product::after {
  left: 50%;
  top: 50%;
  width: 74px;
  height: 74px;
  border-radius: 22px;
  border: 4px solid rgba(79,70,229,0.46);
  transform: translate(-50%, -50%) rotate(12deg);
}

.vb-gallery-eleven-art-forest {
  background: linear-gradient(180deg, #bbf7d0 0%, #16a34a 54%, #052e16 100%);
}

.vb-gallery-eleven-art-forest::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 44% 100%, transparent 0 25%, #064e3b 0 50%, transparent 0),
    conic-gradient(from 45deg at 72% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-eleven-art-forest::after {
  left: 12%;
  top: 16%;
  width: 70px;
  height: 70px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-eleven-body {
  display: grid;
  gap: 10px;
  padding: 18px;
}

.vb-gallery-eleven-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 21px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-eleven-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-gallery-eleven-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  padding-top: 10px;
  border-top: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-gallery-eleven-meta small {
  display: inline-flex;
  padding: 6px 9px;
  border-radius: 999px;
  background: #f1f5f9;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 11px;
  font-weight: 900;
}

@media (max-width: 980px) {
  .vb-gallery-eleven-top {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-eleven-top strong {
    justify-content: center;
    width: 100%;
  }

  .vb-gallery-eleven-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .vb-gallery-eleven-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-eleven-top h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-eleven-grid {
    grid-template-columns: 1fr;
  }

  .vb-gallery-eleven-controls {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-eleven-controls button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This sortable image gallery is useful for portfolio archives, product collections, media libraries, design inspiration pages, photography collections, and any image gallery where users should be able to change the order of visual content.</p>



<h2 class="wp-block-heading">12. Favorite Images Gallery</h2>



<p class="wp-block-paragraph"><strong>A favorite images gallery</strong> lets users save selected images and return to them later. This is useful for product wishlists, design inspiration boards, portfolio collections, real estate galleries, interior design references, travel planning pages, and any visual browsing experience where users may want to remember specific items.</p>



<p class="wp-block-paragraph">This example uses JavaScript localStorage logic. Users can click the heart button on any CSS-illustrated card, and the favorite state remains saved after page refresh. The gallery can also switch between all images and only favorite images.</p>



<ul class="wp-block-list">
<li>Favorite image gallery with JavaScript</li>
<li>localStorage saved favorites</li>
<li>Toggle favorite state per card</li>
<li>Show all or only favorite images</li>
<li>CSS-only illustrated gallery thumbnails</li>
</ul>



<div class="vb-gallery-twelve-demo">
  <div class="vb-gallery-twelve-shell" data-vb-gallery-twelve>
    <div class="vb-gallery-twelve-hero">
      <div>
        <span>Example 12</span>
        <h3>Favorite Images Gallery</h3>
        <p>Save favorite gallery items with localStorage and switch between all images and saved favorites.</p>
      </div>

      <div class="vb-gallery-twelve-actions">
        <button type="button" class="is-active" data-view="all">All Images</button>
        <button type="button" data-view="favorites">Favorites Only</button>
        <strong data-vb-gallery-twelve-count>0 favorites</strong>
      </div>
    </div>

    <div class="vb-gallery-twelve-grid" data-vb-gallery-twelve-grid></div>

    <div class="vb-gallery-twelve-empty" data-vb-gallery-twelve-empty hidden>
      <h4>No favorite images yet</h4>
      <p>Click the heart button on a gallery card to save it as a favorite.</p>
    </div>
  </div>
</div>

<style>
.vb-gallery-twelve-demo,
.vb-gallery-twelve-demo * {
  box-sizing: border-box;
}

.vb-gallery-twelve-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px 18px 44px 18px;
  background:
    radial-gradient(circle at 14% 14%, rgba(236, 72, 153, 0.18), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(251, 146, 60, 0.16), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #fff7ed 52%, #ffffff 100%) !important;
  border: 1px solid rgba(244, 114, 182, 0.24);
  box-shadow: 0 28px 80px rgba(190, 24, 93, 0.10);
}

.vb-gallery-twelve-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-twelve-hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 390px);
  gap: 20px;
  align-items: stretch;
  margin-bottom: 22px;
}

.vb-gallery-twelve-hero > div:first-child {
  padding: clamp(22px, 4vw, 34px);
  border-radius: 34px 10px 34px 10px;
  background:
    radial-gradient(circle at 16% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #831843, #be123c 52%, #9a3412) !important;
  box-shadow: 0 24px 70px rgba(190, 24, 93, 0.22);
}

.vb-gallery-twelve-hero span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.18);
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-twelve-hero h3 {
  max-width: 760px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-twelve-hero p {
  max-width: 720px;
  margin: 0 !important;
  color: #ffe4e6 !important;
  -webkit-text-fill-color: #ffe4e6 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-twelve-actions {
  display: grid;
  align-content: center;
  gap: 12px;
  padding: 22px;
  border-radius: 10px 34px 10px 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.09);
}

.vb-gallery-twelve-actions button {
  appearance: none;
  border: 1px solid rgba(244, 114, 182, 0.22);
  border-radius: 999px;
  background: #fdf2f8;
  color: #9d174d !important;
  -webkit-text-fill-color: #9d174d !important;
  padding: 13px 16px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-gallery-twelve-actions button.is-active {
  background: linear-gradient(135deg, #db2777, #f97316);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  border-color: transparent;
  box-shadow: 0 14px 34px rgba(219, 39, 119, 0.26);
}

.vb-gallery-twelve-actions strong {
  display: flex;
  justify-content: center;
  padding: 12px 14px;
  border-radius: 18px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-gallery-twelve-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-gallery-twelve-card {
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  animation: vbGalleryTwelveIn 0.32s ease both;
}

@keyframes vbGalleryTwelveIn {
  from {
    opacity: 0;
    transform: translateY(14px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.vb-gallery-twelve-art {
  position: relative;
  height: 250px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-twelve-art::before,
.vb-gallery-twelve-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-twelve-art-rose {
  background: linear-gradient(135deg, #500724 0%, #be123c 52%, #fb7185 100%);
}

.vb-gallery-twelve-art-rose::before {
  left: 50%;
  top: 52%;
  width: 150px;
  height: 150px;
  border-radius: 42% 58% 62% 38%;
  background: radial-gradient(circle at 35% 30%, #fff1f2, #fb7185 44%, #9f1239 100%);
  transform: translate(-50%, -50%) rotate(22deg);
  box-shadow: 0 26px 70px rgba(80,7,36,0.36);
}

.vb-gallery-twelve-art-rose::after {
  left: 14%;
  top: 16%;
  width: 74px;
  height: 74px;
  border-radius: 999px;
  background: rgba(255,255,255,0.22);
  filter: blur(6px);
}

.vb-gallery-twelve-art-canyon {
  background: linear-gradient(180deg, #fed7aa 0%, #f97316 50%, #7c2d12 100%);
}

.vb-gallery-twelve-art-canyon::before {
  left: -8%;
  right: -8%;
  bottom: -22%;
  height: 66%;
  border-radius: 50% 50% 0 0;
  background: #431407;
}

.vb-gallery-twelve-art-canyon::after {
  left: 16%;
  top: 16%;
  width: 78px;
  height: 78px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 62px rgba(255,247,237,0.72);
}

.vb-gallery-twelve-art-lagoon {
  background: linear-gradient(180deg, #cffafe 0%, #06b6d4 48%, #164e63 100%);
}

.vb-gallery-twelve-art-lagoon::before {
  left: -6%;
  right: -6%;
  bottom: 26%;
  height: 26%;
  background:
    radial-gradient(circle at 16% 52%, rgba(255,255,255,0.88), transparent 12%),
    radial-gradient(circle at 46% 38%, rgba(255,255,255,0.62), transparent 13%),
    radial-gradient(circle at 78% 58%, rgba(255,255,255,0.72), transparent 14%);
  filter: blur(2px);
}

.vb-gallery-twelve-art-lagoon::after {
  right: 14%;
  top: 16%;
  width: 96px;
  height: 96px;
  border-radius: 999px;
  background: rgba(255,255,255,0.28);
  filter: blur(10px);
}

.vb-gallery-twelve-art-night {
  background: linear-gradient(180deg, #111827 0%, #312e81 54%, #020617 100%);
}

.vb-gallery-twelve-art-night::before {
  inset: 18% 12% auto 12%;
  height: 120px;
  background:
    radial-gradient(circle at 10% 20%, #ffffff 0 2px, transparent 3px),
    radial-gradient(circle at 30% 70%, #ffffff 0 2px, transparent 3px),
    radial-gradient(circle at 52% 32%, #ffffff 0 2px, transparent 3px),
    radial-gradient(circle at 78% 62%, #ffffff 0 2px, transparent 3px),
    radial-gradient(circle at 90% 20%, #ffffff 0 2px, transparent 3px);
}

.vb-gallery-twelve-art-night::after {
  left: 12%;
  right: 12%;
  bottom: 0;
  height: 40%;
  background: #020617;
  clip-path: polygon(0 100%, 0 55%, 12% 70%, 24% 42%, 36% 62%, 48% 30%, 60% 58%, 74% 36%, 88% 64%, 100% 48%, 100% 100%);
}

.vb-gallery-twelve-art-orbit {
  background: radial-gradient(circle at 50% 50%, #ffffff 0%, #c4b5fd 34%, #581c87 100%);
}

.vb-gallery-twelve-art-orbit::before {
  left: 50%;
  top: 50%;
  width: 134px;
  height: 134px;
  border-radius: 999px;
  border: 16px solid rgba(255,255,255,0.36);
  border-top-color: rgba(255,255,255,0.86);
  transform: translate(-50%, -50%) rotate(-18deg);
}

.vb-gallery-twelve-art-orbit::after {
  left: 50%;
  top: 50%;
  width: 74px;
  height: 74px;
  border-radius: 999px;
  background: linear-gradient(135deg, #ffffff, #a78bfa);
  transform: translate(-50%, -50%);
  box-shadow: 0 28px 70px rgba(88,28,135,0.32);
}

.vb-gallery-twelve-art-meadow {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 56%, #052e16 100%);
}

.vb-gallery-twelve-art-meadow::before {
  left: -10%;
  right: -10%;
  bottom: -18%;
  height: 56%;
  border-radius: 50% 50% 0 0;
  background: #166534;
}

.vb-gallery-twelve-art-meadow::after {
  left: 16%;
  top: 14%;
  width: 84px;
  height: 84px;
  border-radius: 999px;
  background: #f0fdf4;
  box-shadow: 0 0 56px rgba(240,253,244,0.72);
}

.vb-gallery-twelve-heart {
  position: absolute;
  z-index: 3;
  top: 14px;
  right: 14px;
  width: 46px;
  height: 46px;
  border: 1px solid rgba(255,255,255,0.24);
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.58);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  backdrop-filter: blur(10px);
  transition: transform 0.2s ease, background 0.2s ease;
}

.vb-gallery-twelve-heart:hover {
  transform: scale(1.06);
}

.vb-gallery-twelve-heart.is-favorite {
  background: linear-gradient(135deg, #db2777, #f97316);
  border-color: transparent;
}

.vb-gallery-twelve-body {
  display: grid;
  gap: 10px;
  padding: 18px;
}

.vb-gallery-twelve-body h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-twelve-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-gallery-twelve-tag {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #fdf2f8;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-twelve-empty {
  margin-top: 18px;
  padding: 26px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px dashed rgba(244, 114, 182, 0.44);
  text-align: center;
}

.vb-gallery-twelve-empty h4 {
  margin: 0 0 8px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 24px !important;
  font-weight: 950 !important;
}

.vb-gallery-twelve-empty p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 15px;
  line-height: 1.6;
}

@media (max-width: 980px) {
  .vb-gallery-twelve-hero {
    grid-template-columns: 1fr;
  }

  .vb-gallery-twelve-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .vb-gallery-twelve-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-twelve-hero h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-twelve-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-twelve]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-twelve-grid]");
  const count = gallery.querySelector("[data-vb-gallery-twelve-count]");
  const empty = gallery.querySelector("[data-vb-gallery-twelve-empty]");
  const viewButtons = gallery.querySelectorAll("[data-view]");
  const storageKey = "vb-gallery-twelve-favorites";

  const items = [
    {
      id: "rose-shape",
      title: "Rose Shape",
      category: "Abstract",
      art: "vb-gallery-twelve-art-rose",
      description: "A CSS-only abstract rose illustration saved as a favorite gallery item."
    },
    {
      id: "canyon-light",
      title: "Canyon Light",
      category: "Travel",
      art: "vb-gallery-twelve-art-canyon",
      description: "A CSS canyon-style thumbnail for travel and inspiration galleries."
    },
    {
      id: "blue-lagoon",
      title: "Blue Lagoon",
      category: "Nature",
      art: "vb-gallery-twelve-art-lagoon",
      description: "A CSS water-inspired illustration for visual collection cards."
    },
    {
      id: "night-peaks",
      title: "Night Peaks",
      category: "Landscape",
      art: "vb-gallery-twelve-art-night",
      description: "A CSS night mountain scene for saved image gallery examples."
    },
    {
      id: "orbit-object",
      title: "Orbit Object",
      category: "Product",
      art: "vb-gallery-twelve-art-orbit",
      description: "A CSS product-style orbit illustration for favorite image cards."
    },
    {
      id: "green-meadow",
      title: "Green Meadow",
      category: "Nature",
      art: "vb-gallery-twelve-art-meadow",
      description: "A CSS meadow illustration for a localStorage favorite gallery."
    }
  ];

  let activeView = "all";
  let favorites = getFavorites();

  function getFavorites() {
    try {
      return JSON.parse(localStorage.getItem(storageKey)) || [];
    } catch (error) {
      return [];
    }
  }

  function saveFavorites() {
    localStorage.setItem(storageKey, JSON.stringify(favorites));
  }

  function isFavorite(id) {
    return favorites.includes(id);
  }

  function toggleFavorite(id) {
    if (isFavorite(id)) {
      favorites = favorites.filter(function (favoriteId) {
        return favoriteId !== id;
      });
    } else {
      favorites.push(id);
    }

    saveFavorites();
    renderGallery();
  }

  function createCard(item, index) {
    const favoriteClass = isFavorite(item.id) ? "is-favorite" : "";
    const heartSymbol = isFavorite(item.id) ? "♥" : "♡";

    return `
      <article class="vb-gallery-twelve-card" style="animation-delay: ${index * 45}ms">
        <div class="vb-gallery-twelve-art ${item.art}" aria-label="${item.title} illustration" role="img">
          <button type="button" class="vb-gallery-twelve-heart ${favoriteClass}" data-favorite-id="${item.id}" aria-label="Toggle favorite for ${item.title}">${heartSymbol}</button>
        </div>

        <div class="vb-gallery-twelve-body">
          <span class="vb-gallery-twelve-tag">${item.category}</span>
          <h4>${item.title}</h4>
          <p>${item.description}</p>
        </div>
      </article>
    `;
  }

  function getVisibleItems() {
    if (activeView === "favorites") {
      return items.filter(function (item) {
        return isFavorite(item.id);
      });
    }

    return items;
  }

  function updateCount() {
    const text = favorites.length === 1 ? "1 favorite" : favorites.length + " favorites";
    count.textContent = text;
  }

  function renderGallery() {
    const visibleItems = getVisibleItems();

    grid.innerHTML = visibleItems.map(createCard).join("");
    empty.hidden = !(activeView === "favorites" && visibleItems.length === 0);
    updateCount();
  }

  grid.addEventListener("click", function (event) {
    const button = event.target.closest("[data-favorite-id]");
    if (!button) return;

    toggleFavorite(button.getAttribute("data-favorite-id"));
  });

  viewButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeView = button.getAttribute("data-view");

      viewButtons.forEach(function (viewButton) {
        viewButton.classList.remove("is-active");
      });

      button.classList.add("is-active");
      renderGallery();
    });
  });

  renderGallery();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-twelve]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-twelve-grid]");
  const count = gallery.querySelector("[data-vb-gallery-twelve-count]");
  const empty = gallery.querySelector("[data-vb-gallery-twelve-empty]");
  const viewButtons = gallery.querySelectorAll("[data-view]");
  const storageKey = "vb-gallery-twelve-favorites";

  const items = [
    {
      id: "rose-shape",
      title: "Rose Shape",
      category: "Abstract",
      art: "vb-gallery-twelve-art-rose",
      description: "A CSS-only abstract rose illustration saved as a favorite gallery item."
    },
    {
      id: "canyon-light",
      title: "Canyon Light",
      category: "Travel",
      art: "vb-gallery-twelve-art-canyon",
      description: "A CSS canyon-style thumbnail for travel and inspiration galleries."
    },
    {
      id: "blue-lagoon",
      title: "Blue Lagoon",
      category: "Nature",
      art: "vb-gallery-twelve-art-lagoon",
      description: "A CSS water-inspired illustration for visual collection cards."
    },
    {
      id: "night-peaks",
      title: "Night Peaks",
      category: "Landscape",
      art: "vb-gallery-twelve-art-night",
      description: "A CSS night mountain scene for saved image gallery examples."
    },
    {
      id: "orbit-object",
      title: "Orbit Object",
      category: "Product",
      art: "vb-gallery-twelve-art-orbit",
      description: "A CSS product-style orbit illustration for favorite image cards."
    },
    {
      id: "green-meadow",
      title: "Green Meadow",
      category: "Nature",
      art: "vb-gallery-twelve-art-meadow",
      description: "A CSS meadow illustration for a localStorage favorite gallery."
    }
  ];

  let activeView = "all";
  let favorites = getFavorites();

  function getFavorites() {
    try {
      return JSON.parse(localStorage.getItem(storageKey)) || [];
    } catch (error) {
      return [];
    }
  }

  function saveFavorites() {
    localStorage.setItem(storageKey, JSON.stringify(favorites));
  }

  function isFavorite(id) {
    return favorites.includes(id);
  }

  function toggleFavorite(id) {
    if (isFavorite(id)) {
      favorites = favorites.filter(function (favoriteId) {
        return favoriteId !== id;
      });
    } else {
      favorites.push(id);
    }

    saveFavorites();
    renderGallery();
  }

  function createCard(item, index) {
    const favoriteClass = isFavorite(item.id) ? "is-favorite" : "";
    const heartSymbol = isFavorite(item.id) ? "♥" : "♡";

    return `
      &lt;article class="vb-gallery-twelve-card" style="animation-delay: ${index * 45}ms"&gt;
        &lt;div class="vb-gallery-twelve-art ${item.art}" aria-label="${item.title} illustration" role="img"&gt;
          &lt;button type="button" class="vb-gallery-twelve-heart ${favoriteClass}" data-favorite-id="${item.id}" aria-label="Toggle favorite for ${item.title}"&gt;${heartSymbol}&lt;/button&gt;
        &lt;/div&gt;

        &lt;div class="vb-gallery-twelve-body"&gt;
          &lt;span class="vb-gallery-twelve-tag"&gt;${item.category}&lt;/span&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
          &lt;p&gt;${item.description}&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    `;
  }

  function getVisibleItems() {
    if (activeView === "favorites") {
      return items.filter(function (item) {
        return isFavorite(item.id);
      });
    }

    return items;
  }

  function updateCount() {
    const text = favorites.length === 1 ? "1 favorite" : favorites.length + " favorites";
    count.textContent = text;
  }

  function renderGallery() {
    const visibleItems = getVisibleItems();

    grid.innerHTML = visibleItems.map(createCard).join("");
    empty.hidden = !(activeView === "favorites" && visibleItems.length === 0);
    updateCount();
  }

  grid.addEventListener("click", function (event) {
    const button = event.target.closest("[data-favorite-id]");
    if (!button) return;

    toggleFavorite(button.getAttribute("data-favorite-id"));
  });

  viewButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      activeView = button.getAttribute("data-view");

      viewButtons.forEach(function (viewButton) {
        viewButton.classList.remove("is-active");
      });

      button.classList.add("is-active");
      renderGallery();
    });
  });

  renderGallery();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-twelve-demo"&gt;
  &lt;div class="vb-gallery-twelve-shell" data-vb-gallery-twelve&gt;
    &lt;div class="vb-gallery-twelve-hero"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 12&lt;/span&gt;
        &lt;h3&gt;Favorite Images Gallery&lt;/h3&gt;
        &lt;p&gt;Save favorite gallery items with localStorage and switch between all images and saved favorites.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-gallery-twelve-actions"&gt;
        &lt;button type="button" class="is-active" data-view="all"&gt;All Images&lt;/button&gt;
        &lt;button type="button" data-view="favorites"&gt;Favorites Only&lt;/button&gt;
        &lt;strong data-vb-gallery-twelve-count&gt;0 favorites&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-twelve-grid" data-vb-gallery-twelve-grid&gt;&lt;/div&gt;

    &lt;div class="vb-gallery-twelve-empty" data-vb-gallery-twelve-empty hidden&gt;
      &lt;h4&gt;No favorite images yet&lt;/h4&gt;
      &lt;p&gt;Click the heart button on a gallery card to save it as a favorite.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-twelve-demo,
.vb-gallery-twelve-demo * {
  box-sizing: border-box;
}

.vb-gallery-twelve-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 44px 18px 44px 18px;
  background:
    radial-gradient(circle at 14% 14%, rgba(236, 72, 153, 0.18), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(251, 146, 60, 0.16), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #fff7ed 52%, #ffffff 100%) !important;
  border: 1px solid rgba(244, 114, 182, 0.24);
  box-shadow: 0 28px 80px rgba(190, 24, 93, 0.10);
}

.vb-gallery-twelve-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-twelve-hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 390px);
  gap: 20px;
  align-items: stretch;
  margin-bottom: 22px;
}

.vb-gallery-twelve-hero > div:first-child {
  padding: clamp(22px, 4vw, 34px);
  border-radius: 34px 10px 34px 10px;
  background:
    radial-gradient(circle at 16% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #831843, #be123c 52%, #9a3412) !important;
  box-shadow: 0 24px 70px rgba(190, 24, 93, 0.22);
}

.vb-gallery-twelve-hero span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.18);
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-twelve-hero h3 {
  max-width: 760px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-twelve-hero p {
  max-width: 720px;
  margin: 0 !important;
  color: #ffe4e6 !important;
  -webkit-text-fill-color: #ffe4e6 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-twelve-actions {
  display: grid;
  align-content: center;
  gap: 12px;
  padding: 22px;
  border-radius: 10px 34px 10px 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.09);
}

.vb-gallery-twelve-actions button {
  appearance: none;
  border: 1px solid rgba(244, 114, 182, 0.22);
  border-radius: 999px;
  background: #fdf2f8;
  color: #9d174d !important;
  -webkit-text-fill-color: #9d174d !important;
  padding: 13px 16px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-gallery-twelve-actions button.is-active {
  background: linear-gradient(135deg, #db2777, #f97316);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  border-color: transparent;
  box-shadow: 0 14px 34px rgba(219, 39, 119, 0.26);
}

.vb-gallery-twelve-actions strong {
  display: flex;
  justify-content: center;
  padding: 12px 14px;
  border-radius: 18px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-gallery-twelve-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-gallery-twelve-card {
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  animation: vbGalleryTwelveIn 0.32s ease both;
}

@keyframes vbGalleryTwelveIn {
  from {
    opacity: 0;
    transform: translateY(14px);
  }

  to {
    opacity: 1;
    transform: translateY(0);
  }
}

.vb-gallery-twelve-art {
  position: relative;
  height: 250px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-twelve-art::before,
.vb-gallery-twelve-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-twelve-art-rose {
  background: linear-gradient(135deg, #500724 0%, #be123c 52%, #fb7185 100%);
}

.vb-gallery-twelve-art-rose::before {
  left: 50%;
  top: 52%;
  width: 150px;
  height: 150px;
  border-radius: 42% 58% 62% 38%;
  background: radial-gradient(circle at 35% 30%, #fff1f2, #fb7185 44%, #9f1239 100%);
  transform: translate(-50%, -50%) rotate(22deg);
  box-shadow: 0 26px 70px rgba(80,7,36,0.36);
}

.vb-gallery-twelve-art-rose::after {
  left: 14%;
  top: 16%;
  width: 74px;
  height: 74px;
  border-radius: 999px;
  background: rgba(255,255,255,0.22);
  filter: blur(6px);
}

.vb-gallery-twelve-art-canyon {
  background: linear-gradient(180deg, #fed7aa 0%, #f97316 50%, #7c2d12 100%);
}

.vb-gallery-twelve-art-canyon::before {
  left: -8%;
  right: -8%;
  bottom: -22%;
  height: 66%;
  border-radius: 50% 50% 0 0;
  background: #431407;
}

.vb-gallery-twelve-art-canyon::after {
  left: 16%;
  top: 16%;
  width: 78px;
  height: 78px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 62px rgba(255,247,237,0.72);
}

.vb-gallery-twelve-art-lagoon {
  background: linear-gradient(180deg, #cffafe 0%, #06b6d4 48%, #164e63 100%);
}

.vb-gallery-twelve-art-lagoon::before {
  left: -6%;
  right: -6%;
  bottom: 26%;
  height: 26%;
  background:
    radial-gradient(circle at 16% 52%, rgba(255,255,255,0.88), transparent 12%),
    radial-gradient(circle at 46% 38%, rgba(255,255,255,0.62), transparent 13%),
    radial-gradient(circle at 78% 58%, rgba(255,255,255,0.72), transparent 14%);
  filter: blur(2px);
}

.vb-gallery-twelve-art-lagoon::after {
  right: 14%;
  top: 16%;
  width: 96px;
  height: 96px;
  border-radius: 999px;
  background: rgba(255,255,255,0.28);
  filter: blur(10px);
}

.vb-gallery-twelve-art-night {
  background: linear-gradient(180deg, #111827 0%, #312e81 54%, #020617 100%);
}

.vb-gallery-twelve-art-night::before {
  inset: 18% 12% auto 12%;
  height: 120px;
  background:
    radial-gradient(circle at 10% 20%, #ffffff 0 2px, transparent 3px),
    radial-gradient(circle at 30% 70%, #ffffff 0 2px, transparent 3px),
    radial-gradient(circle at 52% 32%, #ffffff 0 2px, transparent 3px),
    radial-gradient(circle at 78% 62%, #ffffff 0 2px, transparent 3px),
    radial-gradient(circle at 90% 20%, #ffffff 0 2px, transparent 3px);
}

.vb-gallery-twelve-art-night::after {
  left: 12%;
  right: 12%;
  bottom: 0;
  height: 40%;
  background: #020617;
  clip-path: polygon(0 100%, 0 55%, 12% 70%, 24% 42%, 36% 62%, 48% 30%, 60% 58%, 74% 36%, 88% 64%, 100% 48%, 100% 100%);
}

.vb-gallery-twelve-art-orbit {
  background: radial-gradient(circle at 50% 50%, #ffffff 0%, #c4b5fd 34%, #581c87 100%);
}

.vb-gallery-twelve-art-orbit::before {
  left: 50%;
  top: 50%;
  width: 134px;
  height: 134px;
  border-radius: 999px;
  border: 16px solid rgba(255,255,255,0.36);
  border-top-color: rgba(255,255,255,0.86);
  transform: translate(-50%, -50%) rotate(-18deg);
}

.vb-gallery-twelve-art-orbit::after {
  left: 50%;
  top: 50%;
  width: 74px;
  height: 74px;
  border-radius: 999px;
  background: linear-gradient(135deg, #ffffff, #a78bfa);
  transform: translate(-50%, -50%);
  box-shadow: 0 28px 70px rgba(88,28,135,0.32);
}

.vb-gallery-twelve-art-meadow {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 56%, #052e16 100%);
}

.vb-gallery-twelve-art-meadow::before {
  left: -10%;
  right: -10%;
  bottom: -18%;
  height: 56%;
  border-radius: 50% 50% 0 0;
  background: #166534;
}

.vb-gallery-twelve-art-meadow::after {
  left: 16%;
  top: 14%;
  width: 84px;
  height: 84px;
  border-radius: 999px;
  background: #f0fdf4;
  box-shadow: 0 0 56px rgba(240,253,244,0.72);
}

.vb-gallery-twelve-heart {
  position: absolute;
  z-index: 3;
  top: 14px;
  right: 14px;
  width: 46px;
  height: 46px;
  border: 1px solid rgba(255,255,255,0.24);
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.58);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
  backdrop-filter: blur(10px);
  transition: transform 0.2s ease, background 0.2s ease;
}

.vb-gallery-twelve-heart:hover {
  transform: scale(1.06);
}

.vb-gallery-twelve-heart.is-favorite {
  background: linear-gradient(135deg, #db2777, #f97316);
  border-color: transparent;
}

.vb-gallery-twelve-body {
  display: grid;
  gap: 10px;
  padding: 18px;
}

.vb-gallery-twelve-body h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-twelve-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-gallery-twelve-tag {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #fdf2f8;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-twelve-empty {
  margin-top: 18px;
  padding: 26px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px dashed rgba(244, 114, 182, 0.44);
  text-align: center;
}

.vb-gallery-twelve-empty h4 {
  margin: 0 0 8px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 24px !important;
  font-weight: 950 !important;
}

.vb-gallery-twelve-empty p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 15px;
  line-height: 1.6;
}

@media (max-width: 980px) {
  .vb-gallery-twelve-hero {
    grid-template-columns: 1fr;
  }

  .vb-gallery-twelve-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .vb-gallery-twelve-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-twelve-hero h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-twelve-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This favorite images gallery is useful for visual wishlists, product inspiration boards, design references, travel planning galleries, real estate favorites, portfolio collections, and any image gallery where visitors should be able to save selected items locally.</p>



<h2 class="wp-block-heading">13. Selectable Image Gallery</h2>



<p class="wp-block-paragraph"><strong>A selectable image gallery</strong> lets users select multiple images and track their selected items. This pattern is useful for media managers, product comparison galleries, moodboards, portfolio review tools, image approval systems, real estate shortlist pages, and design selection interfaces.</p>



<p class="wp-block-paragraph">This example uses JavaScript selection state management. Users can click gallery cards to select or unselect them, the selected count updates instantly, selected cards get a clear visual state, and the Clear Selection button resets the gallery. The thumbnail artwork is CSS-only, so the example does not use external image files.</p>



<ul class="wp-block-list">
<li>Selectable JavaScript image gallery</li>
<li>Multi-select image card state</li>
<li>Dynamic selected count</li>
<li>Clear all selected items button</li>
<li>CSS-only illustrated gallery thumbnails</li>
</ul>



<div class="vb-gallery-thirteen-demo">
  <div class="vb-gallery-thirteen-shell" data-vb-gallery-thirteen>
    <div class="vb-gallery-thirteen-header">
      <div>
        <span>Example 13</span>
        <h3>Selectable Image Gallery</h3>
        <p>Select multiple CSS-illustrated gallery cards and manage the selected image count with JavaScript.</p>
      </div>

      <div class="vb-gallery-thirteen-summary">
        <strong data-vb-gallery-thirteen-count>0 selected</strong>
        <button type="button" data-vb-gallery-thirteen-clear>Clear Selection</button>
      </div>
    </div>

    <div class="vb-gallery-thirteen-grid" data-vb-gallery-thirteen-grid></div>
  </div>
</div>

<style>
.vb-gallery-thirteen-demo,
.vb-gallery-thirteen-demo * {
  box-sizing: border-box;
}

.vb-gallery-thirteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 12%, rgba(59, 130, 246, 0.16), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(16, 185, 129, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 52%, #ffffff 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.22);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-gallery-thirteen-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-thirteen-header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(280px, 360px);
  gap: 20px;
  align-items: stretch;
  margin-bottom: 22px;
}

.vb-gallery-thirteen-header > div:first-child {
  padding: clamp(22px, 4vw, 34px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #0f172a, #1d4ed8 54%, #0f766e) !important;
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.22);
}

.vb-gallery-thirteen-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-thirteen-header h3 {
  max-width: 780px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-thirteen-header p {
  max-width: 720px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-thirteen-summary {
  display: grid;
  align-content: center;
  gap: 12px;
  padding: 22px;
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.09);
}

.vb-gallery-thirteen-summary strong {
  display: flex;
  justify-content: center;
  padding: 14px 16px;
  border-radius: 20px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-gallery-thirteen-summary button {
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #0f766e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 13px 16px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 14px 34px rgba(37, 99, 235, 0.24);
}

.vb-gallery-thirteen-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-thirteen-card {
  position: relative;
  overflow: hidden;
  min-height: 330px;
  border: 2px solid transparent;
  border-radius: 30px;
  background: #ffffff;
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  cursor: pointer;
  transition: transform 0.22s ease, border-color 0.22s ease, box-shadow 0.22s ease;
}

.vb-gallery-thirteen-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 26px 64px rgba(15, 23, 42, 0.16);
}

.vb-gallery-thirteen-card.is-selected {
  border-color: rgba(37, 99, 235, 0.86);
  box-shadow: 0 24px 70px rgba(37, 99, 235, 0.22);
}

.vb-gallery-thirteen-check {
  position: absolute;
  z-index: 5;
  top: 14px;
  right: 14px;
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.62);
  border: 1px solid rgba(255,255,255,0.24);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
  backdrop-filter: blur(10px);
  transition: background 0.22s ease, transform 0.22s ease;
}

.vb-gallery-thirteen-card.is-selected .vb-gallery-thirteen-check {
  background: linear-gradient(135deg, #2563eb, #0f766e);
  transform: scale(1.06);
}

.vb-gallery-thirteen-art {
  position: relative;
  height: 215px;
  overflow: hidden;
  background: #0f172a;
}

.vb-gallery-thirteen-art::before,
.vb-gallery-thirteen-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-thirteen-art-horizon {
  background: linear-gradient(180deg, #bfdbfe 0%, #60a5fa 45%, #1e3a8a 100%);
}

.vb-gallery-thirteen-art-horizon::before {
  left: -10%;
  right: -10%;
  bottom: -28%;
  height: 58%;
  border-radius: 50% 50% 0 0;
  background: #0f172a;
}

.vb-gallery-thirteen-art-horizon::after {
  right: 18%;
  top: 16%;
  width: 76px;
  height: 76px;
  border-radius: 999px;
  background: rgba(255,255,255,0.88);
  box-shadow: 0 0 58px rgba(255,255,255,0.66);
}

.vb-gallery-thirteen-art-gradient {
  background: linear-gradient(135deg, #581c87 0%, #db2777 50%, #fb7185 100%);
}

.vb-gallery-thirteen-art-gradient::before {
  left: 50%;
  top: 50%;
  width: 150px;
  height: 150px;
  border-radius: 34px;
  background: rgba(255,255,255,0.18);
  border: 1px solid rgba(255,255,255,0.30);
  transform: translate(-50%, -50%) rotate(18deg);
  backdrop-filter: blur(4px);
}

.vb-gallery-thirteen-art-gradient::after {
  left: 18%;
  top: 18%;
  width: 90px;
  height: 90px;
  border-radius: 999px;
  background: rgba(255,255,255,0.18);
  filter: blur(8px);
}

.vb-gallery-thirteen-art-layers {
  background: linear-gradient(180deg, #ccfbf1 0%, #14b8a6 48%, #134e4a 100%);
}

.vb-gallery-thirteen-art-layers::before {
  left: -12%;
  right: -12%;
  bottom: 0;
  height: 54%;
  background:
    radial-gradient(ellipse at 20% 100%, #042f2e 0 38%, transparent 39%),
    radial-gradient(ellipse at 58% 100%, #115e59 0 42%, transparent 43%),
    radial-gradient(ellipse at 92% 100%, #042f2e 0 38%, transparent 39%);
}

.vb-gallery-thirteen-art-layers::after {
  left: 16%;
  top: 18%;
  width: 84px;
  height: 84px;
  border-radius: 999px;
  background: rgba(240,253,250,0.82);
  filter: blur(5px);
}

.vb-gallery-thirteen-art-cards {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #dbeafe 38%, #1d4ed8 100%);
}

.vb-gallery-thirteen-art-cards::before {
  left: 50%;
  top: 50%;
  width: 118px;
  height: 148px;
  border-radius: 26px;
  background: linear-gradient(135deg, #ffffff, #bfdbfe);
  box-shadow:
    -34px 18px 0 rgba(255,255,255,0.34),
    34px -18px 0 rgba(255,255,255,0.24),
    0 26px 70px rgba(30,64,175,0.32);
  transform: translate(-50%, -50%) rotate(8deg);
}

.vb-gallery-thirteen-art-cards::after {
  left: 50%;
  top: 50%;
  width: 72px;
  height: 12px;
  border-radius: 999px;
  background: #2563eb;
  box-shadow: 0 26px 0 rgba(37,99,235,0.42);
  transform: translate(-50%, -50%) rotate(8deg);
}

.vb-gallery-thirteen-art-sunset {
  background: linear-gradient(180deg, #fde68a 0%, #fb923c 46%, #7f1d1d 100%);
}

.vb-gallery-thirteen-art-sunset::before {
  left: -6%;
  right: -6%;
  bottom: -18%;
  height: 54%;
  background: #431407;
  clip-path: polygon(0 100%, 0 50%, 12% 62%, 24% 38%, 38% 66%, 52% 34%, 66% 62%, 82% 42%, 100% 56%, 100% 100%);
}

.vb-gallery-thirteen-art-sunset::after {
  left: 18%;
  top: 18%;
  width: 88px;
  height: 88px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 70px rgba(255,247,237,0.72);
}

.vb-gallery-thirteen-art-mono {
  background: linear-gradient(135deg, #020617 0%, #334155 52%, #cbd5e1 100%);
}

.vb-gallery-thirteen-art-mono::before {
  left: 18%;
  top: 20%;
  width: 180px;
  height: 180px;
  border-radius: 999px;
  border: 22px solid rgba(255,255,255,0.22);
  border-right-color: rgba(255,255,255,0.62);
  transform: rotate(-18deg);
}

.vb-gallery-thirteen-art-mono::after {
  right: 12%;
  bottom: 12%;
  width: 130px;
  height: 48px;
  border-radius: 999px;
  background: rgba(255,255,255,0.22);
  filter: blur(4px);
}

.vb-gallery-thirteen-body {
  display: grid;
  gap: 8px;
  padding: 18px;
}

.vb-gallery-thirteen-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 21px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-thirteen-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-gallery-thirteen-tag {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #eff6ff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
}

@media (max-width: 1050px) {
  .vb-gallery-thirteen-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 820px) {
  .vb-gallery-thirteen-header {
    grid-template-columns: 1fr;
  }

  .vb-gallery-thirteen-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .vb-gallery-thirteen-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-thirteen-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-thirteen-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-thirteen]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-thirteen-grid]");
  const count = gallery.querySelector("[data-vb-gallery-thirteen-count]");
  const clearButton = gallery.querySelector("[data-vb-gallery-thirteen-clear]");

  const items = [
    {
      id: "horizon",
      title: "Blue Horizon",
      category: "Landscape",
      art: "vb-gallery-thirteen-art-horizon",
      description: "A selectable CSS landscape thumbnail for visual review interfaces."
    },
    {
      id: "gradient",
      title: "Gradient Poster",
      category: "Abstract",
      art: "vb-gallery-thirteen-art-gradient",
      description: "A bold CSS abstract image card for creative selection galleries."
    },
    {
      id: "layers",
      title: "Green Layers",
      category: "Nature",
      art: "vb-gallery-thirteen-art-layers",
      description: "A CSS nature-inspired thumbnail for image selection systems."
    },
    {
      id: "cards",
      title: "Product Stack",
      category: "Product",
      art: "vb-gallery-thirteen-art-cards",
      description: "A CSS product-style visual for choosing campaign assets."
    },
    {
      id: "sunset",
      title: "Sunset Peaks",
      category: "Travel",
      art: "vb-gallery-thirteen-art-sunset",
      description: "A warm CSS travel thumbnail for shortlist gallery layouts."
    },
    {
      id: "mono",
      title: "Mono Orbit",
      category: "Editorial",
      art: "vb-gallery-thirteen-art-mono",
      description: "A monochrome CSS illustration for editorial gallery selection."
    }
  ];

  let selectedIds = [];

  function isSelected(id) {
    return selectedIds.includes(id);
  }

  function updateCount() {
    count.textContent = selectedIds.length === 1 ? "1 selected" : selectedIds.length + " selected";
  }

  function createCard(item, index) {
    const selectedClass = isSelected(item.id) ? "is-selected" : "";
    const checkSymbol = isSelected(item.id) ? "✓" : "+";

    return `
      <article class="vb-gallery-thirteen-card ${selectedClass}" data-select-id="${item.id}" style="animation-delay: ${index * 45}ms">
        <div class="vb-gallery-thirteen-check">${checkSymbol}</div>
        <div class="vb-gallery-thirteen-art ${item.art}" aria-label="${item.title} illustration" role="img"></div>

        <div class="vb-gallery-thirteen-body">
          <span class="vb-gallery-thirteen-tag">${item.category}</span>
          <h4>${item.title}</h4>
          <p>${item.description}</p>
        </div>
      </article>
    `;
  }

  function renderGallery() {
    grid.innerHTML = items.map(createCard).join("");
    updateCount();
  }

  function toggleSelection(id) {
    if (isSelected(id)) {
      selectedIds = selectedIds.filter(function (selectedId) {
        return selectedId !== id;
      });
    } else {
      selectedIds.push(id);
    }

    renderGallery();
  }

  grid.addEventListener("click", function (event) {
    const card = event.target.closest("[data-select-id]");
    if (!card) return;

    toggleSelection(card.getAttribute("data-select-id"));
  });

  clearButton.addEventListener("click", function () {
    selectedIds = [];
    renderGallery();
  });

  renderGallery();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-thirteen]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-thirteen-grid]");
  const count = gallery.querySelector("[data-vb-gallery-thirteen-count]");
  const clearButton = gallery.querySelector("[data-vb-gallery-thirteen-clear]");

  const items = [
    {
      id: "horizon",
      title: "Blue Horizon",
      category: "Landscape",
      art: "vb-gallery-thirteen-art-horizon",
      description: "A selectable CSS landscape thumbnail for visual review interfaces."
    },
    {
      id: "gradient",
      title: "Gradient Poster",
      category: "Abstract",
      art: "vb-gallery-thirteen-art-gradient",
      description: "A bold CSS abstract image card for creative selection galleries."
    },
    {
      id: "layers",
      title: "Green Layers",
      category: "Nature",
      art: "vb-gallery-thirteen-art-layers",
      description: "A CSS nature-inspired thumbnail for image selection systems."
    },
    {
      id: "cards",
      title: "Product Stack",
      category: "Product",
      art: "vb-gallery-thirteen-art-cards",
      description: "A CSS product-style visual for choosing campaign assets."
    },
    {
      id: "sunset",
      title: "Sunset Peaks",
      category: "Travel",
      art: "vb-gallery-thirteen-art-sunset",
      description: "A warm CSS travel thumbnail for shortlist gallery layouts."
    },
    {
      id: "mono",
      title: "Mono Orbit",
      category: "Editorial",
      art: "vb-gallery-thirteen-art-mono",
      description: "A monochrome CSS illustration for editorial gallery selection."
    }
  ];

  let selectedIds = [];

  function isSelected(id) {
    return selectedIds.includes(id);
  }

  function updateCount() {
    count.textContent = selectedIds.length === 1 ? "1 selected" : selectedIds.length + " selected";
  }

  function createCard(item, index) {
    const selectedClass = isSelected(item.id) ? "is-selected" : "";
    const checkSymbol = isSelected(item.id) ? "✓" : "+";

    return `
      &lt;article class="vb-gallery-thirteen-card ${selectedClass}" data-select-id="${item.id}" style="animation-delay: ${index * 45}ms"&gt;
        &lt;div class="vb-gallery-thirteen-check"&gt;${checkSymbol}&lt;/div&gt;
        &lt;div class="vb-gallery-thirteen-art ${item.art}" aria-label="${item.title} illustration" role="img"&gt;&lt;/div&gt;

        &lt;div class="vb-gallery-thirteen-body"&gt;
          &lt;span class="vb-gallery-thirteen-tag"&gt;${item.category}&lt;/span&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
          &lt;p&gt;${item.description}&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    `;
  }

  function renderGallery() {
    grid.innerHTML = items.map(createCard).join("");
    updateCount();
  }

  function toggleSelection(id) {
    if (isSelected(id)) {
      selectedIds = selectedIds.filter(function (selectedId) {
        return selectedId !== id;
      });
    } else {
      selectedIds.push(id);
    }

    renderGallery();
  }

  grid.addEventListener("click", function (event) {
    const card = event.target.closest("[data-select-id]");
    if (!card) return;

    toggleSelection(card.getAttribute("data-select-id"));
  });

  clearButton.addEventListener("click", function () {
    selectedIds = [];
    renderGallery();
  });

  renderGallery();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-thirteen-demo"&gt;
  &lt;div class="vb-gallery-thirteen-shell" data-vb-gallery-thirteen&gt;
    &lt;div class="vb-gallery-thirteen-header"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 13&lt;/span&gt;
        &lt;h3&gt;Selectable Image Gallery&lt;/h3&gt;
        &lt;p&gt;Select multiple CSS-illustrated gallery cards and manage the selected image count with JavaScript.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-gallery-thirteen-summary"&gt;
        &lt;strong data-vb-gallery-thirteen-count&gt;0 selected&lt;/strong&gt;
        &lt;button type="button" data-vb-gallery-thirteen-clear&gt;Clear Selection&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-thirteen-grid" data-vb-gallery-thirteen-grid&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-thirteen-demo,
.vb-gallery-thirteen-demo * {
  box-sizing: border-box;
}

.vb-gallery-thirteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 12%, rgba(59, 130, 246, 0.16), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(16, 185, 129, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 52%, #ffffff 100%) !important;
  border: 1px solid rgba(59, 130, 246, 0.22);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-gallery-thirteen-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-thirteen-header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(280px, 360px);
  gap: 20px;
  align-items: stretch;
  margin-bottom: 22px;
}

.vb-gallery-thirteen-header > div:first-child {
  padding: clamp(22px, 4vw, 34px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #0f172a, #1d4ed8 54%, #0f766e) !important;
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.22);
}

.vb-gallery-thirteen-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-thirteen-header h3 {
  max-width: 780px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-thirteen-header p {
  max-width: 720px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-thirteen-summary {
  display: grid;
  align-content: center;
  gap: 12px;
  padding: 22px;
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.09);
}

.vb-gallery-thirteen-summary strong {
  display: flex;
  justify-content: center;
  padding: 14px 16px;
  border-radius: 20px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-gallery-thirteen-summary button {
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #2563eb, #0f766e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 13px 16px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 14px 34px rgba(37, 99, 235, 0.24);
}

.vb-gallery-thirteen-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-thirteen-card {
  position: relative;
  overflow: hidden;
  min-height: 330px;
  border: 2px solid transparent;
  border-radius: 30px;
  background: #ffffff;
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  cursor: pointer;
  transition: transform 0.22s ease, border-color 0.22s ease, box-shadow 0.22s ease;
}

.vb-gallery-thirteen-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 26px 64px rgba(15, 23, 42, 0.16);
}

.vb-gallery-thirteen-card.is-selected {
  border-color: rgba(37, 99, 235, 0.86);
  box-shadow: 0 24px 70px rgba(37, 99, 235, 0.22);
}

.vb-gallery-thirteen-check {
  position: absolute;
  z-index: 5;
  top: 14px;
  right: 14px;
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.62);
  border: 1px solid rgba(255,255,255,0.24);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
  backdrop-filter: blur(10px);
  transition: background 0.22s ease, transform 0.22s ease;
}

.vb-gallery-thirteen-card.is-selected .vb-gallery-thirteen-check {
  background: linear-gradient(135deg, #2563eb, #0f766e);
  transform: scale(1.06);
}

.vb-gallery-thirteen-art {
  position: relative;
  height: 215px;
  overflow: hidden;
  background: #0f172a;
}

.vb-gallery-thirteen-art::before,
.vb-gallery-thirteen-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-thirteen-art-horizon {
  background: linear-gradient(180deg, #bfdbfe 0%, #60a5fa 45%, #1e3a8a 100%);
}

.vb-gallery-thirteen-art-horizon::before {
  left: -10%;
  right: -10%;
  bottom: -28%;
  height: 58%;
  border-radius: 50% 50% 0 0;
  background: #0f172a;
}

.vb-gallery-thirteen-art-horizon::after {
  right: 18%;
  top: 16%;
  width: 76px;
  height: 76px;
  border-radius: 999px;
  background: rgba(255,255,255,0.88);
  box-shadow: 0 0 58px rgba(255,255,255,0.66);
}

.vb-gallery-thirteen-art-gradient {
  background: linear-gradient(135deg, #581c87 0%, #db2777 50%, #fb7185 100%);
}

.vb-gallery-thirteen-art-gradient::before {
  left: 50%;
  top: 50%;
  width: 150px;
  height: 150px;
  border-radius: 34px;
  background: rgba(255,255,255,0.18);
  border: 1px solid rgba(255,255,255,0.30);
  transform: translate(-50%, -50%) rotate(18deg);
  backdrop-filter: blur(4px);
}

.vb-gallery-thirteen-art-gradient::after {
  left: 18%;
  top: 18%;
  width: 90px;
  height: 90px;
  border-radius: 999px;
  background: rgba(255,255,255,0.18);
  filter: blur(8px);
}

.vb-gallery-thirteen-art-layers {
  background: linear-gradient(180deg, #ccfbf1 0%, #14b8a6 48%, #134e4a 100%);
}

.vb-gallery-thirteen-art-layers::before {
  left: -12%;
  right: -12%;
  bottom: 0;
  height: 54%;
  background:
    radial-gradient(ellipse at 20% 100%, #042f2e 0 38%, transparent 39%),
    radial-gradient(ellipse at 58% 100%, #115e59 0 42%, transparent 43%),
    radial-gradient(ellipse at 92% 100%, #042f2e 0 38%, transparent 39%);
}

.vb-gallery-thirteen-art-layers::after {
  left: 16%;
  top: 18%;
  width: 84px;
  height: 84px;
  border-radius: 999px;
  background: rgba(240,253,250,0.82);
  filter: blur(5px);
}

.vb-gallery-thirteen-art-cards {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #dbeafe 38%, #1d4ed8 100%);
}

.vb-gallery-thirteen-art-cards::before {
  left: 50%;
  top: 50%;
  width: 118px;
  height: 148px;
  border-radius: 26px;
  background: linear-gradient(135deg, #ffffff, #bfdbfe);
  box-shadow:
    -34px 18px 0 rgba(255,255,255,0.34),
    34px -18px 0 rgba(255,255,255,0.24),
    0 26px 70px rgba(30,64,175,0.32);
  transform: translate(-50%, -50%) rotate(8deg);
}

.vb-gallery-thirteen-art-cards::after {
  left: 50%;
  top: 50%;
  width: 72px;
  height: 12px;
  border-radius: 999px;
  background: #2563eb;
  box-shadow: 0 26px 0 rgba(37,99,235,0.42);
  transform: translate(-50%, -50%) rotate(8deg);
}

.vb-gallery-thirteen-art-sunset {
  background: linear-gradient(180deg, #fde68a 0%, #fb923c 46%, #7f1d1d 100%);
}

.vb-gallery-thirteen-art-sunset::before {
  left: -6%;
  right: -6%;
  bottom: -18%;
  height: 54%;
  background: #431407;
  clip-path: polygon(0 100%, 0 50%, 12% 62%, 24% 38%, 38% 66%, 52% 34%, 66% 62%, 82% 42%, 100% 56%, 100% 100%);
}

.vb-gallery-thirteen-art-sunset::after {
  left: 18%;
  top: 18%;
  width: 88px;
  height: 88px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 70px rgba(255,247,237,0.72);
}

.vb-gallery-thirteen-art-mono {
  background: linear-gradient(135deg, #020617 0%, #334155 52%, #cbd5e1 100%);
}

.vb-gallery-thirteen-art-mono::before {
  left: 18%;
  top: 20%;
  width: 180px;
  height: 180px;
  border-radius: 999px;
  border: 22px solid rgba(255,255,255,0.22);
  border-right-color: rgba(255,255,255,0.62);
  transform: rotate(-18deg);
}

.vb-gallery-thirteen-art-mono::after {
  right: 12%;
  bottom: 12%;
  width: 130px;
  height: 48px;
  border-radius: 999px;
  background: rgba(255,255,255,0.22);
  filter: blur(4px);
}

.vb-gallery-thirteen-body {
  display: grid;
  gap: 8px;
  padding: 18px;
}

.vb-gallery-thirteen-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 21px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-thirteen-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-gallery-thirteen-tag {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #eff6ff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
}

@media (max-width: 1050px) {
  .vb-gallery-thirteen-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 820px) {
  .vb-gallery-thirteen-header {
    grid-template-columns: 1fr;
  }

  .vb-gallery-thirteen-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .vb-gallery-thirteen-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-thirteen-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-thirteen-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This selectable image gallery is useful for media management tools, product comparison pages, image approval workflows, real estate shortlist galleries, design moodboards, portfolio review pages, and interactive visual selection interfaces.</p>



<h2 class="wp-block-heading">14. Image Gallery with Tabs</h2>



<p class="wp-block-paragraph"><strong>An image gallery with tabs</strong> organizes multiple image collections inside one compact interface. This is useful for portfolios, product collections, team galleries, event albums, service pages, case studies, travel websites, and visual landing page sections where different groups of images should be separated clearly.</p>



<p class="wp-block-paragraph">This example uses JavaScript tab state and collection switching. Each tab loads a different CSS-illustrated gallery collection, the active tab state updates, and the visible cards re-render from the selected collection data. No external images are used.</p>



<ul class="wp-block-list">
<li>Tabbed JavaScript image gallery</li>
<li>Multiple gallery collections</li>
<li>Active tab state</li>
<li>Dynamic collection rendering</li>
<li>CSS-only illustrated thumbnails</li>
</ul>



<div class="vb-gallery-fourteen-demo">
  <div class="vb-gallery-fourteen-shell" data-vb-gallery-fourteen>
    <div class="vb-gallery-fourteen-intro">
      <span>Example 14</span>
      <h3>Image Gallery with Tabs</h3>
      <p>Switch between different CSS-illustrated gallery collections using JavaScript tab state.</p>
    </div>

    <div class="vb-gallery-fourteen-tabs" role="tablist" data-vb-gallery-fourteen-tabs>
      <button type="button" class="is-active" data-tab="portfolio">Portfolio</button>
      <button type="button" data-tab="products">Products</button>
      <button type="button" data-tab="travel">Travel</button>
      <button type="button" data-tab="events">Events</button>
    </div>

    <div class="vb-gallery-fourteen-status">
      <strong data-vb-gallery-fourteen-title>Portfolio Collection</strong>
      <span data-vb-gallery-fourteen-count>0 items</span>
    </div>

    <div class="vb-gallery-fourteen-grid" data-vb-gallery-fourteen-grid></div>
  </div>
</div>

<style>
.vb-gallery-fourteen-demo,
.vb-gallery-fourteen-demo * {
  box-sizing: border-box;
}

.vb-gallery-fourteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 14px 48px 14px 48px;
  background:
    radial-gradient(circle at 14% 14%, rgba(168, 85, 247, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(34, 211, 238, 0.16), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #ecfeff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.22);
  box-shadow: 0 28px 80px rgba(88, 28, 135, 0.10);
}

.vb-gallery-fourteen-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-fourteen-intro {
  max-width: 820px;
  margin-bottom: 22px;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 10px 34px 10px 34px;
  background:
    radial-gradient(circle at 16% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #581c87, #0f172a 58%, #155e75) !important;
  box-shadow: 0 24px 70px rgba(88, 28, 135, 0.24);
}

.vb-gallery-fourteen-intro span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #e9d5ff !important;
  -webkit-text-fill-color: #e9d5ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-fourteen-intro h3 {
  max-width: 760px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-fourteen-intro p {
  max-width: 720px;
  margin: 0 !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-fourteen-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 16px;
  padding: 12px;
  border-radius: 24px;
  background: rgba(255,255,255,0.78);
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.08);
}

.vb-gallery-fourteen-tabs button {
  appearance: none;
  border: 1px solid rgba(168, 85, 247, 0.22);
  border-radius: 999px;
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  padding: 11px 15px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease;
}

.vb-gallery-fourteen-tabs button:hover {
  transform: translateY(-2px);
  border-color: rgba(168, 85, 247, 0.56);
}

.vb-gallery-fourteen-tabs button.is-active {
  border-color: transparent;
  background: linear-gradient(135deg, #7c3aed, #0891b2);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 14px 34px rgba(124, 58, 237, 0.26);
}

.vb-gallery-fourteen-status {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 18px;
  padding: 14px 16px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.08);
}

.vb-gallery-fourteen-status strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-gallery-fourteen-status span {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #6b21a8 !important;
  -webkit-text-fill-color: #6b21a8 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-gallery-fourteen-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-gallery-fourteen-card {
  overflow: hidden;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  animation: vbGalleryFourteenIn 0.32s ease both;
}

@keyframes vbGalleryFourteenIn {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.vb-gallery-fourteen-art {
  position: relative;
  height: 235px;
  overflow: hidden;
  background: #0f172a;
}

.vb-gallery-fourteen-art::before,
.vb-gallery-fourteen-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-fourteen-art-portfolio-one {
  background: linear-gradient(135deg, #020617 0%, #1d4ed8 52%, #38bdf8 100%);
}

.vb-gallery-fourteen-art-portfolio-one::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 62%;
  border-radius: 26px;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.24), rgba(255,255,255,0.04)),
    repeating-linear-gradient(90deg, rgba(255,255,255,0.16) 0 2px, transparent 2px 16px);
  border: 1px solid rgba(255,255,255,0.26);
}

.vb-gallery-fourteen-art-portfolio-one::after {
  right: 18%;
  bottom: 18%;
  width: 84px;
  height: 84px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-fourteen-art-portfolio-two {
  background: radial-gradient(circle at 50% 50%, #ffffff 0%, #ddd6fe 34%, #4c1d95 100%);
}

.vb-gallery-fourteen-art-portfolio-two::before {
  left: 50%;
  top: 50%;
  width: 160px;
  height: 118px;
  border-radius: 28px;
  background: linear-gradient(135deg, #ffffff, #c4b5fd);
  box-shadow: 0 28px 70px rgba(76,29,149,0.32);
  transform: translate(-50%, -50%) rotate(-9deg);
}

.vb-gallery-fourteen-art-portfolio-two::after {
  left: 50%;
  top: 50%;
  width: 88px;
  height: 12px;
  border-radius: 999px;
  background: #7c3aed;
  box-shadow: 0 26px 0 rgba(124,58,237,0.44);
  transform: translate(-50%, -50%) rotate(-9deg);
}

.vb-gallery-fourteen-art-portfolio-three {
  background: linear-gradient(180deg, #f0f9ff 0%, #0ea5e9 52%, #0c4a6e 100%);
}

.vb-gallery-fourteen-art-portfolio-three::before {
  left: -10%;
  right: -10%;
  bottom: -25%;
  height: 60%;
  border-radius: 50% 50% 0 0;
  background: #082f49;
}

.vb-gallery-fourteen-art-portfolio-three::after {
  right: 16%;
  top: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: rgba(255,255,255,0.84);
  box-shadow: 0 0 54px rgba(255,255,255,0.64);
}

.vb-gallery-fourteen-art-product-one {
  background: linear-gradient(135deg, #fef3c7 0%, #f97316 52%, #7c2d12 100%);
}

.vb-gallery-fourteen-art-product-one::before {
  left: 50%;
  top: 50%;
  width: 136px;
  height: 136px;
  border-radius: 30px;
  background: linear-gradient(135deg, #fff7ed, #fed7aa);
  box-shadow: 0 30px 72px rgba(124,45,18,0.34);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-fourteen-art-product-one::after {
  left: 50%;
  top: 50%;
  width: 66px;
  height: 66px;
  border-radius: 18px;
  border: 4px solid rgba(249,115,22,0.42);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-fourteen-art-product-two {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #fecdd3 36%, #be123c 100%);
}

.vb-gallery-fourteen-art-product-two::before {
  left: 50%;
  top: 50%;
  width: 150px;
  height: 100px;
  border-radius: 999px;
  background: linear-gradient(135deg, #ffffff, #fecdd3);
  box-shadow: 0 28px 70px rgba(190,18,60,0.30);
  transform: translate(-50%, -50%);
}

.vb-gallery-fourteen-art-product-two::after {
  left: 44%;
  top: 42%;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  background: #be123c;
  box-shadow: 48px 18px 0 rgba(190,18,60,0.58);
}

.vb-gallery-fourteen-art-product-three {
  background: linear-gradient(135deg, #ecfeff 0%, #06b6d4 48%, #155e75 100%);
}

.vb-gallery-fourteen-art-product-three::before {
  left: 16%;
  top: 18%;
  width: 68%;
  height: 62%;
  border-radius: 28px;
  background: rgba(255,255,255,0.20);
  border: 1px solid rgba(255,255,255,0.34);
  backdrop-filter: blur(4px);
}

.vb-gallery-fourteen-art-product-three::after {
  left: 50%;
  top: 50%;
  width: 92px;
  height: 92px;
  border-radius: 26px;
  background: rgba(255,255,255,0.70);
  transform: translate(-50%, -50%) rotate(20deg);
}

.vb-gallery-fourteen-art-travel-one {
  background: linear-gradient(180deg, #fed7aa 0%, #fb923c 48%, #7c2d12 100%);
}

.vb-gallery-fourteen-art-travel-one::before {
  left: -8%;
  right: -8%;
  bottom: -20%;
  height: 56%;
  background: #431407;
  clip-path: polygon(0 100%, 0 60%, 18% 42%, 34% 66%, 52% 36%, 70% 60%, 86% 38%, 100% 58%, 100% 100%);
}

.vb-gallery-fourteen-art-travel-one::after {
  right: 18%;
  top: 16%;
  width: 78px;
  height: 78px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 62px rgba(255,247,237,0.72);
}

.vb-gallery-fourteen-art-travel-two {
  background: linear-gradient(180deg, #dbeafe 0%, #2563eb 50%, #1e3a8a 100%);
}

.vb-gallery-fourteen-art-travel-two::before {
  left: -8%;
  right: -8%;
  bottom: 24%;
  height: 24%;
  background:
    radial-gradient(circle at 14% 50%, rgba(255,255,255,0.78), transparent 13%),
    radial-gradient(circle at 44% 38%, rgba(255,255,255,0.58), transparent 14%),
    radial-gradient(circle at 76% 58%, rgba(255,255,255,0.70), transparent 14%);
  filter: blur(2px);
}

.vb-gallery-fourteen-art-travel-two::after {
  left: 16%;
  top: 16%;
  width: 96px;
  height: 96px;
  border-radius: 999px;
  background: rgba(255,255,255,0.24);
  filter: blur(10px);
}

.vb-gallery-fourteen-art-travel-three {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-fourteen-art-travel-three::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 70%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-fourteen-art-travel-three::after {
  right: 16%;
  top: 16%;
  width: 78px;
  height: 78px;
  border-radius: 999px;
  background: rgba(240,253,244,0.78);
  filter: blur(4px);
}

.vb-gallery-fourteen-art-event-one {
  background: linear-gradient(135deg, #111827 0%, #7c3aed 52%, #ec4899 100%);
}

.vb-gallery-fourteen-art-event-one::before {
  left: 12%;
  right: 12%;
  top: 22%;
  height: 56%;
  border-radius: 26px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.20) 0 8px, transparent 8px 18px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.22);
}

.vb-gallery-fourteen-art-event-one::after {
  left: 50%;
  top: 50%;
  width: 76px;
  height: 76px;
  border-radius: 999px;
  background: rgba(255,255,255,0.70);
  transform: translate(-50%, -50%);
  box-shadow: 0 0 70px rgba(255,255,255,0.46);
}

.vb-gallery-fourteen-art-event-two {
  background: linear-gradient(180deg, #020617 0%, #1e293b 58%, #0f172a 100%);
}

.vb-gallery-fourteen-art-event-two::before {
  left: 14%;
  right: 14%;
  top: 18%;
  height: 4px;
  background: repeating-linear-gradient(90deg, #ffffff 0 12px, transparent 12px 28px);
  box-shadow:
    0 44px 0 rgba(255,255,255,0.56),
    0 88px 0 rgba(255,255,255,0.30),
    0 132px 0 rgba(255,255,255,0.18);
}

.vb-gallery-fourteen-art-event-two::after {
  right: 15%;
  top: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: #facc15;
  box-shadow: 0 0 70px rgba(250,204,21,0.60);
}

.vb-gallery-fourteen-art-event-three {
  background: radial-gradient(circle at 50% 50%, #ffffff 0%, #fecaca 32%, #991b1b 100%);
}

.vb-gallery-fourteen-art-event-three::before {
  left: 50%;
  top: 50%;
  width: 150px;
  height: 150px;
  border-radius: 999px;
  border: 18px solid rgba(255,255,255,0.36);
  border-left-color: rgba(255,255,255,0.86);
  transform: translate(-50%, -50%) rotate(18deg);
}

.vb-gallery-fourteen-art-event-three::after {
  left: 50%;
  top: 50%;
  width: 76px;
  height: 76px;
  border-radius: 999px;
  background: rgba(255,255,255,0.76);
  transform: translate(-50%, -50%);
}

.vb-gallery-fourteen-body {
  display: grid;
  gap: 8px;
  padding: 18px;
}

.vb-gallery-fourteen-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 21px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-fourteen-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-gallery-fourteen-tag {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #6b21a8 !important;
  -webkit-text-fill-color: #6b21a8 !important;
  font-size: 11px;
  font-weight: 950;
}

@media (max-width: 980px) {
  .vb-gallery-fourteen-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-fourteen-status {
    align-items: flex-start;
    flex-direction: column;
  }
}

@media (max-width: 620px) {
  .vb-gallery-fourteen-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-fourteen-intro h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-fourteen-tabs {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-fourteen-tabs button {
    width: 100%;
  }

  .vb-gallery-fourteen-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-fourteen]");
  if (!gallery) return;

  const tabs = gallery.querySelector("[data-vb-gallery-fourteen-tabs]");
  const grid = gallery.querySelector("[data-vb-gallery-fourteen-grid]");
  const title = gallery.querySelector("[data-vb-gallery-fourteen-title]");
  const count = gallery.querySelector("[data-vb-gallery-fourteen-count]");

  const collections = {
    portfolio: {
      title: "Portfolio Collection",
      items: [
        {
          title: "Website Concept",
          category: "Portfolio",
          art: "vb-gallery-fourteen-art-portfolio-one",
          description: "A CSS-only portfolio image for web design project galleries."
        },
        {
          title: "Brand System",
          category: "Portfolio",
          art: "vb-gallery-fourteen-art-portfolio-two",
          description: "A CSS visual card for branding and case study collections."
        },
        {
          title: "Landing Page",
          category: "Portfolio",
          art: "vb-gallery-fourteen-art-portfolio-three",
          description: "A CSS illustration for modern landing page project previews."
        }
      ]
    },
    products: {
      title: "Product Collection",
      items: [
        {
          title: "Package Design",
          category: "Product",
          art: "vb-gallery-fourteen-art-product-one",
          description: "A CSS product-style thumbnail for ecommerce gallery tabs."
        },
        {
          title: "Soft Display",
          category: "Product",
          art: "vb-gallery-fourteen-art-product-two",
          description: "A CSS product scene for shop and product launch galleries."
        },
        {
          title: "Glass Object",
          category: "Product",
          art: "vb-gallery-fourteen-art-product-three",
          description: "A CSS glassmorphism product card for visual product collections."
        }
      ]
    },
    travel: {
      title: "Travel Collection",
      items: [
        {
          title: "Warm Canyon",
          category: "Travel",
          art: "vb-gallery-fourteen-art-travel-one",
          description: "A CSS canyon illustration for destination gallery sections."
        },
        {
          title: "Blue Coast",
          category: "Travel",
          art: "vb-gallery-fourteen-art-travel-two",
          description: "A CSS water-inspired card for travel image collections."
        },
        {
          title: "Forest Route",
          category: "Travel",
          art: "vb-gallery-fourteen-art-travel-three",
          description: "A CSS forest card for outdoor and travel galleries."
        }
      ]
    },
    events: {
      title: "Event Collection",
      items: [
        {
          title: "Stage Lights",
          category: "Event",
          art: "vb-gallery-fourteen-art-event-one",
          description: "A CSS stage-inspired image card for event gallery tabs."
        },
        {
          title: "Night Venue",
          category: "Event",
          art: "vb-gallery-fourteen-art-event-two",
          description: "A CSS venue card for conference and live event galleries."
        },
        {
          title: "Circle Motion",
          category: "Event",
          art: "vb-gallery-fourteen-art-event-three",
          description: "A CSS motion-style event thumbnail for visual recaps."
        }
      ]
    }
  };

  function createCard(item, index) {
    return `
      <article class="vb-gallery-fourteen-card" style="animation-delay: ${index * 45}ms">
        <div class="vb-gallery-fourteen-art ${item.art}" aria-label="${item.title} illustration" role="img"></div>

        <div class="vb-gallery-fourteen-body">
          <span class="vb-gallery-fourteen-tag">${item.category}</span>
          <h4>${item.title}</h4>
          <p>${item.description}</p>
        </div>
      </article>
    `;
  }

  function renderCollection(collectionKey) {
    const collection = collections[collectionKey];

    title.textContent = collection.title;
    count.textContent = collection.items.length + " items";
    grid.innerHTML = collection.items.map(createCard).join("");
  }

  tabs.addEventListener("click", function (event) {
    const button = event.target.closest("button[data-tab]");
    if (!button) return;

    tabs.querySelectorAll("button").forEach(function (tabButton) {
      tabButton.classList.remove("is-active");
    });

    button.classList.add("is-active");
    renderCollection(button.getAttribute("data-tab"));
  });

  renderCollection("portfolio");
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-fourteen]");
  if (!gallery) return;

  const tabs = gallery.querySelector("[data-vb-gallery-fourteen-tabs]");
  const grid = gallery.querySelector("[data-vb-gallery-fourteen-grid]");
  const title = gallery.querySelector("[data-vb-gallery-fourteen-title]");
  const count = gallery.querySelector("[data-vb-gallery-fourteen-count]");

  const collections = {
    portfolio: {
      title: "Portfolio Collection",
      items: [
        {
          title: "Website Concept",
          category: "Portfolio",
          art: "vb-gallery-fourteen-art-portfolio-one",
          description: "A CSS-only portfolio image for web design project galleries."
        },
        {
          title: "Brand System",
          category: "Portfolio",
          art: "vb-gallery-fourteen-art-portfolio-two",
          description: "A CSS visual card for branding and case study collections."
        },
        {
          title: "Landing Page",
          category: "Portfolio",
          art: "vb-gallery-fourteen-art-portfolio-three",
          description: "A CSS illustration for modern landing page project previews."
        }
      ]
    },
    products: {
      title: "Product Collection",
      items: [
        {
          title: "Package Design",
          category: "Product",
          art: "vb-gallery-fourteen-art-product-one",
          description: "A CSS product-style thumbnail for ecommerce gallery tabs."
        },
        {
          title: "Soft Display",
          category: "Product",
          art: "vb-gallery-fourteen-art-product-two",
          description: "A CSS product scene for shop and product launch galleries."
        },
        {
          title: "Glass Object",
          category: "Product",
          art: "vb-gallery-fourteen-art-product-three",
          description: "A CSS glassmorphism product card for visual product collections."
        }
      ]
    },
    travel: {
      title: "Travel Collection",
      items: [
        {
          title: "Warm Canyon",
          category: "Travel",
          art: "vb-gallery-fourteen-art-travel-one",
          description: "A CSS canyon illustration for destination gallery sections."
        },
        {
          title: "Blue Coast",
          category: "Travel",
          art: "vb-gallery-fourteen-art-travel-two",
          description: "A CSS water-inspired card for travel image collections."
        },
        {
          title: "Forest Route",
          category: "Travel",
          art: "vb-gallery-fourteen-art-travel-three",
          description: "A CSS forest card for outdoor and travel galleries."
        }
      ]
    },
    events: {
      title: "Event Collection",
      items: [
        {
          title: "Stage Lights",
          category: "Event",
          art: "vb-gallery-fourteen-art-event-one",
          description: "A CSS stage-inspired image card for event gallery tabs."
        },
        {
          title: "Night Venue",
          category: "Event",
          art: "vb-gallery-fourteen-art-event-two",
          description: "A CSS venue card for conference and live event galleries."
        },
        {
          title: "Circle Motion",
          category: "Event",
          art: "vb-gallery-fourteen-art-event-three",
          description: "A CSS motion-style event thumbnail for visual recaps."
        }
      ]
    }
  };

  function createCard(item, index) {
    return `
      &lt;article class="vb-gallery-fourteen-card" style="animation-delay: ${index * 45}ms"&gt;
        &lt;div class="vb-gallery-fourteen-art ${item.art}" aria-label="${item.title} illustration" role="img"&gt;&lt;/div&gt;

        &lt;div class="vb-gallery-fourteen-body"&gt;
          &lt;span class="vb-gallery-fourteen-tag"&gt;${item.category}&lt;/span&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
          &lt;p&gt;${item.description}&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    `;
  }

  function renderCollection(collectionKey) {
    const collection = collections[collectionKey];

    title.textContent = collection.title;
    count.textContent = collection.items.length + " items";
    grid.innerHTML = collection.items.map(createCard).join("");
  }

  tabs.addEventListener("click", function (event) {
    const button = event.target.closest("button[data-tab]");
    if (!button) return;

    tabs.querySelectorAll("button").forEach(function (tabButton) {
      tabButton.classList.remove("is-active");
    });

    button.classList.add("is-active");
    renderCollection(button.getAttribute("data-tab"));
  });

  renderCollection("portfolio");
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-fourteen-demo"&gt;
  &lt;div class="vb-gallery-fourteen-shell" data-vb-gallery-fourteen&gt;
    &lt;div class="vb-gallery-fourteen-intro"&gt;
      &lt;span&gt;Example 14&lt;/span&gt;
      &lt;h3&gt;Image Gallery with Tabs&lt;/h3&gt;
      &lt;p&gt;Switch between different CSS-illustrated gallery collections using JavaScript tab state.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-fourteen-tabs" role="tablist" data-vb-gallery-fourteen-tabs&gt;
      &lt;button type="button" class="is-active" data-tab="portfolio"&gt;Portfolio&lt;/button&gt;
      &lt;button type="button" data-tab="products"&gt;Products&lt;/button&gt;
      &lt;button type="button" data-tab="travel"&gt;Travel&lt;/button&gt;
      &lt;button type="button" data-tab="events"&gt;Events&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-fourteen-status"&gt;
      &lt;strong data-vb-gallery-fourteen-title&gt;Portfolio Collection&lt;/strong&gt;
      &lt;span data-vb-gallery-fourteen-count&gt;0 items&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-fourteen-grid" data-vb-gallery-fourteen-grid&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-fourteen-demo,
.vb-gallery-fourteen-demo * {
  box-sizing: border-box;
}

.vb-gallery-fourteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 14px 48px 14px 48px;
  background:
    radial-gradient(circle at 14% 14%, rgba(168, 85, 247, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(34, 211, 238, 0.16), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #ecfeff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(168, 85, 247, 0.22);
  box-shadow: 0 28px 80px rgba(88, 28, 135, 0.10);
}

.vb-gallery-fourteen-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-fourteen-intro {
  max-width: 820px;
  margin-bottom: 22px;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 10px 34px 10px 34px;
  background:
    radial-gradient(circle at 16% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #581c87, #0f172a 58%, #155e75) !important;
  box-shadow: 0 24px 70px rgba(88, 28, 135, 0.24);
}

.vb-gallery-fourteen-intro span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #e9d5ff !important;
  -webkit-text-fill-color: #e9d5ff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-fourteen-intro h3 {
  max-width: 760px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-fourteen-intro p {
  max-width: 720px;
  margin: 0 !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-fourteen-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 16px;
  padding: 12px;
  border-radius: 24px;
  background: rgba(255,255,255,0.78);
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.08);
}

.vb-gallery-fourteen-tabs button {
  appearance: none;
  border: 1px solid rgba(168, 85, 247, 0.22);
  border-radius: 999px;
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  padding: 11px 15px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease;
}

.vb-gallery-fourteen-tabs button:hover {
  transform: translateY(-2px);
  border-color: rgba(168, 85, 247, 0.56);
}

.vb-gallery-fourteen-tabs button.is-active {
  border-color: transparent;
  background: linear-gradient(135deg, #7c3aed, #0891b2);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 14px 34px rgba(124, 58, 237, 0.26);
}

.vb-gallery-fourteen-status {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 18px;
  padding: 14px 16px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.08);
}

.vb-gallery-fourteen-status strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-gallery-fourteen-status span {
  display: inline-flex;
  padding: 8px 11px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #6b21a8 !important;
  -webkit-text-fill-color: #6b21a8 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-gallery-fourteen-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-gallery-fourteen-card {
  overflow: hidden;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  animation: vbGalleryFourteenIn 0.32s ease both;
}

@keyframes vbGalleryFourteenIn {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.vb-gallery-fourteen-art {
  position: relative;
  height: 235px;
  overflow: hidden;
  background: #0f172a;
}

.vb-gallery-fourteen-art::before,
.vb-gallery-fourteen-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-fourteen-art-portfolio-one {
  background: linear-gradient(135deg, #020617 0%, #1d4ed8 52%, #38bdf8 100%);
}

.vb-gallery-fourteen-art-portfolio-one::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 62%;
  border-radius: 26px;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.24), rgba(255,255,255,0.04)),
    repeating-linear-gradient(90deg, rgba(255,255,255,0.16) 0 2px, transparent 2px 16px);
  border: 1px solid rgba(255,255,255,0.26);
}

.vb-gallery-fourteen-art-portfolio-one::after {
  right: 18%;
  bottom: 18%;
  width: 84px;
  height: 84px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-fourteen-art-portfolio-two {
  background: radial-gradient(circle at 50% 50%, #ffffff 0%, #ddd6fe 34%, #4c1d95 100%);
}

.vb-gallery-fourteen-art-portfolio-two::before {
  left: 50%;
  top: 50%;
  width: 160px;
  height: 118px;
  border-radius: 28px;
  background: linear-gradient(135deg, #ffffff, #c4b5fd);
  box-shadow: 0 28px 70px rgba(76,29,149,0.32);
  transform: translate(-50%, -50%) rotate(-9deg);
}

.vb-gallery-fourteen-art-portfolio-two::after {
  left: 50%;
  top: 50%;
  width: 88px;
  height: 12px;
  border-radius: 999px;
  background: #7c3aed;
  box-shadow: 0 26px 0 rgba(124,58,237,0.44);
  transform: translate(-50%, -50%) rotate(-9deg);
}

.vb-gallery-fourteen-art-portfolio-three {
  background: linear-gradient(180deg, #f0f9ff 0%, #0ea5e9 52%, #0c4a6e 100%);
}

.vb-gallery-fourteen-art-portfolio-three::before {
  left: -10%;
  right: -10%;
  bottom: -25%;
  height: 60%;
  border-radius: 50% 50% 0 0;
  background: #082f49;
}

.vb-gallery-fourteen-art-portfolio-three::after {
  right: 16%;
  top: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: rgba(255,255,255,0.84);
  box-shadow: 0 0 54px rgba(255,255,255,0.64);
}

.vb-gallery-fourteen-art-product-one {
  background: linear-gradient(135deg, #fef3c7 0%, #f97316 52%, #7c2d12 100%);
}

.vb-gallery-fourteen-art-product-one::before {
  left: 50%;
  top: 50%;
  width: 136px;
  height: 136px;
  border-radius: 30px;
  background: linear-gradient(135deg, #fff7ed, #fed7aa);
  box-shadow: 0 30px 72px rgba(124,45,18,0.34);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-fourteen-art-product-one::after {
  left: 50%;
  top: 50%;
  width: 66px;
  height: 66px;
  border-radius: 18px;
  border: 4px solid rgba(249,115,22,0.42);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-fourteen-art-product-two {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #fecdd3 36%, #be123c 100%);
}

.vb-gallery-fourteen-art-product-two::before {
  left: 50%;
  top: 50%;
  width: 150px;
  height: 100px;
  border-radius: 999px;
  background: linear-gradient(135deg, #ffffff, #fecdd3);
  box-shadow: 0 28px 70px rgba(190,18,60,0.30);
  transform: translate(-50%, -50%);
}

.vb-gallery-fourteen-art-product-two::after {
  left: 44%;
  top: 42%;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  background: #be123c;
  box-shadow: 48px 18px 0 rgba(190,18,60,0.58);
}

.vb-gallery-fourteen-art-product-three {
  background: linear-gradient(135deg, #ecfeff 0%, #06b6d4 48%, #155e75 100%);
}

.vb-gallery-fourteen-art-product-three::before {
  left: 16%;
  top: 18%;
  width: 68%;
  height: 62%;
  border-radius: 28px;
  background: rgba(255,255,255,0.20);
  border: 1px solid rgba(255,255,255,0.34);
  backdrop-filter: blur(4px);
}

.vb-gallery-fourteen-art-product-three::after {
  left: 50%;
  top: 50%;
  width: 92px;
  height: 92px;
  border-radius: 26px;
  background: rgba(255,255,255,0.70);
  transform: translate(-50%, -50%) rotate(20deg);
}

.vb-gallery-fourteen-art-travel-one {
  background: linear-gradient(180deg, #fed7aa 0%, #fb923c 48%, #7c2d12 100%);
}

.vb-gallery-fourteen-art-travel-one::before {
  left: -8%;
  right: -8%;
  bottom: -20%;
  height: 56%;
  background: #431407;
  clip-path: polygon(0 100%, 0 60%, 18% 42%, 34% 66%, 52% 36%, 70% 60%, 86% 38%, 100% 58%, 100% 100%);
}

.vb-gallery-fourteen-art-travel-one::after {
  right: 18%;
  top: 16%;
  width: 78px;
  height: 78px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 62px rgba(255,247,237,0.72);
}

.vb-gallery-fourteen-art-travel-two {
  background: linear-gradient(180deg, #dbeafe 0%, #2563eb 50%, #1e3a8a 100%);
}

.vb-gallery-fourteen-art-travel-two::before {
  left: -8%;
  right: -8%;
  bottom: 24%;
  height: 24%;
  background:
    radial-gradient(circle at 14% 50%, rgba(255,255,255,0.78), transparent 13%),
    radial-gradient(circle at 44% 38%, rgba(255,255,255,0.58), transparent 14%),
    radial-gradient(circle at 76% 58%, rgba(255,255,255,0.70), transparent 14%);
  filter: blur(2px);
}

.vb-gallery-fourteen-art-travel-two::after {
  left: 16%;
  top: 16%;
  width: 96px;
  height: 96px;
  border-radius: 999px;
  background: rgba(255,255,255,0.24);
  filter: blur(10px);
}

.vb-gallery-fourteen-art-travel-three {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-fourteen-art-travel-three::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 70%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-fourteen-art-travel-three::after {
  right: 16%;
  top: 16%;
  width: 78px;
  height: 78px;
  border-radius: 999px;
  background: rgba(240,253,244,0.78);
  filter: blur(4px);
}

.vb-gallery-fourteen-art-event-one {
  background: linear-gradient(135deg, #111827 0%, #7c3aed 52%, #ec4899 100%);
}

.vb-gallery-fourteen-art-event-one::before {
  left: 12%;
  right: 12%;
  top: 22%;
  height: 56%;
  border-radius: 26px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.20) 0 8px, transparent 8px 18px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.22);
}

.vb-gallery-fourteen-art-event-one::after {
  left: 50%;
  top: 50%;
  width: 76px;
  height: 76px;
  border-radius: 999px;
  background: rgba(255,255,255,0.70);
  transform: translate(-50%, -50%);
  box-shadow: 0 0 70px rgba(255,255,255,0.46);
}

.vb-gallery-fourteen-art-event-two {
  background: linear-gradient(180deg, #020617 0%, #1e293b 58%, #0f172a 100%);
}

.vb-gallery-fourteen-art-event-two::before {
  left: 14%;
  right: 14%;
  top: 18%;
  height: 4px;
  background: repeating-linear-gradient(90deg, #ffffff 0 12px, transparent 12px 28px);
  box-shadow:
    0 44px 0 rgba(255,255,255,0.56),
    0 88px 0 rgba(255,255,255,0.30),
    0 132px 0 rgba(255,255,255,0.18);
}

.vb-gallery-fourteen-art-event-two::after {
  right: 15%;
  top: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: #facc15;
  box-shadow: 0 0 70px rgba(250,204,21,0.60);
}

.vb-gallery-fourteen-art-event-three {
  background: radial-gradient(circle at 50% 50%, #ffffff 0%, #fecaca 32%, #991b1b 100%);
}

.vb-gallery-fourteen-art-event-three::before {
  left: 50%;
  top: 50%;
  width: 150px;
  height: 150px;
  border-radius: 999px;
  border: 18px solid rgba(255,255,255,0.36);
  border-left-color: rgba(255,255,255,0.86);
  transform: translate(-50%, -50%) rotate(18deg);
}

.vb-gallery-fourteen-art-event-three::after {
  left: 50%;
  top: 50%;
  width: 76px;
  height: 76px;
  border-radius: 999px;
  background: rgba(255,255,255,0.76);
  transform: translate(-50%, -50%);
}

.vb-gallery-fourteen-body {
  display: grid;
  gap: 8px;
  padding: 18px;
}

.vb-gallery-fourteen-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 21px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-fourteen-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-gallery-fourteen-tag {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #6b21a8 !important;
  -webkit-text-fill-color: #6b21a8 !important;
  font-size: 11px;
  font-weight: 950;
}

@media (max-width: 980px) {
  .vb-gallery-fourteen-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-fourteen-status {
    align-items: flex-start;
    flex-direction: column;
  }
}

@media (max-width: 620px) {
  .vb-gallery-fourteen-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-fourteen-intro h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-fourteen-tabs {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-fourteen-tabs button {
    width: 100%;
  }

  .vb-gallery-fourteen-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This image gallery with tabs is useful for portfolio pages, ecommerce product collections, service galleries, event albums, travel collections, case studies, team pages, and landing page sections where several visual categories should stay organized in one compact UI.</p>



<h2 class="wp-block-heading">15. Image Gallery with Animated Filters</h2>



<p class="wp-block-paragraph"><strong>An image gallery with animated filters</strong> makes category switching feel smoother than a simple instant hide/show gallery. This pattern is useful for portfolio pages, agency case studies, product collections, design galleries, travel sections, and creative landing pages where visual transitions improve the browsing experience.</p>



<p class="wp-block-paragraph">This example uses JavaScript to apply a temporary exit animation before re-rendering the filtered gallery. The active category, result count, and animated card entrance are controlled with JavaScript. All thumbnail visuals are CSS-only illustrations, so the demo does not load external images.</p>



<ul class="wp-block-list">
<li>Animated JavaScript image gallery filters</li>
<li>Exit animation before re-rendering</li>
<li>Active category state</li>
<li>Dynamic result counter</li>
<li>CSS-only illustrated gallery cards</li>
</ul>



<div class="vb-gallery-fifteen-demo">
  <div class="vb-gallery-fifteen-shell" data-vb-gallery-fifteen>
    <div class="vb-gallery-fifteen-head">
      <div>
        <span>Example 15</span>
        <h3>Image Gallery with Animated Filters</h3>
        <p>Filter CSS-illustrated gallery cards with smooth exit and entrance animations.</p>
      </div>

      <strong data-vb-gallery-fifteen-count>0 items</strong>
    </div>

    <div class="vb-gallery-fifteen-filters" data-vb-gallery-fifteen-filters>
      <button type="button" class="is-active" data-filter="all">All</button>
      <button type="button" data-filter="brand">Brand</button>
      <button type="button" data-filter="travel">Travel</button>
      <button type="button" data-filter="product">Product</button>
      <button type="button" data-filter="nature">Nature</button>
    </div>

    <div class="vb-gallery-fifteen-grid" data-vb-gallery-fifteen-grid></div>
  </div>
</div>

<style>
.vb-gallery-fifteen-demo,
.vb-gallery-fifteen-demo * {
  box-sizing: border-box;
}

.vb-gallery-fifteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 12%, rgba(245, 158, 11, 0.18), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(236, 72, 153, 0.16), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fdf2f8 52%, #ffffff 100%) !important;
  border: 1px solid rgba(245, 158, 11, 0.24);
  box-shadow: 0 28px 80px rgba(146, 64, 14, 0.10);
}

.vb-gallery-fifteen-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-fifteen-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 20px;
}

.vb-gallery-fifteen-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-fifteen-head h3 {
  max-width: 780px;
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-fifteen-head p {
  max-width: 720px;
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-fifteen-head strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-fifteen-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 22px;
  padding: 12px;
  border-radius: 24px;
  background: rgba(255,255,255,0.78);
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.08);
}

.vb-gallery-fifteen-filters button {
  appearance: none;
  border: 1px solid rgba(245, 158, 11, 0.26);
  border-radius: 999px;
  background: #ffffff;
  color: #374151 !important;
  -webkit-text-fill-color: #374151 !important;
  padding: 11px 15px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  transition: transform 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.vb-gallery-fifteen-filters button:hover {
  transform: translateY(-2px);
  border-color: rgba(245, 158, 11, 0.68);
}

.vb-gallery-fifteen-filters button.is-active {
  border-color: transparent;
  background: linear-gradient(135deg, #f59e0b, #db2777);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 14px 34px rgba(219, 39, 119, 0.22);
}

.vb-gallery-fifteen-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-fifteen-grid.is-changing .vb-gallery-fifteen-card {
  animation: vbGalleryFifteenExit 0.22s ease both;
}

@keyframes vbGalleryFifteenExit {
  to {
    opacity: 0;
    transform: translateY(12px) scale(0.96);
  }
}

.vb-gallery-fifteen-card {
  overflow: hidden;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  animation: vbGalleryFifteenEnter 0.36s ease both;
}

@keyframes vbGalleryFifteenEnter {
  from {
    opacity: 0;
    transform: translateY(18px) scale(0.96);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.vb-gallery-fifteen-art {
  position: relative;
  height: 230px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-fifteen-art::before,
.vb-gallery-fifteen-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-fifteen-art-brand {
  background: linear-gradient(135deg, #111827 0%, #4f46e5 52%, #38bdf8 100%);
}

.vb-gallery-fifteen-art-brand::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 62%;
  border-radius: 26px;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.24), rgba(255,255,255,0.05)),
    repeating-linear-gradient(90deg, rgba(255,255,255,0.17) 0 3px, transparent 3px 18px);
  border: 1px solid rgba(255,255,255,0.25);
}

.vb-gallery-fifteen-art-brand::after {
  right: 16%;
  bottom: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: rgba(255,255,255,0.28);
  filter: blur(8px);
}

.vb-gallery-fifteen-art-travel {
  background: linear-gradient(180deg, #fde68a 0%, #f97316 50%, #7c2d12 100%);
}

.vb-gallery-fifteen-art-travel::before {
  left: -8%;
  right: -8%;
  bottom: -20%;
  height: 58%;
  background: #431407;
  clip-path: polygon(0 100%, 0 60%, 14% 44%, 28% 66%, 46% 34%, 64% 62%, 82% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-fifteen-art-travel::after {
  right: 18%;
  top: 16%;
  width: 78px;
  height: 78px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 62px rgba(255,247,237,0.72);
}

.vb-gallery-fifteen-art-product {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #fce7f3 36%, #be185d 100%);
}

.vb-gallery-fifteen-art-product::before {
  left: 50%;
  top: 50%;
  width: 132px;
  height: 132px;
  border-radius: 30px;
  background: linear-gradient(135deg, #ffffff, #fbcfe8);
  box-shadow: 0 28px 70px rgba(190,24,93,0.32);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-fifteen-art-product::after {
  left: 50%;
  top: 50%;
  width: 68px;
  height: 68px;
  border-radius: 20px;
  border: 4px solid rgba(219,39,119,0.42);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-fifteen-art-nature {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 55%, #052e16 100%);
}

.vb-gallery-fifteen-art-nature::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 70%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-fifteen-art-nature::after {
  right: 16%;
  top: 16%;
  width: 76px;
  height: 76px;
  border-radius: 999px;
  background: rgba(240,253,244,0.84);
  filter: blur(4px);
}

.vb-gallery-fifteen-body {
  display: grid;
  gap: 8px;
  padding: 17px;
}

.vb-gallery-fifteen-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #fffbeb;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-fifteen-body h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-fifteen-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

@media (max-width: 1050px) {
  .vb-gallery-fifteen-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 820px) {
  .vb-gallery-fifteen-head {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-fifteen-head strong {
    justify-content: center;
    width: 100%;
  }

  .vb-gallery-fifteen-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .vb-gallery-fifteen-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-fifteen-head h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-fifteen-filters {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-fifteen-filters button {
    width: 100%;
  }

  .vb-gallery-fifteen-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-fifteen]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-fifteen-grid]");
  const filters = gallery.querySelector("[data-vb-gallery-fifteen-filters]");
  const count = gallery.querySelector("[data-vb-gallery-fifteen-count]");

  const items = [
    {
      title: "Brand Grid",
      category: "brand",
      label: "Brand",
      art: "vb-gallery-fifteen-art-brand",
      description: "A CSS-only brand visual for animated gallery filtering."
    },
    {
      title: "Warm Route",
      category: "travel",
      label: "Travel",
      art: "vb-gallery-fifteen-art-travel",
      description: "A CSS travel card that appears after filter transitions."
    },
    {
      title: "Product Object",
      category: "product",
      label: "Product",
      art: "vb-gallery-fifteen-art-product",
      description: "A CSS product illustration for animated gallery cards."
    },
    {
      title: "Forest Layer",
      category: "nature",
      label: "Nature",
      art: "vb-gallery-fifteen-art-nature",
      description: "A CSS nature visual for filterable image collections."
    },
    {
      title: "Identity Panel",
      category: "brand",
      label: "Brand",
      art: "vb-gallery-fifteen-art-brand",
      description: "A second brand card used for category filter testing."
    },
    {
      title: "Mountain Trip",
      category: "travel",
      label: "Travel",
      art: "vb-gallery-fifteen-art-travel",
      description: "A second travel card rendered by the animated filter."
    },
    {
      title: "Soft Package",
      category: "product",
      label: "Product",
      art: "vb-gallery-fifteen-art-product",
      description: "A second CSS product card for gallery filtering."
    },
    {
      title: "Green Path",
      category: "nature",
      label: "Nature",
      art: "vb-gallery-fifteen-art-nature",
      description: "A second nature card for animated filter behavior."
    }
  ];

  function createCard(item, index) {
    return `
      <article class="vb-gallery-fifteen-card" style="animation-delay: ${index * 45}ms">
        <div class="vb-gallery-fifteen-art ${item.art}" aria-label="${item.title} illustration" role="img"></div>

        <div class="vb-gallery-fifteen-body">
          <span>${item.label}</span>
          <h4>${item.title}</h4>
          <p>${item.description}</p>
        </div>
      </article>
    `;
  }

  function getVisibleItems(filterValue) {
    if (filterValue === "all") {
      return items;
    }

    return items.filter(function (item) {
      return item.category === filterValue;
    });
  }

  function renderGallery(filterValue) {
    const visibleItems = getVisibleItems(filterValue);

    grid.innerHTML = visibleItems.map(createCard).join("");
    count.textContent = visibleItems.length === 1 ? "1 item" : visibleItems.length + " items";
  }

  function animateAndRender(filterValue) {
    grid.classList.add("is-changing");

    window.setTimeout(function () {
      renderGallery(filterValue);
      grid.classList.remove("is-changing");
    }, 220);
  }

  filters.addEventListener("click", function (event) {
    const button = event.target.closest("button[data-filter]");
    if (!button) return;

    filters.querySelectorAll("button").forEach(function (filterButton) {
      filterButton.classList.remove("is-active");
    });

    button.classList.add("is-active");
    animateAndRender(button.getAttribute("data-filter"));
  });

  renderGallery("all");
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-fifteen]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-fifteen-grid]");
  const filters = gallery.querySelector("[data-vb-gallery-fifteen-filters]");
  const count = gallery.querySelector("[data-vb-gallery-fifteen-count]");

  const items = [
    {
      title: "Brand Grid",
      category: "brand",
      label: "Brand",
      art: "vb-gallery-fifteen-art-brand",
      description: "A CSS-only brand visual for animated gallery filtering."
    },
    {
      title: "Warm Route",
      category: "travel",
      label: "Travel",
      art: "vb-gallery-fifteen-art-travel",
      description: "A CSS travel card that appears after filter transitions."
    },
    {
      title: "Product Object",
      category: "product",
      label: "Product",
      art: "vb-gallery-fifteen-art-product",
      description: "A CSS product illustration for animated gallery cards."
    },
    {
      title: "Forest Layer",
      category: "nature",
      label: "Nature",
      art: "vb-gallery-fifteen-art-nature",
      description: "A CSS nature visual for filterable image collections."
    },
    {
      title: "Identity Panel",
      category: "brand",
      label: "Brand",
      art: "vb-gallery-fifteen-art-brand",
      description: "A second brand card used for category filter testing."
    },
    {
      title: "Mountain Trip",
      category: "travel",
      label: "Travel",
      art: "vb-gallery-fifteen-art-travel",
      description: "A second travel card rendered by the animated filter."
    },
    {
      title: "Soft Package",
      category: "product",
      label: "Product",
      art: "vb-gallery-fifteen-art-product",
      description: "A second CSS product card for gallery filtering."
    },
    {
      title: "Green Path",
      category: "nature",
      label: "Nature",
      art: "vb-gallery-fifteen-art-nature",
      description: "A second nature card for animated filter behavior."
    }
  ];

  function createCard(item, index) {
    return `
      &lt;article class="vb-gallery-fifteen-card" style="animation-delay: ${index * 45}ms"&gt;
        &lt;div class="vb-gallery-fifteen-art ${item.art}" aria-label="${item.title} illustration" role="img"&gt;&lt;/div&gt;

        &lt;div class="vb-gallery-fifteen-body"&gt;
          &lt;span&gt;${item.label}&lt;/span&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
          &lt;p&gt;${item.description}&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    `;
  }

  function getVisibleItems(filterValue) {
    if (filterValue === "all") {
      return items;
    }

    return items.filter(function (item) {
      return item.category === filterValue;
    });
  }

  function renderGallery(filterValue) {
    const visibleItems = getVisibleItems(filterValue);

    grid.innerHTML = visibleItems.map(createCard).join("");
    count.textContent = visibleItems.length === 1 ? "1 item" : visibleItems.length + " items";
  }

  function animateAndRender(filterValue) {
    grid.classList.add("is-changing");

    window.setTimeout(function () {
      renderGallery(filterValue);
      grid.classList.remove("is-changing");
    }, 220);
  }

  filters.addEventListener("click", function (event) {
    const button = event.target.closest("button[data-filter]");
    if (!button) return;

    filters.querySelectorAll("button").forEach(function (filterButton) {
      filterButton.classList.remove("is-active");
    });

    button.classList.add("is-active");
    animateAndRender(button.getAttribute("data-filter"));
  });

  renderGallery("all");
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-fifteen-demo"&gt;
  &lt;div class="vb-gallery-fifteen-shell" data-vb-gallery-fifteen&gt;
    &lt;div class="vb-gallery-fifteen-head"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 15&lt;/span&gt;
        &lt;h3&gt;Image Gallery with Animated Filters&lt;/h3&gt;
        &lt;p&gt;Filter CSS-illustrated gallery cards with smooth exit and entrance animations.&lt;/p&gt;
      &lt;/div&gt;

      &lt;strong data-vb-gallery-fifteen-count&gt;0 items&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-fifteen-filters" data-vb-gallery-fifteen-filters&gt;
      &lt;button type="button" class="is-active" data-filter="all"&gt;All&lt;/button&gt;
      &lt;button type="button" data-filter="brand"&gt;Brand&lt;/button&gt;
      &lt;button type="button" data-filter="travel"&gt;Travel&lt;/button&gt;
      &lt;button type="button" data-filter="product"&gt;Product&lt;/button&gt;
      &lt;button type="button" data-filter="nature"&gt;Nature&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-fifteen-grid" data-vb-gallery-fifteen-grid&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-fifteen-demo,
.vb-gallery-fifteen-demo * {
  box-sizing: border-box;
}

.vb-gallery-fifteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 36px;
  background:
    radial-gradient(circle at 14% 12%, rgba(245, 158, 11, 0.18), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(236, 72, 153, 0.16), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fdf2f8 52%, #ffffff 100%) !important;
  border: 1px solid rgba(245, 158, 11, 0.24);
  box-shadow: 0 28px 80px rgba(146, 64, 14, 0.10);
}

.vb-gallery-fifteen-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-fifteen-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 20px;
}

.vb-gallery-fifteen-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-fifteen-head h3 {
  max-width: 780px;
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-fifteen-head p {
  max-width: 720px;
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-fifteen-head strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-fifteen-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 22px;
  padding: 12px;
  border-radius: 24px;
  background: rgba(255,255,255,0.78);
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.08);
}

.vb-gallery-fifteen-filters button {
  appearance: none;
  border: 1px solid rgba(245, 158, 11, 0.26);
  border-radius: 999px;
  background: #ffffff;
  color: #374151 !important;
  -webkit-text-fill-color: #374151 !important;
  padding: 11px 15px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  transition: transform 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.vb-gallery-fifteen-filters button:hover {
  transform: translateY(-2px);
  border-color: rgba(245, 158, 11, 0.68);
}

.vb-gallery-fifteen-filters button.is-active {
  border-color: transparent;
  background: linear-gradient(135deg, #f59e0b, #db2777);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 14px 34px rgba(219, 39, 119, 0.22);
}

.vb-gallery-fifteen-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-fifteen-grid.is-changing .vb-gallery-fifteen-card {
  animation: vbGalleryFifteenExit 0.22s ease both;
}

@keyframes vbGalleryFifteenExit {
  to {
    opacity: 0;
    transform: translateY(12px) scale(0.96);
  }
}

.vb-gallery-fifteen-card {
  overflow: hidden;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  animation: vbGalleryFifteenEnter 0.36s ease both;
}

@keyframes vbGalleryFifteenEnter {
  from {
    opacity: 0;
    transform: translateY(18px) scale(0.96);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.vb-gallery-fifteen-art {
  position: relative;
  height: 230px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-fifteen-art::before,
.vb-gallery-fifteen-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-fifteen-art-brand {
  background: linear-gradient(135deg, #111827 0%, #4f46e5 52%, #38bdf8 100%);
}

.vb-gallery-fifteen-art-brand::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 62%;
  border-radius: 26px;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.24), rgba(255,255,255,0.05)),
    repeating-linear-gradient(90deg, rgba(255,255,255,0.17) 0 3px, transparent 3px 18px);
  border: 1px solid rgba(255,255,255,0.25);
}

.vb-gallery-fifteen-art-brand::after {
  right: 16%;
  bottom: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: rgba(255,255,255,0.28);
  filter: blur(8px);
}

.vb-gallery-fifteen-art-travel {
  background: linear-gradient(180deg, #fde68a 0%, #f97316 50%, #7c2d12 100%);
}

.vb-gallery-fifteen-art-travel::before {
  left: -8%;
  right: -8%;
  bottom: -20%;
  height: 58%;
  background: #431407;
  clip-path: polygon(0 100%, 0 60%, 14% 44%, 28% 66%, 46% 34%, 64% 62%, 82% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-fifteen-art-travel::after {
  right: 18%;
  top: 16%;
  width: 78px;
  height: 78px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 62px rgba(255,247,237,0.72);
}

.vb-gallery-fifteen-art-product {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #fce7f3 36%, #be185d 100%);
}

.vb-gallery-fifteen-art-product::before {
  left: 50%;
  top: 50%;
  width: 132px;
  height: 132px;
  border-radius: 30px;
  background: linear-gradient(135deg, #ffffff, #fbcfe8);
  box-shadow: 0 28px 70px rgba(190,24,93,0.32);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-fifteen-art-product::after {
  left: 50%;
  top: 50%;
  width: 68px;
  height: 68px;
  border-radius: 20px;
  border: 4px solid rgba(219,39,119,0.42);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-fifteen-art-nature {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 55%, #052e16 100%);
}

.vb-gallery-fifteen-art-nature::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 70%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-fifteen-art-nature::after {
  right: 16%;
  top: 16%;
  width: 76px;
  height: 76px;
  border-radius: 999px;
  background: rgba(240,253,244,0.84);
  filter: blur(4px);
}

.vb-gallery-fifteen-body {
  display: grid;
  gap: 8px;
  padding: 17px;
}

.vb-gallery-fifteen-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #fffbeb;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-fifteen-body h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-fifteen-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

@media (max-width: 1050px) {
  .vb-gallery-fifteen-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 820px) {
  .vb-gallery-fifteen-head {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-fifteen-head strong {
    justify-content: center;
    width: 100%;
  }

  .vb-gallery-fifteen-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .vb-gallery-fifteen-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-fifteen-head h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-fifteen-filters {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-fifteen-filters button {
    width: 100%;
  }

  .vb-gallery-fifteen-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This image gallery with animated filters is useful for portfolio websites, agency galleries, product collections, design showcases, travel galleries, and visual landing pages where category filtering should feel smooth and professional.</p>



<h2 class="wp-block-heading">16. Fullscreen Image Viewer Gallery</h2>



<p class="wp-block-paragraph"><strong>A fullscreen image viewer gallery</strong> gives users a focused, distraction-free way to inspect a selected gallery item. It is useful for portfolios, presentation galleries, product previews, case studies, creative collections, and photography-style image sections.</p>



<p class="wp-block-paragraph">This example uses JavaScript viewer state. Clicking a CSS-illustrated gallery card opens a fullscreen-style overlay, injects the selected item data into the viewer, updates the counter, and lets users close the viewer with a button or the Escape key. The image visuals are created entirely with CSS.</p>



<ul class="wp-block-list">
<li>Fullscreen JavaScript image viewer</li>
<li>Selected item state</li>
<li>Dynamic viewer content</li>
<li>Escape key close</li>
<li>CSS-only image illustrations</li>
</ul>



<div class="vb-gallery-sixteen-demo">
  <div class="vb-gallery-sixteen-shell" data-vb-gallery-sixteen>
    <div class="vb-gallery-sixteen-sidebar">
      <span>Example 16</span>
      <h3>Fullscreen Image Viewer Gallery</h3>
      <p>Open CSS-illustrated gallery cards in a focused fullscreen-style JavaScript viewer.</p>
    </div>

    <div class="vb-gallery-sixteen-grid" data-vb-gallery-sixteen-grid></div>

    <div class="vb-gallery-sixteen-viewer" data-vb-gallery-sixteen-viewer hidden>
      <div class="vb-gallery-sixteen-topbar">
        <span data-vb-gallery-sixteen-counter>1 / 1</span>
        <strong data-vb-gallery-sixteen-viewer-category>Category</strong>
        <button type="button" data-vb-gallery-sixteen-close>Close</button>
      </div>

      <div class="vb-gallery-sixteen-stage">
        <div class="vb-gallery-sixteen-stage-art" data-vb-gallery-sixteen-stage-art></div>
      </div>

      <div class="vb-gallery-sixteen-caption">
        <h4 data-vb-gallery-sixteen-viewer-title></h4>
        <p data-vb-gallery-sixteen-viewer-description></p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-gallery-sixteen-demo,
.vb-gallery-sixteen-demo * {
  box-sizing: border-box;
}

.vb-gallery-sixteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 28px;
  background:
    linear-gradient(90deg, rgba(15,23,42,0.05) 1px, transparent 1px),
    linear-gradient(0deg, rgba(15,23,42,0.05) 1px, transparent 1px),
    linear-gradient(135deg, #f8fafc 0%, #f1f5f9 52%, #ffffff 100%) !important;
  background-size: 32px 32px, 32px 32px, auto !important;
  border: 1px solid rgba(100, 116, 139, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-gallery-sixteen-shell {
  display: grid;
  grid-template-columns: minmax(260px, 360px) minmax(0, 1fr);
  gap: 18px;
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-sixteen-sidebar {
  display: grid;
  align-content: center;
  min-width: 0;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 28px;
  background:
    radial-gradient(circle at 16% 18%, rgba(255,255,255,0.14), transparent 34%),
    linear-gradient(135deg, #020617, #111827 58%, #334155) !important;
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.25);
}

.vb-gallery-sixteen-sidebar span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-sixteen-sidebar h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 4.7vw, 58px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-sixteen-sidebar p {
  margin: 0 !important;
  color: #e2e8f0 !important;
  -webkit-text-fill-color: #e2e8f0 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-sixteen-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-sixteen-card {
  overflow: hidden;
  padding: 0;
  border: 0;
  border-radius: 28px;
  background: #ffffff;
  cursor: pointer;
  text-align: left;
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  transition: transform 0.24s ease, box-shadow 0.24s ease;
}

.vb-gallery-sixteen-card:hover {
  transform: translateY(-6px);
  box-shadow: 0 26px 64px rgba(15, 23, 42, 0.16);
}

.vb-gallery-sixteen-art {
  position: relative;
  height: 260px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-sixteen-art::before,
.vb-gallery-sixteen-art::after,
.vb-gallery-sixteen-stage-art::before,
.vb-gallery-sixteen-stage-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-sixteen-art-museum,
.vb-gallery-sixteen-stage-art-museum {
  background: linear-gradient(135deg, #020617 0%, #312e81 52%, #7c3aed 100%);
}

.vb-gallery-sixteen-art-museum::before,
.vb-gallery-sixteen-stage-art-museum::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 58%;
  border-radius: 30px;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.22), rgba(255,255,255,0.04)),
    repeating-linear-gradient(90deg, rgba(255,255,255,0.16) 0 4px, transparent 4px 24px);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-sixteen-art-museum::after,
.vb-gallery-sixteen-stage-art-museum::after {
  right: 16%;
  bottom: 18%;
  width: 92px;
  height: 92px;
  border-radius: 999px;
  background: rgba(255,255,255,0.24);
  filter: blur(8px);
}

.vb-gallery-sixteen-art-sky,
.vb-gallery-sixteen-stage-art-sky {
  background: linear-gradient(180deg, #dbeafe 0%, #3b82f6 50%, #1e3a8a 100%);
}

.vb-gallery-sixteen-art-sky::before,
.vb-gallery-sixteen-stage-art-sky::before {
  left: -8%;
  right: -8%;
  bottom: -20%;
  height: 56%;
  border-radius: 50% 50% 0 0;
  background: #172554;
}

.vb-gallery-sixteen-art-sky::after,
.vb-gallery-sixteen-stage-art-sky::after {
  right: 18%;
  top: 16%;
  width: 88px;
  height: 88px;
  border-radius: 999px;
  background: rgba(255,255,255,0.86);
  box-shadow: 0 0 64px rgba(255,255,255,0.70);
}

.vb-gallery-sixteen-art-object,
.vb-gallery-sixteen-stage-art-object {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #f3e8ff 36%, #581c87 100%);
}

.vb-gallery-sixteen-art-object::before,
.vb-gallery-sixteen-stage-art-object::before {
  left: 50%;
  top: 50%;
  width: 142px;
  height: 142px;
  border-radius: 34px;
  background: linear-gradient(135deg, #ffffff, #ddd6fe);
  box-shadow: 0 30px 80px rgba(88,28,135,0.34);
  transform: translate(-50%, -50%) rotate(16deg);
}

.vb-gallery-sixteen-art-object::after,
.vb-gallery-sixteen-stage-art-object::after {
  left: 50%;
  top: 50%;
  width: 74px;
  height: 74px;
  border-radius: 22px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(16deg);
}

.vb-gallery-sixteen-art-green,
.vb-gallery-sixteen-stage-art-green {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-sixteen-art-green::before,
.vb-gallery-sixteen-stage-art-green::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-sixteen-art-green::after,
.vb-gallery-sixteen-stage-art-green::after {
  right: 16%;
  top: 16%;
  width: 80px;
  height: 80px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-sixteen-body {
  display: grid;
  gap: 8px;
  padding: 18px;
}

.vb-gallery-sixteen-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #f1f5f9;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-sixteen-body h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-sixteen-viewer {
  position: fixed;
  inset: 0;
  z-index: 99999;
  display: grid;
  grid-template-rows: auto 1fr auto;
  background: #020617;
}

.vb-gallery-sixteen-viewer[hidden] {
  display: none;
}

.vb-gallery-sixteen-topbar {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 14px;
  padding: 16px clamp(16px, 4vw, 34px);
  background: rgba(15, 23, 42, 0.92);
  border-bottom: 1px solid rgba(255,255,255,0.10);
}

.vb-gallery-sixteen-topbar span,
.vb-gallery-sixteen-topbar strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-gallery-sixteen-topbar strong {
  text-align: center;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
}

.vb-gallery-sixteen-topbar button {
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #020617;
  padding: 10px 14px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-gallery-sixteen-stage {
  display: grid;
  place-items: center;
  padding: clamp(16px, 4vw, 34px);
}

.vb-gallery-sixteen-stage-art {
  position: relative;
  width: min(980px, 100%);
  height: min(60vh, 620px);
  min-height: 360px;
  overflow: hidden;
  border-radius: 34px;
  box-shadow: 0 34px 110px rgba(0,0,0,0.45);
}

.vb-gallery-sixteen-caption {
  padding: 20px clamp(16px, 4vw, 34px) 28px;
  background: rgba(15, 23, 42, 0.92);
  border-top: 1px solid rgba(255,255,255,0.10);
}

.vb-gallery-sixteen-caption h4 {
  max-width: 920px;
  margin: 0 auto 8px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 4vw, 52px) !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.065em;
}

.vb-gallery-sixteen-caption p {
  max-width: 920px;
  margin: 0 auto !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

@media (max-width: 940px) {
  .vb-gallery-sixteen-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 660px) {
  .vb-gallery-sixteen-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-sixteen-sidebar h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-sixteen-grid {
    grid-template-columns: 1fr;
  }

  .vb-gallery-sixteen-topbar {
    grid-template-columns: 1fr;
    text-align: center;
  }

  .vb-gallery-sixteen-stage-art {
    min-height: 300px;
    border-radius: 24px;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-sixteen]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-sixteen-grid]");
  const viewer = gallery.querySelector("[data-vb-gallery-sixteen-viewer]");
  const closeButton = gallery.querySelector("[data-vb-gallery-sixteen-close]");
  const stageArt = gallery.querySelector("[data-vb-gallery-sixteen-stage-art]");
  const viewerTitle = gallery.querySelector("[data-vb-gallery-sixteen-viewer-title]");
  const viewerCategory = gallery.querySelector("[data-vb-gallery-sixteen-viewer-category]");
  const viewerDescription = gallery.querySelector("[data-vb-gallery-sixteen-viewer-description]");
  const counter = gallery.querySelector("[data-vb-gallery-sixteen-counter]");

  const items = [
    {
      title: "Museum Screen",
      category: "Portfolio",
      art: "vb-gallery-sixteen-art-museum",
      stageArt: "vb-gallery-sixteen-stage-art-museum",
      description: "A fullscreen CSS visual for portfolio previews and creative case studies."
    },
    {
      title: "Open Sky",
      category: "Landscape",
      art: "vb-gallery-sixteen-art-sky",
      stageArt: "vb-gallery-sixteen-stage-art-sky",
      description: "A fullscreen CSS landscape viewer for focused gallery browsing."
    },
    {
      title: "Product Object",
      category: "Product",
      art: "vb-gallery-sixteen-art-object",
      stageArt: "vb-gallery-sixteen-stage-art-object",
      description: "A CSS product-style visual opened inside a fullscreen JavaScript viewer."
    },
    {
      title: "Green Field",
      category: "Nature",
      art: "vb-gallery-sixteen-art-green",
      stageArt: "vb-gallery-sixteen-stage-art-green",
      description: "A CSS nature-style illustration for immersive gallery viewing."
    }
  ];

  function createCard(item, index) {
    return `
      <button type="button" class="vb-gallery-sixteen-card" data-index="${index}">
        <div class="vb-gallery-sixteen-art ${item.art}" aria-label="${item.title} illustration" role="img"></div>

        <div class="vb-gallery-sixteen-body">
          <span>${item.category}</span>
          <h4>${item.title}</h4>
        </div>
      </button>
    `;
  }

  function openViewer(index) {
    const item = items[index];

    stageArt.className = "vb-gallery-sixteen-stage-art " + item.stageArt;
    viewerTitle.textContent = item.title;
    viewerCategory.textContent = item.category;
    viewerDescription.textContent = item.description;
    counter.textContent = Number(index) + 1 + " / " + items.length;

    viewer.hidden = false;
    document.body.style.overflow = "hidden";
  }

  function closeViewer() {
    viewer.hidden = true;
    document.body.style.overflow = "";
  }

  grid.addEventListener("click", function (event) {
    const card = event.target.closest("[data-index]");
    if (!card) return;

    openViewer(card.getAttribute("data-index"));
  });

  closeButton.addEventListener("click", closeViewer);

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape" && !viewer.hidden) {
      closeViewer();
    }
  });

  grid.innerHTML = items.map(createCard).join("");
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-sixteen]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-sixteen-grid]");
  const viewer = gallery.querySelector("[data-vb-gallery-sixteen-viewer]");
  const closeButton = gallery.querySelector("[data-vb-gallery-sixteen-close]");
  const stageArt = gallery.querySelector("[data-vb-gallery-sixteen-stage-art]");
  const viewerTitle = gallery.querySelector("[data-vb-gallery-sixteen-viewer-title]");
  const viewerCategory = gallery.querySelector("[data-vb-gallery-sixteen-viewer-category]");
  const viewerDescription = gallery.querySelector("[data-vb-gallery-sixteen-viewer-description]");
  const counter = gallery.querySelector("[data-vb-gallery-sixteen-counter]");

  const items = [
    {
      title: "Museum Screen",
      category: "Portfolio",
      art: "vb-gallery-sixteen-art-museum",
      stageArt: "vb-gallery-sixteen-stage-art-museum",
      description: "A fullscreen CSS visual for portfolio previews and creative case studies."
    },
    {
      title: "Open Sky",
      category: "Landscape",
      art: "vb-gallery-sixteen-art-sky",
      stageArt: "vb-gallery-sixteen-stage-art-sky",
      description: "A fullscreen CSS landscape viewer for focused gallery browsing."
    },
    {
      title: "Product Object",
      category: "Product",
      art: "vb-gallery-sixteen-art-object",
      stageArt: "vb-gallery-sixteen-stage-art-object",
      description: "A CSS product-style visual opened inside a fullscreen JavaScript viewer."
    },
    {
      title: "Green Field",
      category: "Nature",
      art: "vb-gallery-sixteen-art-green",
      stageArt: "vb-gallery-sixteen-stage-art-green",
      description: "A CSS nature-style illustration for immersive gallery viewing."
    }
  ];

  function createCard(item, index) {
    return `
      &lt;button type="button" class="vb-gallery-sixteen-card" data-index="${index}"&gt;
        &lt;div class="vb-gallery-sixteen-art ${item.art}" aria-label="${item.title} illustration" role="img"&gt;&lt;/div&gt;

        &lt;div class="vb-gallery-sixteen-body"&gt;
          &lt;span&gt;${item.category}&lt;/span&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
        &lt;/div&gt;
      &lt;/button&gt;
    `;
  }

  function openViewer(index) {
    const item = items[index];

    stageArt.className = "vb-gallery-sixteen-stage-art " + item.stageArt;
    viewerTitle.textContent = item.title;
    viewerCategory.textContent = item.category;
    viewerDescription.textContent = item.description;
    counter.textContent = Number(index) + 1 + " / " + items.length;

    viewer.hidden = false;
    document.body.style.overflow = "hidden";
  }

  function closeViewer() {
    viewer.hidden = true;
    document.body.style.overflow = "";
  }

  grid.addEventListener("click", function (event) {
    const card = event.target.closest("[data-index]");
    if (!card) return;

    openViewer(card.getAttribute("data-index"));
  });

  closeButton.addEventListener("click", closeViewer);

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape" && !viewer.hidden) {
      closeViewer();
    }
  });

  grid.innerHTML = items.map(createCard).join("");
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-sixteen-demo"&gt;
  &lt;div class="vb-gallery-sixteen-shell" data-vb-gallery-sixteen&gt;
    &lt;div class="vb-gallery-sixteen-sidebar"&gt;
      &lt;span&gt;Example 16&lt;/span&gt;
      &lt;h3&gt;Fullscreen Image Viewer Gallery&lt;/h3&gt;
      &lt;p&gt;Open CSS-illustrated gallery cards in a focused fullscreen-style JavaScript viewer.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-sixteen-grid" data-vb-gallery-sixteen-grid&gt;&lt;/div&gt;

    &lt;div class="vb-gallery-sixteen-viewer" data-vb-gallery-sixteen-viewer hidden&gt;
      &lt;div class="vb-gallery-sixteen-topbar"&gt;
        &lt;span data-vb-gallery-sixteen-counter&gt;1 / 1&lt;/span&gt;
        &lt;strong data-vb-gallery-sixteen-viewer-category&gt;Category&lt;/strong&gt;
        &lt;button type="button" data-vb-gallery-sixteen-close&gt;Close&lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-gallery-sixteen-stage"&gt;
        &lt;div class="vb-gallery-sixteen-stage-art" data-vb-gallery-sixteen-stage-art&gt;&lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-gallery-sixteen-caption"&gt;
        &lt;h4 data-vb-gallery-sixteen-viewer-title&gt;&lt;/h4&gt;
        &lt;p data-vb-gallery-sixteen-viewer-description&gt;&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-sixteen-demo,
.vb-gallery-sixteen-demo * {
  box-sizing: border-box;
}

.vb-gallery-sixteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 28px;
  background:
    linear-gradient(90deg, rgba(15,23,42,0.05) 1px, transparent 1px),
    linear-gradient(0deg, rgba(15,23,42,0.05) 1px, transparent 1px),
    linear-gradient(135deg, #f8fafc 0%, #f1f5f9 52%, #ffffff 100%) !important;
  background-size: 32px 32px, 32px 32px, auto !important;
  border: 1px solid rgba(100, 116, 139, 0.18);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.10);
}

.vb-gallery-sixteen-shell {
  display: grid;
  grid-template-columns: minmax(260px, 360px) minmax(0, 1fr);
  gap: 18px;
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-sixteen-sidebar {
  display: grid;
  align-content: center;
  min-width: 0;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 28px;
  background:
    radial-gradient(circle at 16% 18%, rgba(255,255,255,0.14), transparent 34%),
    linear-gradient(135deg, #020617, #111827 58%, #334155) !important;
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.25);
}

.vb-gallery-sixteen-sidebar span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-sixteen-sidebar h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 4.7vw, 58px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-sixteen-sidebar p {
  margin: 0 !important;
  color: #e2e8f0 !important;
  -webkit-text-fill-color: #e2e8f0 !important;
  font-size: 15px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-sixteen-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-sixteen-card {
  overflow: hidden;
  padding: 0;
  border: 0;
  border-radius: 28px;
  background: #ffffff;
  cursor: pointer;
  text-align: left;
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  transition: transform 0.24s ease, box-shadow 0.24s ease;
}

.vb-gallery-sixteen-card:hover {
  transform: translateY(-6px);
  box-shadow: 0 26px 64px rgba(15, 23, 42, 0.16);
}

.vb-gallery-sixteen-art {
  position: relative;
  height: 260px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-sixteen-art::before,
.vb-gallery-sixteen-art::after,
.vb-gallery-sixteen-stage-art::before,
.vb-gallery-sixteen-stage-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-sixteen-art-museum,
.vb-gallery-sixteen-stage-art-museum {
  background: linear-gradient(135deg, #020617 0%, #312e81 52%, #7c3aed 100%);
}

.vb-gallery-sixteen-art-museum::before,
.vb-gallery-sixteen-stage-art-museum::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 58%;
  border-radius: 30px;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.22), rgba(255,255,255,0.04)),
    repeating-linear-gradient(90deg, rgba(255,255,255,0.16) 0 4px, transparent 4px 24px);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-sixteen-art-museum::after,
.vb-gallery-sixteen-stage-art-museum::after {
  right: 16%;
  bottom: 18%;
  width: 92px;
  height: 92px;
  border-radius: 999px;
  background: rgba(255,255,255,0.24);
  filter: blur(8px);
}

.vb-gallery-sixteen-art-sky,
.vb-gallery-sixteen-stage-art-sky {
  background: linear-gradient(180deg, #dbeafe 0%, #3b82f6 50%, #1e3a8a 100%);
}

.vb-gallery-sixteen-art-sky::before,
.vb-gallery-sixteen-stage-art-sky::before {
  left: -8%;
  right: -8%;
  bottom: -20%;
  height: 56%;
  border-radius: 50% 50% 0 0;
  background: #172554;
}

.vb-gallery-sixteen-art-sky::after,
.vb-gallery-sixteen-stage-art-sky::after {
  right: 18%;
  top: 16%;
  width: 88px;
  height: 88px;
  border-radius: 999px;
  background: rgba(255,255,255,0.86);
  box-shadow: 0 0 64px rgba(255,255,255,0.70);
}

.vb-gallery-sixteen-art-object,
.vb-gallery-sixteen-stage-art-object {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #f3e8ff 36%, #581c87 100%);
}

.vb-gallery-sixteen-art-object::before,
.vb-gallery-sixteen-stage-art-object::before {
  left: 50%;
  top: 50%;
  width: 142px;
  height: 142px;
  border-radius: 34px;
  background: linear-gradient(135deg, #ffffff, #ddd6fe);
  box-shadow: 0 30px 80px rgba(88,28,135,0.34);
  transform: translate(-50%, -50%) rotate(16deg);
}

.vb-gallery-sixteen-art-object::after,
.vb-gallery-sixteen-stage-art-object::after {
  left: 50%;
  top: 50%;
  width: 74px;
  height: 74px;
  border-radius: 22px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(16deg);
}

.vb-gallery-sixteen-art-green,
.vb-gallery-sixteen-stage-art-green {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-sixteen-art-green::before,
.vb-gallery-sixteen-stage-art-green::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-sixteen-art-green::after,
.vb-gallery-sixteen-stage-art-green::after {
  right: 16%;
  top: 16%;
  width: 80px;
  height: 80px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-sixteen-body {
  display: grid;
  gap: 8px;
  padding: 18px;
}

.vb-gallery-sixteen-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #f1f5f9;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-sixteen-body h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-sixteen-viewer {
  position: fixed;
  inset: 0;
  z-index: 99999;
  display: grid;
  grid-template-rows: auto 1fr auto;
  background: #020617;
}

.vb-gallery-sixteen-viewer[hidden] {
  display: none;
}

.vb-gallery-sixteen-topbar {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 14px;
  padding: 16px clamp(16px, 4vw, 34px);
  background: rgba(15, 23, 42, 0.92);
  border-bottom: 1px solid rgba(255,255,255,0.10);
}

.vb-gallery-sixteen-topbar span,
.vb-gallery-sixteen-topbar strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-gallery-sixteen-topbar strong {
  text-align: center;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
}

.vb-gallery-sixteen-topbar button {
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: #ffffff;
  color: #020617;
  padding: 10px 14px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-gallery-sixteen-stage {
  display: grid;
  place-items: center;
  padding: clamp(16px, 4vw, 34px);
}

.vb-gallery-sixteen-stage-art {
  position: relative;
  width: min(980px, 100%);
  height: min(60vh, 620px);
  min-height: 360px;
  overflow: hidden;
  border-radius: 34px;
  box-shadow: 0 34px 110px rgba(0,0,0,0.45);
}

.vb-gallery-sixteen-caption {
  padding: 20px clamp(16px, 4vw, 34px) 28px;
  background: rgba(15, 23, 42, 0.92);
  border-top: 1px solid rgba(255,255,255,0.10);
}

.vb-gallery-sixteen-caption h4 {
  max-width: 920px;
  margin: 0 auto 8px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 4vw, 52px) !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.065em;
}

.vb-gallery-sixteen-caption p {
  max-width: 920px;
  margin: 0 auto !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

@media (max-width: 940px) {
  .vb-gallery-sixteen-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 660px) {
  .vb-gallery-sixteen-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-sixteen-sidebar h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-sixteen-grid {
    grid-template-columns: 1fr;
  }

  .vb-gallery-sixteen-topbar {
    grid-template-columns: 1fr;
    text-align: center;
  }

  .vb-gallery-sixteen-stage-art {
    min-height: 300px;
    border-radius: 24px;
  }
}</pre>



<p class="wp-block-paragraph">This fullscreen image viewer gallery is useful for portfolio previews, product showcases, design galleries, creative case studies, photography-style sections, and visual landing pages where one selected image should become the main focus.</p>



<h2 class="wp-block-heading">17. Image Gallery with Drag and Drop Reordering</h2>



<p class="wp-block-paragraph"><strong>An image gallery with drag and drop reordering</strong> lets users rearrange visual items directly in the interface. This pattern is useful for portfolio builders, media libraries, product image managers, project dashboards, website builders, moodboards, and admin panels where image order matters.</p>



<p class="wp-block-paragraph">This example uses JavaScript drag and drop events. Users can drag a CSS-illustrated card to a new position, the array order updates, and the gallery re-renders with the new order. All image thumbnails are made with CSS only, so the demo does not load external images.</p>



<ul class="wp-block-list">
<li>Drag and drop image gallery</li>
<li>JavaScript order state management</li>
<li>Reorder cards without page reload</li>
<li>Dynamic order labels</li>
<li>CSS-only illustrated thumbnails</li>
</ul>



<div class="vb-gallery-seventeen-demo">
  <div class="vb-gallery-seventeen-shell" data-vb-gallery-seventeen>
    <div class="vb-gallery-seventeen-head">
      <div>
        <span>Example 17</span>
        <h3>Image Gallery with Drag and Drop Reordering</h3>
        <p>Drag CSS-illustrated gallery cards into a new order and update the layout with JavaScript.</p>
      </div>

      <strong data-vb-gallery-seventeen-status>Drag a card to reorder</strong>
    </div>

    <div class="vb-gallery-seventeen-grid" data-vb-gallery-seventeen-grid></div>
  </div>
</div>

<style>
.vb-gallery-seventeen-demo,
.vb-gallery-seventeen-demo * {
  box-sizing: border-box;
}

.vb-gallery-seventeen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 14% 14%, rgba(14, 165, 233, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #faf5ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.22);
  box-shadow: 0 28px 80px rgba(12, 74, 110, 0.10);
}

.vb-gallery-seventeen-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-seventeen-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 24px;
}

.vb-gallery-seventeen-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-seventeen-head h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-seventeen-head p {
  max-width: 720px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-seventeen-head strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-seventeen-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-gallery-seventeen-card {
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 2px solid transparent;
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  cursor: grab;
  transition: transform 0.22s ease, box-shadow 0.22s ease, border-color 0.22s ease, opacity 0.22s ease;
  animation: vbGallerySeventeenIn 0.32s ease both;
}

@keyframes vbGallerySeventeenIn {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.vb-gallery-seventeen-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 26px 64px rgba(15, 23, 42, 0.16);
}

.vb-gallery-seventeen-card.is-dragging {
  opacity: 0.46;
  transform: scale(0.96);
  cursor: grabbing;
}

.vb-gallery-seventeen-card.is-drag-over {
  border-color: rgba(14, 165, 233, 0.88);
  box-shadow: 0 24px 70px rgba(14, 165, 233, 0.22);
}

.vb-gallery-seventeen-art {
  position: relative;
  height: 240px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-seventeen-art::before,
.vb-gallery-seventeen-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-seventeen-art-blue {
  background: linear-gradient(135deg, #020617 0%, #2563eb 54%, #38bdf8 100%);
}

.vb-gallery-seventeen-art-blue::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 60%;
  border-radius: 28px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 20px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-seventeen-art-blue::after {
  right: 16%;
  bottom: 18%;
  width: 92px;
  height: 92px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-seventeen-art-orange {
  background: linear-gradient(180deg, #fed7aa 0%, #f97316 50%, #7c2d12 100%);
}

.vb-gallery-seventeen-art-orange::before {
  left: -8%;
  right: -8%;
  bottom: -20%;
  height: 58%;
  background: #431407;
  clip-path: polygon(0 100%, 0 58%, 16% 42%, 32% 68%, 50% 36%, 68% 62%, 84% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-seventeen-art-orange::after {
  right: 18%;
  top: 16%;
  width: 78px;
  height: 78px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 62px rgba(255,247,237,0.72);
}

.vb-gallery-seventeen-art-green {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-seventeen-art-green::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-seventeen-art-green::after {
  right: 16%;
  top: 16%;
  width: 80px;
  height: 80px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-seventeen-art-purple {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #ddd6fe 36%, #581c87 100%);
}

.vb-gallery-seventeen-art-purple::before {
  left: 50%;
  top: 50%;
  width: 136px;
  height: 136px;
  border-radius: 34px;
  background: linear-gradient(135deg, #ffffff, #c4b5fd);
  box-shadow: 0 30px 80px rgba(88,28,135,0.34);
  transform: translate(-50%, -50%) rotate(16deg);
}

.vb-gallery-seventeen-art-purple::after {
  left: 50%;
  top: 50%;
  width: 74px;
  height: 74px;
  border-radius: 22px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(16deg);
}

.vb-gallery-seventeen-art-dark {
  background: linear-gradient(180deg, #020617 0%, #1e293b 58%, #0f172a 100%);
}

.vb-gallery-seventeen-art-dark::before {
  left: 14%;
  right: 14%;
  top: 18%;
  height: 4px;
  background: repeating-linear-gradient(90deg, #ffffff 0 12px, transparent 12px 28px);
  box-shadow:
    0 44px 0 rgba(255,255,255,0.56),
    0 88px 0 rgba(255,255,255,0.30),
    0 132px 0 rgba(255,255,255,0.18);
}

.vb-gallery-seventeen-art-dark::after {
  right: 15%;
  top: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: #facc15;
  box-shadow: 0 0 70px rgba(250,204,21,0.60);
}

.vb-gallery-seventeen-art-pink {
  background: linear-gradient(135deg, #500724 0%, #be123c 52%, #fb7185 100%);
}

.vb-gallery-seventeen-art-pink::before {
  left: 50%;
  top: 52%;
  width: 150px;
  height: 150px;
  border-radius: 42% 58% 62% 38%;
  background: radial-gradient(circle at 35% 30%, #fff1f2, #fb7185 44%, #9f1239 100%);
  transform: translate(-50%, -50%) rotate(22deg);
  box-shadow: 0 26px 70px rgba(80,7,36,0.36);
}

.vb-gallery-seventeen-art-pink::after {
  left: 14%;
  top: 16%;
  width: 74px;
  height: 74px;
  border-radius: 999px;
  background: rgba(255,255,255,0.22);
  filter: blur(6px);
}

.vb-gallery-seventeen-body {
  display: grid;
  gap: 8px;
  padding: 18px;
}

.vb-gallery-seventeen-body small {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #f0f9ff;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-seventeen-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 22px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-seventeen-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

@media (max-width: 980px) {
  .vb-gallery-seventeen-head {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-seventeen-head strong {
    justify-content: center;
    width: 100%;
  }

  .vb-gallery-seventeen-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .vb-gallery-seventeen-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-seventeen-head h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-seventeen-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-seventeen]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-seventeen-grid]");
  const status = gallery.querySelector("[data-vb-gallery-seventeen-status]");

  let draggedId = null;

  let items = [
    {
      id: "blue-panel",
      title: "Blue Panel",
      category: "Portfolio",
      art: "vb-gallery-seventeen-art-blue",
      description: "Drag this CSS gallery card to change its position."
    },
    {
      id: "orange-peaks",
      title: "Orange Peaks",
      category: "Travel",
      art: "vb-gallery-seventeen-art-orange",
      description: "The gallery order updates after dropping this card."
    },
    {
      id: "green-route",
      title: "Green Route",
      category: "Nature",
      art: "vb-gallery-seventeen-art-green",
      description: "A CSS-only image card inside a reorderable gallery."
    },
    {
      id: "purple-object",
      title: "Purple Object",
      category: "Product",
      art: "vb-gallery-seventeen-art-purple",
      description: "Use drag and drop to move this product-style card."
    },
    {
      id: "dark-lines",
      title: "Dark Lines",
      category: "Editorial",
      art: "vb-gallery-seventeen-art-dark",
      description: "A dark CSS visual card for drag sorting behavior."
    },
    {
      id: "pink-shape",
      title: "Pink Shape",
      category: "Abstract",
      art: "vb-gallery-seventeen-art-pink",
      description: "A creative CSS thumbnail that can be reordered."
    }
  ];

  function createCard(item, index) {
    return `
      <article class="vb-gallery-seventeen-card" draggable="true" data-id="${item.id}" style="animation-delay: ${index * 40}ms">
        <div class="vb-gallery-seventeen-art ${item.art}" aria-label="${item.title} illustration" role="img"></div>

        <div class="vb-gallery-seventeen-body">
          <small>Order ${index + 1} · ${item.category}</small>
          <h4>${item.title}</h4>
          <p>${item.description}</p>
        </div>
      </article>
    `;
  }

  function renderGallery() {
    grid.innerHTML = items.map(createCard).join("");
  }

  function moveItem(dragId, targetId) {
    if (dragId === targetId) return;

    const dragIndex = items.findIndex(function (item) {
      return item.id === dragId;
    });

    const targetIndex = items.findIndex(function (item) {
      return item.id === targetId;
    });

    if (dragIndex < 0 || targetIndex < 0) return;

    const draggedItem = items.splice(dragIndex, 1)[0];
    items.splice(targetIndex, 0, draggedItem);

    status.textContent = "New order saved in JavaScript state";
    renderGallery();
  }

  grid.addEventListener("dragstart", function (event) {
    const card = event.target.closest("[data-id]");
    if (!card) return;

    draggedId = card.getAttribute("data-id");
    card.classList.add("is-dragging");
    event.dataTransfer.effectAllowed = "move";
  });

  grid.addEventListener("dragover", function (event) {
    event.preventDefault();

    const card = event.target.closest("[data-id]");
    if (!card || card.getAttribute("data-id") === draggedId) return;

    grid.querySelectorAll(".vb-gallery-seventeen-card").forEach(function (item) {
      item.classList.remove("is-drag-over");
    });

    card.classList.add("is-drag-over");
  });

  grid.addEventListener("dragleave", function (event) {
    const card = event.target.closest("[data-id]");
    if (card) {
      card.classList.remove("is-drag-over");
    }
  });

  grid.addEventListener("drop", function (event) {
    event.preventDefault();

    const card = event.target.closest("[data-id]");
    if (!card || !draggedId) return;

    moveItem(draggedId, card.getAttribute("data-id"));
    draggedId = null;
  });

  grid.addEventListener("dragend", function () {
    draggedId = null;

    grid.querySelectorAll(".vb-gallery-seventeen-card").forEach(function (card) {
      card.classList.remove("is-dragging", "is-drag-over");
    });
  });

  renderGallery();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-seventeen]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-seventeen-grid]");
  const status = gallery.querySelector("[data-vb-gallery-seventeen-status]");

  let draggedId = null;

  let items = [
    {
      id: "blue-panel",
      title: "Blue Panel",
      category: "Portfolio",
      art: "vb-gallery-seventeen-art-blue",
      description: "Drag this CSS gallery card to change its position."
    },
    {
      id: "orange-peaks",
      title: "Orange Peaks",
      category: "Travel",
      art: "vb-gallery-seventeen-art-orange",
      description: "The gallery order updates after dropping this card."
    },
    {
      id: "green-route",
      title: "Green Route",
      category: "Nature",
      art: "vb-gallery-seventeen-art-green",
      description: "A CSS-only image card inside a reorderable gallery."
    },
    {
      id: "purple-object",
      title: "Purple Object",
      category: "Product",
      art: "vb-gallery-seventeen-art-purple",
      description: "Use drag and drop to move this product-style card."
    },
    {
      id: "dark-lines",
      title: "Dark Lines",
      category: "Editorial",
      art: "vb-gallery-seventeen-art-dark",
      description: "A dark CSS visual card for drag sorting behavior."
    },
    {
      id: "pink-shape",
      title: "Pink Shape",
      category: "Abstract",
      art: "vb-gallery-seventeen-art-pink",
      description: "A creative CSS thumbnail that can be reordered."
    }
  ];

  function createCard(item, index) {
    return `
      &lt;article class="vb-gallery-seventeen-card" draggable="true" data-id="${item.id}" style="animation-delay: ${index * 40}ms"&gt;
        &lt;div class="vb-gallery-seventeen-art ${item.art}" aria-label="${item.title} illustration" role="img"&gt;&lt;/div&gt;

        &lt;div class="vb-gallery-seventeen-body"&gt;
          &lt;small&gt;Order ${index + 1} · ${item.category}&lt;/small&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
          &lt;p&gt;${item.description}&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    `;
  }

  function renderGallery() {
    grid.innerHTML = items.map(createCard).join("");
  }

  function moveItem(dragId, targetId) {
    if (dragId === targetId) return;

    const dragIndex = items.findIndex(function (item) {
      return item.id === dragId;
    });

    const targetIndex = items.findIndex(function (item) {
      return item.id === targetId;
    });

    if (dragIndex &lt; 0 || targetIndex &lt; 0) return;

    const draggedItem = items.splice(dragIndex, 1)[0];
    items.splice(targetIndex, 0, draggedItem);

    status.textContent = "New order saved in JavaScript state";
    renderGallery();
  }

  grid.addEventListener("dragstart", function (event) {
    const card = event.target.closest("[data-id]");
    if (!card) return;

    draggedId = card.getAttribute("data-id");
    card.classList.add("is-dragging");
    event.dataTransfer.effectAllowed = "move";
  });

  grid.addEventListener("dragover", function (event) {
    event.preventDefault();

    const card = event.target.closest("[data-id]");
    if (!card || card.getAttribute("data-id") === draggedId) return;

    grid.querySelectorAll(".vb-gallery-seventeen-card").forEach(function (item) {
      item.classList.remove("is-drag-over");
    });

    card.classList.add("is-drag-over");
  });

  grid.addEventListener("dragleave", function (event) {
    const card = event.target.closest("[data-id]");
    if (card) {
      card.classList.remove("is-drag-over");
    }
  });

  grid.addEventListener("drop", function (event) {
    event.preventDefault();

    const card = event.target.closest("[data-id]");
    if (!card || !draggedId) return;

    moveItem(draggedId, card.getAttribute("data-id"));
    draggedId = null;
  });

  grid.addEventListener("dragend", function () {
    draggedId = null;

    grid.querySelectorAll(".vb-gallery-seventeen-card").forEach(function (card) {
      card.classList.remove("is-dragging", "is-drag-over");
    });
  });

  renderGallery();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-seventeen-demo"&gt;
  &lt;div class="vb-gallery-seventeen-shell" data-vb-gallery-seventeen&gt;
    &lt;div class="vb-gallery-seventeen-head"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 17&lt;/span&gt;
        &lt;h3&gt;Image Gallery with Drag and Drop Reordering&lt;/h3&gt;
        &lt;p&gt;Drag CSS-illustrated gallery cards into a new order and update the layout with JavaScript.&lt;/p&gt;
      &lt;/div&gt;

      &lt;strong data-vb-gallery-seventeen-status&gt;Drag a card to reorder&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-seventeen-grid" data-vb-gallery-seventeen-grid&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-seventeen-demo,
.vb-gallery-seventeen-demo * {
  box-sizing: border-box;
}

.vb-gallery-seventeen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 14% 14%, rgba(14, 165, 233, 0.18), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #faf5ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(14, 165, 233, 0.22);
  box-shadow: 0 28px 80px rgba(12, 74, 110, 0.10);
}

.vb-gallery-seventeen-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-seventeen-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 24px;
}

.vb-gallery-seventeen-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-seventeen-head h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-seventeen-head p {
  max-width: 720px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-seventeen-head strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-seventeen-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-gallery-seventeen-card {
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 2px solid transparent;
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  cursor: grab;
  transition: transform 0.22s ease, box-shadow 0.22s ease, border-color 0.22s ease, opacity 0.22s ease;
  animation: vbGallerySeventeenIn 0.32s ease both;
}

@keyframes vbGallerySeventeenIn {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.vb-gallery-seventeen-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 26px 64px rgba(15, 23, 42, 0.16);
}

.vb-gallery-seventeen-card.is-dragging {
  opacity: 0.46;
  transform: scale(0.96);
  cursor: grabbing;
}

.vb-gallery-seventeen-card.is-drag-over {
  border-color: rgba(14, 165, 233, 0.88);
  box-shadow: 0 24px 70px rgba(14, 165, 233, 0.22);
}

.vb-gallery-seventeen-art {
  position: relative;
  height: 240px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-seventeen-art::before,
.vb-gallery-seventeen-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-seventeen-art-blue {
  background: linear-gradient(135deg, #020617 0%, #2563eb 54%, #38bdf8 100%);
}

.vb-gallery-seventeen-art-blue::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 60%;
  border-radius: 28px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 20px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-seventeen-art-blue::after {
  right: 16%;
  bottom: 18%;
  width: 92px;
  height: 92px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-seventeen-art-orange {
  background: linear-gradient(180deg, #fed7aa 0%, #f97316 50%, #7c2d12 100%);
}

.vb-gallery-seventeen-art-orange::before {
  left: -8%;
  right: -8%;
  bottom: -20%;
  height: 58%;
  background: #431407;
  clip-path: polygon(0 100%, 0 58%, 16% 42%, 32% 68%, 50% 36%, 68% 62%, 84% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-seventeen-art-orange::after {
  right: 18%;
  top: 16%;
  width: 78px;
  height: 78px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 62px rgba(255,247,237,0.72);
}

.vb-gallery-seventeen-art-green {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-seventeen-art-green::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-seventeen-art-green::after {
  right: 16%;
  top: 16%;
  width: 80px;
  height: 80px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-seventeen-art-purple {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #ddd6fe 36%, #581c87 100%);
}

.vb-gallery-seventeen-art-purple::before {
  left: 50%;
  top: 50%;
  width: 136px;
  height: 136px;
  border-radius: 34px;
  background: linear-gradient(135deg, #ffffff, #c4b5fd);
  box-shadow: 0 30px 80px rgba(88,28,135,0.34);
  transform: translate(-50%, -50%) rotate(16deg);
}

.vb-gallery-seventeen-art-purple::after {
  left: 50%;
  top: 50%;
  width: 74px;
  height: 74px;
  border-radius: 22px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(16deg);
}

.vb-gallery-seventeen-art-dark {
  background: linear-gradient(180deg, #020617 0%, #1e293b 58%, #0f172a 100%);
}

.vb-gallery-seventeen-art-dark::before {
  left: 14%;
  right: 14%;
  top: 18%;
  height: 4px;
  background: repeating-linear-gradient(90deg, #ffffff 0 12px, transparent 12px 28px);
  box-shadow:
    0 44px 0 rgba(255,255,255,0.56),
    0 88px 0 rgba(255,255,255,0.30),
    0 132px 0 rgba(255,255,255,0.18);
}

.vb-gallery-seventeen-art-dark::after {
  right: 15%;
  top: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: #facc15;
  box-shadow: 0 0 70px rgba(250,204,21,0.60);
}

.vb-gallery-seventeen-art-pink {
  background: linear-gradient(135deg, #500724 0%, #be123c 52%, #fb7185 100%);
}

.vb-gallery-seventeen-art-pink::before {
  left: 50%;
  top: 52%;
  width: 150px;
  height: 150px;
  border-radius: 42% 58% 62% 38%;
  background: radial-gradient(circle at 35% 30%, #fff1f2, #fb7185 44%, #9f1239 100%);
  transform: translate(-50%, -50%) rotate(22deg);
  box-shadow: 0 26px 70px rgba(80,7,36,0.36);
}

.vb-gallery-seventeen-art-pink::after {
  left: 14%;
  top: 16%;
  width: 74px;
  height: 74px;
  border-radius: 999px;
  background: rgba(255,255,255,0.22);
  filter: blur(6px);
}

.vb-gallery-seventeen-body {
  display: grid;
  gap: 8px;
  padding: 18px;
}

.vb-gallery-seventeen-body small {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #f0f9ff;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-seventeen-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 22px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-seventeen-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

@media (max-width: 980px) {
  .vb-gallery-seventeen-head {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-seventeen-head strong {
    justify-content: center;
    width: 100%;
  }

  .vb-gallery-seventeen-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .vb-gallery-seventeen-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-seventeen-head h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-seventeen-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This drag and drop image gallery is useful for portfolio builders, media management dashboards, product image ordering, website builders, image approval tools, moodboards, and visual admin interfaces where users need to control the display order.</p>



<h2 class="wp-block-heading">18. Image Gallery with Compare Mode</h2>



<p class="wp-block-paragraph"><strong>An image gallery with compare mode</strong> lets users select two images and view them side by side. This is useful for product comparison, design review, before-and-after layouts, portfolio selection, real estate shortlist pages, visual approval tools, and media library interfaces.</p>



<p class="wp-block-paragraph">This example uses JavaScript compare selection logic. Users can select up to two CSS-illustrated gallery items, the compare panel updates automatically, and selecting a third item replaces the oldest selected item. No external images are loaded.</p>



<ul class="wp-block-list">
<li>Image gallery compare mode</li>
<li>Select two images for comparison</li>
<li>Automatic oldest selection replacement</li>
<li>Dynamic compare panel</li>
<li>CSS-only image thumbnails</li>
</ul>



<div class="vb-gallery-eighteen-demo">
  <div class="vb-gallery-eighteen-shell" data-vb-gallery-eighteen>
    <div class="vb-gallery-eighteen-intro">
      <span>Example 18</span>
      <h3>Image Gallery with Compare Mode</h3>
      <p>Select two CSS-illustrated gallery items and compare them side by side with JavaScript state.</p>
    </div>

    <div class="vb-gallery-eighteen-layout">
      <div class="vb-gallery-eighteen-grid" data-vb-gallery-eighteen-grid></div>

      <aside class="vb-gallery-eighteen-compare">
        <div class="vb-gallery-eighteen-compare-head">
          <strong data-vb-gallery-eighteen-status>Choose 2 images</strong>
          <button type="button" data-vb-gallery-eighteen-clear>Clear</button>
        </div>

        <div class="vb-gallery-eighteen-slots" data-vb-gallery-eighteen-slots>
          <div class="vb-gallery-eighteen-placeholder">
            <span>Slot 1</span>
            <p>Select first image</p>
          </div>

          <div class="vb-gallery-eighteen-placeholder">
            <span>Slot 2</span>
            <p>Select second image</p>
          </div>
        </div>
      </aside>
    </div>
  </div>
</div>

<style>
.vb-gallery-eighteen-demo,
.vb-gallery-eighteen-demo * {
  box-sizing: border-box;
}

.vb-gallery-eighteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 18px 46px 18px 46px;
  background:
    radial-gradient(circle at 14% 14%, rgba(16, 185, 129, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #eff6ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(16, 185, 129, 0.22);
  box-shadow: 0 28px 80px rgba(6, 95, 70, 0.10);
}

.vb-gallery-eighteen-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-eighteen-intro {
  margin-bottom: 22px;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 10px 34px 10px 34px;
  background:
    radial-gradient(circle at 16% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #064e3b, #1e3a8a 58%, #312e81) !important;
  box-shadow: 0 24px 70px rgba(6, 95, 70, 0.22);
}

.vb-gallery-eighteen-intro span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-eighteen-intro h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-eighteen-intro p {
  max-width: 740px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-eighteen-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 370px);
  gap: 18px;
  align-items: start;
}

.vb-gallery-eighteen-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-eighteen-card {
  overflow: hidden;
  border: 2px solid transparent;
  border-radius: 28px;
  background: #ffffff;
  cursor: pointer;
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  transition: transform 0.22s ease, border-color 0.22s ease, box-shadow 0.22s ease;
}

.vb-gallery-eighteen-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 26px 64px rgba(15, 23, 42, 0.15);
}

.vb-gallery-eighteen-card.is-selected {
  border-color: rgba(16, 185, 129, 0.90);
  box-shadow: 0 24px 70px rgba(16, 185, 129, 0.22);
}

.vb-gallery-eighteen-art {
  position: relative;
  height: 225px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-eighteen-art::before,
.vb-gallery-eighteen-art::after,
.vb-gallery-eighteen-slot-art::before,
.vb-gallery-eighteen-slot-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-eighteen-art-a,
.vb-gallery-eighteen-slot-art-a {
  background: linear-gradient(135deg, #020617 0%, #2563eb 54%, #38bdf8 100%);
}

.vb-gallery-eighteen-art-a::before,
.vb-gallery-eighteen-slot-art-a::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 60%;
  border-radius: 28px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 20px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-eighteen-art-a::after,
.vb-gallery-eighteen-slot-art-a::after {
  right: 16%;
  bottom: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-eighteen-art-b,
.vb-gallery-eighteen-slot-art-b {
  background: linear-gradient(180deg, #fed7aa 0%, #f97316 50%, #7c2d12 100%);
}

.vb-gallery-eighteen-art-b::before,
.vb-gallery-eighteen-slot-art-b::before {
  left: -8%;
  right: -8%;
  bottom: -20%;
  height: 58%;
  background: #431407;
  clip-path: polygon(0 100%, 0 58%, 16% 42%, 32% 68%, 50% 36%, 68% 62%, 84% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-eighteen-art-b::after,
.vb-gallery-eighteen-slot-art-b::after {
  right: 18%;
  top: 16%;
  width: 72px;
  height: 72px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 62px rgba(255,247,237,0.72);
}

.vb-gallery-eighteen-art-c,
.vb-gallery-eighteen-slot-art-c {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #ddd6fe 36%, #581c87 100%);
}

.vb-gallery-eighteen-art-c::before,
.vb-gallery-eighteen-slot-art-c::before {
  left: 50%;
  top: 50%;
  width: 124px;
  height: 124px;
  border-radius: 34px;
  background: linear-gradient(135deg, #ffffff, #c4b5fd);
  box-shadow: 0 30px 80px rgba(88,28,135,0.34);
  transform: translate(-50%, -50%) rotate(16deg);
}

.vb-gallery-eighteen-art-c::after,
.vb-gallery-eighteen-slot-art-c::after {
  left: 50%;
  top: 50%;
  width: 68px;
  height: 68px;
  border-radius: 22px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(16deg);
}

.vb-gallery-eighteen-art-d,
.vb-gallery-eighteen-slot-art-d {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-eighteen-art-d::before,
.vb-gallery-eighteen-slot-art-d::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-eighteen-art-d::after,
.vb-gallery-eighteen-slot-art-d::after {
  right: 16%;
  top: 16%;
  width: 76px;
  height: 76px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-eighteen-body {
  display: grid;
  gap: 8px;
  padding: 17px;
}

.vb-gallery-eighteen-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #ecfdf5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-eighteen-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 21px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-eighteen-compare {
  position: sticky;
  top: 18px;
  padding: 16px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
}

.vb-gallery-eighteen-compare-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}

.vb-gallery-eighteen-compare-head strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-gallery-eighteen-compare-head button {
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 9px 12px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-gallery-eighteen-slots {
  display: grid;
  gap: 12px;
}

.vb-gallery-eighteen-slot,
.vb-gallery-eighteen-placeholder {
  overflow: hidden;
  border-radius: 22px;
  border: 1px solid rgba(148, 163, 184, 0.24);
  background: #f8fafc;
}

.vb-gallery-eighteen-placeholder {
  display: grid;
  place-items: center;
  min-height: 170px;
  padding: 20px;
  text-align: center;
  border-style: dashed;
}

.vb-gallery-eighteen-placeholder span {
  display: inline-flex;
  margin-bottom: 8px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-eighteen-placeholder p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-gallery-eighteen-slot-art {
  position: relative;
  height: 150px;
  overflow: hidden;
}

.vb-gallery-eighteen-slot-body {
  padding: 13px;
}

.vb-gallery-eighteen-slot-body span {
  display: inline-flex;
  margin-bottom: 7px;
  padding: 5px 8px;
  border-radius: 999px;
  background: #ecfdf5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 10px;
  font-weight: 950;
}

.vb-gallery-eighteen-slot-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

@media (max-width: 980px) {
  .vb-gallery-eighteen-layout {
    grid-template-columns: 1fr;
  }

  .vb-gallery-eighteen-compare {
    position: static;
  }

  .vb-gallery-eighteen-slots {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .vb-gallery-eighteen-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-eighteen-intro h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-eighteen-grid,
  .vb-gallery-eighteen-slots {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-eighteen]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-eighteen-grid]");
  const slots = gallery.querySelector("[data-vb-gallery-eighteen-slots]");
  const status = gallery.querySelector("[data-vb-gallery-eighteen-status]");
  const clearButton = gallery.querySelector("[data-vb-gallery-eighteen-clear]");

  const items = [
    {
      id: "compare-blue",
      title: "Blue Interface",
      category: "Portfolio",
      art: "vb-gallery-eighteen-art-a",
      slotArt: "vb-gallery-eighteen-slot-art-a"
    },
    {
      id: "compare-sunset",
      title: "Sunset Layout",
      category: "Travel",
      art: "vb-gallery-eighteen-art-b",
      slotArt: "vb-gallery-eighteen-slot-art-b"
    },
    {
      id: "compare-object",
      title: "Product Object",
      category: "Product",
      art: "vb-gallery-eighteen-art-c",
      slotArt: "vb-gallery-eighteen-slot-art-c"
    },
    {
      id: "compare-forest",
      title: "Forest Scene",
      category: "Nature",
      art: "vb-gallery-eighteen-art-d",
      slotArt: "vb-gallery-eighteen-slot-art-d"
    }
  ];

  let selectedIds = [];

  function isSelected(id) {
    return selectedIds.includes(id);
  }

  function createCard(item) {
    const selectedClass = isSelected(item.id) ? "is-selected" : "";

    return `
      <article class="vb-gallery-eighteen-card ${selectedClass}" data-id="${item.id}">
        <div class="vb-gallery-eighteen-art ${item.art}" aria-label="${item.title} illustration" role="img"></div>

        <div class="vb-gallery-eighteen-body">
          <span>${item.category}</span>
          <h4>${item.title}</h4>
        </div>
      </article>
    `;
  }

  function createSlot(item) {
    return `
      <div class="vb-gallery-eighteen-slot">
        <div class="vb-gallery-eighteen-slot-art ${item.slotArt}" aria-label="${item.title} compare illustration" role="img"></div>

        <div class="vb-gallery-eighteen-slot-body">
          <span>${item.category}</span>
          <h4>${item.title}</h4>
        </div>
      </div>
    `;
  }

  function createPlaceholder(number) {
    return `
      <div class="vb-gallery-eighteen-placeholder">
        <div>
          <span>Slot ${number}</span>
          <p>Select ${number === 1 ? "first" : "second"} image</p>
        </div>
      </div>
    `;
  }

  function updateStatus() {
    if (selectedIds.length === 0) {
      status.textContent = "Choose 2 images";
    }

    if (selectedIds.length === 1) {
      status.textContent = "Choose 1 more image";
    }

    if (selectedIds.length === 2) {
      status.textContent = "Compare mode active";
    }
  }

  function renderSlots() {
    const selectedItems = selectedIds.map(function (id) {
      return items.find(function (item) {
        return item.id === id;
      });
    }).filter(Boolean);

    let markup = selectedItems.map(createSlot).join("");

    while (selectedItems.length < 2) {
      markup += createPlaceholder(selectedItems.length + 1);
      selectedItems.push(null);
    }

    slots.innerHTML = markup;
  }

  function renderGallery() {
    grid.innerHTML = items.map(createCard).join("");
    renderSlots();
    updateStatus();
  }

  function toggleCompare(id) {
    if (isSelected(id)) {
      selectedIds = selectedIds.filter(function (selectedId) {
        return selectedId !== id;
      });
    } else {
      if (selectedIds.length >= 2) {
        selectedIds.shift();
      }

      selectedIds.push(id);
    }

    renderGallery();
  }

  grid.addEventListener("click", function (event) {
    const card = event.target.closest("[data-id]");
    if (!card) return;

    toggleCompare(card.getAttribute("data-id"));
  });

  clearButton.addEventListener("click", function () {
    selectedIds = [];
    renderGallery();
  });

  renderGallery();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-eighteen]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-eighteen-grid]");
  const slots = gallery.querySelector("[data-vb-gallery-eighteen-slots]");
  const status = gallery.querySelector("[data-vb-gallery-eighteen-status]");
  const clearButton = gallery.querySelector("[data-vb-gallery-eighteen-clear]");

  const items = [
    {
      id: "compare-blue",
      title: "Blue Interface",
      category: "Portfolio",
      art: "vb-gallery-eighteen-art-a",
      slotArt: "vb-gallery-eighteen-slot-art-a"
    },
    {
      id: "compare-sunset",
      title: "Sunset Layout",
      category: "Travel",
      art: "vb-gallery-eighteen-art-b",
      slotArt: "vb-gallery-eighteen-slot-art-b"
    },
    {
      id: "compare-object",
      title: "Product Object",
      category: "Product",
      art: "vb-gallery-eighteen-art-c",
      slotArt: "vb-gallery-eighteen-slot-art-c"
    },
    {
      id: "compare-forest",
      title: "Forest Scene",
      category: "Nature",
      art: "vb-gallery-eighteen-art-d",
      slotArt: "vb-gallery-eighteen-slot-art-d"
    }
  ];

  let selectedIds = [];

  function isSelected(id) {
    return selectedIds.includes(id);
  }

  function createCard(item) {
    const selectedClass = isSelected(item.id) ? "is-selected" : "";

    return `
      &lt;article class="vb-gallery-eighteen-card ${selectedClass}" data-id="${item.id}"&gt;
        &lt;div class="vb-gallery-eighteen-art ${item.art}" aria-label="${item.title} illustration" role="img"&gt;&lt;/div&gt;

        &lt;div class="vb-gallery-eighteen-body"&gt;
          &lt;span&gt;${item.category}&lt;/span&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    `;
  }

  function createSlot(item) {
    return `
      &lt;div class="vb-gallery-eighteen-slot"&gt;
        &lt;div class="vb-gallery-eighteen-slot-art ${item.slotArt}" aria-label="${item.title} compare illustration" role="img"&gt;&lt;/div&gt;

        &lt;div class="vb-gallery-eighteen-slot-body"&gt;
          &lt;span&gt;${item.category}&lt;/span&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    `;
  }

  function createPlaceholder(number) {
    return `
      &lt;div class="vb-gallery-eighteen-placeholder"&gt;
        &lt;div&gt;
          &lt;span&gt;Slot ${number}&lt;/span&gt;
          &lt;p&gt;Select ${number === 1 ? "first" : "second"} image&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    `;
  }

  function updateStatus() {
    if (selectedIds.length === 0) {
      status.textContent = "Choose 2 images";
    }

    if (selectedIds.length === 1) {
      status.textContent = "Choose 1 more image";
    }

    if (selectedIds.length === 2) {
      status.textContent = "Compare mode active";
    }
  }

  function renderSlots() {
    const selectedItems = selectedIds.map(function (id) {
      return items.find(function (item) {
        return item.id === id;
      });
    }).filter(Boolean);

    let markup = selectedItems.map(createSlot).join("");

    while (selectedItems.length &lt; 2) {
      markup += createPlaceholder(selectedItems.length + 1);
      selectedItems.push(null);
    }

    slots.innerHTML = markup;
  }

  function renderGallery() {
    grid.innerHTML = items.map(createCard).join("");
    renderSlots();
    updateStatus();
  }

  function toggleCompare(id) {
    if (isSelected(id)) {
      selectedIds = selectedIds.filter(function (selectedId) {
        return selectedId !== id;
      });
    } else {
      if (selectedIds.length &gt;= 2) {
        selectedIds.shift();
      }

      selectedIds.push(id);
    }

    renderGallery();
  }

  grid.addEventListener("click", function (event) {
    const card = event.target.closest("[data-id]");
    if (!card) return;

    toggleCompare(card.getAttribute("data-id"));
  });

  clearButton.addEventListener("click", function () {
    selectedIds = [];
    renderGallery();
  });

  renderGallery();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-eighteen-demo"&gt;
  &lt;div class="vb-gallery-eighteen-shell" data-vb-gallery-eighteen&gt;
    &lt;div class="vb-gallery-eighteen-intro"&gt;
      &lt;span&gt;Example 18&lt;/span&gt;
      &lt;h3&gt;Image Gallery with Compare Mode&lt;/h3&gt;
      &lt;p&gt;Select two CSS-illustrated gallery items and compare them side by side with JavaScript state.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-eighteen-layout"&gt;
      &lt;div class="vb-gallery-eighteen-grid" data-vb-gallery-eighteen-grid&gt;&lt;/div&gt;

      &lt;aside class="vb-gallery-eighteen-compare"&gt;
        &lt;div class="vb-gallery-eighteen-compare-head"&gt;
          &lt;strong data-vb-gallery-eighteen-status&gt;Choose 2 images&lt;/strong&gt;
          &lt;button type="button" data-vb-gallery-eighteen-clear&gt;Clear&lt;/button&gt;
        &lt;/div&gt;

        &lt;div class="vb-gallery-eighteen-slots" data-vb-gallery-eighteen-slots&gt;
          &lt;div class="vb-gallery-eighteen-placeholder"&gt;
            &lt;span&gt;Slot 1&lt;/span&gt;
            &lt;p&gt;Select first image&lt;/p&gt;
          &lt;/div&gt;

          &lt;div class="vb-gallery-eighteen-placeholder"&gt;
            &lt;span&gt;Slot 2&lt;/span&gt;
            &lt;p&gt;Select second image&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/aside&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-eighteen-demo,
.vb-gallery-eighteen-demo * {
  box-sizing: border-box;
}

.vb-gallery-eighteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 18px 46px 18px 46px;
  background:
    radial-gradient(circle at 14% 14%, rgba(16, 185, 129, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #eff6ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(16, 185, 129, 0.22);
  box-shadow: 0 28px 80px rgba(6, 95, 70, 0.10);
}

.vb-gallery-eighteen-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-eighteen-intro {
  margin-bottom: 22px;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 10px 34px 10px 34px;
  background:
    radial-gradient(circle at 16% 18%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #064e3b, #1e3a8a 58%, #312e81) !important;
  box-shadow: 0 24px 70px rgba(6, 95, 70, 0.22);
}

.vb-gallery-eighteen-intro span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-eighteen-intro h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-eighteen-intro p {
  max-width: 740px;
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-eighteen-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(300px, 370px);
  gap: 18px;
  align-items: start;
}

.vb-gallery-eighteen-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-eighteen-card {
  overflow: hidden;
  border: 2px solid transparent;
  border-radius: 28px;
  background: #ffffff;
  cursor: pointer;
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  transition: transform 0.22s ease, border-color 0.22s ease, box-shadow 0.22s ease;
}

.vb-gallery-eighteen-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 26px 64px rgba(15, 23, 42, 0.15);
}

.vb-gallery-eighteen-card.is-selected {
  border-color: rgba(16, 185, 129, 0.90);
  box-shadow: 0 24px 70px rgba(16, 185, 129, 0.22);
}

.vb-gallery-eighteen-art {
  position: relative;
  height: 225px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-eighteen-art::before,
.vb-gallery-eighteen-art::after,
.vb-gallery-eighteen-slot-art::before,
.vb-gallery-eighteen-slot-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-eighteen-art-a,
.vb-gallery-eighteen-slot-art-a {
  background: linear-gradient(135deg, #020617 0%, #2563eb 54%, #38bdf8 100%);
}

.vb-gallery-eighteen-art-a::before,
.vb-gallery-eighteen-slot-art-a::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 60%;
  border-radius: 28px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 20px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-eighteen-art-a::after,
.vb-gallery-eighteen-slot-art-a::after {
  right: 16%;
  bottom: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-eighteen-art-b,
.vb-gallery-eighteen-slot-art-b {
  background: linear-gradient(180deg, #fed7aa 0%, #f97316 50%, #7c2d12 100%);
}

.vb-gallery-eighteen-art-b::before,
.vb-gallery-eighteen-slot-art-b::before {
  left: -8%;
  right: -8%;
  bottom: -20%;
  height: 58%;
  background: #431407;
  clip-path: polygon(0 100%, 0 58%, 16% 42%, 32% 68%, 50% 36%, 68% 62%, 84% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-eighteen-art-b::after,
.vb-gallery-eighteen-slot-art-b::after {
  right: 18%;
  top: 16%;
  width: 72px;
  height: 72px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 62px rgba(255,247,237,0.72);
}

.vb-gallery-eighteen-art-c,
.vb-gallery-eighteen-slot-art-c {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #ddd6fe 36%, #581c87 100%);
}

.vb-gallery-eighteen-art-c::before,
.vb-gallery-eighteen-slot-art-c::before {
  left: 50%;
  top: 50%;
  width: 124px;
  height: 124px;
  border-radius: 34px;
  background: linear-gradient(135deg, #ffffff, #c4b5fd);
  box-shadow: 0 30px 80px rgba(88,28,135,0.34);
  transform: translate(-50%, -50%) rotate(16deg);
}

.vb-gallery-eighteen-art-c::after,
.vb-gallery-eighteen-slot-art-c::after {
  left: 50%;
  top: 50%;
  width: 68px;
  height: 68px;
  border-radius: 22px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(16deg);
}

.vb-gallery-eighteen-art-d,
.vb-gallery-eighteen-slot-art-d {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-eighteen-art-d::before,
.vb-gallery-eighteen-slot-art-d::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-eighteen-art-d::after,
.vb-gallery-eighteen-slot-art-d::after {
  right: 16%;
  top: 16%;
  width: 76px;
  height: 76px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-eighteen-body {
  display: grid;
  gap: 8px;
  padding: 17px;
}

.vb-gallery-eighteen-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #ecfdf5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-eighteen-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 21px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-eighteen-compare {
  position: sticky;
  top: 18px;
  padding: 16px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
}

.vb-gallery-eighteen-compare-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}

.vb-gallery-eighteen-compare-head strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-gallery-eighteen-compare-head button {
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 9px 12px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-gallery-eighteen-slots {
  display: grid;
  gap: 12px;
}

.vb-gallery-eighteen-slot,
.vb-gallery-eighteen-placeholder {
  overflow: hidden;
  border-radius: 22px;
  border: 1px solid rgba(148, 163, 184, 0.24);
  background: #f8fafc;
}

.vb-gallery-eighteen-placeholder {
  display: grid;
  place-items: center;
  min-height: 170px;
  padding: 20px;
  text-align: center;
  border-style: dashed;
}

.vb-gallery-eighteen-placeholder span {
  display: inline-flex;
  margin-bottom: 8px;
  padding: 6px 9px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-eighteen-placeholder p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  font-weight: 750;
}

.vb-gallery-eighteen-slot-art {
  position: relative;
  height: 150px;
  overflow: hidden;
}

.vb-gallery-eighteen-slot-body {
  padding: 13px;
}

.vb-gallery-eighteen-slot-body span {
  display: inline-flex;
  margin-bottom: 7px;
  padding: 5px 8px;
  border-radius: 999px;
  background: #ecfdf5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 10px;
  font-weight: 950;
}

.vb-gallery-eighteen-slot-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

@media (max-width: 980px) {
  .vb-gallery-eighteen-layout {
    grid-template-columns: 1fr;
  }

  .vb-gallery-eighteen-compare {
    position: static;
  }

  .vb-gallery-eighteen-slots {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .vb-gallery-eighteen-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-eighteen-intro h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-eighteen-grid,
  .vb-gallery-eighteen-slots {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This image gallery with compare mode is useful for product comparisons, design reviews, before-and-after interfaces, real estate shortlists, portfolio selection tools, media libraries, and image approval dashboards.</p>



<h2 class="wp-block-heading">19. Image Gallery with Slideshow Mode</h2>



<p class="wp-block-paragraph"><strong>An image gallery with slideshow mode</strong> lets visitors watch gallery items automatically instead of clicking through every card manually. This is useful for homepage galleries, product highlights, portfolio showcases, event recaps, presentation sections, travel galleries, and visual landing pages.</p>



<p class="wp-block-paragraph">This example uses JavaScript slideshow state. Users can start or pause the slideshow, move to the next or previous item manually, and watch the progress bar reset for each slide. The gallery thumbnails and large preview are CSS-only illustrations, so no external image files are loaded.</p>



<ul class="wp-block-list">
<li>JavaScript slideshow image gallery</li>
<li>Start and pause slideshow mode</li>
<li>Next and previous controls</li>
<li>Automatic progress bar reset</li>
<li>CSS-only illustrated image slides</li>
</ul>



<div class="vb-gallery-nineteen-demo">
  <div class="vb-gallery-nineteen-shell" data-vb-gallery-nineteen>
    <div class="vb-gallery-nineteen-header">
      <div>
        <span>Example 19</span>
        <h3>Image Gallery with Slideshow Mode</h3>
        <p>Turn a CSS-illustrated gallery into an automatic slideshow with JavaScript controls.</p>
      </div>

      <strong data-vb-gallery-nineteen-status>Paused</strong>
    </div>

    <div class="vb-gallery-nineteen-stage">
      <div class="vb-gallery-nineteen-art" data-vb-gallery-nineteen-art></div>

      <div class="vb-gallery-nineteen-overlay">
        <span data-vb-gallery-nineteen-category>Category</span>
        <h4 data-vb-gallery-nineteen-title>Gallery Title</h4>
        <p data-vb-gallery-nineteen-description>Gallery description.</p>

        <div class="vb-gallery-nineteen-progress">
          <div data-vb-gallery-nineteen-progress></div>
        </div>
      </div>
    </div>

    <div class="vb-gallery-nineteen-controls">
      <button type="button" data-vb-gallery-nineteen-prev>Previous</button>
      <button type="button" data-vb-gallery-nineteen-toggle>Start Slideshow</button>
      <button type="button" data-vb-gallery-nineteen-next>Next</button>
    </div>

    <div class="vb-gallery-nineteen-thumbs" data-vb-gallery-nineteen-thumbs></div>
  </div>
</div>

<style>
.vb-gallery-nineteen-demo,
.vb-gallery-nineteen-demo * {
  box-sizing: border-box;
}

.vb-gallery-nineteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 42px;
  background:
    radial-gradient(circle at 12% 12%, rgba(79, 70, 229, 0.18), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(236, 72, 153, 0.16), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #fdf2f8 52%, #ffffff 100%) !important;
  border: 1px solid rgba(129, 140, 248, 0.24);
  box-shadow: 0 28px 80px rgba(67, 56, 202, 0.10);
}

.vb-gallery-nineteen-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-nineteen-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 22px;
}

.vb-gallery-nineteen-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #e0e7ff;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-nineteen-header h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-nineteen-header p {
  max-width: 730px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-nineteen-header strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-nineteen-stage {
  position: relative;
  min-height: 520px;
  overflow: hidden;
  border-radius: 34px;
  background: #111827;
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.18);
}

.vb-gallery-nineteen-art {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: #111827;
  transition: opacity 0.3s ease, transform 0.3s ease;
}

.vb-gallery-nineteen-art::before,
.vb-gallery-nineteen-art::after,
.vb-gallery-nineteen-thumb-art::before,
.vb-gallery-nineteen-thumb-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-nineteen-art.is-changing {
  opacity: 0.35;
  transform: scale(1.03);
}

.vb-gallery-nineteen-art-cinema,
.vb-gallery-nineteen-thumb-art-cinema {
  background: linear-gradient(135deg, #020617 0%, #312e81 50%, #7c3aed 100%);
}

.vb-gallery-nineteen-art-cinema::before,
.vb-gallery-nineteen-thumb-art-cinema::before {
  left: 12%;
  top: 18%;
  width: 76%;
  height: 58%;
  border-radius: 32px;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.22), rgba(255,255,255,0.04)),
    repeating-linear-gradient(90deg, rgba(255,255,255,0.17) 0 4px, transparent 4px 24px);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-nineteen-art-cinema::after,
.vb-gallery-nineteen-thumb-art-cinema::after {
  right: 18%;
  bottom: 18%;
  width: 104px;
  height: 104px;
  border-radius: 999px;
  background: rgba(255,255,255,0.24);
  filter: blur(8px);
}

.vb-gallery-nineteen-art-sunset,
.vb-gallery-nineteen-thumb-art-sunset {
  background: linear-gradient(180deg, #fde68a 0%, #fb923c 48%, #7c2d12 100%);
}

.vb-gallery-nineteen-art-sunset::before,
.vb-gallery-nineteen-thumb-art-sunset::before {
  left: -8%;
  right: -8%;
  bottom: -18%;
  height: 56%;
  background: #431407;
  clip-path: polygon(0 100%, 0 58%, 15% 42%, 30% 66%, 48% 34%, 66% 62%, 83% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-nineteen-art-sunset::after,
.vb-gallery-nineteen-thumb-art-sunset::after {
  right: 18%;
  top: 16%;
  width: 92px;
  height: 92px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 70px rgba(255,247,237,0.72);
}

.vb-gallery-nineteen-art-product,
.vb-gallery-nineteen-thumb-art-product {
  background: radial-gradient(circle at 50% 44%, #ffffff 0%, #f3e8ff 36%, #581c87 100%);
}

.vb-gallery-nineteen-art-product::before,
.vb-gallery-nineteen-thumb-art-product::before {
  left: 50%;
  top: 50%;
  width: 156px;
  height: 156px;
  border-radius: 34px;
  background: linear-gradient(135deg, #ffffff, #c4b5fd);
  box-shadow: 0 30px 80px rgba(88,28,135,0.34);
  transform: translate(-50%, -50%) rotate(16deg);
}

.vb-gallery-nineteen-art-product::after,
.vb-gallery-nineteen-thumb-art-product::after {
  left: 50%;
  top: 50%;
  width: 82px;
  height: 82px;
  border-radius: 22px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(16deg);
}

.vb-gallery-nineteen-art-forest,
.vb-gallery-nineteen-thumb-art-forest {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-nineteen-art-forest::before,
.vb-gallery-nineteen-thumb-art-forest::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-nineteen-art-forest::after,
.vb-gallery-nineteen-thumb-art-forest::after {
  right: 16%;
  top: 16%;
  width: 88px;
  height: 88px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-nineteen-overlay {
  position: absolute;
  z-index: 2;
  left: clamp(18px, 4vw, 38px);
  right: clamp(18px, 4vw, 38px);
  bottom: clamp(18px, 4vw, 34px);
  max-width: 660px;
  padding: clamp(18px, 3vw, 28px);
  border-radius: 28px;
  background: rgba(15, 23, 42, 0.70);
  border: 1px solid rgba(255,255,255,0.14);
  backdrop-filter: blur(14px);
}

.vb-gallery-nineteen-overlay > span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-gallery-nineteen-overlay h4 {
  margin: 0 0 8px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 4vw, 52px) !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.065em;
}

.vb-gallery-nineteen-overlay p {
  margin: 0 0 18px !important;
  color: #e2e8f0 !important;
  -webkit-text-fill-color: #e2e8f0 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-gallery-nineteen-progress {
  height: 10px;
  overflow: hidden;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
}

.vb-gallery-nineteen-progress div {
  width: 0%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(135deg, #818cf8, #f472b6);
}

.vb-gallery-nineteen-progress div.is-playing {
  animation: vbGalleryNineteenProgress 3.2s linear forwards;
}

@keyframes vbGalleryNineteenProgress {
  from {
    width: 0%;
  }

  to {
    width: 100%;
  }
}

.vb-gallery-nineteen-controls {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  margin-top: 18px;
  padding: 12px;
  border-radius: 24px;
  background: rgba(255,255,255,0.78);
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-gallery-nineteen-controls button {
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 12px 16px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-gallery-nineteen-controls button:nth-child(2) {
  background: linear-gradient(135deg, #4f46e5, #db2777);
  box-shadow: 0 14px 34px rgba(79, 70, 229, 0.24);
}

.vb-gallery-nineteen-thumbs {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
  margin-top: 16px;
}

.vb-gallery-nineteen-thumb {
  overflow: hidden;
  padding: 0;
  border: 2px solid transparent;
  border-radius: 20px;
  background: #ffffff;
  cursor: pointer;
  text-align: left;
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.09);
}

.vb-gallery-nineteen-thumb.is-active {
  border-color: rgba(79, 70, 229, 0.90);
  box-shadow: 0 20px 48px rgba(79, 70, 229, 0.18);
}

.vb-gallery-nineteen-thumb-art {
  position: relative;
  height: 120px;
  overflow: hidden;
}

.vb-gallery-nineteen-thumb strong {
  display: block;
  padding: 11px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 13px;
  line-height: 1.2;
  font-weight: 950;
}

@media (max-width: 820px) {
  .vb-gallery-nineteen-header {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-nineteen-header strong {
    justify-content: center;
    width: 100%;
  }

  .vb-gallery-nineteen-thumbs {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-nineteen-stage {
    min-height: 460px;
  }
}

@media (max-width: 560px) {
  .vb-gallery-nineteen-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-nineteen-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-nineteen-controls {
    display: grid;
    grid-template-columns: 1fr;
  }

  .vb-gallery-nineteen-stage {
    min-height: 520px;
    border-radius: 24px;
  }

  .vb-gallery-nineteen-overlay {
    left: 14px;
    right: 14px;
    bottom: 14px;
    border-radius: 22px;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-nineteen]");
  if (!gallery) return;

  const stageArt = gallery.querySelector("[data-vb-gallery-nineteen-art]");
  const title = gallery.querySelector("[data-vb-gallery-nineteen-title]");
  const category = gallery.querySelector("[data-vb-gallery-nineteen-category]");
  const description = gallery.querySelector("[data-vb-gallery-nineteen-description]");
  const status = gallery.querySelector("[data-vb-gallery-nineteen-status]");
  const progress = gallery.querySelector("[data-vb-gallery-nineteen-progress]");
  const prevButton = gallery.querySelector("[data-vb-gallery-nineteen-prev]");
  const nextButton = gallery.querySelector("[data-vb-gallery-nineteen-next]");
  const toggleButton = gallery.querySelector("[data-vb-gallery-nineteen-toggle]");
  const thumbs = gallery.querySelector("[data-vb-gallery-nineteen-thumbs]");

  const items = [
    {
      title: "Cinema Portfolio",
      category: "Portfolio",
      art: "vb-gallery-nineteen-art-cinema",
      thumbArt: "vb-gallery-nineteen-thumb-art-cinema",
      description: "A CSS-only portfolio slide for homepage galleries and creative showcases."
    },
    {
      title: "Sunset Campaign",
      category: "Travel",
      art: "vb-gallery-nineteen-art-sunset",
      thumbArt: "vb-gallery-nineteen-thumb-art-sunset",
      description: "A warm travel-inspired CSS slide for automatic visual storytelling."
    },
    {
      title: "Product Feature",
      category: "Product",
      art: "vb-gallery-nineteen-art-product",
      thumbArt: "vb-gallery-nineteen-thumb-art-product",
      description: "A CSS product-style slide for launch sections and visual product galleries."
    },
    {
      title: "Forest Story",
      category: "Nature",
      art: "vb-gallery-nineteen-art-forest",
      thumbArt: "vb-gallery-nineteen-thumb-art-forest",
      description: "A CSS nature slide for peaceful galleries, landing pages, and visual recaps."
    }
  ];

  let currentIndex = 0;
  let isPlaying = false;
  let timerId = null;
  const slideDuration = 3200;

  function createThumb(item, index) {
    const activeClass = index === currentIndex ? "is-active" : "";

    return `
      <button type="button" class="vb-gallery-nineteen-thumb ${activeClass}" data-index="${index}">
        <div class="vb-gallery-nineteen-thumb-art ${item.thumbArt}" aria-label="${item.title} thumbnail" role="img"></div>
        <strong>${item.title}</strong>
      </button>
    `;
  }

  function renderThumbs() {
    thumbs.innerHTML = items.map(createThumb).join("");
  }

  function resetProgress() {
    progress.classList.remove("is-playing");
    progress.style.animation = "none";
    progress.offsetHeight;
    progress.style.animation = "";
    progress.classList.toggle("is-playing", isPlaying);
  }

  function renderSlide() {
    const item = items[currentIndex];

    stageArt.classList.add("is-changing");

    window.setTimeout(function () {
      stageArt.className = "vb-gallery-nineteen-art " + item.art;
      title.textContent = item.title;
      category.textContent = item.category;
      description.textContent = item.description;
      renderThumbs();
      resetProgress();
    }, 160);
  }

  function showNext() {
    currentIndex = (currentIndex + 1) % items.length;
    renderSlide();
  }

  function showPrevious() {
    currentIndex = (currentIndex - 1 + items.length) % items.length;
    renderSlide();
  }

  function stopTimer() {
    window.clearInterval(timerId);
    timerId = null;
  }

  function startTimer() {
    stopTimer();
    timerId = window.setInterval(showNext, slideDuration);
  }

  function updatePlayState() {
    status.textContent = isPlaying ? "Playing slideshow" : "Paused";
    toggleButton.textContent = isPlaying ? "Pause Slideshow" : "Start Slideshow";
    resetProgress();

    if (isPlaying) {
      startTimer();
    } else {
      stopTimer();
    }
  }

  prevButton.addEventListener("click", function () {
    showPrevious();

    if (isPlaying) {
      startTimer();
    }
  });

  nextButton.addEventListener("click", function () {
    showNext();

    if (isPlaying) {
      startTimer();
    }
  });

  toggleButton.addEventListener("click", function () {
    isPlaying = !isPlaying;
    updatePlayState();
  });

  thumbs.addEventListener("click", function (event) {
    const thumb = event.target.closest("[data-index]");
    if (!thumb) return;

    currentIndex = Number(thumb.getAttribute("data-index"));
    renderSlide();

    if (isPlaying) {
      startTimer();
    }
  });

  renderSlide();
  updatePlayState();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-nineteen]");
  if (!gallery) return;

  const stageArt = gallery.querySelector("[data-vb-gallery-nineteen-art]");
  const title = gallery.querySelector("[data-vb-gallery-nineteen-title]");
  const category = gallery.querySelector("[data-vb-gallery-nineteen-category]");
  const description = gallery.querySelector("[data-vb-gallery-nineteen-description]");
  const status = gallery.querySelector("[data-vb-gallery-nineteen-status]");
  const progress = gallery.querySelector("[data-vb-gallery-nineteen-progress]");
  const prevButton = gallery.querySelector("[data-vb-gallery-nineteen-prev]");
  const nextButton = gallery.querySelector("[data-vb-gallery-nineteen-next]");
  const toggleButton = gallery.querySelector("[data-vb-gallery-nineteen-toggle]");
  const thumbs = gallery.querySelector("[data-vb-gallery-nineteen-thumbs]");

  const items = [
    {
      title: "Cinema Portfolio",
      category: "Portfolio",
      art: "vb-gallery-nineteen-art-cinema",
      thumbArt: "vb-gallery-nineteen-thumb-art-cinema",
      description: "A CSS-only portfolio slide for homepage galleries and creative showcases."
    },
    {
      title: "Sunset Campaign",
      category: "Travel",
      art: "vb-gallery-nineteen-art-sunset",
      thumbArt: "vb-gallery-nineteen-thumb-art-sunset",
      description: "A warm travel-inspired CSS slide for automatic visual storytelling."
    },
    {
      title: "Product Feature",
      category: "Product",
      art: "vb-gallery-nineteen-art-product",
      thumbArt: "vb-gallery-nineteen-thumb-art-product",
      description: "A CSS product-style slide for launch sections and visual product galleries."
    },
    {
      title: "Forest Story",
      category: "Nature",
      art: "vb-gallery-nineteen-art-forest",
      thumbArt: "vb-gallery-nineteen-thumb-art-forest",
      description: "A CSS nature slide for peaceful galleries, landing pages, and visual recaps."
    }
  ];

  let currentIndex = 0;
  let isPlaying = false;
  let timerId = null;
  const slideDuration = 3200;

  function createThumb(item, index) {
    const activeClass = index === currentIndex ? "is-active" : "";

    return `
      &lt;button type="button" class="vb-gallery-nineteen-thumb ${activeClass}" data-index="${index}"&gt;
        &lt;div class="vb-gallery-nineteen-thumb-art ${item.thumbArt}" aria-label="${item.title} thumbnail" role="img"&gt;&lt;/div&gt;
        &lt;strong&gt;${item.title}&lt;/strong&gt;
      &lt;/button&gt;
    `;
  }

  function renderThumbs() {
    thumbs.innerHTML = items.map(createThumb).join("");
  }

  function resetProgress() {
    progress.classList.remove("is-playing");
    progress.style.animation = "none";
    progress.offsetHeight;
    progress.style.animation = "";
    progress.classList.toggle("is-playing", isPlaying);
  }

  function renderSlide() {
    const item = items[currentIndex];

    stageArt.classList.add("is-changing");

    window.setTimeout(function () {
      stageArt.className = "vb-gallery-nineteen-art " + item.art;
      title.textContent = item.title;
      category.textContent = item.category;
      description.textContent = item.description;
      renderThumbs();
      resetProgress();
    }, 160);
  }

  function showNext() {
    currentIndex = (currentIndex + 1) % items.length;
    renderSlide();
  }

  function showPrevious() {
    currentIndex = (currentIndex - 1 + items.length) % items.length;
    renderSlide();
  }

  function stopTimer() {
    window.clearInterval(timerId);
    timerId = null;
  }

  function startTimer() {
    stopTimer();
    timerId = window.setInterval(showNext, slideDuration);
  }

  function updatePlayState() {
    status.textContent = isPlaying ? "Playing slideshow" : "Paused";
    toggleButton.textContent = isPlaying ? "Pause Slideshow" : "Start Slideshow";
    resetProgress();

    if (isPlaying) {
      startTimer();
    } else {
      stopTimer();
    }
  }

  prevButton.addEventListener("click", function () {
    showPrevious();

    if (isPlaying) {
      startTimer();
    }
  });

  nextButton.addEventListener("click", function () {
    showNext();

    if (isPlaying) {
      startTimer();
    }
  });

  toggleButton.addEventListener("click", function () {
    isPlaying = !isPlaying;
    updatePlayState();
  });

  thumbs.addEventListener("click", function (event) {
    const thumb = event.target.closest("[data-index]");
    if (!thumb) return;

    currentIndex = Number(thumb.getAttribute("data-index"));
    renderSlide();

    if (isPlaying) {
      startTimer();
    }
  });

  renderSlide();
  updatePlayState();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-nineteen-demo"&gt;
  &lt;div class="vb-gallery-nineteen-shell" data-vb-gallery-nineteen&gt;
    &lt;div class="vb-gallery-nineteen-header"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 19&lt;/span&gt;
        &lt;h3&gt;Image Gallery with Slideshow Mode&lt;/h3&gt;
        &lt;p&gt;Turn a CSS-illustrated gallery into an automatic slideshow with JavaScript controls.&lt;/p&gt;
      &lt;/div&gt;

      &lt;strong data-vb-gallery-nineteen-status&gt;Paused&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-nineteen-stage"&gt;
      &lt;div class="vb-gallery-nineteen-art" data-vb-gallery-nineteen-art&gt;&lt;/div&gt;

      &lt;div class="vb-gallery-nineteen-overlay"&gt;
        &lt;span data-vb-gallery-nineteen-category&gt;Category&lt;/span&gt;
        &lt;h4 data-vb-gallery-nineteen-title&gt;Gallery Title&lt;/h4&gt;
        &lt;p data-vb-gallery-nineteen-description&gt;Gallery description.&lt;/p&gt;

        &lt;div class="vb-gallery-nineteen-progress"&gt;
          &lt;div data-vb-gallery-nineteen-progress&gt;&lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-nineteen-controls"&gt;
      &lt;button type="button" data-vb-gallery-nineteen-prev&gt;Previous&lt;/button&gt;
      &lt;button type="button" data-vb-gallery-nineteen-toggle&gt;Start Slideshow&lt;/button&gt;
      &lt;button type="button" data-vb-gallery-nineteen-next&gt;Next&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-nineteen-thumbs" data-vb-gallery-nineteen-thumbs&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-nineteen-demo,
.vb-gallery-nineteen-demo * {
  box-sizing: border-box;
}

.vb-gallery-nineteen-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 42px;
  background:
    radial-gradient(circle at 12% 12%, rgba(79, 70, 229, 0.18), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(236, 72, 153, 0.16), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #fdf2f8 52%, #ffffff 100%) !important;
  border: 1px solid rgba(129, 140, 248, 0.24);
  box-shadow: 0 28px 80px rgba(67, 56, 202, 0.10);
}

.vb-gallery-nineteen-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-nineteen-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 22px;
}

.vb-gallery-nineteen-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #e0e7ff;
  color: #3730a3 !important;
  -webkit-text-fill-color: #3730a3 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-nineteen-header h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-nineteen-header p {
  max-width: 730px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-nineteen-header strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-nineteen-stage {
  position: relative;
  min-height: 520px;
  overflow: hidden;
  border-radius: 34px;
  background: #111827;
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.18);
}

.vb-gallery-nineteen-art {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: #111827;
  transition: opacity 0.3s ease, transform 0.3s ease;
}

.vb-gallery-nineteen-art::before,
.vb-gallery-nineteen-art::after,
.vb-gallery-nineteen-thumb-art::before,
.vb-gallery-nineteen-thumb-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-nineteen-art.is-changing {
  opacity: 0.35;
  transform: scale(1.03);
}

.vb-gallery-nineteen-art-cinema,
.vb-gallery-nineteen-thumb-art-cinema {
  background: linear-gradient(135deg, #020617 0%, #312e81 50%, #7c3aed 100%);
}

.vb-gallery-nineteen-art-cinema::before,
.vb-gallery-nineteen-thumb-art-cinema::before {
  left: 12%;
  top: 18%;
  width: 76%;
  height: 58%;
  border-radius: 32px;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.22), rgba(255,255,255,0.04)),
    repeating-linear-gradient(90deg, rgba(255,255,255,0.17) 0 4px, transparent 4px 24px);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-nineteen-art-cinema::after,
.vb-gallery-nineteen-thumb-art-cinema::after {
  right: 18%;
  bottom: 18%;
  width: 104px;
  height: 104px;
  border-radius: 999px;
  background: rgba(255,255,255,0.24);
  filter: blur(8px);
}

.vb-gallery-nineteen-art-sunset,
.vb-gallery-nineteen-thumb-art-sunset {
  background: linear-gradient(180deg, #fde68a 0%, #fb923c 48%, #7c2d12 100%);
}

.vb-gallery-nineteen-art-sunset::before,
.vb-gallery-nineteen-thumb-art-sunset::before {
  left: -8%;
  right: -8%;
  bottom: -18%;
  height: 56%;
  background: #431407;
  clip-path: polygon(0 100%, 0 58%, 15% 42%, 30% 66%, 48% 34%, 66% 62%, 83% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-nineteen-art-sunset::after,
.vb-gallery-nineteen-thumb-art-sunset::after {
  right: 18%;
  top: 16%;
  width: 92px;
  height: 92px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 70px rgba(255,247,237,0.72);
}

.vb-gallery-nineteen-art-product,
.vb-gallery-nineteen-thumb-art-product {
  background: radial-gradient(circle at 50% 44%, #ffffff 0%, #f3e8ff 36%, #581c87 100%);
}

.vb-gallery-nineteen-art-product::before,
.vb-gallery-nineteen-thumb-art-product::before {
  left: 50%;
  top: 50%;
  width: 156px;
  height: 156px;
  border-radius: 34px;
  background: linear-gradient(135deg, #ffffff, #c4b5fd);
  box-shadow: 0 30px 80px rgba(88,28,135,0.34);
  transform: translate(-50%, -50%) rotate(16deg);
}

.vb-gallery-nineteen-art-product::after,
.vb-gallery-nineteen-thumb-art-product::after {
  left: 50%;
  top: 50%;
  width: 82px;
  height: 82px;
  border-radius: 22px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(16deg);
}

.vb-gallery-nineteen-art-forest,
.vb-gallery-nineteen-thumb-art-forest {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-nineteen-art-forest::before,
.vb-gallery-nineteen-thumb-art-forest::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-nineteen-art-forest::after,
.vb-gallery-nineteen-thumb-art-forest::after {
  right: 16%;
  top: 16%;
  width: 88px;
  height: 88px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-nineteen-overlay {
  position: absolute;
  z-index: 2;
  left: clamp(18px, 4vw, 38px);
  right: clamp(18px, 4vw, 38px);
  bottom: clamp(18px, 4vw, 34px);
  max-width: 660px;
  padding: clamp(18px, 3vw, 28px);
  border-radius: 28px;
  background: rgba(15, 23, 42, 0.70);
  border: 1px solid rgba(255,255,255,0.14);
  backdrop-filter: blur(14px);
}

.vb-gallery-nineteen-overlay > span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-gallery-nineteen-overlay h4 {
  margin: 0 0 8px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 4vw, 52px) !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.065em;
}

.vb-gallery-nineteen-overlay p {
  margin: 0 0 18px !important;
  color: #e2e8f0 !important;
  -webkit-text-fill-color: #e2e8f0 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-gallery-nineteen-progress {
  height: 10px;
  overflow: hidden;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
}

.vb-gallery-nineteen-progress div {
  width: 0%;
  height: 100%;
  border-radius: inherit;
  background: linear-gradient(135deg, #818cf8, #f472b6);
}

.vb-gallery-nineteen-progress div.is-playing {
  animation: vbGalleryNineteenProgress 3.2s linear forwards;
}

@keyframes vbGalleryNineteenProgress {
  from {
    width: 0%;
  }

  to {
    width: 100%;
  }
}

.vb-gallery-nineteen-controls {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
  margin-top: 18px;
  padding: 12px;
  border-radius: 24px;
  background: rgba(255,255,255,0.78);
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-gallery-nineteen-controls button {
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 12px 16px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
}

.vb-gallery-nineteen-controls button:nth-child(2) {
  background: linear-gradient(135deg, #4f46e5, #db2777);
  box-shadow: 0 14px 34px rgba(79, 70, 229, 0.24);
}

.vb-gallery-nineteen-thumbs {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 12px;
  margin-top: 16px;
}

.vb-gallery-nineteen-thumb {
  overflow: hidden;
  padding: 0;
  border: 2px solid transparent;
  border-radius: 20px;
  background: #ffffff;
  cursor: pointer;
  text-align: left;
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.09);
}

.vb-gallery-nineteen-thumb.is-active {
  border-color: rgba(79, 70, 229, 0.90);
  box-shadow: 0 20px 48px rgba(79, 70, 229, 0.18);
}

.vb-gallery-nineteen-thumb-art {
  position: relative;
  height: 120px;
  overflow: hidden;
}

.vb-gallery-nineteen-thumb strong {
  display: block;
  padding: 11px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 13px;
  line-height: 1.2;
  font-weight: 950;
}

@media (max-width: 820px) {
  .vb-gallery-nineteen-header {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-nineteen-header strong {
    justify-content: center;
    width: 100%;
  }

  .vb-gallery-nineteen-thumbs {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-nineteen-stage {
    min-height: 460px;
  }
}

@media (max-width: 560px) {
  .vb-gallery-nineteen-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-nineteen-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-nineteen-controls {
    display: grid;
    grid-template-columns: 1fr;
  }

  .vb-gallery-nineteen-stage {
    min-height: 520px;
    border-radius: 24px;
  }

  .vb-gallery-nineteen-overlay {
    left: 14px;
    right: 14px;
    bottom: 14px;
    border-radius: 22px;
  }
}</pre>



<p class="wp-block-paragraph">This image gallery with slideshow mode is useful for homepage showcases, portfolio highlights, product previews, event recaps, travel galleries, presentation-style sections, and visual landing pages where gallery content should rotate automatically.</p>



<h2 class="wp-block-heading">20. Image Gallery with Search</h2>



<p class="wp-block-paragraph"><strong>An image gallery with search</strong> helps users find relevant visuals quickly inside a larger gallery. This pattern is useful for media libraries, portfolio archives, product galleries, documentation image collections, real estate listings, travel galleries, and design inspiration pages.</p>



<p class="wp-block-paragraph">This example uses JavaScript text search across gallery titles, categories, and keywords. As the user types, the gallery updates immediately, the result count changes, and an empty state appears when no items match. The thumbnails are CSS-only illustrations, so the demo does not use external images.</p>



<ul class="wp-block-list">
<li>Searchable JavaScript image gallery</li>
<li>Live search input filtering</li>
<li>Searches title, category, and keywords</li>
<li>Dynamic result counter and empty state</li>
<li>CSS-only illustrated thumbnails</li>
</ul>



<div class="vb-gallery-twenty-demo">
  <div class="vb-gallery-twenty-shell" data-vb-gallery-twenty>
    <div class="vb-gallery-twenty-hero">
      <span>Example 20</span>
      <h3>Image Gallery with Search</h3>
      <p>Search CSS-illustrated gallery items by title, category, and keywords with JavaScript live filtering.</p>

      <div class="vb-gallery-twenty-search">
        <input type="search" placeholder="Search gallery items, for example: product, forest, blue..." data-vb-gallery-twenty-search>
        <strong data-vb-gallery-twenty-count>0 results</strong>
      </div>
    </div>

    <div class="vb-gallery-twenty-grid" data-vb-gallery-twenty-grid></div>

    <div class="vb-gallery-twenty-empty" data-vb-gallery-twenty-empty hidden>
      <h4>No gallery items found</h4>
      <p>Try searching for portfolio, product, travel, forest, blue, sunset, abstract, or city.</p>
    </div>
  </div>
</div>

<style>
.vb-gallery-twenty-demo,
.vb-gallery-twenty-demo * {
  box-sizing: border-box;
}

.vb-gallery-twenty-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    linear-gradient(90deg, rgba(15, 23, 42, 0.05) 1px, transparent 1px),
    linear-gradient(0deg, rgba(15, 23, 42, 0.05) 1px, transparent 1px),
    linear-gradient(135deg, #f8fafc 0%, #f0f9ff 52%, #ffffff 100%) !important;
  background-size: 32px 32px, 32px 32px, auto !important;
  border: 1px solid rgba(14, 165, 233, 0.20);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.09);
}

.vb-gallery-twenty-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-twenty-hero {
  margin-bottom: 24px;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 16% 18%, rgba(255,255,255,0.14), transparent 34%),
    linear-gradient(135deg, #082f49, #1d4ed8 52%, #0f172a) !important;
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.22);
}

.vb-gallery-twenty-hero > span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-twenty-hero h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-twenty-hero p {
  max-width: 760px;
  margin: 0 0 22px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-twenty-search {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 12px;
  max-width: 820px;
}

.vb-gallery-twenty-search input {
  width: 100%;
  min-height: 54px;
  border: 1px solid rgba(255,255,255,0.22);
  border-radius: 18px;
  background: rgba(255,255,255,0.12);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 0 16px;
  font-size: 15px;
  font-weight: 750;
  outline: none;
  backdrop-filter: blur(10px);
}

.vb-gallery-twenty-search input::placeholder {
  color: rgba(255,255,255,0.68);
  -webkit-text-fill-color: rgba(255,255,255,0.68);
}

.vb-gallery-twenty-search input:focus {
  border-color: rgba(186, 230, 253, 0.90);
  box-shadow: 0 0 0 4px rgba(186, 230, 253, 0.12);
}

.vb-gallery-twenty-search strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 54px;
  padding: 0 16px;
  border-radius: 18px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-twenty-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-twenty-card {
  overflow: hidden;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  animation: vbGalleryTwentyIn 0.32s ease both;
}

@keyframes vbGalleryTwentyIn {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.vb-gallery-twenty-art {
  position: relative;
  height: 225px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-twenty-art::before,
.vb-gallery-twenty-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-twenty-art-blue {
  background: linear-gradient(135deg, #020617 0%, #2563eb 54%, #38bdf8 100%);
}

.vb-gallery-twenty-art-blue::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 60%;
  border-radius: 28px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 20px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-twenty-art-blue::after {
  right: 16%;
  bottom: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-twenty-art-sunset {
  background: linear-gradient(180deg, #fde68a 0%, #fb923c 48%, #7c2d12 100%);
}

.vb-gallery-twenty-art-sunset::before {
  left: -8%;
  right: -8%;
  bottom: -18%;
  height: 56%;
  background: #431407;
  clip-path: polygon(0 100%, 0 58%, 15% 42%, 30% 66%, 48% 34%, 66% 62%, 83% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-twenty-art-sunset::after {
  right: 18%;
  top: 16%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 64px rgba(255,247,237,0.72);
}

.vb-gallery-twenty-art-product {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #e0e7ff 36%, #3730a3 100%);
}

.vb-gallery-twenty-art-product::before {
  left: 50%;
  top: 50%;
  width: 130px;
  height: 130px;
  border-radius: 30px;
  background: linear-gradient(135deg, #ffffff, #c7d2fe);
  box-shadow: 0 30px 80px rgba(55,48,163,0.32);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twenty-art-product::after {
  left: 50%;
  top: 50%;
  width: 68px;
  height: 68px;
  border-radius: 20px;
  border: 4px solid rgba(79,70,229,0.46);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twenty-art-forest {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-twenty-art-forest::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-twenty-art-forest::after {
  right: 16%;
  top: 16%;
  width: 80px;
  height: 80px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-twenty-art-city {
  background: linear-gradient(180deg, #312e81 0%, #111827 66%, #020617 100%);
}

.vb-gallery-twenty-art-city::before {
  left: 10%;
  bottom: 0;
  width: 18%;
  height: 58%;
  background: #020617;
  box-shadow:
    70px -42px 0 #020617,
    142px -12px 0 #020617,
    224px -62px 0 #020617,
    304px -24px 0 #020617;
}

.vb-gallery-twenty-art-city::after {
  inset: 18% 10% auto 10%;
  height: 3px;
  background: repeating-linear-gradient(90deg, rgba(255,255,255,0.82) 0 8px, transparent 8px 24px);
  box-shadow:
    0 34px 0 rgba(255,255,255,0.42),
    0 70px 0 rgba(255,255,255,0.22);
}

.vb-gallery-twenty-art-abstract {
  background: linear-gradient(135deg, #500724 0%, #be123c 52%, #fb7185 100%);
}

.vb-gallery-twenty-art-abstract::before {
  left: 50%;
  top: 52%;
  width: 140px;
  height: 140px;
  border-radius: 42% 58% 62% 38%;
  background: radial-gradient(circle at 35% 30%, #fff1f2, #fb7185 44%, #9f1239 100%);
  transform: translate(-50%, -50%) rotate(22deg);
  box-shadow: 0 26px 70px rgba(80,7,36,0.36);
}

.vb-gallery-twenty-art-abstract::after {
  left: 14%;
  top: 16%;
  width: 74px;
  height: 74px;
  border-radius: 999px;
  background: rgba(255,255,255,0.22);
  filter: blur(6px);
}

.vb-gallery-twenty-body {
  display: grid;
  gap: 8px;
  padding: 17px;
}

.vb-gallery-twenty-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-twenty-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 21px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-twenty-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-gallery-twenty-empty {
  margin-top: 18px;
  padding: 28px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px dashed rgba(14, 165, 233, 0.36);
  text-align: center;
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.07);
}

.vb-gallery-twenty-empty h4 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 24px !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
}

.vb-gallery-twenty-empty p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 1050px) {
  .vb-gallery-twenty-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 820px) {
  .vb-gallery-twenty-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-twenty-search {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-gallery-twenty-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-twenty-hero h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-twenty-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-twenty]");
  if (!gallery) return;

  const searchInput = gallery.querySelector("[data-vb-gallery-twenty-search]");
  const grid = gallery.querySelector("[data-vb-gallery-twenty-grid]");
  const count = gallery.querySelector("[data-vb-gallery-twenty-count]");
  const empty = gallery.querySelector("[data-vb-gallery-twenty-empty]");

  const items = [
    {
      title: "Blue Portfolio",
      category: "Portfolio",
      keywords: "blue web design project interface agency",
      art: "vb-gallery-twenty-art-blue",
      description: "A CSS-only blue portfolio card for searchable gallery interfaces."
    },
    {
      title: "Sunset Travel",
      category: "Travel",
      keywords: "sunset orange mountain travel warm destination",
      art: "vb-gallery-twenty-art-sunset",
      description: "A CSS sunset card for travel gallery search examples."
    },
    {
      title: "Product Display",
      category: "Product",
      keywords: "product ecommerce object shop launch item",
      art: "vb-gallery-twenty-art-product",
      description: "A CSS product thumbnail for searchable ecommerce galleries."
    },
    {
      title: "Forest Route",
      category: "Nature",
      keywords: "forest green nature outdoor trees landscape",
      art: "vb-gallery-twenty-art-forest",
      description: "A CSS forest image card for nature gallery searches."
    },
    {
      title: "City Night",
      category: "Architecture",
      keywords: "city night skyline architecture urban dark buildings",
      art: "vb-gallery-twenty-art-city",
      description: "A CSS city card for architecture and urban image searches."
    },
    {
      title: "Abstract Rose",
      category: "Abstract",
      keywords: "abstract pink rose creative shape poster",
      art: "vb-gallery-twenty-art-abstract",
      description: "A CSS abstract gallery item for creative search filters."
    }
  ];

  function createCard(item, index) {
    return `
      <article class="vb-gallery-twenty-card" style="animation-delay: ${index * 45}ms">
        <div class="vb-gallery-twenty-art ${item.art}" aria-label="${item.title} illustration" role="img"></div>

        <div class="vb-gallery-twenty-body">
          <span>${item.category}</span>
          <h4>${item.title}</h4>
          <p>${item.description}</p>
        </div>
      </article>
    `;
  }

  function searchItems(query) {
    const normalizedQuery = query.trim().toLowerCase();

    if (!normalizedQuery) {
      return items;
    }

    return items.filter(function (item) {
      const searchableText = [
        item.title,
        item.category,
        item.keywords,
        item.description
      ].join(" ").toLowerCase();

      return searchableText.includes(normalizedQuery);
    });
  }

  function renderGallery() {
    const visibleItems = searchItems(searchInput.value);

    grid.innerHTML = visibleItems.map(createCard).join("");
    count.textContent = visibleItems.length === 1 ? "1 result" : visibleItems.length + " results";
    empty.hidden = visibleItems.length > 0;
  }

  searchInput.addEventListener("input", renderGallery);

  renderGallery();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-twenty]");
  if (!gallery) return;

  const searchInput = gallery.querySelector("[data-vb-gallery-twenty-search]");
  const grid = gallery.querySelector("[data-vb-gallery-twenty-grid]");
  const count = gallery.querySelector("[data-vb-gallery-twenty-count]");
  const empty = gallery.querySelector("[data-vb-gallery-twenty-empty]");

  const items = [
    {
      title: "Blue Portfolio",
      category: "Portfolio",
      keywords: "blue web design project interface agency",
      art: "vb-gallery-twenty-art-blue",
      description: "A CSS-only blue portfolio card for searchable gallery interfaces."
    },
    {
      title: "Sunset Travel",
      category: "Travel",
      keywords: "sunset orange mountain travel warm destination",
      art: "vb-gallery-twenty-art-sunset",
      description: "A CSS sunset card for travel gallery search examples."
    },
    {
      title: "Product Display",
      category: "Product",
      keywords: "product ecommerce object shop launch item",
      art: "vb-gallery-twenty-art-product",
      description: "A CSS product thumbnail for searchable ecommerce galleries."
    },
    {
      title: "Forest Route",
      category: "Nature",
      keywords: "forest green nature outdoor trees landscape",
      art: "vb-gallery-twenty-art-forest",
      description: "A CSS forest image card for nature gallery searches."
    },
    {
      title: "City Night",
      category: "Architecture",
      keywords: "city night skyline architecture urban dark buildings",
      art: "vb-gallery-twenty-art-city",
      description: "A CSS city card for architecture and urban image searches."
    },
    {
      title: "Abstract Rose",
      category: "Abstract",
      keywords: "abstract pink rose creative shape poster",
      art: "vb-gallery-twenty-art-abstract",
      description: "A CSS abstract gallery item for creative search filters."
    }
  ];

  function createCard(item, index) {
    return `
      &lt;article class="vb-gallery-twenty-card" style="animation-delay: ${index * 45}ms"&gt;
        &lt;div class="vb-gallery-twenty-art ${item.art}" aria-label="${item.title} illustration" role="img"&gt;&lt;/div&gt;

        &lt;div class="vb-gallery-twenty-body"&gt;
          &lt;span&gt;${item.category}&lt;/span&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
          &lt;p&gt;${item.description}&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    `;
  }

  function searchItems(query) {
    const normalizedQuery = query.trim().toLowerCase();

    if (!normalizedQuery) {
      return items;
    }

    return items.filter(function (item) {
      const searchableText = [
        item.title,
        item.category,
        item.keywords,
        item.description
      ].join(" ").toLowerCase();

      return searchableText.includes(normalizedQuery);
    });
  }

  function renderGallery() {
    const visibleItems = searchItems(searchInput.value);

    grid.innerHTML = visibleItems.map(createCard).join("");
    count.textContent = visibleItems.length === 1 ? "1 result" : visibleItems.length + " results";
    empty.hidden = visibleItems.length &gt; 0;
  }

  searchInput.addEventListener("input", renderGallery);

  renderGallery();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-twenty-demo"&gt;
  &lt;div class="vb-gallery-twenty-shell" data-vb-gallery-twenty&gt;
    &lt;div class="vb-gallery-twenty-hero"&gt;
      &lt;span&gt;Example 20&lt;/span&gt;
      &lt;h3&gt;Image Gallery with Search&lt;/h3&gt;
      &lt;p&gt;Search CSS-illustrated gallery items by title, category, and keywords with JavaScript live filtering.&lt;/p&gt;

      &lt;div class="vb-gallery-twenty-search"&gt;
        &lt;input type="search" placeholder="Search gallery items, for example: product, forest, blue..." data-vb-gallery-twenty-search&gt;
        &lt;strong data-vb-gallery-twenty-count&gt;0 results&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-twenty-grid" data-vb-gallery-twenty-grid&gt;&lt;/div&gt;

    &lt;div class="vb-gallery-twenty-empty" data-vb-gallery-twenty-empty hidden&gt;
      &lt;h4&gt;No gallery items found&lt;/h4&gt;
      &lt;p&gt;Try searching for portfolio, product, travel, forest, blue, sunset, abstract, or city.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-twenty-demo,
.vb-gallery-twenty-demo * {
  box-sizing: border-box;
}

.vb-gallery-twenty-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    linear-gradient(90deg, rgba(15, 23, 42, 0.05) 1px, transparent 1px),
    linear-gradient(0deg, rgba(15, 23, 42, 0.05) 1px, transparent 1px),
    linear-gradient(135deg, #f8fafc 0%, #f0f9ff 52%, #ffffff 100%) !important;
  background-size: 32px 32px, 32px 32px, auto !important;
  border: 1px solid rgba(14, 165, 233, 0.20);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.09);
}

.vb-gallery-twenty-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-twenty-hero {
  margin-bottom: 24px;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 16% 18%, rgba(255,255,255,0.14), transparent 34%),
    linear-gradient(135deg, #082f49, #1d4ed8 52%, #0f172a) !important;
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.22);
}

.vb-gallery-twenty-hero > span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.13);
  border: 1px solid rgba(255,255,255,0.18);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-twenty-hero h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-twenty-hero p {
  max-width: 760px;
  margin: 0 0 22px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-twenty-search {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  gap: 12px;
  max-width: 820px;
}

.vb-gallery-twenty-search input {
  width: 100%;
  min-height: 54px;
  border: 1px solid rgba(255,255,255,0.22);
  border-radius: 18px;
  background: rgba(255,255,255,0.12);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 0 16px;
  font-size: 15px;
  font-weight: 750;
  outline: none;
  backdrop-filter: blur(10px);
}

.vb-gallery-twenty-search input::placeholder {
  color: rgba(255,255,255,0.68);
  -webkit-text-fill-color: rgba(255,255,255,0.68);
}

.vb-gallery-twenty-search input:focus {
  border-color: rgba(186, 230, 253, 0.90);
  box-shadow: 0 0 0 4px rgba(186, 230, 253, 0.12);
}

.vb-gallery-twenty-search strong {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 54px;
  padding: 0 16px;
  border-radius: 18px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-twenty-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-twenty-card {
  overflow: hidden;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  animation: vbGalleryTwentyIn 0.32s ease both;
}

@keyframes vbGalleryTwentyIn {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.vb-gallery-twenty-art {
  position: relative;
  height: 225px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-twenty-art::before,
.vb-gallery-twenty-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-twenty-art-blue {
  background: linear-gradient(135deg, #020617 0%, #2563eb 54%, #38bdf8 100%);
}

.vb-gallery-twenty-art-blue::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 60%;
  border-radius: 28px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 20px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-twenty-art-blue::after {
  right: 16%;
  bottom: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-twenty-art-sunset {
  background: linear-gradient(180deg, #fde68a 0%, #fb923c 48%, #7c2d12 100%);
}

.vb-gallery-twenty-art-sunset::before {
  left: -8%;
  right: -8%;
  bottom: -18%;
  height: 56%;
  background: #431407;
  clip-path: polygon(0 100%, 0 58%, 15% 42%, 30% 66%, 48% 34%, 66% 62%, 83% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-twenty-art-sunset::after {
  right: 18%;
  top: 16%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 64px rgba(255,247,237,0.72);
}

.vb-gallery-twenty-art-product {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #e0e7ff 36%, #3730a3 100%);
}

.vb-gallery-twenty-art-product::before {
  left: 50%;
  top: 50%;
  width: 130px;
  height: 130px;
  border-radius: 30px;
  background: linear-gradient(135deg, #ffffff, #c7d2fe);
  box-shadow: 0 30px 80px rgba(55,48,163,0.32);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twenty-art-product::after {
  left: 50%;
  top: 50%;
  width: 68px;
  height: 68px;
  border-radius: 20px;
  border: 4px solid rgba(79,70,229,0.46);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twenty-art-forest {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-twenty-art-forest::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-twenty-art-forest::after {
  right: 16%;
  top: 16%;
  width: 80px;
  height: 80px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-twenty-art-city {
  background: linear-gradient(180deg, #312e81 0%, #111827 66%, #020617 100%);
}

.vb-gallery-twenty-art-city::before {
  left: 10%;
  bottom: 0;
  width: 18%;
  height: 58%;
  background: #020617;
  box-shadow:
    70px -42px 0 #020617,
    142px -12px 0 #020617,
    224px -62px 0 #020617,
    304px -24px 0 #020617;
}

.vb-gallery-twenty-art-city::after {
  inset: 18% 10% auto 10%;
  height: 3px;
  background: repeating-linear-gradient(90deg, rgba(255,255,255,0.82) 0 8px, transparent 8px 24px);
  box-shadow:
    0 34px 0 rgba(255,255,255,0.42),
    0 70px 0 rgba(255,255,255,0.22);
}

.vb-gallery-twenty-art-abstract {
  background: linear-gradient(135deg, #500724 0%, #be123c 52%, #fb7185 100%);
}

.vb-gallery-twenty-art-abstract::before {
  left: 50%;
  top: 52%;
  width: 140px;
  height: 140px;
  border-radius: 42% 58% 62% 38%;
  background: radial-gradient(circle at 35% 30%, #fff1f2, #fb7185 44%, #9f1239 100%);
  transform: translate(-50%, -50%) rotate(22deg);
  box-shadow: 0 26px 70px rgba(80,7,36,0.36);
}

.vb-gallery-twenty-art-abstract::after {
  left: 14%;
  top: 16%;
  width: 74px;
  height: 74px;
  border-radius: 999px;
  background: rgba(255,255,255,0.22);
  filter: blur(6px);
}

.vb-gallery-twenty-body {
  display: grid;
  gap: 8px;
  padding: 17px;
}

.vb-gallery-twenty-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-twenty-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 21px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-twenty-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-gallery-twenty-empty {
  margin-top: 18px;
  padding: 28px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px dashed rgba(14, 165, 233, 0.36);
  text-align: center;
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.07);
}

.vb-gallery-twenty-empty h4 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 24px !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
}

.vb-gallery-twenty-empty p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 1050px) {
  .vb-gallery-twenty-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 820px) {
  .vb-gallery-twenty-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-twenty-search {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 560px) {
  .vb-gallery-twenty-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-twenty-hero h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-twenty-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This image gallery with search is useful for large media libraries, portfolio archives, product galleries, travel collections, real estate listings, documentation visuals, and any image-heavy page where users need to find specific visuals quickly.</p>



<h2 class="wp-block-heading">21. Image Gallery with Keyboard Navigation</h2>



<p class="wp-block-paragraph"><strong>An image gallery with keyboard navigation</strong> improves usability by letting visitors move through gallery items with the keyboard. This pattern is useful for portfolio galleries, product previews, media libraries, documentation galleries, presentation sections, and accessible image viewers.</p>



<p class="wp-block-paragraph">This example uses JavaScript keyboard event handling. Users can click a gallery item, then use Arrow Left and Arrow Right to move between items. The selected item, preview artwork, title, category, and counter update dynamically. All visuals are CSS-only illustrations, so the example does not use external image files.</p>



<ul class="wp-block-list">
<li>Keyboard-friendly JavaScript image gallery</li>
<li>Arrow Left and Arrow Right navigation</li>
<li>Clickable gallery thumbnails</li>
<li>Dynamic selected image preview</li>
<li>CSS-only illustrated gallery visuals</li>
</ul>



<div class="vb-gallery-twentyone-demo">
  <div class="vb-gallery-twentyone-shell" data-vb-gallery-twentyone>
    <div class="vb-gallery-twentyone-header">
      <div>
        <span>Example 21</span>
        <h3>Image Gallery with Keyboard Navigation</h3>
        <p>Click a gallery item, then use Arrow Left and Arrow Right to move through CSS-illustrated images.</p>
      </div>

      <strong data-vb-gallery-twentyone-counter>1 / 5</strong>
    </div>

    <div class="vb-gallery-twentyone-layout">
      <div class="vb-gallery-twentyone-preview">
        <div class="vb-gallery-twentyone-preview-art" data-vb-gallery-twentyone-preview-art></div>

        <div class="vb-gallery-twentyone-preview-content">
          <span data-vb-gallery-twentyone-category>Category</span>
          <h4 data-vb-gallery-twentyone-title>Gallery Item</h4>
          <p data-vb-gallery-twentyone-description>Use the keyboard to move between items.</p>

          <div class="vb-gallery-twentyone-keys">
            <kbd>←</kbd>
            <span>Use keyboard arrows</span>
            <kbd>→</kbd>
          </div>
        </div>
      </div>

      <div class="vb-gallery-twentyone-list" data-vb-gallery-twentyone-list></div>
    </div>
  </div>
</div>

<style>
.vb-gallery-twentyone-demo,
.vb-gallery-twentyone-demo * {
  box-sizing: border-box;
}

.vb-gallery-twentyone-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 12% 12%, rgba(37, 99, 235, 0.16), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(20, 184, 166, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #f0fdfa 52%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.22);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-gallery-twentyone-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-twentyone-header {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 24px;
}

.vb-gallery-twentyone-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-twentyone-header h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-twentyone-header p {
  max-width: 740px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-twentyone-header strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-twentyone-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(280px, 360px);
  gap: 18px;
  align-items: stretch;
}

.vb-gallery-twentyone-preview {
  position: relative;
  overflow: hidden;
  min-height: 560px;
  border-radius: 34px;
  background: #0f172a;
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.18);
}

.vb-gallery-twentyone-preview-art {
  position: absolute;
  inset: 0;
  overflow: hidden;
  background: #111827;
  transition: transform 0.32s ease, opacity 0.32s ease;
}

.vb-gallery-twentyone-preview-art.is-changing {
  opacity: 0.42;
  transform: scale(1.04);
}

.vb-gallery-twentyone-preview-art::before,
.vb-gallery-twentyone-preview-art::after,
.vb-gallery-twentyone-thumb-art::before,
.vb-gallery-twentyone-thumb-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-twentyone-art-blue,
.vb-gallery-twentyone-thumb-blue {
  background: linear-gradient(135deg, #020617 0%, #1d4ed8 54%, #38bdf8 100%);
}

.vb-gallery-twentyone-art-blue::before,
.vb-gallery-twentyone-thumb-blue::before {
  left: 12%;
  top: 18%;
  width: 76%;
  height: 58%;
  border-radius: 34px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 22px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-twentyone-art-blue::after,
.vb-gallery-twentyone-thumb-blue::after {
  right: 16%;
  bottom: 18%;
  width: 104px;
  height: 104px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-twentyone-art-orange,
.vb-gallery-twentyone-thumb-orange {
  background: linear-gradient(180deg, #fde68a 0%, #fb923c 48%, #7c2d12 100%);
}

.vb-gallery-twentyone-art-orange::before,
.vb-gallery-twentyone-thumb-orange::before {
  left: -8%;
  right: -8%;
  bottom: -18%;
  height: 56%;
  background: #431407;
  clip-path: polygon(0 100%, 0 58%, 15% 42%, 30% 66%, 48% 34%, 66% 62%, 83% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-twentyone-art-orange::after,
.vb-gallery-twentyone-thumb-orange::after {
  right: 18%;
  top: 16%;
  width: 92px;
  height: 92px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 70px rgba(255,247,237,0.72);
}

.vb-gallery-twentyone-art-purple,
.vb-gallery-twentyone-thumb-purple {
  background: radial-gradient(circle at 50% 44%, #ffffff 0%, #ddd6fe 36%, #581c87 100%);
}

.vb-gallery-twentyone-art-purple::before,
.vb-gallery-twentyone-thumb-purple::before {
  left: 50%;
  top: 50%;
  width: 156px;
  height: 156px;
  border-radius: 36px;
  background: linear-gradient(135deg, #ffffff, #c4b5fd);
  box-shadow: 0 30px 80px rgba(88,28,135,0.34);
  transform: translate(-50%, -50%) rotate(16deg);
}

.vb-gallery-twentyone-art-purple::after,
.vb-gallery-twentyone-thumb-purple::after {
  left: 50%;
  top: 50%;
  width: 82px;
  height: 82px;
  border-radius: 22px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(16deg);
}

.vb-gallery-twentyone-art-green,
.vb-gallery-twentyone-thumb-green {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-twentyone-art-green::before,
.vb-gallery-twentyone-thumb-green::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-twentyone-art-green::after,
.vb-gallery-twentyone-thumb-green::after {
  right: 16%;
  top: 16%;
  width: 88px;
  height: 88px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-twentyone-art-city,
.vb-gallery-twentyone-thumb-city {
  background: linear-gradient(180deg, #312e81 0%, #111827 66%, #020617 100%);
}

.vb-gallery-twentyone-art-city::before,
.vb-gallery-twentyone-thumb-city::before {
  left: 10%;
  bottom: 0;
  width: 18%;
  height: 58%;
  background: #020617;
  box-shadow:
    70px -42px 0 #020617,
    142px -12px 0 #020617,
    224px -62px 0 #020617,
    304px -24px 0 #020617;
}

.vb-gallery-twentyone-art-city::after,
.vb-gallery-twentyone-thumb-city::after {
  inset: 18% 10% auto 10%;
  height: 3px;
  background: repeating-linear-gradient(90deg, rgba(255,255,255,0.82) 0 8px, transparent 8px 24px);
  box-shadow:
    0 34px 0 rgba(255,255,255,0.42),
    0 70px 0 rgba(255,255,255,0.22);
}

.vb-gallery-twentyone-preview-content {
  position: absolute;
  z-index: 2;
  left: clamp(18px, 4vw, 38px);
  right: clamp(18px, 4vw, 38px);
  bottom: clamp(18px, 4vw, 34px);
  max-width: 680px;
  padding: clamp(18px, 3vw, 28px);
  border-radius: 28px;
  background: rgba(15, 23, 42, 0.72);
  border: 1px solid rgba(255,255,255,0.14);
  backdrop-filter: blur(14px);
}

.vb-gallery-twentyone-preview-content > span {
  display: inline-flex;
  margin-bottom: 10px;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-gallery-twentyone-preview-content h4 {
  margin: 0 0 8px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 4vw, 52px) !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.065em;
}

.vb-gallery-twentyone-preview-content p {
  margin: 0 0 16px !important;
  color: #e2e8f0 !important;
  -webkit-text-fill-color: #e2e8f0 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-gallery-twentyone-keys {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
}

.vb-gallery-twentyone-keys kbd {
  display: inline-grid;
  place-items: center;
  min-width: 42px;
  height: 38px;
  border-radius: 12px;
  background: #ffffff;
  color: #0f172a;
  font-size: 18px;
  font-weight: 950;
  box-shadow: inset 0 -3px 0 rgba(15,23,42,0.18);
}

.vb-gallery-twentyone-keys span {
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-gallery-twentyone-list {
  display: grid;
  gap: 12px;
}

.vb-gallery-twentyone-thumb {
  display: grid;
  grid-template-columns: 110px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 10px;
  border: 2px solid transparent;
  border-radius: 22px;
  background: #ffffff;
  cursor: pointer;
  text-align: left;
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.08);
  transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
}

.vb-gallery-twentyone-thumb:hover {
  transform: translateY(-2px);
}

.vb-gallery-twentyone-thumb.is-active {
  border-color: rgba(37, 99, 235, 0.86);
  box-shadow: 0 20px 50px rgba(37, 99, 235, 0.16);
}

.vb-gallery-twentyone-thumb-art {
  position: relative;
  height: 86px;
  overflow: hidden;
  border-radius: 16px;
}

.vb-gallery-twentyone-thumb strong {
  display: block;
  margin-bottom: 5px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  line-height: 1.15;
  font-weight: 950;
}

.vb-gallery-twentyone-thumb small {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 850;
}

@media (max-width: 980px) {
  .vb-gallery-twentyone-layout {
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentyone-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-twentyone-thumb {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 720px) {
  .vb-gallery-twentyone-header {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-twentyone-header strong {
    justify-content: center;
    width: 100%;
  }

  .vb-gallery-twentyone-preview {
    min-height: 520px;
  }
}

@media (max-width: 560px) {
  .vb-gallery-twentyone-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-twentyone-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-twentyone-list {
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentyone-preview {
    min-height: 560px;
    border-radius: 24px;
  }

  .vb-gallery-twentyone-preview-content {
    left: 14px;
    right: 14px;
    bottom: 14px;
    border-radius: 22px;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-twentyone]");
  if (!gallery) return;

  const previewArt = gallery.querySelector("[data-vb-gallery-twentyone-preview-art]");
  const title = gallery.querySelector("[data-vb-gallery-twentyone-title]");
  const category = gallery.querySelector("[data-vb-gallery-twentyone-category]");
  const description = gallery.querySelector("[data-vb-gallery-twentyone-description]");
  const counter = gallery.querySelector("[data-vb-gallery-twentyone-counter]");
  const list = gallery.querySelector("[data-vb-gallery-twentyone-list]");

  const items = [
    {
      title: "Blue Interface",
      category: "Portfolio",
      description: "A CSS-only portfolio visual controlled by keyboard navigation.",
      art: "vb-gallery-twentyone-art-blue",
      thumb: "vb-gallery-twentyone-thumb-blue"
    },
    {
      title: "Sunset Frame",
      category: "Travel",
      description: "A warm travel-style image item for arrow-key gallery movement.",
      art: "vb-gallery-twentyone-art-orange",
      thumb: "vb-gallery-twentyone-thumb-orange"
    },
    {
      title: "Product Object",
      category: "Product",
      description: "A CSS product-style gallery item selected with keyboard controls.",
      art: "vb-gallery-twentyone-art-purple",
      thumb: "vb-gallery-twentyone-thumb-purple"
    },
    {
      title: "Green Route",
      category: "Nature",
      description: "A CSS nature visual for accessible gallery navigation patterns.",
      art: "vb-gallery-twentyone-art-green",
      thumb: "vb-gallery-twentyone-thumb-green"
    },
    {
      title: "City Night",
      category: "Architecture",
      description: "A CSS city illustration for keyboard-friendly visual browsing.",
      art: "vb-gallery-twentyone-art-city",
      thumb: "vb-gallery-twentyone-thumb-city"
    }
  ];

  let activeIndex = 0;

  function createThumb(item, index) {
    const activeClass = index === activeIndex ? "is-active" : "";

    return `
      <button type="button" class="vb-gallery-twentyone-thumb ${activeClass}" data-index="${index}">
        <div class="vb-gallery-twentyone-thumb-art ${item.thumb}" aria-label="${item.title} thumbnail" role="img"></div>
        <div>
          <strong>${item.title}</strong>
          <small>${item.category}</small>
        </div>
      </button>
    `;
  }

  function renderThumbs() {
    list.innerHTML = items.map(createThumb).join("");
  }

  function renderActiveItem() {
    const item = items[activeIndex];

    previewArt.classList.add("is-changing");

    window.setTimeout(function () {
      previewArt.className = "vb-gallery-twentyone-preview-art " + item.art;
      title.textContent = item.title;
      category.textContent = item.category;
      description.textContent = item.description;
      counter.textContent = activeIndex + 1 + " / " + items.length;
      renderThumbs();
    }, 140);
  }

  function showNext() {
    activeIndex = (activeIndex + 1) % items.length;
    renderActiveItem();
  }

  function showPrevious() {
    activeIndex = (activeIndex - 1 + items.length) % items.length;
    renderActiveItem();
  }

  list.addEventListener("click", function (event) {
    const button = event.target.closest("[data-index]");
    if (!button) return;

    activeIndex = Number(button.getAttribute("data-index"));
    renderActiveItem();
  });

  document.addEventListener("keydown", function (event) {
    const galleryVisible = gallery.getBoundingClientRect().top < window.innerHeight &#038;&#038; gallery.getBoundingClientRect().bottom > 0;
    if (!galleryVisible) return;

    if (event.key === "ArrowRight") {
      showNext();
    }

    if (event.key === "ArrowLeft") {
      showPrevious();
    }
  });

  renderActiveItem();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-twentyone]");
  if (!gallery) return;

  const previewArt = gallery.querySelector("[data-vb-gallery-twentyone-preview-art]");
  const title = gallery.querySelector("[data-vb-gallery-twentyone-title]");
  const category = gallery.querySelector("[data-vb-gallery-twentyone-category]");
  const description = gallery.querySelector("[data-vb-gallery-twentyone-description]");
  const counter = gallery.querySelector("[data-vb-gallery-twentyone-counter]");
  const list = gallery.querySelector("[data-vb-gallery-twentyone-list]");

  const items = [
    {
      title: "Blue Interface",
      category: "Portfolio",
      description: "A CSS-only portfolio visual controlled by keyboard navigation.",
      art: "vb-gallery-twentyone-art-blue",
      thumb: "vb-gallery-twentyone-thumb-blue"
    },
    {
      title: "Sunset Frame",
      category: "Travel",
      description: "A warm travel-style image item for arrow-key gallery movement.",
      art: "vb-gallery-twentyone-art-orange",
      thumb: "vb-gallery-twentyone-thumb-orange"
    },
    {
      title: "Product Object",
      category: "Product",
      description: "A CSS product-style gallery item selected with keyboard controls.",
      art: "vb-gallery-twentyone-art-purple",
      thumb: "vb-gallery-twentyone-thumb-purple"
    },
    {
      title: "Green Route",
      category: "Nature",
      description: "A CSS nature visual for accessible gallery navigation patterns.",
      art: "vb-gallery-twentyone-art-green",
      thumb: "vb-gallery-twentyone-thumb-green"
    },
    {
      title: "City Night",
      category: "Architecture",
      description: "A CSS city illustration for keyboard-friendly visual browsing.",
      art: "vb-gallery-twentyone-art-city",
      thumb: "vb-gallery-twentyone-thumb-city"
    }
  ];

  let activeIndex = 0;

  function createThumb(item, index) {
    const activeClass = index === activeIndex ? "is-active" : "";

    return `
      &lt;button type="button" class="vb-gallery-twentyone-thumb ${activeClass}" data-index="${index}"&gt;
        &lt;div class="vb-gallery-twentyone-thumb-art ${item.thumb}" aria-label="${item.title} thumbnail" role="img"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;strong&gt;${item.title}&lt;/strong&gt;
          &lt;small&gt;${item.category}&lt;/small&gt;
        &lt;/div&gt;
      &lt;/button&gt;
    `;
  }

  function renderThumbs() {
    list.innerHTML = items.map(createThumb).join("");
  }

  function renderActiveItem() {
    const item = items[activeIndex];

    previewArt.classList.add("is-changing");

    window.setTimeout(function () {
      previewArt.className = "vb-gallery-twentyone-preview-art " + item.art;
      title.textContent = item.title;
      category.textContent = item.category;
      description.textContent = item.description;
      counter.textContent = activeIndex + 1 + " / " + items.length;
      renderThumbs();
    }, 140);
  }

  function showNext() {
    activeIndex = (activeIndex + 1) % items.length;
    renderActiveItem();
  }

  function showPrevious() {
    activeIndex = (activeIndex - 1 + items.length) % items.length;
    renderActiveItem();
  }

  list.addEventListener("click", function (event) {
    const button = event.target.closest("[data-index]");
    if (!button) return;

    activeIndex = Number(button.getAttribute("data-index"));
    renderActiveItem();
  });

  document.addEventListener("keydown", function (event) {
    const galleryVisible = gallery.getBoundingClientRect().top &lt; window.innerHeight && gallery.getBoundingClientRect().bottom &gt; 0;
    if (!galleryVisible) return;

    if (event.key === "ArrowRight") {
      showNext();
    }

    if (event.key === "ArrowLeft") {
      showPrevious();
    }
  });

  renderActiveItem();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-twentyone-demo"&gt;
  &lt;div class="vb-gallery-twentyone-shell" data-vb-gallery-twentyone&gt;
    &lt;div class="vb-gallery-twentyone-header"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 21&lt;/span&gt;
        &lt;h3&gt;Image Gallery with Keyboard Navigation&lt;/h3&gt;
        &lt;p&gt;Click a gallery item, then use Arrow Left and Arrow Right to move through CSS-illustrated images.&lt;/p&gt;
      &lt;/div&gt;

      &lt;strong data-vb-gallery-twentyone-counter&gt;1 / 5&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-twentyone-layout"&gt;
      &lt;div class="vb-gallery-twentyone-preview"&gt;
        &lt;div class="vb-gallery-twentyone-preview-art" data-vb-gallery-twentyone-preview-art&gt;&lt;/div&gt;

        &lt;div class="vb-gallery-twentyone-preview-content"&gt;
          &lt;span data-vb-gallery-twentyone-category&gt;Category&lt;/span&gt;
          &lt;h4 data-vb-gallery-twentyone-title&gt;Gallery Item&lt;/h4&gt;
          &lt;p data-vb-gallery-twentyone-description&gt;Use the keyboard to move between items.&lt;/p&gt;

          &lt;div class="vb-gallery-twentyone-keys"&gt;
            &lt;kbd&gt;←&lt;/kbd&gt;
            &lt;span&gt;Use keyboard arrows&lt;/span&gt;
            &lt;kbd&gt;→&lt;/kbd&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-gallery-twentyone-list" data-vb-gallery-twentyone-list&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-twentyone-demo,
.vb-gallery-twentyone-demo * {
  box-sizing: border-box;
}

.vb-gallery-twentyone-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 12% 12%, rgba(37, 99, 235, 0.16), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(20, 184, 166, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #f0fdfa 52%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.22);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

/* CSS jätkub live näidises täismahus.
   Kopeerimisel kasuta ülal olevat live CSS-i, kus kogu näidise stiil on 100% olemas. */</pre>



<p class="wp-block-paragraph">This image gallery with keyboard navigation is useful for accessible portfolio galleries, product previews, media libraries, documentation galleries, design review tools, and presentation-style visual sections where users should move through images without relying only on mouse clicks.</p>



<h2 class="wp-block-heading">22. Image Gallery with Random Shuffle</h2>



<p class="wp-block-paragraph"><strong>An image gallery with random shuffle</strong> lets users rearrange gallery items into a fresh order with one click. This pattern is useful for inspiration boards, creative portfolios, moodboards, product discovery sections, random project showcases, design galleries, and playful visual browsing interfaces.</p>



<p class="wp-block-paragraph">This example uses JavaScript array shuffling with the Fisher-Yates algorithm. Clicking the Shuffle Gallery button randomizes the item order, updates the shuffle counter, and re-renders the CSS-only gallery cards with entrance animation. No external image URLs are used.</p>



<ul class="wp-block-list">
<li>Random shuffle image gallery</li>
<li>Fisher-Yates shuffle algorithm</li>
<li>Shuffle count state</li>
<li>Dynamic gallery re-rendering</li>
<li>CSS-only image thumbnails</li>
</ul>



<div class="vb-gallery-twentytwo-demo">
  <div class="vb-gallery-twentytwo-shell" data-vb-gallery-twentytwo>
    <div class="vb-gallery-twentytwo-top">
      <div>
        <span>Example 22</span>
        <h3>Image Gallery with Random Shuffle</h3>
        <p>Shuffle CSS-illustrated gallery cards into a new random order using JavaScript.</p>
      </div>

      <div class="vb-gallery-twentytwo-actions">
        <strong data-vb-gallery-twentytwo-count>0 shuffles</strong>
        <button type="button" data-vb-gallery-twentytwo-shuffle>Shuffle Gallery</button>
      </div>
    </div>

    <div class="vb-gallery-twentytwo-grid" data-vb-gallery-twentytwo-grid></div>
  </div>
</div>

<style>
.vb-gallery-twentytwo-demo,
.vb-gallery-twentytwo-demo * {
  box-sizing: border-box;
}

.vb-gallery-twentytwo-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 46px 18px 46px 18px;
  background:
    radial-gradient(circle at 12% 12%, rgba(236, 72, 153, 0.18), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(245, 158, 11, 0.16), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #fffbeb 52%, #ffffff 100%) !important;
  border: 1px solid rgba(236, 72, 153, 0.22);
  box-shadow: 0 28px 80px rgba(190, 24, 93, 0.10);
}

.vb-gallery-twentytwo-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-twentytwo-top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 340px);
  gap: 18px;
  margin-bottom: 24px;
}

.vb-gallery-twentytwo-top > div:first-child {
  padding: clamp(22px, 4vw, 34px);
  border-radius: 34px 10px 34px 10px;
  background:
    radial-gradient(circle at 18% 20%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #831843, #be123c 52%, #92400e) !important;
  box-shadow: 0 24px 70px rgba(190, 24, 93, 0.22);
}

.vb-gallery-twentytwo-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.18);
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-twentytwo-top h3 {
  max-width: 800px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-twentytwo-top p {
  max-width: 730px;
  margin: 0 !important;
  color: #fff7ed !important;
  -webkit-text-fill-color: #fff7ed !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-twentytwo-actions {
  display: grid;
  align-content: center;
  gap: 12px;
  padding: 22px;
  border-radius: 10px 34px 10px 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.09);
}

.vb-gallery-twentytwo-actions strong {
  display: flex;
  justify-content: center;
  padding: 14px 16px;
  border-radius: 20px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-gallery-twentytwo-actions button {
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #db2777, #f59e0b);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 14px 18px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 14px 34px rgba(219, 39, 119, 0.24);
}

.vb-gallery-twentytwo-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-twentytwo-card {
  overflow: hidden;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  animation: vbGalleryTwentytwoIn 0.34s ease both;
}

@keyframes vbGalleryTwentytwoIn {
  from {
    opacity: 0;
    transform: translateY(18px) rotate(-1deg) scale(0.96);
  }

  to {
    opacity: 1;
    transform: translateY(0) rotate(0deg) scale(1);
  }
}

.vb-gallery-twentytwo-art {
  position: relative;
  height: 225px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-twentytwo-art::before,
.vb-gallery-twentytwo-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-twentytwo-art-pink {
  background: linear-gradient(135deg, #500724 0%, #be123c 52%, #fb7185 100%);
}

.vb-gallery-twentytwo-art-pink::before {
  left: 50%;
  top: 52%;
  width: 140px;
  height: 140px;
  border-radius: 42% 58% 62% 38%;
  background: radial-gradient(circle at 35% 30%, #fff1f2, #fb7185 44%, #9f1239 100%);
  transform: translate(-50%, -50%) rotate(22deg);
  box-shadow: 0 26px 70px rgba(80,7,36,0.36);
}

.vb-gallery-twentytwo-art-pink::after {
  left: 14%;
  top: 16%;
  width: 74px;
  height: 74px;
  border-radius: 999px;
  background: rgba(255,255,255,0.22);
  filter: blur(6px);
}

.vb-gallery-twentytwo-art-blue {
  background: linear-gradient(135deg, #020617 0%, #2563eb 54%, #38bdf8 100%);
}

.vb-gallery-twentytwo-art-blue::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 60%;
  border-radius: 28px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 20px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-twentytwo-art-blue::after {
  right: 16%;
  bottom: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-twentytwo-art-gold {
  background: linear-gradient(180deg, #fef3c7 0%, #f59e0b 52%, #78350f 100%);
}

.vb-gallery-twentytwo-art-gold::before {
  left: -8%;
  right: -8%;
  bottom: -18%;
  height: 56%;
  background: #451a03;
  clip-path: polygon(0 100%, 0 58%, 15% 42%, 30% 66%, 48% 34%, 66% 62%, 83% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-twentytwo-art-gold::after {
  right: 18%;
  top: 16%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: #fffbeb;
  box-shadow: 0 0 64px rgba(255,251,235,0.72);
}

.vb-gallery-twentytwo-art-green {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-twentytwo-art-green::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-twentytwo-art-green::after {
  right: 16%;
  top: 16%;
  width: 80px;
  height: 80px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-twentytwo-art-purple {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #e9d5ff 36%, #581c87 100%);
}

.vb-gallery-twentytwo-art-purple::before {
  left: 50%;
  top: 50%;
  width: 130px;
  height: 130px;
  border-radius: 30px;
  background: linear-gradient(135deg, #ffffff, #d8b4fe);
  box-shadow: 0 30px 80px rgba(88,28,135,0.32);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentytwo-art-purple::after {
  left: 50%;
  top: 50%;
  width: 68px;
  height: 68px;
  border-radius: 20px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentytwo-art-city {
  background: linear-gradient(180deg, #312e81 0%, #111827 66%, #020617 100%);
}

.vb-gallery-twentytwo-art-city::before {
  left: 10%;
  bottom: 0;
  width: 18%;
  height: 58%;
  background: #020617;
  box-shadow:
    70px -42px 0 #020617,
    142px -12px 0 #020617,
    224px -62px 0 #020617,
    304px -24px 0 #020617;
}

.vb-gallery-twentytwo-art-city::after {
  inset: 18% 10% auto 10%;
  height: 3px;
  background: repeating-linear-gradient(90deg, rgba(255,255,255,0.82) 0 8px, transparent 8px 24px);
  box-shadow:
    0 34px 0 rgba(255,255,255,0.42),
    0 70px 0 rgba(255,255,255,0.22);
}

.vb-gallery-twentytwo-body {
  display: grid;
  gap: 8px;
  padding: 17px;
}

.vb-gallery-twentytwo-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #fdf2f8;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-twentytwo-body h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-twentytwo-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

@media (max-width: 1050px) {
  .vb-gallery-twentytwo-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 820px) {
  .vb-gallery-twentytwo-top {
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentytwo-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .vb-gallery-twentytwo-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-twentytwo-top h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-twentytwo-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-twentytwo]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-twentytwo-grid]");
  const button = gallery.querySelector("[data-vb-gallery-twentytwo-shuffle]");
  const count = gallery.querySelector("[data-vb-gallery-twentytwo-count]");

  let shuffleCount = 0;

  let items = [
    {
      title: "Pink Shape",
      category: "Abstract",
      art: "vb-gallery-twentytwo-art-pink",
      description: "A CSS-only abstract card for shuffled image gallery layouts."
    },
    {
      title: "Blue Interface",
      category: "Portfolio",
      art: "vb-gallery-twentytwo-art-blue",
      description: "A CSS portfolio card that changes position when shuffled."
    },
    {
      title: "Gold Journey",
      category: "Travel",
      art: "vb-gallery-twentytwo-art-gold",
      description: "A warm CSS travel card for randomized gallery browsing."
    },
    {
      title: "Green Forest",
      category: "Nature",
      art: "vb-gallery-twentytwo-art-green",
      description: "A CSS nature card that can appear in any shuffled order."
    },
    {
      title: "Purple Product",
      category: "Product",
      art: "vb-gallery-twentytwo-art-purple",
      description: "A CSS product object card for random discovery sections."
    },
    {
      title: "City Night",
      category: "Architecture",
      art: "vb-gallery-twentytwo-art-city",
      description: "A CSS city illustration used inside a random image gallery."
    }
  ];

  function createCard(item, index) {
    return `
      <article class="vb-gallery-twentytwo-card" style="animation-delay: ${index * 45}ms">
        <div class="vb-gallery-twentytwo-art ${item.art}" aria-label="${item.title} illustration" role="img"></div>

        <div class="vb-gallery-twentytwo-body">
          <span>${item.category}</span>
          <h4>${item.title}</h4>
          <p>${item.description}</p>
        </div>
      </article>
    `;
  }

  function shuffleItems(array) {
    const shuffled = array.slice();

    for (let index = shuffled.length - 1; index > 0; index -= 1) {
      const randomIndex = Math.floor(Math.random() * (index + 1));
      const currentItem = shuffled[index];

      shuffled[index] = shuffled[randomIndex];
      shuffled[randomIndex] = currentItem;
    }

    return shuffled;
  }

  function renderGallery() {
    grid.innerHTML = items.map(createCard).join("");
    count.textContent = shuffleCount === 1 ? "1 shuffle" : shuffleCount + " shuffles";
  }

  button.addEventListener("click", function () {
    items = shuffleItems(items);
    shuffleCount += 1;
    renderGallery();
  });

  renderGallery();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-twentytwo]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-twentytwo-grid]");
  const button = gallery.querySelector("[data-vb-gallery-twentytwo-shuffle]");
  const count = gallery.querySelector("[data-vb-gallery-twentytwo-count]");

  let shuffleCount = 0;

  let items = [
    {
      title: "Pink Shape",
      category: "Abstract",
      art: "vb-gallery-twentytwo-art-pink",
      description: "A CSS-only abstract card for shuffled image gallery layouts."
    },
    {
      title: "Blue Interface",
      category: "Portfolio",
      art: "vb-gallery-twentytwo-art-blue",
      description: "A CSS portfolio card that changes position when shuffled."
    },
    {
      title: "Gold Journey",
      category: "Travel",
      art: "vb-gallery-twentytwo-art-gold",
      description: "A warm CSS travel card for randomized gallery browsing."
    },
    {
      title: "Green Forest",
      category: "Nature",
      art: "vb-gallery-twentytwo-art-green",
      description: "A CSS nature card that can appear in any shuffled order."
    },
    {
      title: "Purple Product",
      category: "Product",
      art: "vb-gallery-twentytwo-art-purple",
      description: "A CSS product object card for random discovery sections."
    },
    {
      title: "City Night",
      category: "Architecture",
      art: "vb-gallery-twentytwo-art-city",
      description: "A CSS city illustration used inside a random image gallery."
    }
  ];

  function createCard(item, index) {
    return `
      &lt;article class="vb-gallery-twentytwo-card" style="animation-delay: ${index * 45}ms"&gt;
        &lt;div class="vb-gallery-twentytwo-art ${item.art}" aria-label="${item.title} illustration" role="img"&gt;&lt;/div&gt;

        &lt;div class="vb-gallery-twentytwo-body"&gt;
          &lt;span&gt;${item.category}&lt;/span&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
          &lt;p&gt;${item.description}&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    `;
  }

  function shuffleItems(array) {
    const shuffled = array.slice();

    for (let index = shuffled.length - 1; index &gt; 0; index -= 1) {
      const randomIndex = Math.floor(Math.random() * (index + 1));
      const currentItem = shuffled[index];

      shuffled[index] = shuffled[randomIndex];
      shuffled[randomIndex] = currentItem;
    }

    return shuffled;
  }

  function renderGallery() {
    grid.innerHTML = items.map(createCard).join("");
    count.textContent = shuffleCount === 1 ? "1 shuffle" : shuffleCount + " shuffles";
  }

  button.addEventListener("click", function () {
    items = shuffleItems(items);
    shuffleCount += 1;
    renderGallery();
  });

  renderGallery();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-twentytwo-demo"&gt;
  &lt;div class="vb-gallery-twentytwo-shell" data-vb-gallery-twentytwo&gt;
    &lt;div class="vb-gallery-twentytwo-top"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 22&lt;/span&gt;
        &lt;h3&gt;Image Gallery with Random Shuffle&lt;/h3&gt;
        &lt;p&gt;Shuffle CSS-illustrated gallery cards into a new random order using JavaScript.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-gallery-twentytwo-actions"&gt;
        &lt;strong data-vb-gallery-twentytwo-count&gt;0 shuffles&lt;/strong&gt;
        &lt;button type="button" data-vb-gallery-twentytwo-shuffle&gt;Shuffle Gallery&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-twentytwo-grid" data-vb-gallery-twentytwo-grid&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-twentytwo-demo,
.vb-gallery-twentytwo-demo * {
  box-sizing: border-box;
}

.vb-gallery-twentytwo-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 46px 18px 46px 18px;
  background:
    radial-gradient(circle at 12% 12%, rgba(236, 72, 153, 0.18), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(245, 158, 11, 0.16), transparent 34%),
    linear-gradient(135deg, #fdf2f8 0%, #fffbeb 52%, #ffffff 100%) !important;
  border: 1px solid rgba(236, 72, 153, 0.22);
  box-shadow: 0 28px 80px rgba(190, 24, 93, 0.10);
}

.vb-gallery-twentytwo-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-twentytwo-top {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 340px);
  gap: 18px;
  margin-bottom: 24px;
}

.vb-gallery-twentytwo-top > div:first-child {
  padding: clamp(22px, 4vw, 34px);
  border-radius: 34px 10px 34px 10px;
  background:
    radial-gradient(circle at 18% 20%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #831843, #be123c 52%, #92400e) !important;
  box-shadow: 0 24px 70px rgba(190, 24, 93, 0.22);
}

.vb-gallery-twentytwo-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.18);
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-twentytwo-top h3 {
  max-width: 800px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-twentytwo-top p {
  max-width: 730px;
  margin: 0 !important;
  color: #fff7ed !important;
  -webkit-text-fill-color: #fff7ed !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-twentytwo-actions {
  display: grid;
  align-content: center;
  gap: 12px;
  padding: 22px;
  border-radius: 10px 34px 10px 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.09);
}

.vb-gallery-twentytwo-actions strong {
  display: flex;
  justify-content: center;
  padding: 14px 16px;
  border-radius: 20px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-gallery-twentytwo-actions button {
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #db2777, #f59e0b);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 14px 18px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 14px 34px rgba(219, 39, 119, 0.24);
}

.vb-gallery-twentytwo-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-twentytwo-card {
  overflow: hidden;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  animation: vbGalleryTwentytwoIn 0.34s ease both;
}

@keyframes vbGalleryTwentytwoIn {
  from {
    opacity: 0;
    transform: translateY(18px) rotate(-1deg) scale(0.96);
  }

  to {
    opacity: 1;
    transform: translateY(0) rotate(0deg) scale(1);
  }
}

.vb-gallery-twentytwo-art {
  position: relative;
  height: 225px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-twentytwo-art::before,
.vb-gallery-twentytwo-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-twentytwo-art-pink {
  background: linear-gradient(135deg, #500724 0%, #be123c 52%, #fb7185 100%);
}

.vb-gallery-twentytwo-art-pink::before {
  left: 50%;
  top: 52%;
  width: 140px;
  height: 140px;
  border-radius: 42% 58% 62% 38%;
  background: radial-gradient(circle at 35% 30%, #fff1f2, #fb7185 44%, #9f1239 100%);
  transform: translate(-50%, -50%) rotate(22deg);
  box-shadow: 0 26px 70px rgba(80,7,36,0.36);
}

.vb-gallery-twentytwo-art-pink::after {
  left: 14%;
  top: 16%;
  width: 74px;
  height: 74px;
  border-radius: 999px;
  background: rgba(255,255,255,0.22);
  filter: blur(6px);
}

.vb-gallery-twentytwo-art-blue {
  background: linear-gradient(135deg, #020617 0%, #2563eb 54%, #38bdf8 100%);
}

.vb-gallery-twentytwo-art-blue::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 60%;
  border-radius: 28px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 20px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-twentytwo-art-blue::after {
  right: 16%;
  bottom: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-twentytwo-art-gold {
  background: linear-gradient(180deg, #fef3c7 0%, #f59e0b 52%, #78350f 100%);
}

.vb-gallery-twentytwo-art-gold::before {
  left: -8%;
  right: -8%;
  bottom: -18%;
  height: 56%;
  background: #451a03;
  clip-path: polygon(0 100%, 0 58%, 15% 42%, 30% 66%, 48% 34%, 66% 62%, 83% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-twentytwo-art-gold::after {
  right: 18%;
  top: 16%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: #fffbeb;
  box-shadow: 0 0 64px rgba(255,251,235,0.72);
}

.vb-gallery-twentytwo-art-green {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-twentytwo-art-green::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-twentytwo-art-green::after {
  right: 16%;
  top: 16%;
  width: 80px;
  height: 80px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-twentytwo-art-purple {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #e9d5ff 36%, #581c87 100%);
}

.vb-gallery-twentytwo-art-purple::before {
  left: 50%;
  top: 50%;
  width: 130px;
  height: 130px;
  border-radius: 30px;
  background: linear-gradient(135deg, #ffffff, #d8b4fe);
  box-shadow: 0 30px 80px rgba(88,28,135,0.32);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentytwo-art-purple::after {
  left: 50%;
  top: 50%;
  width: 68px;
  height: 68px;
  border-radius: 20px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentytwo-art-city {
  background: linear-gradient(180deg, #312e81 0%, #111827 66%, #020617 100%);
}

.vb-gallery-twentytwo-art-city::before {
  left: 10%;
  bottom: 0;
  width: 18%;
  height: 58%;
  background: #020617;
  box-shadow:
    70px -42px 0 #020617,
    142px -12px 0 #020617,
    224px -62px 0 #020617,
    304px -24px 0 #020617;
}

.vb-gallery-twentytwo-art-city::after {
  inset: 18% 10% auto 10%;
  height: 3px;
  background: repeating-linear-gradient(90deg, rgba(255,255,255,0.82) 0 8px, transparent 8px 24px);
  box-shadow:
    0 34px 0 rgba(255,255,255,0.42),
    0 70px 0 rgba(255,255,255,0.22);
}

.vb-gallery-twentytwo-body {
  display: grid;
  gap: 8px;
  padding: 17px;
}

.vb-gallery-twentytwo-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #fdf2f8;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-twentytwo-body h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-twentytwo-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

@media (max-width: 1050px) {
  .vb-gallery-twentytwo-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 820px) {
  .vb-gallery-twentytwo-top {
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentytwo-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .vb-gallery-twentytwo-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-twentytwo-top h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-twentytwo-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This image gallery with random shuffle is useful for inspiration boards, creative portfolios, moodboards, product discovery sections, random project showcases, visual idea generators, and playful image-heavy browsing experiences.</p>



<h2 class="wp-block-heading">23. Image Gallery with Multi Tag Filtering</h2>



<p class="wp-block-paragraph"><strong>An image gallery with multi tag filtering</strong> lets users combine several tags to narrow down visible gallery items. This is useful for portfolio archives, product collections, design inspiration boards, travel galleries, media libraries, and visual search pages where one category filter is not enough.</p>



<p class="wp-block-paragraph">This example uses JavaScript Set state to store active tags. Users can turn multiple tags on or off, and the gallery only shows CSS-illustrated items that match every selected tag. The active tags, result count, clear button, and empty state all update dynamically.</p>



<ul class="wp-block-list">
<li>Multi tag JavaScript image gallery</li>
<li>Uses Set state for active tags</li>
<li>Matches every selected tag</li>
<li>Dynamic result count and empty state</li>
<li>CSS-only illustrated thumbnails</li>
</ul>



<div class="vb-gallery-twentythree-demo">
  <div class="vb-gallery-twentythree-shell" data-vb-gallery-twentythree>
    <div class="vb-gallery-twentythree-hero">
      <div>
        <span>Example 23</span>
        <h3>Image Gallery with Multi Tag Filtering</h3>
        <p>Select several tags and show only CSS-illustrated gallery items that match every active tag.</p>
      </div>

      <div class="vb-gallery-twentythree-panel">
        <strong data-vb-gallery-twentythree-count>0 results</strong>
        <button type="button" data-vb-gallery-twentythree-clear>Clear Tags</button>
      </div>
    </div>

    <div class="vb-gallery-twentythree-tags" data-vb-gallery-twentythree-tags>
      <button type="button" data-tag="portfolio">Portfolio</button>
      <button type="button" data-tag="product">Product</button>
      <button type="button" data-tag="travel">Travel</button>
      <button type="button" data-tag="dark">Dark</button>
      <button type="button" data-tag="bright">Bright</button>
      <button type="button" data-tag="nature">Nature</button>
    </div>

    <div class="vb-gallery-twentythree-active" data-vb-gallery-twentythree-active>Active tags: none</div>

    <div class="vb-gallery-twentythree-grid" data-vb-gallery-twentythree-grid></div>

    <div class="vb-gallery-twentythree-empty" data-vb-gallery-twentythree-empty hidden>
      <h4>No matching gallery items</h4>
      <p>Remove one tag or try a different tag combination.</p>
    </div>
  </div>
</div>

<style>
.vb-gallery-twentythree-demo,
.vb-gallery-twentythree-demo * {
  box-sizing: border-box;
}

.vb-gallery-twentythree-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 14%, rgba(20, 184, 166, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdfa 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.22);
  box-shadow: 0 28px 80px rgba(15, 118, 110, 0.10);
}

.vb-gallery-twentythree-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-twentythree-hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 340px);
  gap: 18px;
  margin-bottom: 18px;
}

.vb-gallery-twentythree-hero > div:first-child {
  padding: clamp(22px, 4vw, 34px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 18% 20%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #0f766e, #3730a3 58%, #111827) !important;
  box-shadow: 0 24px 70px rgba(15, 118, 110, 0.22);
}

.vb-gallery-twentythree-hero span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.18);
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-twentythree-hero h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-twentythree-hero p {
  max-width: 740px;
  margin: 0 !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-twentythree-panel {
  display: grid;
  align-content: center;
  gap: 12px;
  padding: 22px;
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.09);
}

.vb-gallery-twentythree-panel strong {
  display: flex;
  justify-content: center;
  padding: 14px 16px;
  border-radius: 20px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-gallery-twentythree-panel button {
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #0f766e, #4f46e5);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 14px 18px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 14px 34px rgba(79, 70, 229, 0.22);
}

.vb-gallery-twentythree-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 12px;
  padding: 12px;
  border-radius: 24px;
  background: rgba(255,255,255,0.78);
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.08);
}

.vb-gallery-twentythree-tags button {
  appearance: none;
  border: 1px solid rgba(20, 184, 166, 0.24);
  border-radius: 999px;
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  padding: 11px 15px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  transition: transform 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.vb-gallery-twentythree-tags button:hover {
  transform: translateY(-2px);
  border-color: rgba(20, 184, 166, 0.62);
}

.vb-gallery-twentythree-tags button.is-active {
  border-color: transparent;
  background: linear-gradient(135deg, #0f766e, #4f46e5);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 14px 34px rgba(15, 118, 110, 0.22);
}

.vb-gallery-twentythree-active {
  margin-bottom: 18px;
  padding: 12px 14px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  line-height: 1.5;
  font-weight: 850;
}

.vb-gallery-twentythree-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-gallery-twentythree-card {
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  animation: vbGalleryTwentythreeIn 0.34s ease both;
}

@keyframes vbGalleryTwentythreeIn {
  from {
    opacity: 0;
    transform: translateY(16px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.vb-gallery-twentythree-art {
  position: relative;
  height: 245px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-twentythree-art::before,
.vb-gallery-twentythree-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-twentythree-art-interface {
  background: linear-gradient(135deg, #020617 0%, #2563eb 54%, #38bdf8 100%);
}

.vb-gallery-twentythree-art-interface::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 60%;
  border-radius: 28px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 20px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-twentythree-art-interface::after {
  right: 16%;
  bottom: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-twentythree-art-pack {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #ddd6fe 36%, #581c87 100%);
}

.vb-gallery-twentythree-art-pack::before {
  left: 50%;
  top: 50%;
  width: 132px;
  height: 132px;
  border-radius: 30px;
  background: linear-gradient(135deg, #ffffff, #c4b5fd);
  box-shadow: 0 30px 80px rgba(88,28,135,0.32);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentythree-art-pack::after {
  left: 50%;
  top: 50%;
  width: 68px;
  height: 68px;
  border-radius: 20px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentythree-art-sunset {
  background: linear-gradient(180deg, #fde68a 0%, #fb923c 48%, #7c2d12 100%);
}

.vb-gallery-twentythree-art-sunset::before {
  left: -8%;
  right: -8%;
  bottom: -18%;
  height: 56%;
  background: #431407;
  clip-path: polygon(0 100%, 0 58%, 15% 42%, 30% 66%, 48% 34%, 66% 62%, 83% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-twentythree-art-sunset::after {
  right: 18%;
  top: 16%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 64px rgba(255,247,237,0.72);
}

.vb-gallery-twentythree-art-forest {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-twentythree-art-forest::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-twentythree-art-forest::after {
  right: 16%;
  top: 16%;
  width: 80px;
  height: 80px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-twentythree-art-dark {
  background: linear-gradient(180deg, #020617 0%, #1e293b 58%, #0f172a 100%);
}

.vb-gallery-twentythree-art-dark::before {
  left: 14%;
  right: 14%;
  top: 18%;
  height: 4px;
  background: repeating-linear-gradient(90deg, #ffffff 0 12px, transparent 12px 28px);
  box-shadow:
    0 44px 0 rgba(255,255,255,0.56),
    0 88px 0 rgba(255,255,255,0.30),
    0 132px 0 rgba(255,255,255,0.18);
}

.vb-gallery-twentythree-art-dark::after {
  right: 15%;
  top: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: #facc15;
  box-shadow: 0 0 70px rgba(250,204,21,0.60);
}

.vb-gallery-twentythree-art-bright {
  background: linear-gradient(135deg, #ecfeff 0%, #06b6d4 48%, #0f766e 100%);
}

.vb-gallery-twentythree-art-bright::before {
  left: 16%;
  top: 18%;
  width: 68%;
  height: 62%;
  border-radius: 28px;
  background: rgba(255,255,255,0.20);
  border: 1px solid rgba(255,255,255,0.34);
  backdrop-filter: blur(4px);
}

.vb-gallery-twentythree-art-bright::after {
  left: 50%;
  top: 50%;
  width: 92px;
  height: 92px;
  border-radius: 26px;
  background: rgba(255,255,255,0.70);
  transform: translate(-50%, -50%) rotate(20deg);
}

.vb-gallery-twentythree-body {
  display: grid;
  gap: 10px;
  padding: 18px;
}

.vb-gallery-twentythree-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 22px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-twentythree-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-gallery-twentythree-card-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.vb-gallery-twentythree-card-tags small {
  display: inline-flex;
  padding: 5px 8px;
  border-radius: 999px;
  background: #f0fdfa;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 10px;
  font-weight: 950;
}

.vb-gallery-twentythree-empty {
  margin-top: 18px;
  padding: 28px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px dashed rgba(20, 184, 166, 0.40);
  text-align: center;
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.07);
}

.vb-gallery-twentythree-empty h4 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 24px !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
}

.vb-gallery-twentythree-empty p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 980px) {
  .vb-gallery-twentythree-hero {
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentythree-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .vb-gallery-twentythree-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-twentythree-hero h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-twentythree-tags {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-twentythree-tags button {
    width: 100%;
  }

  .vb-gallery-twentythree-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-twentythree]");
  if (!gallery) return;

  const tagWrap = gallery.querySelector("[data-vb-gallery-twentythree-tags]");
  const grid = gallery.querySelector("[data-vb-gallery-twentythree-grid]");
  const count = gallery.querySelector("[data-vb-gallery-twentythree-count]");
  const activeText = gallery.querySelector("[data-vb-gallery-twentythree-active]");
  const clearButton = gallery.querySelector("[data-vb-gallery-twentythree-clear]");
  const empty = gallery.querySelector("[data-vb-gallery-twentythree-empty]");

  const activeTags = new Set();

  const items = [
    {
      title: "Interface Concept",
      description: "A CSS interface thumbnail for portfolio and dark gallery filters.",
      art: "vb-gallery-twentythree-art-interface",
      tags: ["portfolio", "dark"]
    },
    {
      title: "Product Package",
      description: "A CSS product visual that matches product and bright tag searches.",
      art: "vb-gallery-twentythree-art-pack",
      tags: ["product", "bright"]
    },
    {
      title: "Sunset Road",
      description: "A warm CSS travel image that matches travel and bright tags.",
      art: "vb-gallery-twentythree-art-sunset",
      tags: ["travel", "bright"]
    },
    {
      title: "Forest Path",
      description: "A CSS nature card for nature and bright gallery filtering.",
      art: "vb-gallery-twentythree-art-forest",
      tags: ["nature", "bright"]
    },
    {
      title: "Night Editorial",
      description: "A dark CSS visual that works for portfolio and dark filters.",
      art: "vb-gallery-twentythree-art-dark",
      tags: ["portfolio", "dark"]
    },
    {
      title: "Glass Product",
      description: "A bright CSS product visual for product and bright tag combinations.",
      art: "vb-gallery-twentythree-art-bright",
      tags: ["product", "bright"]
    }
  ];

  function createCard(item, index) {
    const tagMarkup = item.tags.map(function (tag) {
      return "<small>" + tag + "</small>";
    }).join("");

    return `
      <article class="vb-gallery-twentythree-card" style="animation-delay: ${index * 45}ms">
        <div class="vb-gallery-twentythree-art ${item.art}" aria-label="${item.title} illustration" role="img"></div>

        <div class="vb-gallery-twentythree-body">
          <div class="vb-gallery-twentythree-card-tags">${tagMarkup}</div>
          <h4>${item.title}</h4>
          <p>${item.description}</p>
        </div>
      </article>
    `;
  }

  function itemMatchesActiveTags(item) {
    if (activeTags.size === 0) return true;

    return Array.from(activeTags).every(function (tag) {
      return item.tags.includes(tag);
    });
  }

  function updateActiveText() {
    if (activeTags.size === 0) {
      activeText.textContent = "Active tags: none";
      return;
    }

    activeText.textContent = "Active tags: " + Array.from(activeTags).join(", ");
  }

  function renderGallery() {
    const visibleItems = items.filter(itemMatchesActiveTags);

    grid.innerHTML = visibleItems.map(createCard).join("");
    count.textContent = visibleItems.length === 1 ? "1 result" : visibleItems.length + " results";
    empty.hidden = visibleItems.length > 0;
    updateActiveText();

    tagWrap.querySelectorAll("button[data-tag]").forEach(function (button) {
      button.classList.toggle("is-active", activeTags.has(button.getAttribute("data-tag")));
    });
  }

  tagWrap.addEventListener("click", function (event) {
    const button = event.target.closest("button[data-tag]");
    if (!button) return;

    const tag = button.getAttribute("data-tag");

    if (activeTags.has(tag)) {
      activeTags.delete(tag);
    } else {
      activeTags.add(tag);
    }

    renderGallery();
  });

  clearButton.addEventListener("click", function () {
    activeTags.clear();
    renderGallery();
  });

  renderGallery();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-twentythree]");
  if (!gallery) return;

  const tagWrap = gallery.querySelector("[data-vb-gallery-twentythree-tags]");
  const grid = gallery.querySelector("[data-vb-gallery-twentythree-grid]");
  const count = gallery.querySelector("[data-vb-gallery-twentythree-count]");
  const activeText = gallery.querySelector("[data-vb-gallery-twentythree-active]");
  const clearButton = gallery.querySelector("[data-vb-gallery-twentythree-clear]");
  const empty = gallery.querySelector("[data-vb-gallery-twentythree-empty]");

  const activeTags = new Set();

  const items = [
    {
      title: "Interface Concept",
      description: "A CSS interface thumbnail for portfolio and dark gallery filters.",
      art: "vb-gallery-twentythree-art-interface",
      tags: ["portfolio", "dark"]
    },
    {
      title: "Product Package",
      description: "A CSS product visual that matches product and bright tag searches.",
      art: "vb-gallery-twentythree-art-pack",
      tags: ["product", "bright"]
    },
    {
      title: "Sunset Road",
      description: "A warm CSS travel image that matches travel and bright tags.",
      art: "vb-gallery-twentythree-art-sunset",
      tags: ["travel", "bright"]
    },
    {
      title: "Forest Path",
      description: "A CSS nature card for nature and bright gallery filtering.",
      art: "vb-gallery-twentythree-art-forest",
      tags: ["nature", "bright"]
    },
    {
      title: "Night Editorial",
      description: "A dark CSS visual that works for portfolio and dark filters.",
      art: "vb-gallery-twentythree-art-dark",
      tags: ["portfolio", "dark"]
    },
    {
      title: "Glass Product",
      description: "A bright CSS product visual for product and bright tag combinations.",
      art: "vb-gallery-twentythree-art-bright",
      tags: ["product", "bright"]
    }
  ];

  function createCard(item, index) {
    const tagMarkup = item.tags.map(function (tag) {
      return "&lt;small&gt;" + tag + "&lt;/small&gt;";
    }).join("");

    return `
      &lt;article class="vb-gallery-twentythree-card" style="animation-delay: ${index * 45}ms"&gt;
        &lt;div class="vb-gallery-twentythree-art ${item.art}" aria-label="${item.title} illustration" role="img"&gt;&lt;/div&gt;

        &lt;div class="vb-gallery-twentythree-body"&gt;
          &lt;div class="vb-gallery-twentythree-card-tags"&gt;${tagMarkup}&lt;/div&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
          &lt;p&gt;${item.description}&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    `;
  }

  function itemMatchesActiveTags(item) {
    if (activeTags.size === 0) return true;

    return Array.from(activeTags).every(function (tag) {
      return item.tags.includes(tag);
    });
  }

  function updateActiveText() {
    if (activeTags.size === 0) {
      activeText.textContent = "Active tags: none";
      return;
    }

    activeText.textContent = "Active tags: " + Array.from(activeTags).join(", ");
  }

  function renderGallery() {
    const visibleItems = items.filter(itemMatchesActiveTags);

    grid.innerHTML = visibleItems.map(createCard).join("");
    count.textContent = visibleItems.length === 1 ? "1 result" : visibleItems.length + " results";
    empty.hidden = visibleItems.length &gt; 0;
    updateActiveText();

    tagWrap.querySelectorAll("button[data-tag]").forEach(function (button) {
      button.classList.toggle("is-active", activeTags.has(button.getAttribute("data-tag")));
    });
  }

  tagWrap.addEventListener("click", function (event) {
    const button = event.target.closest("button[data-tag]");
    if (!button) return;

    const tag = button.getAttribute("data-tag");

    if (activeTags.has(tag)) {
      activeTags.delete(tag);
    } else {
      activeTags.add(tag);
    }

    renderGallery();
  });

  clearButton.addEventListener("click", function () {
    activeTags.clear();
    renderGallery();
  });

  renderGallery();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-twentythree-demo"&gt;
  &lt;div class="vb-gallery-twentythree-shell" data-vb-gallery-twentythree&gt;
    &lt;div class="vb-gallery-twentythree-hero"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 23&lt;/span&gt;
        &lt;h3&gt;Image Gallery with Multi Tag Filtering&lt;/h3&gt;
        &lt;p&gt;Select several tags and show only CSS-illustrated gallery items that match every active tag.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-gallery-twentythree-panel"&gt;
        &lt;strong data-vb-gallery-twentythree-count&gt;0 results&lt;/strong&gt;
        &lt;button type="button" data-vb-gallery-twentythree-clear&gt;Clear Tags&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-twentythree-tags" data-vb-gallery-twentythree-tags&gt;
      &lt;button type="button" data-tag="portfolio"&gt;Portfolio&lt;/button&gt;
      &lt;button type="button" data-tag="product"&gt;Product&lt;/button&gt;
      &lt;button type="button" data-tag="travel"&gt;Travel&lt;/button&gt;
      &lt;button type="button" data-tag="dark"&gt;Dark&lt;/button&gt;
      &lt;button type="button" data-tag="bright"&gt;Bright&lt;/button&gt;
      &lt;button type="button" data-tag="nature"&gt;Nature&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-twentythree-active" data-vb-gallery-twentythree-active&gt;Active tags: none&lt;/div&gt;

    &lt;div class="vb-gallery-twentythree-grid" data-vb-gallery-twentythree-grid&gt;&lt;/div&gt;

    &lt;div class="vb-gallery-twentythree-empty" data-vb-gallery-twentythree-empty hidden&gt;
      &lt;h4&gt;No matching gallery items&lt;/h4&gt;
      &lt;p&gt;Remove one tag or try a different tag combination.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-twentythree-demo,
.vb-gallery-twentythree-demo * {
  box-sizing: border-box;
}

.vb-gallery-twentythree-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 14%, rgba(20, 184, 166, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(99, 102, 241, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdfa 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(20, 184, 166, 0.22);
  box-shadow: 0 28px 80px rgba(15, 118, 110, 0.10);
}

.vb-gallery-twentythree-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-twentythree-hero {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 340px);
  gap: 18px;
  margin-bottom: 18px;
}

.vb-gallery-twentythree-hero > div:first-child {
  padding: clamp(22px, 4vw, 34px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 18% 20%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #0f766e, #3730a3 58%, #111827) !important;
  box-shadow: 0 24px 70px rgba(15, 118, 110, 0.22);
}

.vb-gallery-twentythree-hero span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.18);
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-twentythree-hero h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-twentythree-hero p {
  max-width: 740px;
  margin: 0 !important;
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-twentythree-panel {
  display: grid;
  align-content: center;
  gap: 12px;
  padding: 22px;
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.09);
}

.vb-gallery-twentythree-panel strong {
  display: flex;
  justify-content: center;
  padding: 14px 16px;
  border-radius: 20px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-gallery-twentythree-panel button {
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #0f766e, #4f46e5);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 14px 18px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 14px 34px rgba(79, 70, 229, 0.22);
}

.vb-gallery-twentythree-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 12px;
  padding: 12px;
  border-radius: 24px;
  background: rgba(255,255,255,0.78);
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.08);
}

.vb-gallery-twentythree-tags button {
  appearance: none;
  border: 1px solid rgba(20, 184, 166, 0.24);
  border-radius: 999px;
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  padding: 11px 15px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  transition: transform 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.vb-gallery-twentythree-tags button:hover {
  transform: translateY(-2px);
  border-color: rgba(20, 184, 166, 0.62);
}

.vb-gallery-twentythree-tags button.is-active {
  border-color: transparent;
  background: linear-gradient(135deg, #0f766e, #4f46e5);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 14px 34px rgba(15, 118, 110, 0.22);
}

.vb-gallery-twentythree-active {
  margin-bottom: 18px;
  padding: 12px 14px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  line-height: 1.5;
  font-weight: 850;
}

.vb-gallery-twentythree-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-gallery-twentythree-card {
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  animation: vbGalleryTwentythreeIn 0.34s ease both;
}

@keyframes vbGalleryTwentythreeIn {
  from {
    opacity: 0;
    transform: translateY(16px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.vb-gallery-twentythree-art {
  position: relative;
  height: 245px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-twentythree-art::before,
.vb-gallery-twentythree-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-twentythree-art-interface {
  background: linear-gradient(135deg, #020617 0%, #2563eb 54%, #38bdf8 100%);
}

.vb-gallery-twentythree-art-interface::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 60%;
  border-radius: 28px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 20px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-twentythree-art-interface::after {
  right: 16%;
  bottom: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-twentythree-art-pack {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #ddd6fe 36%, #581c87 100%);
}

.vb-gallery-twentythree-art-pack::before {
  left: 50%;
  top: 50%;
  width: 132px;
  height: 132px;
  border-radius: 30px;
  background: linear-gradient(135deg, #ffffff, #c4b5fd);
  box-shadow: 0 30px 80px rgba(88,28,135,0.32);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentythree-art-pack::after {
  left: 50%;
  top: 50%;
  width: 68px;
  height: 68px;
  border-radius: 20px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentythree-art-sunset {
  background: linear-gradient(180deg, #fde68a 0%, #fb923c 48%, #7c2d12 100%);
}

.vb-gallery-twentythree-art-sunset::before {
  left: -8%;
  right: -8%;
  bottom: -18%;
  height: 56%;
  background: #431407;
  clip-path: polygon(0 100%, 0 58%, 15% 42%, 30% 66%, 48% 34%, 66% 62%, 83% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-twentythree-art-sunset::after {
  right: 18%;
  top: 16%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 64px rgba(255,247,237,0.72);
}

.vb-gallery-twentythree-art-forest {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-twentythree-art-forest::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-twentythree-art-forest::after {
  right: 16%;
  top: 16%;
  width: 80px;
  height: 80px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-twentythree-art-dark {
  background: linear-gradient(180deg, #020617 0%, #1e293b 58%, #0f172a 100%);
}

.vb-gallery-twentythree-art-dark::before {
  left: 14%;
  right: 14%;
  top: 18%;
  height: 4px;
  background: repeating-linear-gradient(90deg, #ffffff 0 12px, transparent 12px 28px);
  box-shadow:
    0 44px 0 rgba(255,255,255,0.56),
    0 88px 0 rgba(255,255,255,0.30),
    0 132px 0 rgba(255,255,255,0.18);
}

.vb-gallery-twentythree-art-dark::after {
  right: 15%;
  top: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: #facc15;
  box-shadow: 0 0 70px rgba(250,204,21,0.60);
}

.vb-gallery-twentythree-art-bright {
  background: linear-gradient(135deg, #ecfeff 0%, #06b6d4 48%, #0f766e 100%);
}

.vb-gallery-twentythree-art-bright::before {
  left: 16%;
  top: 18%;
  width: 68%;
  height: 62%;
  border-radius: 28px;
  background: rgba(255,255,255,0.20);
  border: 1px solid rgba(255,255,255,0.34);
  backdrop-filter: blur(4px);
}

.vb-gallery-twentythree-art-bright::after {
  left: 50%;
  top: 50%;
  width: 92px;
  height: 92px;
  border-radius: 26px;
  background: rgba(255,255,255,0.70);
  transform: translate(-50%, -50%) rotate(20deg);
}

.vb-gallery-twentythree-body {
  display: grid;
  gap: 10px;
  padding: 18px;
}

.vb-gallery-twentythree-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 22px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-twentythree-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-gallery-twentythree-card-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
}

.vb-gallery-twentythree-card-tags small {
  display: inline-flex;
  padding: 5px 8px;
  border-radius: 999px;
  background: #f0fdfa;
  color: #0f766e !important;
  -webkit-text-fill-color: #0f766e !important;
  font-size: 10px;
  font-weight: 950;
}

.vb-gallery-twentythree-empty {
  margin-top: 18px;
  padding: 28px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px dashed rgba(20, 184, 166, 0.40);
  text-align: center;
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.07);
}

.vb-gallery-twentythree-empty h4 {
  margin: 0 0 8px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 24px !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
}

.vb-gallery-twentythree-empty p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 980px) {
  .vb-gallery-twentythree-hero {
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentythree-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .vb-gallery-twentythree-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-twentythree-hero h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-twentythree-tags {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-twentythree-tags button {
    width: 100%;
  }

  .vb-gallery-twentythree-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This image gallery with multi tag filtering is useful for portfolio archives, product galleries, design inspiration boards, media libraries, travel collections, and any image-heavy page where users need more precise filtering than one category button.</p>



<h2 class="wp-block-heading">24. Image Gallery with View Switcher</h2>



<p class="wp-block-paragraph"><strong>An image gallery with a view switcher</strong> lets users change how the same visual content is displayed. This is useful for portfolio pages, media libraries, ecommerce product galleries, case study archives, real estate galleries, and dashboards where different users prefer different browsing layouts.</p>



<p class="wp-block-paragraph">This example uses JavaScript layout mode state. Users can switch between grid view, list view, and featured view. The gallery keeps the same CSS-illustrated image data but re-renders the layout differently based on the selected view mode.</p>



<ul class="wp-block-list">
<li>JavaScript gallery view switcher</li>
<li>Grid, list, and featured layouts</li>
<li>Shared gallery data source</li>
<li>Dynamic layout mode state</li>
<li>CSS-only illustrated image cards</li>
</ul>



<div class="vb-gallery-twentyfour-demo">
  <div class="vb-gallery-twentyfour-shell" data-vb-gallery-twentyfour>
    <div class="vb-gallery-twentyfour-head">
      <div>
        <span>Example 24</span>
        <h3>Image Gallery with View Switcher</h3>
        <p>Switch the same CSS-illustrated gallery data between grid, list, and featured layouts.</p>
      </div>

      <strong data-vb-gallery-twentyfour-status>Grid view</strong>
    </div>

    <div class="vb-gallery-twentyfour-controls" data-vb-gallery-twentyfour-controls>
      <button type="button" class="is-active" data-view="grid">Grid View</button>
      <button type="button" data-view="list">List View</button>
      <button type="button" data-view="featured">Featured View</button>
    </div>

    <div class="vb-gallery-twentyfour-output" data-vb-gallery-twentyfour-output></div>
  </div>
</div>

<style>
.vb-gallery-twentyfour-demo,
.vb-gallery-twentyfour-demo * {
  box-sizing: border-box;
}

.vb-gallery-twentyfour-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 42px;
  background:
    radial-gradient(circle at 12% 12%, rgba(249, 115, 22, 0.16), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #f0f9ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(249, 115, 22, 0.22);
  box-shadow: 0 28px 80px rgba(154, 52, 18, 0.10);
}

.vb-gallery-twentyfour-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-twentyfour-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 20px;
}

.vb-gallery-twentyfour-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-twentyfour-head h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-twentyfour-head p {
  max-width: 740px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-twentyfour-head strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-twentyfour-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 22px;
  padding: 12px;
  border-radius: 24px;
  background: rgba(255,255,255,0.78);
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.08);
}

.vb-gallery-twentyfour-controls button {
  appearance: none;
  border: 1px solid rgba(249, 115, 22, 0.24);
  border-radius: 999px;
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  padding: 11px 15px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  transition: transform 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.vb-gallery-twentyfour-controls button:hover {
  transform: translateY(-2px);
  border-color: rgba(249, 115, 22, 0.62);
}

.vb-gallery-twentyfour-controls button.is-active {
  border-color: transparent;
  background: linear-gradient(135deg, #f97316, #0284c7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 14px 34px rgba(249, 115, 22, 0.22);
}

.vb-gallery-twentyfour-output {
  min-height: 360px;
}

.vb-gallery-twentyfour-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-gallery-twentyfour-list {
  display: grid;
  gap: 14px;
}

.vb-gallery-twentyfour-featured {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(280px, 0.65fr);
  gap: 16px;
  align-items: stretch;
}

.vb-gallery-twentyfour-featured-side {
  display: grid;
  gap: 16px;
}

.vb-gallery-twentyfour-card {
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  animation: vbGalleryTwentyfourIn 0.34s ease both;
}

@keyframes vbGalleryTwentyfourIn {
  from {
    opacity: 0;
    transform: translateY(16px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.vb-gallery-twentyfour-card.is-list {
  display: grid;
  grid-template-columns: 260px minmax(0, 1fr);
  align-items: stretch;
}

.vb-gallery-twentyfour-card.is-featured-main .vb-gallery-twentyfour-art {
  height: 520px;
}

.vb-gallery-twentyfour-card.is-featured-small {
  display: grid;
  grid-template-columns: 140px minmax(0, 1fr);
}

.vb-gallery-twentyfour-card.is-featured-small .vb-gallery-twentyfour-art {
  height: auto;
  min-height: 170px;
}

.vb-gallery-twentyfour-art {
  position: relative;
  height: 245px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-twentyfour-art::before,
.vb-gallery-twentyfour-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-twentyfour-art-blue {
  background: linear-gradient(135deg, #020617 0%, #2563eb 54%, #38bdf8 100%);
}

.vb-gallery-twentyfour-art-blue::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 60%;
  border-radius: 28px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 20px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-twentyfour-art-blue::after {
  right: 16%;
  bottom: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-twentyfour-art-orange {
  background: linear-gradient(180deg, #fde68a 0%, #fb923c 48%, #7c2d12 100%);
}

.vb-gallery-twentyfour-art-orange::before {
  left: -8%;
  right: -8%;
  bottom: -18%;
  height: 56%;
  background: #431407;
  clip-path: polygon(0 100%, 0 58%, 15% 42%, 30% 66%, 48% 34%, 66% 62%, 83% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-twentyfour-art-orange::after {
  right: 18%;
  top: 16%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 64px rgba(255,247,237,0.72);
}

.vb-gallery-twentyfour-art-purple {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #ddd6fe 36%, #581c87 100%);
}

.vb-gallery-twentyfour-art-purple::before {
  left: 50%;
  top: 50%;
  width: 132px;
  height: 132px;
  border-radius: 30px;
  background: linear-gradient(135deg, #ffffff, #c4b5fd);
  box-shadow: 0 30px 80px rgba(88,28,135,0.32);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentyfour-art-purple::after {
  left: 50%;
  top: 50%;
  width: 68px;
  height: 68px;
  border-radius: 20px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentyfour-art-green {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-twentyfour-art-green::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-twentyfour-art-green::after {
  right: 16%;
  top: 16%;
  width: 80px;
  height: 80px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-twentyfour-art-pink {
  background: linear-gradient(135deg, #500724 0%, #be123c 52%, #fb7185 100%);
}

.vb-gallery-twentyfour-art-pink::before {
  left: 50%;
  top: 52%;
  width: 140px;
  height: 140px;
  border-radius: 42% 58% 62% 38%;
  background: radial-gradient(circle at 35% 30%, #fff1f2, #fb7185 44%, #9f1239 100%);
  transform: translate(-50%, -50%) rotate(22deg);
  box-shadow: 0 26px 70px rgba(80,7,36,0.36);
}

.vb-gallery-twentyfour-art-pink::after {
  left: 14%;
  top: 16%;
  width: 74px;
  height: 74px;
  border-radius: 999px;
  background: rgba(255,255,255,0.22);
  filter: blur(6px);
}

.vb-gallery-twentyfour-body {
  display: grid;
  gap: 9px;
  padding: 18px;
  align-content: center;
}

.vb-gallery-twentyfour-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #fff7ed;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-twentyfour-body h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-twentyfour-card.is-featured-main .vb-gallery-twentyfour-body h4 {
  font-size: clamp(30px, 4vw, 52px) !important;
  letter-spacing: -0.065em;
}

.vb-gallery-twentyfour-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

@media (max-width: 980px) {
  .vb-gallery-twentyfour-head {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-twentyfour-head strong {
    justify-content: center;
    width: 100%;
  }

  .vb-gallery-twentyfour-grid,
  .vb-gallery-twentyfour-featured {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-twentyfour-featured-side {
    grid-column: 1 / -1;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-twentyfour-card.is-list {
    grid-template-columns: 220px minmax(0, 1fr);
  }
}

@media (max-width: 700px) {
  .vb-gallery-twentyfour-card.is-list,
  .vb-gallery-twentyfour-card.is-featured-small {
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentyfour-card.is-featured-small .vb-gallery-twentyfour-art {
    height: 230px;
  }
}

@media (max-width: 620px) {
  .vb-gallery-twentyfour-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-twentyfour-head h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-twentyfour-controls {
    display: grid;
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentyfour-grid,
  .vb-gallery-twentyfour-featured,
  .vb-gallery-twentyfour-featured-side {
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentyfour-card.is-featured-main .vb-gallery-twentyfour-art {
    height: 330px;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-twentyfour]");
  if (!gallery) return;

  const controls = gallery.querySelector("[data-vb-gallery-twentyfour-controls]");
  const output = gallery.querySelector("[data-vb-gallery-twentyfour-output]");
  const status = gallery.querySelector("[data-vb-gallery-twentyfour-status]");

  let activeView = "grid";

  const items = [
    {
      title: "Blue Portfolio",
      category: "Portfolio",
      art: "vb-gallery-twentyfour-art-blue",
      description: "A CSS-only portfolio thumbnail for flexible gallery layout switching."
    },
    {
      title: "Orange Travel",
      category: "Travel",
      art: "vb-gallery-twentyfour-art-orange",
      description: "A warm CSS travel image that can appear in grid, list, or featured view."
    },
    {
      title: "Purple Product",
      category: "Product",
      art: "vb-gallery-twentyfour-art-purple",
      description: "A CSS product card used as shared data across multiple gallery views."
    },
    {
      title: "Green Nature",
      category: "Nature",
      art: "vb-gallery-twentyfour-art-green",
      description: "A CSS nature visual that adapts to the selected gallery layout mode."
    },
    {
      title: "Pink Abstract",
      category: "Abstract",
      art: "vb-gallery-twentyfour-art-pink",
      description: "A creative CSS image card for view switcher gallery interfaces."
    }
  ];

  function createCard(item, index, extraClass) {
    const className = extraClass ? "vb-gallery-twentyfour-card " + extraClass : "vb-gallery-twentyfour-card";

    return `
      <article class="${className}" style="animation-delay: ${index * 45}ms">
        <div class="vb-gallery-twentyfour-art ${item.art}" aria-label="${item.title} illustration" role="img"></div>

        <div class="vb-gallery-twentyfour-body">
          <span>${item.category}</span>
          <h4>${item.title}</h4>
          <p>${item.description}</p>
        </div>
      </article>
    `;
  }

  function renderGridView() {
    output.innerHTML = `
      <div class="vb-gallery-twentyfour-grid">
        ${items.map(function (item, index) {
          return createCard(item, index, "");
        }).join("")}
      </div>
    `;
  }

  function renderListView() {
    output.innerHTML = `
      <div class="vb-gallery-twentyfour-list">
        ${items.map(function (item, index) {
          return createCard(item, index, "is-list");
        }).join("")}
      </div>
    `;
  }

  function renderFeaturedView() {
    const mainItem = items[0];
    const sideItems = items.slice(1);

    output.innerHTML = `
      <div class="vb-gallery-twentyfour-featured">
        ${createCard(mainItem, 0, "is-featured-main")}

        <div class="vb-gallery-twentyfour-featured-side">
          ${sideItems.map(function (item, index) {
            return createCard(item, index + 1, "is-featured-small");
          }).join("")}
        </div>
      </div>
    `;
  }

  function updateStatus() {
    const labels = {
      grid: "Grid view",
      list: "List view",
      featured: "Featured view"
    };

    status.textContent = labels[activeView];
  }

  function renderView() {
    if (activeView === "grid") {
      renderGridView();
    }

    if (activeView === "list") {
      renderListView();
    }

    if (activeView === "featured") {
      renderFeaturedView();
    }

    updateStatus();

    controls.querySelectorAll("button[data-view]").forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-view") === activeView);
    });
  }

  controls.addEventListener("click", function (event) {
    const button = event.target.closest("button[data-view]");
    if (!button) return;

    activeView = button.getAttribute("data-view");
    renderView();
  });

  renderView();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-twentyfour]");
  if (!gallery) return;

  const controls = gallery.querySelector("[data-vb-gallery-twentyfour-controls]");
  const output = gallery.querySelector("[data-vb-gallery-twentyfour-output]");
  const status = gallery.querySelector("[data-vb-gallery-twentyfour-status]");

  let activeView = "grid";

  const items = [
    {
      title: "Blue Portfolio",
      category: "Portfolio",
      art: "vb-gallery-twentyfour-art-blue",
      description: "A CSS-only portfolio thumbnail for flexible gallery layout switching."
    },
    {
      title: "Orange Travel",
      category: "Travel",
      art: "vb-gallery-twentyfour-art-orange",
      description: "A warm CSS travel image that can appear in grid, list, or featured view."
    },
    {
      title: "Purple Product",
      category: "Product",
      art: "vb-gallery-twentyfour-art-purple",
      description: "A CSS product card used as shared data across multiple gallery views."
    },
    {
      title: "Green Nature",
      category: "Nature",
      art: "vb-gallery-twentyfour-art-green",
      description: "A CSS nature visual that adapts to the selected gallery layout mode."
    },
    {
      title: "Pink Abstract",
      category: "Abstract",
      art: "vb-gallery-twentyfour-art-pink",
      description: "A creative CSS image card for view switcher gallery interfaces."
    }
  ];

  function createCard(item, index, extraClass) {
    const className = extraClass ? "vb-gallery-twentyfour-card " + extraClass : "vb-gallery-twentyfour-card";

    return `
      &lt;article class="${className}" style="animation-delay: ${index * 45}ms"&gt;
        &lt;div class="vb-gallery-twentyfour-art ${item.art}" aria-label="${item.title} illustration" role="img"&gt;&lt;/div&gt;

        &lt;div class="vb-gallery-twentyfour-body"&gt;
          &lt;span&gt;${item.category}&lt;/span&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
          &lt;p&gt;${item.description}&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    `;
  }

  function renderGridView() {
    output.innerHTML = `
      &lt;div class="vb-gallery-twentyfour-grid"&gt;
        ${items.map(function (item, index) {
          return createCard(item, index, "");
        }).join("")}
      &lt;/div&gt;
    `;
  }

  function renderListView() {
    output.innerHTML = `
      &lt;div class="vb-gallery-twentyfour-list"&gt;
        ${items.map(function (item, index) {
          return createCard(item, index, "is-list");
        }).join("")}
      &lt;/div&gt;
    `;
  }

  function renderFeaturedView() {
    const mainItem = items[0];
    const sideItems = items.slice(1);

    output.innerHTML = `
      &lt;div class="vb-gallery-twentyfour-featured"&gt;
        ${createCard(mainItem, 0, "is-featured-main")}

        &lt;div class="vb-gallery-twentyfour-featured-side"&gt;
          ${sideItems.map(function (item, index) {
            return createCard(item, index + 1, "is-featured-small");
          }).join("")}
        &lt;/div&gt;
      &lt;/div&gt;
    `;
  }

  function updateStatus() {
    const labels = {
      grid: "Grid view",
      list: "List view",
      featured: "Featured view"
    };

    status.textContent = labels[activeView];
  }

  function renderView() {
    if (activeView === "grid") {
      renderGridView();
    }

    if (activeView === "list") {
      renderListView();
    }

    if (activeView === "featured") {
      renderFeaturedView();
    }

    updateStatus();

    controls.querySelectorAll("button[data-view]").forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-view") === activeView);
    });
  }

  controls.addEventListener("click", function (event) {
    const button = event.target.closest("button[data-view]");
    if (!button) return;

    activeView = button.getAttribute("data-view");
    renderView();
  });

  renderView();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-twentyfour-demo"&gt;
  &lt;div class="vb-gallery-twentyfour-shell" data-vb-gallery-twentyfour&gt;
    &lt;div class="vb-gallery-twentyfour-head"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 24&lt;/span&gt;
        &lt;h3&gt;Image Gallery with View Switcher&lt;/h3&gt;
        &lt;p&gt;Switch the same CSS-illustrated gallery data between grid, list, and featured layouts.&lt;/p&gt;
      &lt;/div&gt;

      &lt;strong data-vb-gallery-twentyfour-status&gt;Grid view&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-twentyfour-controls" data-vb-gallery-twentyfour-controls&gt;
      &lt;button type="button" class="is-active" data-view="grid"&gt;Grid View&lt;/button&gt;
      &lt;button type="button" data-view="list"&gt;List View&lt;/button&gt;
      &lt;button type="button" data-view="featured"&gt;Featured View&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-twentyfour-output" data-vb-gallery-twentyfour-output&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-twentyfour-demo,
.vb-gallery-twentyfour-demo * {
  box-sizing: border-box;
}

.vb-gallery-twentyfour-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 42px;
  background:
    radial-gradient(circle at 12% 12%, rgba(249, 115, 22, 0.16), transparent 34%),
    radial-gradient(circle at 88% 16%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #f0f9ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(249, 115, 22, 0.22);
  box-shadow: 0 28px 80px rgba(154, 52, 18, 0.10);
}

.vb-gallery-twentyfour-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-twentyfour-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 20px;
}

.vb-gallery-twentyfour-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-twentyfour-head h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-twentyfour-head p {
  max-width: 740px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-twentyfour-head strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-twentyfour-controls {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 22px;
  padding: 12px;
  border-radius: 24px;
  background: rgba(255,255,255,0.78);
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.08);
}

.vb-gallery-twentyfour-controls button {
  appearance: none;
  border: 1px solid rgba(249, 115, 22, 0.24);
  border-radius: 999px;
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  padding: 11px 15px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  transition: transform 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.vb-gallery-twentyfour-controls button:hover {
  transform: translateY(-2px);
  border-color: rgba(249, 115, 22, 0.62);
}

.vb-gallery-twentyfour-controls button.is-active {
  border-color: transparent;
  background: linear-gradient(135deg, #f97316, #0284c7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 14px 34px rgba(249, 115, 22, 0.22);
}

.vb-gallery-twentyfour-output {
  min-height: 360px;
}

.vb-gallery-twentyfour-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-gallery-twentyfour-list {
  display: grid;
  gap: 14px;
}

.vb-gallery-twentyfour-featured {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(280px, 0.65fr);
  gap: 16px;
  align-items: stretch;
}

.vb-gallery-twentyfour-featured-side {
  display: grid;
  gap: 16px;
}

.vb-gallery-twentyfour-card {
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  animation: vbGalleryTwentyfourIn 0.34s ease both;
}

@keyframes vbGalleryTwentyfourIn {
  from {
    opacity: 0;
    transform: translateY(16px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.vb-gallery-twentyfour-card.is-list {
  display: grid;
  grid-template-columns: 260px minmax(0, 1fr);
  align-items: stretch;
}

.vb-gallery-twentyfour-card.is-featured-main .vb-gallery-twentyfour-art {
  height: 520px;
}

.vb-gallery-twentyfour-card.is-featured-small {
  display: grid;
  grid-template-columns: 140px minmax(0, 1fr);
}

.vb-gallery-twentyfour-card.is-featured-small .vb-gallery-twentyfour-art {
  height: auto;
  min-height: 170px;
}

.vb-gallery-twentyfour-art {
  position: relative;
  height: 245px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-twentyfour-art::before,
.vb-gallery-twentyfour-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-twentyfour-art-blue {
  background: linear-gradient(135deg, #020617 0%, #2563eb 54%, #38bdf8 100%);
}

.vb-gallery-twentyfour-art-blue::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 60%;
  border-radius: 28px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 20px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-twentyfour-art-blue::after {
  right: 16%;
  bottom: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-twentyfour-art-orange {
  background: linear-gradient(180deg, #fde68a 0%, #fb923c 48%, #7c2d12 100%);
}

.vb-gallery-twentyfour-art-orange::before {
  left: -8%;
  right: -8%;
  bottom: -18%;
  height: 56%;
  background: #431407;
  clip-path: polygon(0 100%, 0 58%, 15% 42%, 30% 66%, 48% 34%, 66% 62%, 83% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-twentyfour-art-orange::after {
  right: 18%;
  top: 16%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: #fff7ed;
  box-shadow: 0 0 64px rgba(255,247,237,0.72);
}

.vb-gallery-twentyfour-art-purple {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #ddd6fe 36%, #581c87 100%);
}

.vb-gallery-twentyfour-art-purple::before {
  left: 50%;
  top: 50%;
  width: 132px;
  height: 132px;
  border-radius: 30px;
  background: linear-gradient(135deg, #ffffff, #c4b5fd);
  box-shadow: 0 30px 80px rgba(88,28,135,0.32);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentyfour-art-purple::after {
  left: 50%;
  top: 50%;
  width: 68px;
  height: 68px;
  border-radius: 20px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentyfour-art-green {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-twentyfour-art-green::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-twentyfour-art-green::after {
  right: 16%;
  top: 16%;
  width: 80px;
  height: 80px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-twentyfour-art-pink {
  background: linear-gradient(135deg, #500724 0%, #be123c 52%, #fb7185 100%);
}

.vb-gallery-twentyfour-art-pink::before {
  left: 50%;
  top: 52%;
  width: 140px;
  height: 140px;
  border-radius: 42% 58% 62% 38%;
  background: radial-gradient(circle at 35% 30%, #fff1f2, #fb7185 44%, #9f1239 100%);
  transform: translate(-50%, -50%) rotate(22deg);
  box-shadow: 0 26px 70px rgba(80,7,36,0.36);
}

.vb-gallery-twentyfour-art-pink::after {
  left: 14%;
  top: 16%;
  width: 74px;
  height: 74px;
  border-radius: 999px;
  background: rgba(255,255,255,0.22);
  filter: blur(6px);
}

.vb-gallery-twentyfour-body {
  display: grid;
  gap: 9px;
  padding: 18px;
  align-content: center;
}

.vb-gallery-twentyfour-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #fff7ed;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-twentyfour-body h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-twentyfour-card.is-featured-main .vb-gallery-twentyfour-body h4 {
  font-size: clamp(30px, 4vw, 52px) !important;
  letter-spacing: -0.065em;
}

.vb-gallery-twentyfour-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

@media (max-width: 980px) {
  .vb-gallery-twentyfour-head {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-twentyfour-head strong {
    justify-content: center;
    width: 100%;
  }

  .vb-gallery-twentyfour-grid,
  .vb-gallery-twentyfour-featured {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-twentyfour-featured-side {
    grid-column: 1 / -1;
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-gallery-twentyfour-card.is-list {
    grid-template-columns: 220px minmax(0, 1fr);
  }
}

@media (max-width: 700px) {
  .vb-gallery-twentyfour-card.is-list,
  .vb-gallery-twentyfour-card.is-featured-small {
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentyfour-card.is-featured-small .vb-gallery-twentyfour-art {
    height: 230px;
  }
}

@media (max-width: 620px) {
  .vb-gallery-twentyfour-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-twentyfour-head h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-twentyfour-controls {
    display: grid;
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentyfour-grid,
  .vb-gallery-twentyfour-featured,
  .vb-gallery-twentyfour-featured-side {
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentyfour-card.is-featured-main .vb-gallery-twentyfour-art {
    height: 330px;
  }
}</pre>



<p class="wp-block-paragraph">This image gallery with a view switcher is useful for portfolio pages, media libraries, product galleries, real estate listings, case study archives, dashboards, and visual browsing interfaces where users should control how gallery content is displayed.</p>



<h2 class="wp-block-heading">25. Image Gallery with Favorite Items</h2>



<p class="wp-block-paragraph"><strong>An image gallery with favorite items</strong> lets users save images they like while browsing. This pattern is useful for portfolio inspiration pages, product galleries, real estate listings, travel galleries, media libraries, moodboards, and design selection interfaces.</p>



<p class="wp-block-paragraph">This example uses JavaScript favorite state with <code>localStorage</code>. Users can mark CSS-illustrated gallery items as favorites, switch between all items and favorites only, and keep their favorites after page refresh. No external image files are used.</p>



<ul class="wp-block-list">
<li>Favorite image gallery items</li>
<li>JavaScript localStorage state</li>
<li>All items and favorites-only views</li>
<li>Dynamic favorite count</li>
<li>CSS-only gallery thumbnails</li>
</ul>



<div class="vb-gallery-twentyfive-demo">
  <div class="vb-gallery-twentyfive-shell" data-vb-gallery-twentyfive>
    <div class="vb-gallery-twentyfive-header">
      <div>
        <span>Example 25</span>
        <h3>Image Gallery with Favorite Items</h3>
        <p>Save CSS-illustrated gallery items as favorites and keep them with JavaScript localStorage.</p>
      </div>

      <div class="vb-gallery-twentyfive-summary">
        <strong data-vb-gallery-twentyfive-count>0 favorites</strong>
        <button type="button" data-vb-gallery-twentyfive-clear>Clear Favorites</button>
      </div>
    </div>

    <div class="vb-gallery-twentyfive-tabs" data-vb-gallery-twentyfive-tabs>
      <button type="button" class="is-active" data-view="all">All Gallery Items</button>
      <button type="button" data-view="favorites">Favorites Only</button>
    </div>

    <div class="vb-gallery-twentyfive-grid" data-vb-gallery-twentyfive-grid></div>

    <div class="vb-gallery-twentyfive-empty" data-vb-gallery-twentyfive-empty hidden>
      <h4>No favorite images yet</h4>
      <p>Mark a gallery card as favorite and it will appear in this view.</p>
    </div>
  </div>
</div>

<style>
.vb-gallery-twentyfive-demo,
.vb-gallery-twentyfive-demo * {
  box-sizing: border-box;
}

.vb-gallery-twentyfive-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 14% 14%, rgba(244, 63, 94, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #faf5ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(244, 63, 94, 0.22);
  box-shadow: 0 28px 80px rgba(190, 18, 60, 0.10);
}

.vb-gallery-twentyfive-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-twentyfive-header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 340px);
  gap: 18px;
  margin-bottom: 18px;
}

.vb-gallery-twentyfive-header > div:first-child {
  padding: clamp(22px, 4vw, 34px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 18% 20%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #881337, #7e22ce 58%, #111827) !important;
  box-shadow: 0 24px 70px rgba(190, 18, 60, 0.22);
}

.vb-gallery-twentyfive-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.18);
  color: #ffe4e6 !important;
  -webkit-text-fill-color: #ffe4e6 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-twentyfive-header h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-twentyfive-header p {
  max-width: 740px;
  margin: 0 !important;
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-twentyfive-summary {
  display: grid;
  align-content: center;
  gap: 12px;
  padding: 22px;
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.09);
}

.vb-gallery-twentyfive-summary strong {
  display: flex;
  justify-content: center;
  padding: 14px 16px;
  border-radius: 20px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-gallery-twentyfive-summary button {
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #e11d48, #7e22ce);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 14px 18px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 14px 34px rgba(225, 29, 72, 0.24);
}

.vb-gallery-twentyfive-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 22px;
  padding: 12px;
  border-radius: 24px;
  background: rgba(255,255,255,0.78);
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.08);
}

.vb-gallery-twentyfive-tabs button {
  appearance: none;
  border: 1px solid rgba(244, 63, 94, 0.24);
  border-radius: 999px;
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  padding: 11px 15px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  transition: transform 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.vb-gallery-twentyfive-tabs button:hover {
  transform: translateY(-2px);
  border-color: rgba(244, 63, 94, 0.62);
}

.vb-gallery-twentyfive-tabs button.is-active {
  border-color: transparent;
  background: linear-gradient(135deg, #e11d48, #7e22ce);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 14px 34px rgba(225, 29, 72, 0.22);
}

.vb-gallery-twentyfive-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-gallery-twentyfive-card {
  position: relative;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  animation: vbGalleryTwentyfiveIn 0.34s ease both;
}

@keyframes vbGalleryTwentyfiveIn {
  from {
    opacity: 0;
    transform: translateY(16px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.vb-gallery-twentyfive-fav {
  position: absolute;
  z-index: 5;
  top: 14px;
  right: 14px;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.62);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  font-weight: 950;
  cursor: pointer;
  backdrop-filter: blur(10px);
  transition: transform 0.2s ease, background 0.2s ease;
}

.vb-gallery-twentyfive-fav:hover {
  transform: scale(1.08);
}

.vb-gallery-twentyfive-fav.is-favorite {
  background: linear-gradient(135deg, #e11d48, #7e22ce);
}

.vb-gallery-twentyfive-art {
  position: relative;
  height: 245px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-twentyfive-art::before,
.vb-gallery-twentyfive-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-twentyfive-art-rose {
  background: linear-gradient(135deg, #500724 0%, #be123c 52%, #fb7185 100%);
}

.vb-gallery-twentyfive-art-rose::before {
  left: 50%;
  top: 52%;
  width: 150px;
  height: 150px;
  border-radius: 42% 58% 62% 38%;
  background: radial-gradient(circle at 35% 30%, #fff1f2, #fb7185 44%, #9f1239 100%);
  transform: translate(-50%, -50%) rotate(22deg);
  box-shadow: 0 26px 70px rgba(80,7,36,0.36);
}

.vb-gallery-twentyfive-art-rose::after {
  left: 14%;
  top: 16%;
  width: 74px;
  height: 74px;
  border-radius: 999px;
  background: rgba(255,255,255,0.22);
  filter: blur(6px);
}

.vb-gallery-twentyfive-art-violet {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #ddd6fe 36%, #581c87 100%);
}

.vb-gallery-twentyfive-art-violet::before {
  left: 50%;
  top: 50%;
  width: 132px;
  height: 132px;
  border-radius: 30px;
  background: linear-gradient(135deg, #ffffff, #c4b5fd);
  box-shadow: 0 30px 80px rgba(88,28,135,0.32);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentyfive-art-violet::after {
  left: 50%;
  top: 50%;
  width: 68px;
  height: 68px;
  border-radius: 20px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentyfive-art-blue {
  background: linear-gradient(135deg, #020617 0%, #2563eb 54%, #38bdf8 100%);
}

.vb-gallery-twentyfive-art-blue::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 60%;
  border-radius: 28px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 20px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-twentyfive-art-blue::after {
  right: 16%;
  bottom: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-twentyfive-art-gold {
  background: linear-gradient(180deg, #fef3c7 0%, #f59e0b 52%, #78350f 100%);
}

.vb-gallery-twentyfive-art-gold::before {
  left: -8%;
  right: -8%;
  bottom: -18%;
  height: 56%;
  background: #451a03;
  clip-path: polygon(0 100%, 0 58%, 15% 42%, 30% 66%, 48% 34%, 66% 62%, 83% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-twentyfive-art-gold::after {
  right: 18%;
  top: 16%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: #fffbeb;
  box-shadow: 0 0 64px rgba(255,251,235,0.72);
}

.vb-gallery-twentyfive-art-green {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-twentyfive-art-green::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-twentyfive-art-green::after {
  right: 16%;
  top: 16%;
  width: 80px;
  height: 80px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-twentyfive-art-city {
  background: linear-gradient(180deg, #312e81 0%, #111827 66%, #020617 100%);
}

.vb-gallery-twentyfive-art-city::before {
  left: 10%;
  bottom: 0;
  width: 18%;
  height: 58%;
  background: #020617;
  box-shadow:
    70px -42px 0 #020617,
    142px -12px 0 #020617,
    224px -62px 0 #020617,
    304px -24px 0 #020617;
}

.vb-gallery-twentyfive-art-city::after {
  inset: 18% 10% auto 10%;
  height: 3px;
  background: repeating-linear-gradient(90deg, rgba(255,255,255,0.82) 0 8px, transparent 8px 24px);
  box-shadow:
    0 34px 0 rgba(255,255,255,0.42),
    0 70px 0 rgba(255,255,255,0.22);
}

.vb-gallery-twentyfive-body {
  display: grid;
  gap: 8px;
  padding: 18px;
}

.vb-gallery-twentyfive-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #fff1f2;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-twentyfive-body h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-twentyfive-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-gallery-twentyfive-empty {
  margin-top: 18px;
  padding: 28px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px dashed rgba(244, 63, 94, 0.40);
  text-align: center;
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.07);
}

.vb-gallery-twentyfive-empty h4 {
  margin: 0 0 8px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 24px !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
}

.vb-gallery-twentyfive-empty p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 980px) {
  .vb-gallery-twentyfive-header {
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentyfive-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .vb-gallery-twentyfive-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-twentyfive-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-twentyfive-tabs {
    display: grid;
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentyfive-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-twentyfive]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-twentyfive-grid]");
  const tabs = gallery.querySelector("[data-vb-gallery-twentyfive-tabs]");
  const count = gallery.querySelector("[data-vb-gallery-twentyfive-count]");
  const clearButton = gallery.querySelector("[data-vb-gallery-twentyfive-clear]");
  const empty = gallery.querySelector("[data-vb-gallery-twentyfive-empty]");
  const storageKey = "vbGalleryTwentyfiveFavorites";

  let activeView = "all";
  let favoriteIds = loadFavorites();

  const items = [
    {
      id: "rose-poster",
      title: "Rose Poster",
      category: "Abstract",
      art: "vb-gallery-twentyfive-art-rose",
      description: "A CSS-only abstract image card that can be saved as a favorite."
    },
    {
      id: "violet-object",
      title: "Violet Object",
      category: "Product",
      art: "vb-gallery-twentyfive-art-violet",
      description: "A CSS product-style gallery item with favorite state."
    },
    {
      id: "blue-interface",
      title: "Blue Interface",
      category: "Portfolio",
      art: "vb-gallery-twentyfive-art-blue",
      description: "A CSS portfolio visual that can be saved to localStorage."
    },
    {
      id: "gold-journey",
      title: "Gold Journey",
      category: "Travel",
      art: "vb-gallery-twentyfive-art-gold",
      description: "A warm CSS travel image for favorite gallery browsing."
    },
    {
      id: "green-forest",
      title: "Green Forest",
      category: "Nature",
      art: "vb-gallery-twentyfive-art-green",
      description: "A CSS nature card that can be kept in the favorites list."
    },
    {
      id: "city-night",
      title: "City Night",
      category: "Architecture",
      art: "vb-gallery-twentyfive-art-city",
      description: "A CSS city illustration with persistent favorite behavior."
    }
  ];

  function loadFavorites() {
    try {
      return JSON.parse(localStorage.getItem(storageKey)) || [];
    } catch (error) {
      return [];
    }
  }

  function saveFavorites() {
    localStorage.setItem(storageKey, JSON.stringify(favoriteIds));
  }

  function isFavorite(id) {
    return favoriteIds.includes(id);
  }

  function getVisibleItems() {
    if (activeView === "favorites") {
      return items.filter(function (item) {
        return isFavorite(item.id);
      });
    }

    return items;
  }

  function createCard(item, index) {
    const favoriteClass = isFavorite(item.id) ? "is-favorite" : "";
    const symbol = isFavorite(item.id) ? "♥" : "♡";

    return `
      <article class="vb-gallery-twentyfive-card" style="animation-delay: ${index * 45}ms">
        <button type="button" class="vb-gallery-twentyfive-fav ${favoriteClass}" data-favorite-id="${item.id}" aria-label="Toggle favorite for ${item.title}">${symbol}</button>

        <div class="vb-gallery-twentyfive-art ${item.art}" aria-label="${item.title} illustration" role="img"></div>

        <div class="vb-gallery-twentyfive-body">
          <span>${item.category}</span>
          <h4>${item.title}</h4>
          <p>${item.description}</p>
        </div>
      </article>
    `;
  }

  function updateCount() {
    count.textContent = favoriteIds.length === 1 ? "1 favorite" : favoriteIds.length + " favorites";
  }

  function renderGallery() {
    const visibleItems = getVisibleItems();

    grid.innerHTML = visibleItems.map(createCard).join("");
    empty.hidden = !(activeView === "favorites" && visibleItems.length === 0);
    updateCount();

    tabs.querySelectorAll("button[data-view]").forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-view") === activeView);
    });
  }

  function toggleFavorite(id) {
    if (isFavorite(id)) {
      favoriteIds = favoriteIds.filter(function (favoriteId) {
        return favoriteId !== id;
      });
    } else {
      favoriteIds.push(id);
    }

    saveFavorites();
    renderGallery();
  }

  grid.addEventListener("click", function (event) {
    const button = event.target.closest("[data-favorite-id]");
    if (!button) return;

    toggleFavorite(button.getAttribute("data-favorite-id"));
  });

  tabs.addEventListener("click", function (event) {
    const button = event.target.closest("button[data-view]");
    if (!button) return;

    activeView = button.getAttribute("data-view");
    renderGallery();
  });

  clearButton.addEventListener("click", function () {
    favoriteIds = [];
    saveFavorites();
    renderGallery();
  });

  renderGallery();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-twentyfive]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-twentyfive-grid]");
  const tabs = gallery.querySelector("[data-vb-gallery-twentyfive-tabs]");
  const count = gallery.querySelector("[data-vb-gallery-twentyfive-count]");
  const clearButton = gallery.querySelector("[data-vb-gallery-twentyfive-clear]");
  const empty = gallery.querySelector("[data-vb-gallery-twentyfive-empty]");
  const storageKey = "vbGalleryTwentyfiveFavorites";

  let activeView = "all";
  let favoriteIds = loadFavorites();

  const items = [
    {
      id: "rose-poster",
      title: "Rose Poster",
      category: "Abstract",
      art: "vb-gallery-twentyfive-art-rose",
      description: "A CSS-only abstract image card that can be saved as a favorite."
    },
    {
      id: "violet-object",
      title: "Violet Object",
      category: "Product",
      art: "vb-gallery-twentyfive-art-violet",
      description: "A CSS product-style gallery item with favorite state."
    },
    {
      id: "blue-interface",
      title: "Blue Interface",
      category: "Portfolio",
      art: "vb-gallery-twentyfive-art-blue",
      description: "A CSS portfolio visual that can be saved to localStorage."
    },
    {
      id: "gold-journey",
      title: "Gold Journey",
      category: "Travel",
      art: "vb-gallery-twentyfive-art-gold",
      description: "A warm CSS travel image for favorite gallery browsing."
    },
    {
      id: "green-forest",
      title: "Green Forest",
      category: "Nature",
      art: "vb-gallery-twentyfive-art-green",
      description: "A CSS nature card that can be kept in the favorites list."
    },
    {
      id: "city-night",
      title: "City Night",
      category: "Architecture",
      art: "vb-gallery-twentyfive-art-city",
      description: "A CSS city illustration with persistent favorite behavior."
    }
  ];

  function loadFavorites() {
    try {
      return JSON.parse(localStorage.getItem(storageKey)) || [];
    } catch (error) {
      return [];
    }
  }

  function saveFavorites() {
    localStorage.setItem(storageKey, JSON.stringify(favoriteIds));
  }

  function isFavorite(id) {
    return favoriteIds.includes(id);
  }

  function getVisibleItems() {
    if (activeView === "favorites") {
      return items.filter(function (item) {
        return isFavorite(item.id);
      });
    }

    return items;
  }

  function createCard(item, index) {
    const favoriteClass = isFavorite(item.id) ? "is-favorite" : "";
    const symbol = isFavorite(item.id) ? "♥" : "♡";

    return `
      &lt;article class="vb-gallery-twentyfive-card" style="animation-delay: ${index * 45}ms"&gt;
        &lt;button type="button" class="vb-gallery-twentyfive-fav ${favoriteClass}" data-favorite-id="${item.id}" aria-label="Toggle favorite for ${item.title}"&gt;${symbol}&lt;/button&gt;

        &lt;div class="vb-gallery-twentyfive-art ${item.art}" aria-label="${item.title} illustration" role="img"&gt;&lt;/div&gt;

        &lt;div class="vb-gallery-twentyfive-body"&gt;
          &lt;span&gt;${item.category}&lt;/span&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
          &lt;p&gt;${item.description}&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    `;
  }

  function updateCount() {
    count.textContent = favoriteIds.length === 1 ? "1 favorite" : favoriteIds.length + " favorites";
  }

  function renderGallery() {
    const visibleItems = getVisibleItems();

    grid.innerHTML = visibleItems.map(createCard).join("");
    empty.hidden = !(activeView === "favorites" && visibleItems.length === 0);
    updateCount();

    tabs.querySelectorAll("button[data-view]").forEach(function (button) {
      button.classList.toggle("is-active", button.getAttribute("data-view") === activeView);
    });
  }

  function toggleFavorite(id) {
    if (isFavorite(id)) {
      favoriteIds = favoriteIds.filter(function (favoriteId) {
        return favoriteId !== id;
      });
    } else {
      favoriteIds.push(id);
    }

    saveFavorites();
    renderGallery();
  }

  grid.addEventListener("click", function (event) {
    const button = event.target.closest("[data-favorite-id]");
    if (!button) return;

    toggleFavorite(button.getAttribute("data-favorite-id"));
  });

  tabs.addEventListener("click", function (event) {
    const button = event.target.closest("button[data-view]");
    if (!button) return;

    activeView = button.getAttribute("data-view");
    renderGallery();
  });

  clearButton.addEventListener("click", function () {
    favoriteIds = [];
    saveFavorites();
    renderGallery();
  });

  renderGallery();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-twentyfive-demo"&gt;
  &lt;div class="vb-gallery-twentyfive-shell" data-vb-gallery-twentyfive&gt;
    &lt;div class="vb-gallery-twentyfive-header"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 25&lt;/span&gt;
        &lt;h3&gt;Image Gallery with Favorite Items&lt;/h3&gt;
        &lt;p&gt;Save CSS-illustrated gallery items as favorites and keep them with JavaScript localStorage.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-gallery-twentyfive-summary"&gt;
        &lt;strong data-vb-gallery-twentyfive-count&gt;0 favorites&lt;/strong&gt;
        &lt;button type="button" data-vb-gallery-twentyfive-clear&gt;Clear Favorites&lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-twentyfive-tabs" data-vb-gallery-twentyfive-tabs&gt;
      &lt;button type="button" class="is-active" data-view="all"&gt;All Gallery Items&lt;/button&gt;
      &lt;button type="button" data-view="favorites"&gt;Favorites Only&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-twentyfive-grid" data-vb-gallery-twentyfive-grid&gt;&lt;/div&gt;

    &lt;div class="vb-gallery-twentyfive-empty" data-vb-gallery-twentyfive-empty hidden&gt;
      &lt;h4&gt;No favorite images yet&lt;/h4&gt;
      &lt;p&gt;Mark a gallery card as favorite and it will appear in this view.&lt;/p&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-twentyfive-demo,
.vb-gallery-twentyfive-demo * {
  box-sizing: border-box;
}

.vb-gallery-twentyfive-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 14% 14%, rgba(244, 63, 94, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #faf5ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(244, 63, 94, 0.22);
  box-shadow: 0 28px 80px rgba(190, 18, 60, 0.10);
}

.vb-gallery-twentyfive-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-twentyfive-header {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 340px);
  gap: 18px;
  margin-bottom: 18px;
}

.vb-gallery-twentyfive-header > div:first-child {
  padding: clamp(22px, 4vw, 34px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 18% 20%, rgba(255,255,255,0.16), transparent 34%),
    linear-gradient(135deg, #881337, #7e22ce 58%, #111827) !important;
  box-shadow: 0 24px 70px rgba(190, 18, 60, 0.22);
}

.vb-gallery-twentyfive-header span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  border: 1px solid rgba(255,255,255,0.18);
  color: #ffe4e6 !important;
  -webkit-text-fill-color: #ffe4e6 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-twentyfive-header h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-twentyfive-header p {
  max-width: 740px;
  margin: 0 !important;
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-twentyfive-summary {
  display: grid;
  align-content: center;
  gap: 12px;
  padding: 22px;
  border-radius: 34px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.09);
}

.vb-gallery-twentyfive-summary strong {
  display: flex;
  justify-content: center;
  padding: 14px 16px;
  border-radius: 20px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-gallery-twentyfive-summary button {
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #e11d48, #7e22ce);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 14px 18px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 14px 34px rgba(225, 29, 72, 0.24);
}

.vb-gallery-twentyfive-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 22px;
  padding: 12px;
  border-radius: 24px;
  background: rgba(255,255,255,0.78);
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.08);
}

.vb-gallery-twentyfive-tabs button {
  appearance: none;
  border: 1px solid rgba(244, 63, 94, 0.24);
  border-radius: 999px;
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  padding: 11px 15px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  transition: transform 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.vb-gallery-twentyfive-tabs button:hover {
  transform: translateY(-2px);
  border-color: rgba(244, 63, 94, 0.62);
}

.vb-gallery-twentyfive-tabs button.is-active {
  border-color: transparent;
  background: linear-gradient(135deg, #e11d48, #7e22ce);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 14px 34px rgba(225, 29, 72, 0.22);
}

.vb-gallery-twentyfive-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-gallery-twentyfive-card {
  position: relative;
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  animation: vbGalleryTwentyfiveIn 0.34s ease both;
}

@keyframes vbGalleryTwentyfiveIn {
  from {
    opacity: 0;
    transform: translateY(16px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.vb-gallery-twentyfive-fav {
  position: absolute;
  z-index: 5;
  top: 14px;
  right: 14px;
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border: 0;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.62);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  font-weight: 950;
  cursor: pointer;
  backdrop-filter: blur(10px);
  transition: transform 0.2s ease, background 0.2s ease;
}

.vb-gallery-twentyfive-fav:hover {
  transform: scale(1.08);
}

.vb-gallery-twentyfive-fav.is-favorite {
  background: linear-gradient(135deg, #e11d48, #7e22ce);
}

.vb-gallery-twentyfive-art {
  position: relative;
  height: 245px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-twentyfive-art::before,
.vb-gallery-twentyfive-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-twentyfive-art-rose {
  background: linear-gradient(135deg, #500724 0%, #be123c 52%, #fb7185 100%);
}

.vb-gallery-twentyfive-art-rose::before {
  left: 50%;
  top: 52%;
  width: 150px;
  height: 150px;
  border-radius: 42% 58% 62% 38%;
  background: radial-gradient(circle at 35% 30%, #fff1f2, #fb7185 44%, #9f1239 100%);
  transform: translate(-50%, -50%) rotate(22deg);
  box-shadow: 0 26px 70px rgba(80,7,36,0.36);
}

.vb-gallery-twentyfive-art-rose::after {
  left: 14%;
  top: 16%;
  width: 74px;
  height: 74px;
  border-radius: 999px;
  background: rgba(255,255,255,0.22);
  filter: blur(6px);
}

.vb-gallery-twentyfive-art-violet {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #ddd6fe 36%, #581c87 100%);
}

.vb-gallery-twentyfive-art-violet::before {
  left: 50%;
  top: 50%;
  width: 132px;
  height: 132px;
  border-radius: 30px;
  background: linear-gradient(135deg, #ffffff, #c4b5fd);
  box-shadow: 0 30px 80px rgba(88,28,135,0.32);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentyfive-art-violet::after {
  left: 50%;
  top: 50%;
  width: 68px;
  height: 68px;
  border-radius: 20px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentyfive-art-blue {
  background: linear-gradient(135deg, #020617 0%, #2563eb 54%, #38bdf8 100%);
}

.vb-gallery-twentyfive-art-blue::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 60%;
  border-radius: 28px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 20px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-twentyfive-art-blue::after {
  right: 16%;
  bottom: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-twentyfive-art-gold {
  background: linear-gradient(180deg, #fef3c7 0%, #f59e0b 52%, #78350f 100%);
}

.vb-gallery-twentyfive-art-gold::before {
  left: -8%;
  right: -8%;
  bottom: -18%;
  height: 56%;
  background: #451a03;
  clip-path: polygon(0 100%, 0 58%, 15% 42%, 30% 66%, 48% 34%, 66% 62%, 83% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-twentyfive-art-gold::after {
  right: 18%;
  top: 16%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: #fffbeb;
  box-shadow: 0 0 64px rgba(255,251,235,0.72);
}

.vb-gallery-twentyfive-art-green {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-twentyfive-art-green::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-twentyfive-art-green::after {
  right: 16%;
  top: 16%;
  width: 80px;
  height: 80px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-twentyfive-art-city {
  background: linear-gradient(180deg, #312e81 0%, #111827 66%, #020617 100%);
}

.vb-gallery-twentyfive-art-city::before {
  left: 10%;
  bottom: 0;
  width: 18%;
  height: 58%;
  background: #020617;
  box-shadow:
    70px -42px 0 #020617,
    142px -12px 0 #020617,
    224px -62px 0 #020617,
    304px -24px 0 #020617;
}

.vb-gallery-twentyfive-art-city::after {
  inset: 18% 10% auto 10%;
  height: 3px;
  background: repeating-linear-gradient(90deg, rgba(255,255,255,0.82) 0 8px, transparent 8px 24px);
  box-shadow:
    0 34px 0 rgba(255,255,255,0.42),
    0 70px 0 rgba(255,255,255,0.22);
}

.vb-gallery-twentyfive-body {
  display: grid;
  gap: 8px;
  padding: 18px;
}

.vb-gallery-twentyfive-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #fff1f2;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-twentyfive-body h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-twentyfive-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-gallery-twentyfive-empty {
  margin-top: 18px;
  padding: 28px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px dashed rgba(244, 63, 94, 0.40);
  text-align: center;
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.07);
}

.vb-gallery-twentyfive-empty h4 {
  margin: 0 0 8px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 24px !important;
  line-height: 1.1 !important;
  font-weight: 950 !important;
}

.vb-gallery-twentyfive-empty p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 15px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 980px) {
  .vb-gallery-twentyfive-header {
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentyfive-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .vb-gallery-twentyfive-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-twentyfive-header h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-twentyfive-tabs {
    display: grid;
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentyfive-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This image gallery with favorite items is useful for inspiration galleries, product shortlists, real estate favorites, travel wishlists, media libraries, moodboards, and visual selection interfaces where users need to save preferred images.</p>



<h2 class="wp-block-heading">26. Image Gallery with Load More Pagination</h2>



<p class="wp-block-paragraph"><strong>An image gallery with load more pagination</strong> helps large galleries stay fast and easy to browse. Instead of showing every image at once, the gallery displays a limited number of items first and adds more when the user clicks a button.</p>



<p class="wp-block-paragraph">This example uses JavaScript pagination state. The gallery starts with four CSS-illustrated items, the Load More button adds the next batch, the progress text updates, and the button disappears when all items are visible. The thumbnails are CSS-only illustrations, so no external images are loaded.</p>



<ul class="wp-block-list">
<li>Load more image gallery</li>
<li>JavaScript pagination state</li>
<li>Batch-based gallery rendering</li>
<li>Dynamic progress text</li>
<li>CSS-only gallery cards</li>
</ul>



<div class="vb-gallery-twentysix-demo">
  <div class="vb-gallery-twentysix-shell" data-vb-gallery-twentysix>
    <div class="vb-gallery-twentysix-top">
      <div>
        <span>Example 26</span>
        <h3>Image Gallery with Load More Pagination</h3>
        <p>Reveal CSS-illustrated gallery cards in batches with JavaScript load more pagination.</p>
      </div>

      <strong data-vb-gallery-twentysix-progress>Showing 0 of 0</strong>
    </div>

    <div class="vb-gallery-twentysix-grid" data-vb-gallery-twentysix-grid></div>

    <div class="vb-gallery-twentysix-actions">
      <button type="button" data-vb-gallery-twentysix-more>Load More Images</button>
    </div>
  </div>
</div>

<style>
.vb-gallery-twentysix-demo,
.vb-gallery-twentysix-demo * {
  box-sizing: border-box;
}

.vb-gallery-twentysix-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    linear-gradient(90deg, rgba(15, 23, 42, 0.05) 1px, transparent 1px),
    linear-gradient(0deg, rgba(15, 23, 42, 0.05) 1px, transparent 1px),
    linear-gradient(135deg, #f8fafc 0%, #ecfeff 52%, #ffffff 100%) !important;
  background-size: 32px 32px, 32px 32px, auto !important;
  border: 1px solid rgba(6, 182, 212, 0.20);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.09);
}

.vb-gallery-twentysix-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-twentysix-top {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 24px;
}

.vb-gallery-twentysix-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #cffafe;
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-twentysix-top h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-twentysix-top p {
  max-width: 740px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-twentysix-top strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-twentysix-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-twentysix-card {
  overflow: hidden;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  animation: vbGalleryTwentysixIn 0.34s ease both;
}

@keyframes vbGalleryTwentysixIn {
  from {
    opacity: 0;
    transform: translateY(16px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.vb-gallery-twentysix-art {
  position: relative;
  height: 225px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-twentysix-art::before,
.vb-gallery-twentysix-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-twentysix-art-blue {
  background: linear-gradient(135deg, #020617 0%, #2563eb 54%, #38bdf8 100%);
}

.vb-gallery-twentysix-art-blue::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 60%;
  border-radius: 28px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 20px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-twentysix-art-blue::after {
  right: 16%;
  bottom: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-twentysix-art-cyan {
  background: linear-gradient(135deg, #ecfeff 0%, #06b6d4 48%, #0f766e 100%);
}

.vb-gallery-twentysix-art-cyan::before {
  left: 16%;
  top: 18%;
  width: 68%;
  height: 62%;
  border-radius: 28px;
  background: rgba(255,255,255,0.20);
  border: 1px solid rgba(255,255,255,0.34);
  backdrop-filter: blur(4px);
}

.vb-gallery-twentysix-art-cyan::after {
  left: 50%;
  top: 50%;
  width: 92px;
  height: 92px;
  border-radius: 26px;
  background: rgba(255,255,255,0.70);
  transform: translate(-50%, -50%) rotate(20deg);
}

.vb-gallery-twentysix-art-gold {
  background: linear-gradient(180deg, #fef3c7 0%, #f59e0b 52%, #78350f 100%);
}

.vb-gallery-twentysix-art-gold::before {
  left: -8%;
  right: -8%;
  bottom: -18%;
  height: 56%;
  background: #451a03;
  clip-path: polygon(0 100%, 0 58%, 15% 42%, 30% 66%, 48% 34%, 66% 62%, 83% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-twentysix-art-gold::after {
  right: 18%;
  top: 16%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: #fffbeb;
  box-shadow: 0 0 64px rgba(255,251,235,0.72);
}

.vb-gallery-twentysix-art-green {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-twentysix-art-green::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-twentysix-art-green::after {
  right: 16%;
  top: 16%;
  width: 80px;
  height: 80px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-twentysix-art-purple {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #ddd6fe 36%, #581c87 100%);
}

.vb-gallery-twentysix-art-purple::before {
  left: 50%;
  top: 50%;
  width: 132px;
  height: 132px;
  border-radius: 30px;
  background: linear-gradient(135deg, #ffffff, #c4b5fd);
  box-shadow: 0 30px 80px rgba(88,28,135,0.32);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentysix-art-purple::after {
  left: 50%;
  top: 50%;
  width: 68px;
  height: 68px;
  border-radius: 20px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentysix-art-pink {
  background: linear-gradient(135deg, #500724 0%, #be123c 52%, #fb7185 100%);
}

.vb-gallery-twentysix-art-pink::before {
  left: 50%;
  top: 52%;
  width: 140px;
  height: 140px;
  border-radius: 42% 58% 62% 38%;
  background: radial-gradient(circle at 35% 30%, #fff1f2, #fb7185 44%, #9f1239 100%);
  transform: translate(-50%, -50%) rotate(22deg);
  box-shadow: 0 26px 70px rgba(80,7,36,0.36);
}

.vb-gallery-twentysix-art-pink::after {
  left: 14%;
  top: 16%;
  width: 74px;
  height: 74px;
  border-radius: 999px;
  background: rgba(255,255,255,0.22);
  filter: blur(6px);
}

.vb-gallery-twentysix-art-city {
  background: linear-gradient(180deg, #312e81 0%, #111827 66%, #020617 100%);
}

.vb-gallery-twentysix-art-city::before {
  left: 10%;
  bottom: 0;
  width: 18%;
  height: 58%;
  background: #020617;
  box-shadow:
    70px -42px 0 #020617,
    142px -12px 0 #020617,
    224px -62px 0 #020617,
    304px -24px 0 #020617;
}

.vb-gallery-twentysix-art-city::after {
  inset: 18% 10% auto 10%;
  height: 3px;
  background: repeating-linear-gradient(90deg, rgba(255,255,255,0.82) 0 8px, transparent 8px 24px);
  box-shadow:
    0 34px 0 rgba(255,255,255,0.42),
    0 70px 0 rgba(255,255,255,0.22);
}

.vb-gallery-twentysix-art-red {
  background: radial-gradient(circle at 50% 50%, #ffffff 0%, #fecaca 32%, #991b1b 100%);
}

.vb-gallery-twentysix-art-red::before {
  left: 50%;
  top: 50%;
  width: 150px;
  height: 150px;
  border-radius: 999px;
  border: 18px solid rgba(255,255,255,0.36);
  border-left-color: rgba(255,255,255,0.86);
  transform: translate(-50%, -50%) rotate(18deg);
}

.vb-gallery-twentysix-art-red::after {
  left: 50%;
  top: 50%;
  width: 76px;
  height: 76px;
  border-radius: 999px;
  background: rgba(255,255,255,0.76);
  transform: translate(-50%, -50%);
}

.vb-gallery-twentysix-body {
  display: grid;
  gap: 8px;
  padding: 17px;
}

.vb-gallery-twentysix-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #ecfeff;
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-twentysix-body h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-twentysix-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-gallery-twentysix-actions {
  display: flex;
  justify-content: center;
  margin-top: 22px;
}

.vb-gallery-twentysix-actions button {
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #06b6d4, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 15px 22px;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 36px rgba(6, 182, 212, 0.24);
}

.vb-gallery-twentysix-actions button[hidden] {
  display: none;
}

@media (max-width: 1050px) {
  .vb-gallery-twentysix-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 820px) {
  .vb-gallery-twentysix-top {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-twentysix-top strong {
    justify-content: center;
    width: 100%;
  }

  .vb-gallery-twentysix-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .vb-gallery-twentysix-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-twentysix-top h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-twentysix-grid {
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentysix-actions button {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-twentysix]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-twentysix-grid]");
  const progress = gallery.querySelector("[data-vb-gallery-twentysix-progress]");
  const moreButton = gallery.querySelector("[data-vb-gallery-twentysix-more]");

  const batchSize = 4;
  let visibleCount = batchSize;

  const items = [
    {
      title: "Blue Portfolio",
      category: "Portfolio",
      art: "vb-gallery-twentysix-art-blue",
      description: "A CSS-only gallery image loaded in the first visible batch."
    },
    {
      title: "Cyan Product",
      category: "Product",
      art: "vb-gallery-twentysix-art-cyan",
      description: "A clean CSS visual card for paginated image gallery sections."
    },
    {
      title: "Gold Travel",
      category: "Travel",
      art: "vb-gallery-twentysix-art-gold",
      description: "A warm CSS card revealed by the load more gallery system."
    },
    {
      title: "Green Forest",
      category: "Nature",
      art: "vb-gallery-twentysix-art-green",
      description: "A CSS nature image included in the first gallery batch."
    },
    {
      title: "Purple Object",
      category: "Product",
      art: "vb-gallery-twentysix-art-purple",
      description: "A CSS product-style card shown after clicking load more."
    },
    {
      title: "Pink Abstract",
      category: "Abstract",
      art: "vb-gallery-twentysix-art-pink",
      description: "A creative CSS thumbnail loaded in a later gallery batch."
    },
    {
      title: "City Night",
      category: "Architecture",
      art: "vb-gallery-twentysix-art-city",
      description: "A CSS city visual revealed through pagination state."
    },
    {
      title: "Red Motion",
      category: "Event",
      art: "vb-gallery-twentysix-art-red",
      description: "A CSS event-style card loaded when more items are requested."
    }
  ];

  function createCard(item, index) {
    return `
      <article class="vb-gallery-twentysix-card" style="animation-delay: ${index * 45}ms">
        <div class="vb-gallery-twentysix-art ${item.art}" aria-label="${item.title} illustration" role="img"></div>

        <div class="vb-gallery-twentysix-body">
          <span>${item.category}</span>
          <h4>${item.title}</h4>
          <p>${item.description}</p>
        </div>
      </article>
    `;
  }

  function renderGallery() {
    const visibleItems = items.slice(0, visibleCount);

    grid.innerHTML = visibleItems.map(createCard).join("");
    progress.textContent = "Showing " + visibleItems.length + " of " + items.length;
    moreButton.hidden = visibleItems.length >= items.length;
  }

  moreButton.addEventListener("click", function () {
    visibleCount = Math.min(visibleCount + batchSize, items.length);
    renderGallery();
  });

  renderGallery();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-twentysix]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-twentysix-grid]");
  const progress = gallery.querySelector("[data-vb-gallery-twentysix-progress]");
  const moreButton = gallery.querySelector("[data-vb-gallery-twentysix-more]");

  const batchSize = 4;
  let visibleCount = batchSize;

  const items = [
    {
      title: "Blue Portfolio",
      category: "Portfolio",
      art: "vb-gallery-twentysix-art-blue",
      description: "A CSS-only gallery image loaded in the first visible batch."
    },
    {
      title: "Cyan Product",
      category: "Product",
      art: "vb-gallery-twentysix-art-cyan",
      description: "A clean CSS visual card for paginated image gallery sections."
    },
    {
      title: "Gold Travel",
      category: "Travel",
      art: "vb-gallery-twentysix-art-gold",
      description: "A warm CSS card revealed by the load more gallery system."
    },
    {
      title: "Green Forest",
      category: "Nature",
      art: "vb-gallery-twentysix-art-green",
      description: "A CSS nature image included in the first gallery batch."
    },
    {
      title: "Purple Object",
      category: "Product",
      art: "vb-gallery-twentysix-art-purple",
      description: "A CSS product-style card shown after clicking load more."
    },
    {
      title: "Pink Abstract",
      category: "Abstract",
      art: "vb-gallery-twentysix-art-pink",
      description: "A creative CSS thumbnail loaded in a later gallery batch."
    },
    {
      title: "City Night",
      category: "Architecture",
      art: "vb-gallery-twentysix-art-city",
      description: "A CSS city visual revealed through pagination state."
    },
    {
      title: "Red Motion",
      category: "Event",
      art: "vb-gallery-twentysix-art-red",
      description: "A CSS event-style card loaded when more items are requested."
    }
  ];

  function createCard(item, index) {
    return `
      &lt;article class="vb-gallery-twentysix-card" style="animation-delay: ${index * 45}ms"&gt;
        &lt;div class="vb-gallery-twentysix-art ${item.art}" aria-label="${item.title} illustration" role="img"&gt;&lt;/div&gt;

        &lt;div class="vb-gallery-twentysix-body"&gt;
          &lt;span&gt;${item.category}&lt;/span&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
          &lt;p&gt;${item.description}&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    `;
  }

  function renderGallery() {
    const visibleItems = items.slice(0, visibleCount);

    grid.innerHTML = visibleItems.map(createCard).join("");
    progress.textContent = "Showing " + visibleItems.length + " of " + items.length;
    moreButton.hidden = visibleItems.length &gt;= items.length;
  }

  moreButton.addEventListener("click", function () {
    visibleCount = Math.min(visibleCount + batchSize, items.length);
    renderGallery();
  });

  renderGallery();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-twentysix-demo"&gt;
  &lt;div class="vb-gallery-twentysix-shell" data-vb-gallery-twentysix&gt;
    &lt;div class="vb-gallery-twentysix-top"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 26&lt;/span&gt;
        &lt;h3&gt;Image Gallery with Load More Pagination&lt;/h3&gt;
        &lt;p&gt;Reveal CSS-illustrated gallery cards in batches with JavaScript load more pagination.&lt;/p&gt;
      &lt;/div&gt;

      &lt;strong data-vb-gallery-twentysix-progress&gt;Showing 0 of 0&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-twentysix-grid" data-vb-gallery-twentysix-grid&gt;&lt;/div&gt;

    &lt;div class="vb-gallery-twentysix-actions"&gt;
      &lt;button type="button" data-vb-gallery-twentysix-more&gt;Load More Images&lt;/button&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-twentysix-demo,
.vb-gallery-twentysix-demo * {
  box-sizing: border-box;
}

.vb-gallery-twentysix-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    linear-gradient(90deg, rgba(15, 23, 42, 0.05) 1px, transparent 1px),
    linear-gradient(0deg, rgba(15, 23, 42, 0.05) 1px, transparent 1px),
    linear-gradient(135deg, #f8fafc 0%, #ecfeff 52%, #ffffff 100%) !important;
  background-size: 32px 32px, 32px 32px, auto !important;
  border: 1px solid rgba(6, 182, 212, 0.20);
  box-shadow: 0 28px 80px rgba(15, 23, 42, 0.09);
}

.vb-gallery-twentysix-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-twentysix-top {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 24px;
}

.vb-gallery-twentysix-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #cffafe;
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-twentysix-top h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-twentysix-top p {
  max-width: 740px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-twentysix-top strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-twentysix-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-twentysix-card {
  overflow: hidden;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  animation: vbGalleryTwentysixIn 0.34s ease both;
}

@keyframes vbGalleryTwentysixIn {
  from {
    opacity: 0;
    transform: translateY(16px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.vb-gallery-twentysix-art {
  position: relative;
  height: 225px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-twentysix-art::before,
.vb-gallery-twentysix-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-twentysix-art-blue {
  background: linear-gradient(135deg, #020617 0%, #2563eb 54%, #38bdf8 100%);
}

.vb-gallery-twentysix-art-blue::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 60%;
  border-radius: 28px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 20px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-twentysix-art-blue::after {
  right: 16%;
  bottom: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-twentysix-art-cyan {
  background: linear-gradient(135deg, #ecfeff 0%, #06b6d4 48%, #0f766e 100%);
}

.vb-gallery-twentysix-art-cyan::before {
  left: 16%;
  top: 18%;
  width: 68%;
  height: 62%;
  border-radius: 28px;
  background: rgba(255,255,255,0.20);
  border: 1px solid rgba(255,255,255,0.34);
  backdrop-filter: blur(4px);
}

.vb-gallery-twentysix-art-cyan::after {
  left: 50%;
  top: 50%;
  width: 92px;
  height: 92px;
  border-radius: 26px;
  background: rgba(255,255,255,0.70);
  transform: translate(-50%, -50%) rotate(20deg);
}

.vb-gallery-twentysix-art-gold {
  background: linear-gradient(180deg, #fef3c7 0%, #f59e0b 52%, #78350f 100%);
}

.vb-gallery-twentysix-art-gold::before {
  left: -8%;
  right: -8%;
  bottom: -18%;
  height: 56%;
  background: #451a03;
  clip-path: polygon(0 100%, 0 58%, 15% 42%, 30% 66%, 48% 34%, 66% 62%, 83% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-twentysix-art-gold::after {
  right: 18%;
  top: 16%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: #fffbeb;
  box-shadow: 0 0 64px rgba(255,251,235,0.72);
}

.vb-gallery-twentysix-art-green {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-twentysix-art-green::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-twentysix-art-green::after {
  right: 16%;
  top: 16%;
  width: 80px;
  height: 80px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-twentysix-art-purple {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #ddd6fe 36%, #581c87 100%);
}

.vb-gallery-twentysix-art-purple::before {
  left: 50%;
  top: 50%;
  width: 132px;
  height: 132px;
  border-radius: 30px;
  background: linear-gradient(135deg, #ffffff, #c4b5fd);
  box-shadow: 0 30px 80px rgba(88,28,135,0.32);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentysix-art-purple::after {
  left: 50%;
  top: 50%;
  width: 68px;
  height: 68px;
  border-radius: 20px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentysix-art-pink {
  background: linear-gradient(135deg, #500724 0%, #be123c 52%, #fb7185 100%);
}

.vb-gallery-twentysix-art-pink::before {
  left: 50%;
  top: 52%;
  width: 140px;
  height: 140px;
  border-radius: 42% 58% 62% 38%;
  background: radial-gradient(circle at 35% 30%, #fff1f2, #fb7185 44%, #9f1239 100%);
  transform: translate(-50%, -50%) rotate(22deg);
  box-shadow: 0 26px 70px rgba(80,7,36,0.36);
}

.vb-gallery-twentysix-art-pink::after {
  left: 14%;
  top: 16%;
  width: 74px;
  height: 74px;
  border-radius: 999px;
  background: rgba(255,255,255,0.22);
  filter: blur(6px);
}

.vb-gallery-twentysix-art-city {
  background: linear-gradient(180deg, #312e81 0%, #111827 66%, #020617 100%);
}

.vb-gallery-twentysix-art-city::before {
  left: 10%;
  bottom: 0;
  width: 18%;
  height: 58%;
  background: #020617;
  box-shadow:
    70px -42px 0 #020617,
    142px -12px 0 #020617,
    224px -62px 0 #020617,
    304px -24px 0 #020617;
}

.vb-gallery-twentysix-art-city::after {
  inset: 18% 10% auto 10%;
  height: 3px;
  background: repeating-linear-gradient(90deg, rgba(255,255,255,0.82) 0 8px, transparent 8px 24px);
  box-shadow:
    0 34px 0 rgba(255,255,255,0.42),
    0 70px 0 rgba(255,255,255,0.22);
}

.vb-gallery-twentysix-art-red {
  background: radial-gradient(circle at 50% 50%, #ffffff 0%, #fecaca 32%, #991b1b 100%);
}

.vb-gallery-twentysix-art-red::before {
  left: 50%;
  top: 50%;
  width: 150px;
  height: 150px;
  border-radius: 999px;
  border: 18px solid rgba(255,255,255,0.36);
  border-left-color: rgba(255,255,255,0.86);
  transform: translate(-50%, -50%) rotate(18deg);
}

.vb-gallery-twentysix-art-red::after {
  left: 50%;
  top: 50%;
  width: 76px;
  height: 76px;
  border-radius: 999px;
  background: rgba(255,255,255,0.76);
  transform: translate(-50%, -50%);
}

.vb-gallery-twentysix-body {
  display: grid;
  gap: 8px;
  padding: 17px;
}

.vb-gallery-twentysix-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #ecfeff;
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-twentysix-body h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-twentysix-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-gallery-twentysix-actions {
  display: flex;
  justify-content: center;
  margin-top: 22px;
}

.vb-gallery-twentysix-actions button {
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(135deg, #06b6d4, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 15px 22px;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
  box-shadow: 0 16px 36px rgba(6, 182, 212, 0.24);
}

.vb-gallery-twentysix-actions button[hidden] {
  display: none;
}

@media (max-width: 1050px) {
  .vb-gallery-twentysix-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 820px) {
  .vb-gallery-twentysix-top {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-twentysix-top strong {
    justify-content: center;
    width: 100%;
  }

  .vb-gallery-twentysix-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .vb-gallery-twentysix-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-twentysix-top h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-twentysix-grid {
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentysix-actions button {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This image gallery with load more pagination is useful for large portfolios, media libraries, ecommerce image galleries, real estate galleries, travel collections, and image-heavy landing pages where loading every item immediately would make the page feel too long.</p>



<h2 class="wp-block-heading">27. Image Gallery with Image Detail Drawer</h2>



<p class="wp-block-paragraph"><strong>An image gallery with an image detail drawer</strong> lets users inspect extra information without leaving the gallery. This pattern is useful for portfolio case studies, product galleries, real estate images, media libraries, design review tools, travel collections, and visual documentation pages.</p>



<p class="wp-block-paragraph">This example uses JavaScript drawer state. Clicking a CSS-illustrated gallery item opens a side drawer with the selected image title, category, date, size, tags, and description. The drawer can be closed with the close button, overlay click, or Escape key. No external image files are loaded.</p>



<ul class="wp-block-list">
<li>Image gallery with detail drawer</li>
<li>JavaScript selected item state</li>
<li>Dynamic image metadata panel</li>
<li>Close with button, overlay, or Escape key</li>
<li>CSS-only illustrated thumbnails</li>
</ul>



<div class="vb-gallery-twentyseven-demo">
  <div class="vb-gallery-twentyseven-shell" data-vb-gallery-twentyseven>
    <div class="vb-gallery-twentyseven-head">
      <div>
        <span>Example 27</span>
        <h3>Image Gallery with Image Detail Drawer</h3>
        <p>Click a CSS-illustrated gallery card and open a JavaScript-powered detail drawer.</p>
      </div>

      <strong data-vb-gallery-twentyseven-status>Select an image</strong>
    </div>

    <div class="vb-gallery-twentyseven-grid" data-vb-gallery-twentyseven-grid></div>

    <div class="vb-gallery-twentyseven-overlay" data-vb-gallery-twentyseven-overlay hidden></div>

    <aside class="vb-gallery-twentyseven-drawer" data-vb-gallery-twentyseven-drawer hidden>
      <button type="button" class="vb-gallery-twentyseven-close" data-vb-gallery-twentyseven-close>Close</button>

      <div class="vb-gallery-twentyseven-drawer-art" data-vb-gallery-twentyseven-drawer-art></div>

      <div class="vb-gallery-twentyseven-drawer-content">
        <span data-vb-gallery-twentyseven-drawer-category>Category</span>
        <h4 data-vb-gallery-twentyseven-drawer-title>Gallery Item</h4>
        <p data-vb-gallery-twentyseven-drawer-description>Selected image description.</p>

        <div class="vb-gallery-twentyseven-meta">
          <div>
            <small>Date</small>
            <strong data-vb-gallery-twentyseven-drawer-date>2026</strong>
          </div>

          <div>
            <small>Size</small>
            <strong data-vb-gallery-twentyseven-drawer-size>1600×900</strong>
          </div>
        </div>

        <div class="vb-gallery-twentyseven-tags" data-vb-gallery-twentyseven-drawer-tags></div>
      </div>
    </aside>
  </div>
</div>

<style>
.vb-gallery-twentyseven-demo,
.vb-gallery-twentyseven-demo * {
  box-sizing: border-box;
}

.vb-gallery-twentyseven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 14% 14%, rgba(37, 99, 235, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(16, 185, 129, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 52%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.20);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-gallery-twentyseven-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-twentyseven-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 24px;
}

.vb-gallery-twentyseven-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-twentyseven-head h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-twentyseven-head p {
  max-width: 740px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-twentyseven-head strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-twentyseven-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-gallery-twentyseven-card {
  overflow: hidden;
  padding: 0;
  border: 0;
  border-radius: 30px;
  background: #ffffff;
  cursor: pointer;
  text-align: left;
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  transition: transform 0.22s ease, box-shadow 0.22s ease;
  animation: vbGalleryTwentysevenIn 0.34s ease both;
}

@keyframes vbGalleryTwentysevenIn {
  from {
    opacity: 0;
    transform: translateY(16px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.vb-gallery-twentyseven-card:hover {
  transform: translateY(-6px);
  box-shadow: 0 26px 64px rgba(15, 23, 42, 0.16);
}

.vb-gallery-twentyseven-art,
.vb-gallery-twentyseven-drawer-art {
  position: relative;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-twentyseven-art {
  height: 245px;
}

.vb-gallery-twentyseven-drawer-art {
  height: 320px;
}

.vb-gallery-twentyseven-art::before,
.vb-gallery-twentyseven-art::after,
.vb-gallery-twentyseven-drawer-art::before,
.vb-gallery-twentyseven-drawer-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-twentyseven-art-blue,
.vb-gallery-twentyseven-drawer-art-blue {
  background: linear-gradient(135deg, #020617 0%, #2563eb 54%, #38bdf8 100%);
}

.vb-gallery-twentyseven-art-blue::before,
.vb-gallery-twentyseven-drawer-art-blue::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 60%;
  border-radius: 28px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 20px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-twentyseven-art-blue::after,
.vb-gallery-twentyseven-drawer-art-blue::after {
  right: 16%;
  bottom: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-twentyseven-art-gold,
.vb-gallery-twentyseven-drawer-art-gold {
  background: linear-gradient(180deg, #fef3c7 0%, #f59e0b 52%, #78350f 100%);
}

.vb-gallery-twentyseven-art-gold::before,
.vb-gallery-twentyseven-drawer-art-gold::before {
  left: -8%;
  right: -8%;
  bottom: -18%;
  height: 56%;
  background: #451a03;
  clip-path: polygon(0 100%, 0 58%, 15% 42%, 30% 66%, 48% 34%, 66% 62%, 83% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-twentyseven-art-gold::after,
.vb-gallery-twentyseven-drawer-art-gold::after {
  right: 18%;
  top: 16%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: #fffbeb;
  box-shadow: 0 0 64px rgba(255,251,235,0.72);
}

.vb-gallery-twentyseven-art-purple,
.vb-gallery-twentyseven-drawer-art-purple {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #ddd6fe 36%, #581c87 100%);
}

.vb-gallery-twentyseven-art-purple::before,
.vb-gallery-twentyseven-drawer-art-purple::before {
  left: 50%;
  top: 50%;
  width: 132px;
  height: 132px;
  border-radius: 30px;
  background: linear-gradient(135deg, #ffffff, #c4b5fd);
  box-shadow: 0 30px 80px rgba(88,28,135,0.32);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentyseven-art-purple::after,
.vb-gallery-twentyseven-drawer-art-purple::after {
  left: 50%;
  top: 50%;
  width: 68px;
  height: 68px;
  border-radius: 20px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentyseven-art-green,
.vb-gallery-twentyseven-drawer-art-green {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-twentyseven-art-green::before,
.vb-gallery-twentyseven-drawer-art-green::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-twentyseven-art-green::after,
.vb-gallery-twentyseven-drawer-art-green::after {
  right: 16%;
  top: 16%;
  width: 80px;
  height: 80px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-twentyseven-art-pink,
.vb-gallery-twentyseven-drawer-art-pink {
  background: linear-gradient(135deg, #500724 0%, #be123c 52%, #fb7185 100%);
}

.vb-gallery-twentyseven-art-pink::before,
.vb-gallery-twentyseven-drawer-art-pink::before {
  left: 50%;
  top: 52%;
  width: 140px;
  height: 140px;
  border-radius: 42% 58% 62% 38%;
  background: radial-gradient(circle at 35% 30%, #fff1f2, #fb7185 44%, #9f1239 100%);
  transform: translate(-50%, -50%) rotate(22deg);
  box-shadow: 0 26px 70px rgba(80,7,36,0.36);
}

.vb-gallery-twentyseven-art-pink::after,
.vb-gallery-twentyseven-drawer-art-pink::after {
  left: 14%;
  top: 16%;
  width: 74px;
  height: 74px;
  border-radius: 999px;
  background: rgba(255,255,255,0.22);
  filter: blur(6px);
}

.vb-gallery-twentyseven-art-city,
.vb-gallery-twentyseven-drawer-art-city {
  background: linear-gradient(180deg, #312e81 0%, #111827 66%, #020617 100%);
}

.vb-gallery-twentyseven-art-city::before,
.vb-gallery-twentyseven-drawer-art-city::before {
  left: 10%;
  bottom: 0;
  width: 18%;
  height: 58%;
  background: #020617;
  box-shadow:
    70px -42px 0 #020617,
    142px -12px 0 #020617,
    224px -62px 0 #020617,
    304px -24px 0 #020617;
}

.vb-gallery-twentyseven-art-city::after,
.vb-gallery-twentyseven-drawer-art-city::after {
  inset: 18% 10% auto 10%;
  height: 3px;
  background: repeating-linear-gradient(90deg, rgba(255,255,255,0.82) 0 8px, transparent 8px 24px);
  box-shadow:
    0 34px 0 rgba(255,255,255,0.42),
    0 70px 0 rgba(255,255,255,0.22);
}

.vb-gallery-twentyseven-body {
  display: grid;
  gap: 8px;
  padding: 18px;
}

.vb-gallery-twentyseven-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #eff6ff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-twentyseven-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 22px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-twentyseven-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-gallery-twentyseven-overlay {
  position: fixed;
  inset: 0;
  z-index: 99998;
  background: rgba(15, 23, 42, 0.54);
  backdrop-filter: blur(6px);
}

.vb-gallery-twentyseven-overlay[hidden] {
  display: none;
}

.vb-gallery-twentyseven-drawer {
  position: fixed;
  z-index: 99999;
  top: 18px;
  right: 18px;
  bottom: 18px;
  width: min(460px, calc(100vw - 36px));
  overflow: auto;
  border-radius: 34px;
  background: #ffffff;
  box-shadow: 0 34px 120px rgba(15, 23, 42, 0.34);
  animation: vbGalleryTwentysevenDrawer 0.28s ease both;
}

.vb-gallery-twentyseven-drawer[hidden] {
  display: none;
}

@keyframes vbGalleryTwentysevenDrawer {
  from {
    opacity: 0;
    transform: translateX(40px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateX(0) scale(1);
  }
}

.vb-gallery-twentyseven-close {
  position: sticky;
  top: 14px;
  z-index: 10;
  float: right;
  margin: 14px 14px -58px 0;
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.78);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 10px 14px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
  backdrop-filter: blur(10px);
}

.vb-gallery-twentyseven-drawer-content {
  display: grid;
  gap: 14px;
  padding: 22px;
}

.vb-gallery-twentyseven-drawer-content > span {
  display: inline-flex;
  width: fit-content;
  padding: 7px 10px;
  border-radius: 999px;
  background: #eff6ff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-gallery-twentyseven-drawer-content h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(30px, 4vw, 48px) !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-gallery-twentyseven-drawer-content p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-gallery-twentyseven-meta {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.vb-gallery-twentyseven-meta div {
  padding: 14px;
  border-radius: 20px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-gallery-twentyseven-meta small {
  display: block;
  margin-bottom: 5px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 11px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-gallery-twentyseven-meta strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-gallery-twentyseven-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-gallery-twentyseven-tags small {
  display: inline-flex;
  padding: 6px 9px;
  border-radius: 999px;
  background: #ecfdf5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 11px;
  font-weight: 950;
}

@media (max-width: 980px) {
  .vb-gallery-twentyseven-head {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-twentyseven-head strong {
    justify-content: center;
    width: 100%;
  }

  .vb-gallery-twentyseven-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .vb-gallery-twentyseven-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-twentyseven-head h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-twentyseven-grid {
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentyseven-drawer {
    inset: auto 10px 10px 10px;
    width: auto;
    max-height: calc(100vh - 20px);
    border-radius: 26px;
  }

  .vb-gallery-twentyseven-drawer-art {
    height: 240px;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-twentyseven]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-twentyseven-grid]");
  const status = gallery.querySelector("[data-vb-gallery-twentyseven-status]");
  const overlay = gallery.querySelector("[data-vb-gallery-twentyseven-overlay]");
  const drawer = gallery.querySelector("[data-vb-gallery-twentyseven-drawer]");
  const closeButton = gallery.querySelector("[data-vb-gallery-twentyseven-close]");
  const drawerArt = gallery.querySelector("[data-vb-gallery-twentyseven-drawer-art]");
  const drawerTitle = gallery.querySelector("[data-vb-gallery-twentyseven-drawer-title]");
  const drawerCategory = gallery.querySelector("[data-vb-gallery-twentyseven-drawer-category]");
  const drawerDescription = gallery.querySelector("[data-vb-gallery-twentyseven-drawer-description]");
  const drawerDate = gallery.querySelector("[data-vb-gallery-twentyseven-drawer-date]");
  const drawerSize = gallery.querySelector("[data-vb-gallery-twentyseven-drawer-size]");
  const drawerTags = gallery.querySelector("[data-vb-gallery-twentyseven-drawer-tags]");

  const items = [
    {
      id: "blue-interface",
      title: "Blue Interface",
      category: "Portfolio",
      art: "vb-gallery-twentyseven-art-blue",
      drawerArt: "vb-gallery-twentyseven-drawer-art-blue",
      date: "Jan 2026",
      size: "1600×900",
      tags: ["portfolio", "ui", "blue"],
      description: "A CSS-only portfolio image concept with a clean interface-inspired visual."
    },
    {
      id: "gold-travel",
      title: "Gold Travel",
      category: "Travel",
      art: "vb-gallery-twentyseven-art-gold",
      drawerArt: "vb-gallery-twentyseven-drawer-art-gold",
      date: "Feb 2026",
      size: "1400×1000",
      tags: ["travel", "warm", "campaign"],
      description: "A warm CSS travel image concept for destination galleries and landing pages."
    },
    {
      id: "purple-product",
      title: "Purple Product",
      category: "Product",
      art: "vb-gallery-twentyseven-art-purple",
      drawerArt: "vb-gallery-twentyseven-drawer-art-purple",
      date: "Mar 2026",
      size: "1200×1200",
      tags: ["product", "launch", "object"],
      description: "A product-style CSS image used for ecommerce galleries and launch sections."
    },
    {
      id: "green-forest",
      title: "Green Forest",
      category: "Nature",
      art: "vb-gallery-twentyseven-art-green",
      drawerArt: "vb-gallery-twentyseven-drawer-art-green",
      date: "Apr 2026",
      size: "1800×1100",
      tags: ["nature", "green", "outdoor"],
      description: "A CSS nature illustration for peaceful galleries, travel pages, and moodboards."
    },
    {
      id: "pink-abstract",
      title: "Pink Abstract",
      category: "Abstract",
      art: "vb-gallery-twentyseven-art-pink",
      drawerArt: "vb-gallery-twentyseven-drawer-art-pink",
      date: "May 2026",
      size: "1500×1500",
      tags: ["abstract", "creative", "poster"],
      description: "A bright abstract CSS image concept for creative inspiration galleries."
    },
    {
      id: "city-night",
      title: "City Night",
      category: "Architecture",
      art: "vb-gallery-twentyseven-art-city",
      drawerArt: "vb-gallery-twentyseven-drawer-art-city",
      date: "Jun 2026",
      size: "1920×1080",
      tags: ["city", "architecture", "night"],
      description: "A CSS city-night image card for real estate, architecture, and urban galleries."
    }
  ];

  function createCard(item, index) {
    return `
      <button type="button" class="vb-gallery-twentyseven-card" data-id="${item.id}" style="animation-delay: ${index * 45}ms">
        <div class="vb-gallery-twentyseven-art ${item.art}" aria-label="${item.title} illustration" role="img"></div>

        <div class="vb-gallery-twentyseven-body">
          <span>${item.category}</span>
          <h4>${item.title}</h4>
          <p>${item.description}</p>
        </div>
      </button>
    `;
  }

  function openDrawer(id) {
    const item = items.find(function (galleryItem) {
      return galleryItem.id === id;
    });

    if (!item) return;

    drawerArt.className = "vb-gallery-twentyseven-drawer-art " + item.drawerArt;
    drawerTitle.textContent = item.title;
    drawerCategory.textContent = item.category;
    drawerDescription.textContent = item.description;
    drawerDate.textContent = item.date;
    drawerSize.textContent = item.size;
    drawerTags.innerHTML = item.tags.map(function (tag) {
      return "<small>" + tag + "</small>";
    }).join("");

    status.textContent = "Viewing: " + item.title;
    overlay.hidden = false;
    drawer.hidden = false;
    document.body.style.overflow = "hidden";
  }

  function closeDrawer() {
    overlay.hidden = true;
    drawer.hidden = true;
    status.textContent = "Select an image";
    document.body.style.overflow = "";
  }

  grid.addEventListener("click", function (event) {
    const card = event.target.closest("[data-id]");
    if (!card) return;

    openDrawer(card.getAttribute("data-id"));
  });

  closeButton.addEventListener("click", closeDrawer);
  overlay.addEventListener("click", closeDrawer);

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape" && !drawer.hidden) {
      closeDrawer();
    }
  });

  grid.innerHTML = items.map(createCard).join("");
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-twentyseven]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-twentyseven-grid]");
  const status = gallery.querySelector("[data-vb-gallery-twentyseven-status]");
  const overlay = gallery.querySelector("[data-vb-gallery-twentyseven-overlay]");
  const drawer = gallery.querySelector("[data-vb-gallery-twentyseven-drawer]");
  const closeButton = gallery.querySelector("[data-vb-gallery-twentyseven-close]");
  const drawerArt = gallery.querySelector("[data-vb-gallery-twentyseven-drawer-art]");
  const drawerTitle = gallery.querySelector("[data-vb-gallery-twentyseven-drawer-title]");
  const drawerCategory = gallery.querySelector("[data-vb-gallery-twentyseven-drawer-category]");
  const drawerDescription = gallery.querySelector("[data-vb-gallery-twentyseven-drawer-description]");
  const drawerDate = gallery.querySelector("[data-vb-gallery-twentyseven-drawer-date]");
  const drawerSize = gallery.querySelector("[data-vb-gallery-twentyseven-drawer-size]");
  const drawerTags = gallery.querySelector("[data-vb-gallery-twentyseven-drawer-tags]");

  const items = [
    {
      id: "blue-interface",
      title: "Blue Interface",
      category: "Portfolio",
      art: "vb-gallery-twentyseven-art-blue",
      drawerArt: "vb-gallery-twentyseven-drawer-art-blue",
      date: "Jan 2026",
      size: "1600×900",
      tags: ["portfolio", "ui", "blue"],
      description: "A CSS-only portfolio image concept with a clean interface-inspired visual."
    },
    {
      id: "gold-travel",
      title: "Gold Travel",
      category: "Travel",
      art: "vb-gallery-twentyseven-art-gold",
      drawerArt: "vb-gallery-twentyseven-drawer-art-gold",
      date: "Feb 2026",
      size: "1400×1000",
      tags: ["travel", "warm", "campaign"],
      description: "A warm CSS travel image concept for destination galleries and landing pages."
    },
    {
      id: "purple-product",
      title: "Purple Product",
      category: "Product",
      art: "vb-gallery-twentyseven-art-purple",
      drawerArt: "vb-gallery-twentyseven-drawer-art-purple",
      date: "Mar 2026",
      size: "1200×1200",
      tags: ["product", "launch", "object"],
      description: "A product-style CSS image used for ecommerce galleries and launch sections."
    },
    {
      id: "green-forest",
      title: "Green Forest",
      category: "Nature",
      art: "vb-gallery-twentyseven-art-green",
      drawerArt: "vb-gallery-twentyseven-drawer-art-green",
      date: "Apr 2026",
      size: "1800×1100",
      tags: ["nature", "green", "outdoor"],
      description: "A CSS nature illustration for peaceful galleries, travel pages, and moodboards."
    },
    {
      id: "pink-abstract",
      title: "Pink Abstract",
      category: "Abstract",
      art: "vb-gallery-twentyseven-art-pink",
      drawerArt: "vb-gallery-twentyseven-drawer-art-pink",
      date: "May 2026",
      size: "1500×1500",
      tags: ["abstract", "creative", "poster"],
      description: "A bright abstract CSS image concept for creative inspiration galleries."
    },
    {
      id: "city-night",
      title: "City Night",
      category: "Architecture",
      art: "vb-gallery-twentyseven-art-city",
      drawerArt: "vb-gallery-twentyseven-drawer-art-city",
      date: "Jun 2026",
      size: "1920×1080",
      tags: ["city", "architecture", "night"],
      description: "A CSS city-night image card for real estate, architecture, and urban galleries."
    }
  ];

  function createCard(item, index) {
    return `
      &lt;button type="button" class="vb-gallery-twentyseven-card" data-id="${item.id}" style="animation-delay: ${index * 45}ms"&gt;
        &lt;div class="vb-gallery-twentyseven-art ${item.art}" aria-label="${item.title} illustration" role="img"&gt;&lt;/div&gt;

        &lt;div class="vb-gallery-twentyseven-body"&gt;
          &lt;span&gt;${item.category}&lt;/span&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
          &lt;p&gt;${item.description}&lt;/p&gt;
        &lt;/div&gt;
      &lt;/button&gt;
    `;
  }

  function openDrawer(id) {
    const item = items.find(function (galleryItem) {
      return galleryItem.id === id;
    });

    if (!item) return;

    drawerArt.className = "vb-gallery-twentyseven-drawer-art " + item.drawerArt;
    drawerTitle.textContent = item.title;
    drawerCategory.textContent = item.category;
    drawerDescription.textContent = item.description;
    drawerDate.textContent = item.date;
    drawerSize.textContent = item.size;
    drawerTags.innerHTML = item.tags.map(function (tag) {
      return "&lt;small&gt;" + tag + "&lt;/small&gt;";
    }).join("");

    status.textContent = "Viewing: " + item.title;
    overlay.hidden = false;
    drawer.hidden = false;
    document.body.style.overflow = "hidden";
  }

  function closeDrawer() {
    overlay.hidden = true;
    drawer.hidden = true;
    status.textContent = "Select an image";
    document.body.style.overflow = "";
  }

  grid.addEventListener("click", function (event) {
    const card = event.target.closest("[data-id]");
    if (!card) return;

    openDrawer(card.getAttribute("data-id"));
  });

  closeButton.addEventListener("click", closeDrawer);
  overlay.addEventListener("click", closeDrawer);

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape" && !drawer.hidden) {
      closeDrawer();
    }
  });

  grid.innerHTML = items.map(createCard).join("");
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-twentyseven-demo"&gt;
  &lt;div class="vb-gallery-twentyseven-shell" data-vb-gallery-twentyseven&gt;
    &lt;div class="vb-gallery-twentyseven-head"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 27&lt;/span&gt;
        &lt;h3&gt;Image Gallery with Image Detail Drawer&lt;/h3&gt;
        &lt;p&gt;Click a CSS-illustrated gallery card and open a JavaScript-powered detail drawer.&lt;/p&gt;
      &lt;/div&gt;

      &lt;strong data-vb-gallery-twentyseven-status&gt;Select an image&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-twentyseven-grid" data-vb-gallery-twentyseven-grid&gt;&lt;/div&gt;

    &lt;div class="vb-gallery-twentyseven-overlay" data-vb-gallery-twentyseven-overlay hidden&gt;&lt;/div&gt;

    &lt;aside class="vb-gallery-twentyseven-drawer" data-vb-gallery-twentyseven-drawer hidden&gt;
      &lt;button type="button" class="vb-gallery-twentyseven-close" data-vb-gallery-twentyseven-close&gt;Close&lt;/button&gt;

      &lt;div class="vb-gallery-twentyseven-drawer-art" data-vb-gallery-twentyseven-drawer-art&gt;&lt;/div&gt;

      &lt;div class="vb-gallery-twentyseven-drawer-content"&gt;
        &lt;span data-vb-gallery-twentyseven-drawer-category&gt;Category&lt;/span&gt;
        &lt;h4 data-vb-gallery-twentyseven-drawer-title&gt;Gallery Item&lt;/h4&gt;
        &lt;p data-vb-gallery-twentyseven-drawer-description&gt;Selected image description.&lt;/p&gt;

        &lt;div class="vb-gallery-twentyseven-meta"&gt;
          &lt;div&gt;
            &lt;small&gt;Date&lt;/small&gt;
            &lt;strong data-vb-gallery-twentyseven-drawer-date&gt;2026&lt;/strong&gt;
          &lt;/div&gt;

          &lt;div&gt;
            &lt;small&gt;Size&lt;/small&gt;
            &lt;strong data-vb-gallery-twentyseven-drawer-size&gt;1600×900&lt;/strong&gt;
          &lt;/div&gt;
        &lt;/div&gt;

        &lt;div class="vb-gallery-twentyseven-tags" data-vb-gallery-twentyseven-drawer-tags&gt;&lt;/div&gt;
      &lt;/div&gt;
    &lt;/aside&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-twentyseven-demo,
.vb-gallery-twentyseven-demo * {
  box-sizing: border-box;
}

.vb-gallery-twentyseven-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 14% 14%, rgba(37, 99, 235, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(16, 185, 129, 0.16), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 52%, #ffffff 100%) !important;
  border: 1px solid rgba(37, 99, 235, 0.20);
  box-shadow: 0 28px 80px rgba(30, 64, 175, 0.10);
}

.vb-gallery-twentyseven-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-twentyseven-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 24px;
}

.vb-gallery-twentyseven-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-twentyseven-head h3 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-twentyseven-head p {
  max-width: 740px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-twentyseven-head strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-twentyseven-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-gallery-twentyseven-card {
  overflow: hidden;
  padding: 0;
  border: 0;
  border-radius: 30px;
  background: #ffffff;
  cursor: pointer;
  text-align: left;
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  transition: transform 0.22s ease, box-shadow 0.22s ease;
  animation: vbGalleryTwentysevenIn 0.34s ease both;
}

@keyframes vbGalleryTwentysevenIn {
  from {
    opacity: 0;
    transform: translateY(16px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.vb-gallery-twentyseven-card:hover {
  transform: translateY(-6px);
  box-shadow: 0 26px 64px rgba(15, 23, 42, 0.16);
}

.vb-gallery-twentyseven-art,
.vb-gallery-twentyseven-drawer-art {
  position: relative;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-twentyseven-art {
  height: 245px;
}

.vb-gallery-twentyseven-drawer-art {
  height: 320px;
}

.vb-gallery-twentyseven-art::before,
.vb-gallery-twentyseven-art::after,
.vb-gallery-twentyseven-drawer-art::before,
.vb-gallery-twentyseven-drawer-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-twentyseven-art-blue,
.vb-gallery-twentyseven-drawer-art-blue {
  background: linear-gradient(135deg, #020617 0%, #2563eb 54%, #38bdf8 100%);
}

.vb-gallery-twentyseven-art-blue::before,
.vb-gallery-twentyseven-drawer-art-blue::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 60%;
  border-radius: 28px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 20px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-twentyseven-art-blue::after,
.vb-gallery-twentyseven-drawer-art-blue::after {
  right: 16%;
  bottom: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-twentyseven-art-gold,
.vb-gallery-twentyseven-drawer-art-gold {
  background: linear-gradient(180deg, #fef3c7 0%, #f59e0b 52%, #78350f 100%);
}

.vb-gallery-twentyseven-art-gold::before,
.vb-gallery-twentyseven-drawer-art-gold::before {
  left: -8%;
  right: -8%;
  bottom: -18%;
  height: 56%;
  background: #451a03;
  clip-path: polygon(0 100%, 0 58%, 15% 42%, 30% 66%, 48% 34%, 66% 62%, 83% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-twentyseven-art-gold::after,
.vb-gallery-twentyseven-drawer-art-gold::after {
  right: 18%;
  top: 16%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: #fffbeb;
  box-shadow: 0 0 64px rgba(255,251,235,0.72);
}

.vb-gallery-twentyseven-art-purple,
.vb-gallery-twentyseven-drawer-art-purple {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #ddd6fe 36%, #581c87 100%);
}

.vb-gallery-twentyseven-art-purple::before,
.vb-gallery-twentyseven-drawer-art-purple::before {
  left: 50%;
  top: 50%;
  width: 132px;
  height: 132px;
  border-radius: 30px;
  background: linear-gradient(135deg, #ffffff, #c4b5fd);
  box-shadow: 0 30px 80px rgba(88,28,135,0.32);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentyseven-art-purple::after,
.vb-gallery-twentyseven-drawer-art-purple::after {
  left: 50%;
  top: 50%;
  width: 68px;
  height: 68px;
  border-radius: 20px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentyseven-art-green,
.vb-gallery-twentyseven-drawer-art-green {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-twentyseven-art-green::before,
.vb-gallery-twentyseven-drawer-art-green::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-twentyseven-art-green::after,
.vb-gallery-twentyseven-drawer-art-green::after {
  right: 16%;
  top: 16%;
  width: 80px;
  height: 80px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-twentyseven-art-pink,
.vb-gallery-twentyseven-drawer-art-pink {
  background: linear-gradient(135deg, #500724 0%, #be123c 52%, #fb7185 100%);
}

.vb-gallery-twentyseven-art-pink::before,
.vb-gallery-twentyseven-drawer-art-pink::before {
  left: 50%;
  top: 52%;
  width: 140px;
  height: 140px;
  border-radius: 42% 58% 62% 38%;
  background: radial-gradient(circle at 35% 30%, #fff1f2, #fb7185 44%, #9f1239 100%);
  transform: translate(-50%, -50%) rotate(22deg);
  box-shadow: 0 26px 70px rgba(80,7,36,0.36);
}

.vb-gallery-twentyseven-art-pink::after,
.vb-gallery-twentyseven-drawer-art-pink::after {
  left: 14%;
  top: 16%;
  width: 74px;
  height: 74px;
  border-radius: 999px;
  background: rgba(255,255,255,0.22);
  filter: blur(6px);
}

.vb-gallery-twentyseven-art-city,
.vb-gallery-twentyseven-drawer-art-city {
  background: linear-gradient(180deg, #312e81 0%, #111827 66%, #020617 100%);
}

.vb-gallery-twentyseven-art-city::before,
.vb-gallery-twentyseven-drawer-art-city::before {
  left: 10%;
  bottom: 0;
  width: 18%;
  height: 58%;
  background: #020617;
  box-shadow:
    70px -42px 0 #020617,
    142px -12px 0 #020617,
    224px -62px 0 #020617,
    304px -24px 0 #020617;
}

.vb-gallery-twentyseven-art-city::after,
.vb-gallery-twentyseven-drawer-art-city::after {
  inset: 18% 10% auto 10%;
  height: 3px;
  background: repeating-linear-gradient(90deg, rgba(255,255,255,0.82) 0 8px, transparent 8px 24px);
  box-shadow:
    0 34px 0 rgba(255,255,255,0.42),
    0 70px 0 rgba(255,255,255,0.22);
}

.vb-gallery-twentyseven-body {
  display: grid;
  gap: 8px;
  padding: 18px;
}

.vb-gallery-twentyseven-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #eff6ff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-twentyseven-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 22px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-twentyseven-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-gallery-twentyseven-overlay {
  position: fixed;
  inset: 0;
  z-index: 99998;
  background: rgba(15, 23, 42, 0.54);
  backdrop-filter: blur(6px);
}

.vb-gallery-twentyseven-overlay[hidden] {
  display: none;
}

.vb-gallery-twentyseven-drawer {
  position: fixed;
  z-index: 99999;
  top: 18px;
  right: 18px;
  bottom: 18px;
  width: min(460px, calc(100vw - 36px));
  overflow: auto;
  border-radius: 34px;
  background: #ffffff;
  box-shadow: 0 34px 120px rgba(15, 23, 42, 0.34);
  animation: vbGalleryTwentysevenDrawer 0.28s ease both;
}

.vb-gallery-twentyseven-drawer[hidden] {
  display: none;
}

@keyframes vbGalleryTwentysevenDrawer {
  from {
    opacity: 0;
    transform: translateX(40px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateX(0) scale(1);
  }
}

.vb-gallery-twentyseven-close {
  position: sticky;
  top: 14px;
  z-index: 10;
  float: right;
  margin: 14px 14px -58px 0;
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.78);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 10px 14px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
  backdrop-filter: blur(10px);
}

.vb-gallery-twentyseven-drawer-content {
  display: grid;
  gap: 14px;
  padding: 22px;
}

.vb-gallery-twentyseven-drawer-content > span {
  display: inline-flex;
  width: fit-content;
  padding: 7px 10px;
  border-radius: 999px;
  background: #eff6ff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-gallery-twentyseven-drawer-content h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(30px, 4vw, 48px) !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-gallery-twentyseven-drawer-content p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-gallery-twentyseven-meta {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 10px;
}

.vb-gallery-twentyseven-meta div {
  padding: 14px;
  border-radius: 20px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-gallery-twentyseven-meta small {
  display: block;
  margin-bottom: 5px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 11px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-gallery-twentyseven-meta strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-gallery-twentyseven-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
}

.vb-gallery-twentyseven-tags small {
  display: inline-flex;
  padding: 6px 9px;
  border-radius: 999px;
  background: #ecfdf5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 11px;
  font-weight: 950;
}

@media (max-width: 980px) {
  .vb-gallery-twentyseven-head {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-twentyseven-head strong {
    justify-content: center;
    width: 100%;
  }

  .vb-gallery-twentyseven-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .vb-gallery-twentyseven-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-twentyseven-head h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-twentyseven-grid {
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentyseven-drawer {
    inset: auto 10px 10px 10px;
    width: auto;
    max-height: calc(100vh - 20px);
    border-radius: 26px;
  }

  .vb-gallery-twentyseven-drawer-art {
    height: 240px;
  }
}</pre>



<p class="wp-block-paragraph">This image gallery with an image detail drawer is useful for portfolio case studies, ecommerce product galleries, media libraries, real estate photo collections, visual documentation, and image-heavy pages where users need more context without opening a separate page.</p>



<h2 class="wp-block-heading">28. Image Gallery with Select and Bulk Actions</h2>



<p class="wp-block-paragraph"><strong>An image gallery with select and bulk actions</strong> works well when users need to manage several images at once. This pattern is useful for media libraries, admin dashboards, product image managers, portfolio review tools, client approval galleries, and visual asset management interfaces.</p>



<p class="wp-block-paragraph">This example uses JavaScript selection state. Users can select multiple CSS-illustrated gallery cards, select all, clear selection, and apply a simulated bulk archive action. The selected count, action message, and selected card styles update instantly.</p>



<ul class="wp-block-list">
<li>Selectable image gallery cards</li>
<li>JavaScript Set state for selected images</li>
<li>Select all and clear selection</li>
<li>Simulated bulk action</li>
<li>CSS-only illustrated gallery visuals</li>
</ul>



<div class="vb-gallery-twentyeight-demo">
  <div class="vb-gallery-twentyeight-shell" data-vb-gallery-twentyeight>
    <div class="vb-gallery-twentyeight-top">
      <div>
        <span>Example 28</span>
        <h3>Image Gallery with Select and Bulk Actions</h3>
        <p>Select multiple CSS-illustrated gallery cards and run JavaScript bulk actions.</p>
      </div>

      <strong data-vb-gallery-twentyeight-count>0 selected</strong>
    </div>

    <div class="vb-gallery-twentyeight-toolbar">
      <button type="button" data-vb-gallery-twentyeight-select-all>Select All</button>
      <button type="button" data-vb-gallery-twentyeight-clear>Clear Selection</button>
      <button type="button" data-vb-gallery-twentyeight-archive>Archive Selected</button>
    </div>

    <div class="vb-gallery-twentyeight-message" data-vb-gallery-twentyeight-message>Select gallery images to enable a bulk action.</div>

    <div class="vb-gallery-twentyeight-grid" data-vb-gallery-twentyeight-grid></div>
  </div>
</div>

<style>
.vb-gallery-twentyeight-demo,
.vb-gallery-twentyeight-demo * {
  box-sizing: border-box;
}

.vb-gallery-twentyeight-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 14%, rgba(245, 158, 11, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(239, 68, 68, 0.14), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fff1f2 52%, #ffffff 100%) !important;
  border: 1px solid rgba(245, 158, 11, 0.22);
  box-shadow: 0 28px 80px rgba(146, 64, 14, 0.10);
}

.vb-gallery-twentyeight-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-twentyeight-top {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 20px;
}

.vb-gallery-twentyeight-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-twentyeight-top h3 {
  max-width: 850px;
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-twentyeight-top p {
  max-width: 750px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-twentyeight-top strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-twentyeight-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 12px;
  padding: 12px;
  border-radius: 24px;
  background: rgba(255,255,255,0.78);
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.08);
}

.vb-gallery-twentyeight-toolbar button {
  appearance: none;
  border: 1px solid rgba(245, 158, 11, 0.24);
  border-radius: 999px;
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  padding: 11px 15px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  transition: transform 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.vb-gallery-twentyeight-toolbar button:hover {
  transform: translateY(-2px);
  border-color: rgba(245, 158, 11, 0.62);
}

.vb-gallery-twentyeight-toolbar button:last-child {
  border-color: transparent;
  background: linear-gradient(135deg, #f59e0b, #ef4444);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 14px 34px rgba(245, 158, 11, 0.22);
}

.vb-gallery-twentyeight-message {
  margin-bottom: 18px;
  padding: 12px 14px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  line-height: 1.5;
  font-weight: 850;
}

.vb-gallery-twentyeight-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-twentyeight-card {
  position: relative;
  overflow: hidden;
  padding: 0;
  border: 2px solid transparent;
  border-radius: 28px;
  background: #ffffff;
  cursor: pointer;
  text-align: left;
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  transition: transform 0.22s ease, border-color 0.22s ease, box-shadow 0.22s ease, opacity 0.22s ease;
  animation: vbGalleryTwentyeightIn 0.34s ease both;
}

@keyframes vbGalleryTwentyeightIn {
  from {
    opacity: 0;
    transform: translateY(16px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.vb-gallery-twentyeight-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 26px 64px rgba(15, 23, 42, 0.15);
}

.vb-gallery-twentyeight-card.is-selected {
  border-color: rgba(245, 158, 11, 0.92);
  box-shadow: 0 24px 70px rgba(245, 158, 11, 0.24);
}

.vb-gallery-twentyeight-card.is-archived {
  opacity: 0.42;
  filter: grayscale(1);
}

.vb-gallery-twentyeight-check {
  position: absolute;
  z-index: 6;
  top: 13px;
  right: 13px;
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.62);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
  backdrop-filter: blur(10px);
}

.vb-gallery-twentyeight-card.is-selected .vb-gallery-twentyeight-check {
  background: linear-gradient(135deg, #f59e0b, #ef4444);
}

.vb-gallery-twentyeight-art {
  position: relative;
  height: 225px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-twentyeight-art::before,
.vb-gallery-twentyeight-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-twentyeight-art-blue {
  background: linear-gradient(135deg, #020617 0%, #2563eb 54%, #38bdf8 100%);
}

.vb-gallery-twentyeight-art-blue::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 60%;
  border-radius: 28px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 20px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-twentyeight-art-blue::after {
  right: 16%;
  bottom: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-twentyeight-art-gold {
  background: linear-gradient(180deg, #fef3c7 0%, #f59e0b 52%, #78350f 100%);
}

.vb-gallery-twentyeight-art-gold::before {
  left: -8%;
  right: -8%;
  bottom: -18%;
  height: 56%;
  background: #451a03;
  clip-path: polygon(0 100%, 0 58%, 15% 42%, 30% 66%, 48% 34%, 66% 62%, 83% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-twentyeight-art-gold::after {
  right: 18%;
  top: 16%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: #fffbeb;
  box-shadow: 0 0 64px rgba(255,251,235,0.72);
}

.vb-gallery-twentyeight-art-purple {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #ddd6fe 36%, #581c87 100%);
}

.vb-gallery-twentyeight-art-purple::before {
  left: 50%;
  top: 50%;
  width: 132px;
  height: 132px;
  border-radius: 30px;
  background: linear-gradient(135deg, #ffffff, #c4b5fd);
  box-shadow: 0 30px 80px rgba(88,28,135,0.32);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentyeight-art-purple::after {
  left: 50%;
  top: 50%;
  width: 68px;
  height: 68px;
  border-radius: 20px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentyeight-art-green {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-twentyeight-art-green::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-twentyeight-art-green::after {
  right: 16%;
  top: 16%;
  width: 80px;
  height: 80px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-twentyeight-art-pink {
  background: linear-gradient(135deg, #500724 0%, #be123c 52%, #fb7185 100%);
}

.vb-gallery-twentyeight-art-pink::before {
  left: 50%;
  top: 52%;
  width: 140px;
  height: 140px;
  border-radius: 42% 58% 62% 38%;
  background: radial-gradient(circle at 35% 30%, #fff1f2, #fb7185 44%, #9f1239 100%);
  transform: translate(-50%, -50%) rotate(22deg);
  box-shadow: 0 26px 70px rgba(80,7,36,0.36);
}

.vb-gallery-twentyeight-art-pink::after {
  left: 14%;
  top: 16%;
  width: 74px;
  height: 74px;
  border-radius: 999px;
  background: rgba(255,255,255,0.22);
  filter: blur(6px);
}

.vb-gallery-twentyeight-art-city {
  background: linear-gradient(180deg, #312e81 0%, #111827 66%, #020617 100%);
}

.vb-gallery-twentyeight-art-city::before {
  left: 10%;
  bottom: 0;
  width: 18%;
  height: 58%;
  background: #020617;
  box-shadow:
    70px -42px 0 #020617,
    142px -12px 0 #020617,
    224px -62px 0 #020617,
    304px -24px 0 #020617;
}

.vb-gallery-twentyeight-art-city::after {
  inset: 18% 10% auto 10%;
  height: 3px;
  background: repeating-linear-gradient(90deg, rgba(255,255,255,0.82) 0 8px, transparent 8px 24px);
  box-shadow:
    0 34px 0 rgba(255,255,255,0.42),
    0 70px 0 rgba(255,255,255,0.22);
}

.vb-gallery-twentyeight-art-cyan {
  background: linear-gradient(135deg, #ecfeff 0%, #06b6d4 48%, #0f766e 100%);
}

.vb-gallery-twentyeight-art-cyan::before {
  left: 16%;
  top: 18%;
  width: 68%;
  height: 62%;
  border-radius: 28px;
  background: rgba(255,255,255,0.20);
  border: 1px solid rgba(255,255,255,0.34);
  backdrop-filter: blur(4px);
}

.vb-gallery-twentyeight-art-cyan::after {
  left: 50%;
  top: 50%;
  width: 92px;
  height: 92px;
  border-radius: 26px;
  background: rgba(255,255,255,0.70);
  transform: translate(-50%, -50%) rotate(20deg);
}

.vb-gallery-twentyeight-art-red {
  background: radial-gradient(circle at 50% 50%, #ffffff 0%, #fecaca 32%, #991b1b 100%);
}

.vb-gallery-twentyeight-art-red::before {
  left: 50%;
  top: 50%;
  width: 150px;
  height: 150px;
  border-radius: 999px;
  border: 18px solid rgba(255,255,255,0.36);
  border-left-color: rgba(255,255,255,0.86);
  transform: translate(-50%, -50%) rotate(18deg);
}

.vb-gallery-twentyeight-art-red::after {
  left: 50%;
  top: 50%;
  width: 76px;
  height: 76px;
  border-radius: 999px;
  background: rgba(255,255,255,0.76);
  transform: translate(-50%, -50%);
}

.vb-gallery-twentyeight-body {
  display: grid;
  gap: 8px;
  padding: 17px;
}

.vb-gallery-twentyeight-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #fffbeb;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-twentyeight-body h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-twentyeight-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

@media (max-width: 1050px) {
  .vb-gallery-twentyeight-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 820px) {
  .vb-gallery-twentyeight-top {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-twentyeight-top strong {
    justify-content: center;
    width: 100%;
  }

  .vb-gallery-twentyeight-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .vb-gallery-twentyeight-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-twentyeight-top h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-twentyeight-toolbar {
    display: grid;
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentyeight-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-twentyeight]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-twentyeight-grid]");
  const count = gallery.querySelector("[data-vb-gallery-twentyeight-count]");
  const message = gallery.querySelector("[data-vb-gallery-twentyeight-message]");
  const selectAllButton = gallery.querySelector("[data-vb-gallery-twentyeight-select-all]");
  const clearButton = gallery.querySelector("[data-vb-gallery-twentyeight-clear]");
  const archiveButton = gallery.querySelector("[data-vb-gallery-twentyeight-archive]");

  const selectedIds = new Set();
  const archivedIds = new Set();

  const items = [
    {
      id: "bulk-blue",
      title: "Blue Portfolio",
      category: "Portfolio",
      art: "vb-gallery-twentyeight-art-blue",
      description: "A CSS-only portfolio image for selectable gallery workflows."
    },
    {
      id: "bulk-gold",
      title: "Gold Travel",
      category: "Travel",
      art: "vb-gallery-twentyeight-art-gold",
      description: "A warm CSS travel card that can be selected for bulk actions."
    },
    {
      id: "bulk-purple",
      title: "Purple Product",
      category: "Product",
      art: "vb-gallery-twentyeight-art-purple",
      description: "A CSS product visual used in multi-select gallery management."
    },
    {
      id: "bulk-green",
      title: "Green Nature",
      category: "Nature",
      art: "vb-gallery-twentyeight-art-green",
      description: "A CSS nature image that can be selected and archived."
    },
    {
      id: "bulk-pink",
      title: "Pink Abstract",
      category: "Abstract",
      art: "vb-gallery-twentyeight-art-pink",
      description: "A creative CSS gallery card for selection state examples."
    },
    {
      id: "bulk-city",
      title: "City Night",
      category: "Architecture",
      art: "vb-gallery-twentyeight-art-city",
      description: "A CSS city image for admin-style image gallery actions."
    },
    {
      id: "bulk-cyan",
      title: "Cyan Glass",
      category: "Design",
      art: "vb-gallery-twentyeight-art-cyan",
      description: "A bright CSS image card that supports selected and archived states."
    },
    {
      id: "bulk-red",
      title: "Red Motion",
      category: "Event",
      art: "vb-gallery-twentyeight-art-red",
      description: "A CSS event-style image used for gallery bulk action testing."
    }
  ];

  function createCard(item, index) {
    const selectedClass = selectedIds.has(item.id) ? "is-selected" : "";
    const archivedClass = archivedIds.has(item.id) ? "is-archived" : "";
    const checkText = selectedIds.has(item.id) ? "✓" : "+";

    return `
      <button type="button" class="vb-gallery-twentyeight-card ${selectedClass} ${archivedClass}" data-id="${item.id}" style="animation-delay: ${index * 35}ms">
        <span class="vb-gallery-twentyeight-check">${checkText}</span>
        <div class="vb-gallery-twentyeight-art ${item.art}" aria-label="${item.title} illustration" role="img"></div>

        <div class="vb-gallery-twentyeight-body">
          <span>${item.category}</span>
          <h4>${item.title}</h4>
          <p>${item.description}</p>
        </div>
      </button>
    `;
  }

  function updateCount() {
    count.textContent = selectedIds.size === 1 ? "1 selected" : selectedIds.size + " selected";
  }

  function updateMessage(text) {
    if (text) {
      message.textContent = text;
      return;
    }

    if (selectedIds.size === 0) {
      message.textContent = "Select gallery images to enable a bulk action.";
    } else {
      message.textContent = "Ready to run a bulk action on " + selectedIds.size + " selected image" + (selectedIds.size === 1 ? "." : "s.");
    }
  }

  function renderGallery(messageText) {
    grid.innerHTML = items.map(createCard).join("");
    updateCount();
    updateMessage(messageText);
  }

  function toggleSelected(id) {
    if (archivedIds.has(id)) return;

    if (selectedIds.has(id)) {
      selectedIds.delete(id);
    } else {
      selectedIds.add(id);
    }

    renderGallery();
  }

  grid.addEventListener("click", function (event) {
    const card = event.target.closest("[data-id]");
    if (!card) return;

    toggleSelected(card.getAttribute("data-id"));
  });

  selectAllButton.addEventListener("click", function () {
    items.forEach(function (item) {
      if (!archivedIds.has(item.id)) {
        selectedIds.add(item.id);
      }
    });

    renderGallery("All active gallery images selected.");
  });

  clearButton.addEventListener("click", function () {
    selectedIds.clear();
    renderGallery("Selection cleared.");
  });

  archiveButton.addEventListener("click", function () {
    if (selectedIds.size === 0) {
      renderGallery("Select at least one image before running a bulk action.");
      return;
    }

    selectedIds.forEach(function (id) {
      archivedIds.add(id);
    });

    const archivedCount = selectedIds.size;
    selectedIds.clear();
    renderGallery(archivedCount + " image" + (archivedCount === 1 ? " was" : "s were") + " archived in JavaScript state.");
  });

  renderGallery();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-twentyeight]");
  if (!gallery) return;

  const grid = gallery.querySelector("[data-vb-gallery-twentyeight-grid]");
  const count = gallery.querySelector("[data-vb-gallery-twentyeight-count]");
  const message = gallery.querySelector("[data-vb-gallery-twentyeight-message]");
  const selectAllButton = gallery.querySelector("[data-vb-gallery-twentyeight-select-all]");
  const clearButton = gallery.querySelector("[data-vb-gallery-twentyeight-clear]");
  const archiveButton = gallery.querySelector("[data-vb-gallery-twentyeight-archive]");

  const selectedIds = new Set();
  const archivedIds = new Set();

  const items = [
    {
      id: "bulk-blue",
      title: "Blue Portfolio",
      category: "Portfolio",
      art: "vb-gallery-twentyeight-art-blue",
      description: "A CSS-only portfolio image for selectable gallery workflows."
    },
    {
      id: "bulk-gold",
      title: "Gold Travel",
      category: "Travel",
      art: "vb-gallery-twentyeight-art-gold",
      description: "A warm CSS travel card that can be selected for bulk actions."
    },
    {
      id: "bulk-purple",
      title: "Purple Product",
      category: "Product",
      art: "vb-gallery-twentyeight-art-purple",
      description: "A CSS product visual used in multi-select gallery management."
    },
    {
      id: "bulk-green",
      title: "Green Nature",
      category: "Nature",
      art: "vb-gallery-twentyeight-art-green",
      description: "A CSS nature image that can be selected and archived."
    },
    {
      id: "bulk-pink",
      title: "Pink Abstract",
      category: "Abstract",
      art: "vb-gallery-twentyeight-art-pink",
      description: "A creative CSS gallery card for selection state examples."
    },
    {
      id: "bulk-city",
      title: "City Night",
      category: "Architecture",
      art: "vb-gallery-twentyeight-art-city",
      description: "A CSS city image for admin-style image gallery actions."
    },
    {
      id: "bulk-cyan",
      title: "Cyan Glass",
      category: "Design",
      art: "vb-gallery-twentyeight-art-cyan",
      description: "A bright CSS image card that supports selected and archived states."
    },
    {
      id: "bulk-red",
      title: "Red Motion",
      category: "Event",
      art: "vb-gallery-twentyeight-art-red",
      description: "A CSS event-style image used for gallery bulk action testing."
    }
  ];

  function createCard(item, index) {
    const selectedClass = selectedIds.has(item.id) ? "is-selected" : "";
    const archivedClass = archivedIds.has(item.id) ? "is-archived" : "";
    const checkText = selectedIds.has(item.id) ? "✓" : "+";

    return `
      &lt;button type="button" class="vb-gallery-twentyeight-card ${selectedClass} ${archivedClass}" data-id="${item.id}" style="animation-delay: ${index * 35}ms"&gt;
        &lt;span class="vb-gallery-twentyeight-check"&gt;${checkText}&lt;/span&gt;
        &lt;div class="vb-gallery-twentyeight-art ${item.art}" aria-label="${item.title} illustration" role="img"&gt;&lt;/div&gt;

        &lt;div class="vb-gallery-twentyeight-body"&gt;
          &lt;span&gt;${item.category}&lt;/span&gt;
          &lt;h4&gt;${item.title}&lt;/h4&gt;
          &lt;p&gt;${item.description}&lt;/p&gt;
        &lt;/div&gt;
      &lt;/button&gt;
    `;
  }

  function updateCount() {
    count.textContent = selectedIds.size === 1 ? "1 selected" : selectedIds.size + " selected";
  }

  function updateMessage(text) {
    if (text) {
      message.textContent = text;
      return;
    }

    if (selectedIds.size === 0) {
      message.textContent = "Select gallery images to enable a bulk action.";
    } else {
      message.textContent = "Ready to run a bulk action on " + selectedIds.size + " selected image" + (selectedIds.size === 1 ? "." : "s.");
    }
  }

  function renderGallery(messageText) {
    grid.innerHTML = items.map(createCard).join("");
    updateCount();
    updateMessage(messageText);
  }

  function toggleSelected(id) {
    if (archivedIds.has(id)) return;

    if (selectedIds.has(id)) {
      selectedIds.delete(id);
    } else {
      selectedIds.add(id);
    }

    renderGallery();
  }

  grid.addEventListener("click", function (event) {
    const card = event.target.closest("[data-id]");
    if (!card) return;

    toggleSelected(card.getAttribute("data-id"));
  });

  selectAllButton.addEventListener("click", function () {
    items.forEach(function (item) {
      if (!archivedIds.has(item.id)) {
        selectedIds.add(item.id);
      }
    });

    renderGallery("All active gallery images selected.");
  });

  clearButton.addEventListener("click", function () {
    selectedIds.clear();
    renderGallery("Selection cleared.");
  });

  archiveButton.addEventListener("click", function () {
    if (selectedIds.size === 0) {
      renderGallery("Select at least one image before running a bulk action.");
      return;
    }

    selectedIds.forEach(function (id) {
      archivedIds.add(id);
    });

    const archivedCount = selectedIds.size;
    selectedIds.clear();
    renderGallery(archivedCount + " image" + (archivedCount === 1 ? " was" : "s were") + " archived in JavaScript state.");
  });

  renderGallery();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-twentyeight-demo"&gt;
  &lt;div class="vb-gallery-twentyeight-shell" data-vb-gallery-twentyeight&gt;
    &lt;div class="vb-gallery-twentyeight-top"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 28&lt;/span&gt;
        &lt;h3&gt;Image Gallery with Select and Bulk Actions&lt;/h3&gt;
        &lt;p&gt;Select multiple CSS-illustrated gallery cards and run JavaScript bulk actions.&lt;/p&gt;
      &lt;/div&gt;

      &lt;strong data-vb-gallery-twentyeight-count&gt;0 selected&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-twentyeight-toolbar"&gt;
      &lt;button type="button" data-vb-gallery-twentyeight-select-all&gt;Select All&lt;/button&gt;
      &lt;button type="button" data-vb-gallery-twentyeight-clear&gt;Clear Selection&lt;/button&gt;
      &lt;button type="button" data-vb-gallery-twentyeight-archive&gt;Archive Selected&lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-twentyeight-message" data-vb-gallery-twentyeight-message&gt;Select gallery images to enable a bulk action.&lt;/div&gt;

    &lt;div class="vb-gallery-twentyeight-grid" data-vb-gallery-twentyeight-grid&gt;&lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-twentyeight-demo,
.vb-gallery-twentyeight-demo * {
  box-sizing: border-box;
}

.vb-gallery-twentyeight-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 14% 14%, rgba(245, 158, 11, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(239, 68, 68, 0.14), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fff1f2 52%, #ffffff 100%) !important;
  border: 1px solid rgba(245, 158, 11, 0.22);
  box-shadow: 0 28px 80px rgba(146, 64, 14, 0.10);
}

.vb-gallery-twentyeight-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-twentyeight-top {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 20px;
}

.vb-gallery-twentyeight-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #fef3c7;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-twentyeight-top h3 {
  max-width: 850px;
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-twentyeight-top p {
  max-width: 750px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-twentyeight-top strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-twentyeight-toolbar {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin-bottom: 12px;
  padding: 12px;
  border-radius: 24px;
  background: rgba(255,255,255,0.78);
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 38px rgba(15, 23, 42, 0.08);
}

.vb-gallery-twentyeight-toolbar button {
  appearance: none;
  border: 1px solid rgba(245, 158, 11, 0.24);
  border-radius: 999px;
  background: #ffffff;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  padding: 11px 15px;
  font-size: 13px;
  font-weight: 950;
  cursor: pointer;
  transition: transform 0.2s ease, border-color 0.2s ease, background 0.2s ease;
}

.vb-gallery-twentyeight-toolbar button:hover {
  transform: translateY(-2px);
  border-color: rgba(245, 158, 11, 0.62);
}

.vb-gallery-twentyeight-toolbar button:last-child {
  border-color: transparent;
  background: linear-gradient(135deg, #f59e0b, #ef4444);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 14px 34px rgba(245, 158, 11, 0.22);
}

.vb-gallery-twentyeight-message {
  margin-bottom: 18px;
  padding: 12px 14px;
  border-radius: 18px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 13px;
  line-height: 1.5;
  font-weight: 850;
}

.vb-gallery-twentyeight-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-gallery-twentyeight-card {
  position: relative;
  overflow: hidden;
  padding: 0;
  border: 2px solid transparent;
  border-radius: 28px;
  background: #ffffff;
  cursor: pointer;
  text-align: left;
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  transition: transform 0.22s ease, border-color 0.22s ease, box-shadow 0.22s ease, opacity 0.22s ease;
  animation: vbGalleryTwentyeightIn 0.34s ease both;
}

@keyframes vbGalleryTwentyeightIn {
  from {
    opacity: 0;
    transform: translateY(16px) scale(0.98);
  }

  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}

.vb-gallery-twentyeight-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 26px 64px rgba(15, 23, 42, 0.15);
}

.vb-gallery-twentyeight-card.is-selected {
  border-color: rgba(245, 158, 11, 0.92);
  box-shadow: 0 24px 70px rgba(245, 158, 11, 0.24);
}

.vb-gallery-twentyeight-card.is-archived {
  opacity: 0.42;
  filter: grayscale(1);
}

.vb-gallery-twentyeight-check {
  position: absolute;
  z-index: 6;
  top: 13px;
  right: 13px;
  display: grid;
  place-items: center;
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.62);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
  backdrop-filter: blur(10px);
}

.vb-gallery-twentyeight-card.is-selected .vb-gallery-twentyeight-check {
  background: linear-gradient(135deg, #f59e0b, #ef4444);
}

.vb-gallery-twentyeight-art {
  position: relative;
  height: 225px;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-twentyeight-art::before,
.vb-gallery-twentyeight-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-twentyeight-art-blue {
  background: linear-gradient(135deg, #020617 0%, #2563eb 54%, #38bdf8 100%);
}

.vb-gallery-twentyeight-art-blue::before {
  left: 14%;
  top: 18%;
  width: 72%;
  height: 60%;
  border-radius: 28px;
  background:
    repeating-linear-gradient(90deg, rgba(255,255,255,0.18) 0 4px, transparent 4px 20px),
    rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.24);
}

.vb-gallery-twentyeight-art-blue::after {
  right: 16%;
  bottom: 18%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
  filter: blur(8px);
}

.vb-gallery-twentyeight-art-gold {
  background: linear-gradient(180deg, #fef3c7 0%, #f59e0b 52%, #78350f 100%);
}

.vb-gallery-twentyeight-art-gold::before {
  left: -8%;
  right: -8%;
  bottom: -18%;
  height: 56%;
  background: #451a03;
  clip-path: polygon(0 100%, 0 58%, 15% 42%, 30% 66%, 48% 34%, 66% 62%, 83% 40%, 100% 58%, 100% 100%);
}

.vb-gallery-twentyeight-art-gold::after {
  right: 18%;
  top: 16%;
  width: 82px;
  height: 82px;
  border-radius: 999px;
  background: #fffbeb;
  box-shadow: 0 0 64px rgba(255,251,235,0.72);
}

.vb-gallery-twentyeight-art-purple {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #ddd6fe 36%, #581c87 100%);
}

.vb-gallery-twentyeight-art-purple::before {
  left: 50%;
  top: 50%;
  width: 132px;
  height: 132px;
  border-radius: 30px;
  background: linear-gradient(135deg, #ffffff, #c4b5fd);
  box-shadow: 0 30px 80px rgba(88,28,135,0.32);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentyeight-art-purple::after {
  left: 50%;
  top: 50%;
  width: 68px;
  height: 68px;
  border-radius: 20px;
  border: 4px solid rgba(124,58,237,0.46);
  transform: translate(-50%, -50%) rotate(14deg);
}

.vb-gallery-twentyeight-art-green {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-twentyeight-art-green::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-twentyeight-art-green::after {
  right: 16%;
  top: 16%;
  width: 80px;
  height: 80px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-twentyeight-art-pink {
  background: linear-gradient(135deg, #500724 0%, #be123c 52%, #fb7185 100%);
}

.vb-gallery-twentyeight-art-pink::before {
  left: 50%;
  top: 52%;
  width: 140px;
  height: 140px;
  border-radius: 42% 58% 62% 38%;
  background: radial-gradient(circle at 35% 30%, #fff1f2, #fb7185 44%, #9f1239 100%);
  transform: translate(-50%, -50%) rotate(22deg);
  box-shadow: 0 26px 70px rgba(80,7,36,0.36);
}

.vb-gallery-twentyeight-art-pink::after {
  left: 14%;
  top: 16%;
  width: 74px;
  height: 74px;
  border-radius: 999px;
  background: rgba(255,255,255,0.22);
  filter: blur(6px);
}

.vb-gallery-twentyeight-art-city {
  background: linear-gradient(180deg, #312e81 0%, #111827 66%, #020617 100%);
}

.vb-gallery-twentyeight-art-city::before {
  left: 10%;
  bottom: 0;
  width: 18%;
  height: 58%;
  background: #020617;
  box-shadow:
    70px -42px 0 #020617,
    142px -12px 0 #020617,
    224px -62px 0 #020617,
    304px -24px 0 #020617;
}

.vb-gallery-twentyeight-art-city::after {
  inset: 18% 10% auto 10%;
  height: 3px;
  background: repeating-linear-gradient(90deg, rgba(255,255,255,0.82) 0 8px, transparent 8px 24px);
  box-shadow:
    0 34px 0 rgba(255,255,255,0.42),
    0 70px 0 rgba(255,255,255,0.22);
}

.vb-gallery-twentyeight-art-cyan {
  background: linear-gradient(135deg, #ecfeff 0%, #06b6d4 48%, #0f766e 100%);
}

.vb-gallery-twentyeight-art-cyan::before {
  left: 16%;
  top: 18%;
  width: 68%;
  height: 62%;
  border-radius: 28px;
  background: rgba(255,255,255,0.20);
  border: 1px solid rgba(255,255,255,0.34);
  backdrop-filter: blur(4px);
}

.vb-gallery-twentyeight-art-cyan::after {
  left: 50%;
  top: 50%;
  width: 92px;
  height: 92px;
  border-radius: 26px;
  background: rgba(255,255,255,0.70);
  transform: translate(-50%, -50%) rotate(20deg);
}

.vb-gallery-twentyeight-art-red {
  background: radial-gradient(circle at 50% 50%, #ffffff 0%, #fecaca 32%, #991b1b 100%);
}

.vb-gallery-twentyeight-art-red::before {
  left: 50%;
  top: 50%;
  width: 150px;
  height: 150px;
  border-radius: 999px;
  border: 18px solid rgba(255,255,255,0.36);
  border-left-color: rgba(255,255,255,0.86);
  transform: translate(-50%, -50%) rotate(18deg);
}

.vb-gallery-twentyeight-art-red::after {
  left: 50%;
  top: 50%;
  width: 76px;
  height: 76px;
  border-radius: 999px;
  background: rgba(255,255,255,0.76);
  transform: translate(-50%, -50%);
}

.vb-gallery-twentyeight-body {
  display: grid;
  gap: 8px;
  padding: 17px;
}

.vb-gallery-twentyeight-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #fffbeb;
  color: #92400e !important;
  -webkit-text-fill-color: #92400e !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-twentyeight-body h4 {
  margin: 0 !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 21px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-twentyeight-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

@media (max-width: 1050px) {
  .vb-gallery-twentyeight-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (max-width: 820px) {
  .vb-gallery-twentyeight-top {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-twentyeight-top strong {
    justify-content: center;
    width: 100%;
  }

  .vb-gallery-twentyeight-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 560px) {
  .vb-gallery-twentyeight-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-twentyeight-top h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-twentyeight-toolbar {
    display: grid;
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentyeight-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This image gallery with select and bulk actions is useful for media libraries, product image managers, admin dashboards, client approval galleries, asset review tools, and any image management interface where users need to handle several gallery items at once.</p>



<h2 class="wp-block-heading">29. Image Gallery with Zoom and Pan Viewer</h2>



<p class="wp-block-paragraph"><strong>An image gallery with zoom and pan viewer</strong> lets users inspect visual details inside a larger preview window. This JavaScript gallery pattern is useful for product images, portfolio previews, map-style visuals, technical screenshots, artwork galleries, real estate images, and media viewers where users need more control than a normal lightbox.</p>



<p class="wp-block-paragraph">This example uses JavaScript zoom and pan state. Users can open a CSS-generated gallery image, zoom in, zoom out, reset the view, drag the image inside the viewer, use mouse wheel zoom, and close the viewer with the Escape key. The demo uses CSS-only illustrated images, so it does not load any external image files.</p>



<ul class="wp-block-list">
<li>JavaScript zoom and pan gallery viewer</li>
<li>Mouse drag panning inside the image preview</li>
<li>Zoom in, zoom out, reset, and wheel zoom</li>
<li>Escape key and overlay close support</li>
<li>CSS-only illustrated gallery images</li>
</ul>



<div class="vb-gallery-twentynine-demo">
  <div class="vb-gallery-twentynine-shell" data-vb-gallery-twentynine>
    <div class="vb-gallery-twentynine-head">
      <div>
        <span>Example 29</span>
        <h3>Image Gallery with Zoom and Pan Viewer</h3>
        <p>Open a CSS-generated gallery image, zoom into it, and drag the preview around with JavaScript.</p>
      </div>

      <strong data-vb-gallery-twentynine-status>Click an image</strong>
    </div>

    <div class="vb-gallery-twentynine-grid">
      <button type="button" class="vb-gallery-twentynine-card" data-title="Circuit Detail" data-category="Technical" data-art="circuit">
        <div class="vb-gallery-twentynine-art vb-gallery-twentynine-art-circuit" aria-label="Circuit Detail illustration" role="img"></div>
        <div class="vb-gallery-twentynine-body">
          <span>Technical</span>
          <h4>Circuit Detail</h4>
          <p>Open and zoom into a technical CSS illustration.</p>
        </div>
      </button>

      <button type="button" class="vb-gallery-twentynine-card" data-title="Product Closeup" data-category="Product" data-art="product">
        <div class="vb-gallery-twentynine-art vb-gallery-twentynine-art-product" aria-label="Product Closeup illustration" role="img"></div>
        <div class="vb-gallery-twentynine-body">
          <span>Product</span>
          <h4>Product Closeup</h4>
          <p>Inspect a product-style CSS card in the viewer.</p>
        </div>
      </button>

      <button type="button" class="vb-gallery-twentynine-card" data-title="Map Pattern" data-category="Map UI" data-art="map">
        <div class="vb-gallery-twentynine-art vb-gallery-twentynine-art-map" aria-label="Map Pattern illustration" role="img"></div>
        <div class="vb-gallery-twentynine-body">
          <span>Map UI</span>
          <h4>Map Pattern</h4>
          <p>Pan around a map-style CSS visual after zooming.</p>
        </div>
      </button>
    </div>

    <div class="vb-gallery-twentynine-viewer" data-vb-gallery-twentynine-viewer hidden>
      <div class="vb-gallery-twentynine-backdrop" data-vb-gallery-twentynine-close></div>

      <div class="vb-gallery-twentynine-modal">
        <div class="vb-gallery-twentynine-toolbar">
          <div>
            <span data-vb-gallery-twentynine-category>Category</span>
            <strong data-vb-gallery-twentynine-title>Gallery Image</strong>
          </div>

          <div class="vb-gallery-twentynine-tools">
            <button type="button" data-vb-gallery-twentynine-zoom-out>−</button>
            <button type="button" data-vb-gallery-twentynine-reset>Reset</button>
            <button type="button" data-vb-gallery-twentynine-zoom-in>+</button>
            <button type="button" data-vb-gallery-twentynine-close>Close</button>
          </div>
        </div>

        <div class="vb-gallery-twentynine-canvas" data-vb-gallery-twentynine-canvas>
          <div class="vb-gallery-twentynine-large" data-vb-gallery-twentynine-large></div>
        </div>

        <div class="vb-gallery-twentynine-hint" data-vb-gallery-twentynine-hint>Zoom: 100% · Drag inside the preview to pan</div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-gallery-twentynine-demo,
.vb-gallery-twentynine-demo * {
  box-sizing: border-box;
}

.vb-gallery-twentynine-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 14% 14%, rgba(34, 197, 94, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #eff6ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.22);
  box-shadow: 0 28px 80px rgba(21, 128, 61, 0.10);
}

.vb-gallery-twentynine-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-twentynine-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 24px;
}

.vb-gallery-twentynine-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-twentynine-head h3 {
  max-width: 840px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-twentynine-head p {
  max-width: 760px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-twentynine-head strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-twentynine-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-gallery-twentynine-card {
  overflow: hidden;
  padding: 0;
  border: 0;
  border-radius: 30px;
  background: #ffffff;
  text-align: left;
  cursor: zoom-in;
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  transition: transform 0.22s ease, box-shadow 0.22s ease;
}

.vb-gallery-twentynine-card:hover {
  transform: translateY(-6px);
  box-shadow: 0 26px 64px rgba(15, 23, 42, 0.16);
}

.vb-gallery-twentynine-art,
.vb-gallery-twentynine-large {
  position: relative;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-twentynine-art {
  height: 270px;
}

.vb-gallery-twentynine-large {
  width: 780px;
  height: 520px;
  max-width: none;
  transform-origin: center center;
  cursor: grab;
  user-select: none;
}

.vb-gallery-twentynine-large.is-dragging {
  cursor: grabbing;
}

.vb-gallery-twentynine-art::before,
.vb-gallery-twentynine-art::after,
.vb-gallery-twentynine-large::before,
.vb-gallery-twentynine-large::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-twentynine-art-circuit,
.vb-gallery-twentynine-large-circuit {
  background:
    linear-gradient(90deg, rgba(34,197,94,0.18) 1px, transparent 1px),
    linear-gradient(0deg, rgba(34,197,94,0.18) 1px, transparent 1px),
    radial-gradient(circle at 25% 30%, rgba(134,239,172,0.72), transparent 12%),
    radial-gradient(circle at 74% 68%, rgba(59,130,246,0.52), transparent 14%),
    linear-gradient(135deg, #020617, #064e3b 54%, #0f172a);
  background-size: 34px 34px, 34px 34px, auto, auto, auto;
}

.vb-gallery-twentynine-art-circuit::before,
.vb-gallery-twentynine-large-circuit::before {
  left: 12%;
  top: 20%;
  width: 76%;
  height: 56%;
  border-radius: 26px;
  border: 2px solid rgba(134,239,172,0.42);
  background:
    linear-gradient(90deg, transparent 0 28%, rgba(134,239,172,0.70) 28% 30%, transparent 30% 100%),
    linear-gradient(0deg, transparent 0 48%, rgba(96,165,250,0.65) 48% 50%, transparent 50% 100%);
}

.vb-gallery-twentynine-art-circuit::after,
.vb-gallery-twentynine-large-circuit::after {
  left: 22%;
  top: 30%;
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: #86efac;
  box-shadow:
    160px 120px 0 #60a5fa,
    340px 34px 0 #86efac,
    420px 160px 0 #22c55e;
}

.vb-gallery-twentynine-art-product,
.vb-gallery-twentynine-large-product {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #e0e7ff 34%, #312e81 100%);
}

.vb-gallery-twentynine-art-product::before,
.vb-gallery-twentynine-large-product::before {
  left: 50%;
  top: 50%;
  width: 170px;
  height: 170px;
  border-radius: 34px;
  background: linear-gradient(135deg, #ffffff, #c7d2fe);
  box-shadow: 0 30px 80px rgba(49,46,129,0.34);
  transform: translate(-50%, -50%) rotate(18deg);
}

.vb-gallery-twentynine-art-product::after,
.vb-gallery-twentynine-large-product::after {
  left: 50%;
  top: 50%;
  width: 92px;
  height: 92px;
  border-radius: 24px;
  border: 5px solid rgba(79,70,229,0.50);
  transform: translate(-50%, -50%) rotate(18deg);
}

.vb-gallery-twentynine-art-map,
.vb-gallery-twentynine-large-map {
  background:
    radial-gradient(circle at 24% 34%, #fef3c7 0 7%, transparent 8%),
    radial-gradient(circle at 64% 66%, #bfdbfe 0 8%, transparent 9%),
    linear-gradient(135deg, #f8fafc, #dbeafe 46%, #bbf7d0);
}

.vb-gallery-twentynine-art-map::before,
.vb-gallery-twentynine-large-map::before {
  inset: 13%;
  border-radius: 34px;
  background:
    linear-gradient(48deg, transparent 0 46%, rgba(15,23,42,0.16) 46% 48%, transparent 48% 100%),
    linear-gradient(-28deg, transparent 0 38%, rgba(15,23,42,0.12) 38% 40%, transparent 40% 100%),
    linear-gradient(90deg, transparent 0 58%, rgba(15,23,42,0.10) 58% 60%, transparent 60% 100%);
  border: 2px solid rgba(15,23,42,0.10);
}

.vb-gallery-twentynine-art-map::after,
.vb-gallery-twentynine-large-map::after {
  left: 42%;
  top: 32%;
  width: 44px;
  height: 44px;
  border-radius: 999px 999px 999px 0;
  background: #ef4444;
  transform: rotate(-45deg);
  box-shadow: 180px 110px 0 #2563eb, -120px 140px 0 #16a34a;
}

.vb-gallery-twentynine-body {
  display: grid;
  gap: 8px;
  padding: 18px;
}

.vb-gallery-twentynine-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-twentynine-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 22px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-twentynine-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-gallery-twentynine-viewer[hidden] {
  display: none;
}

.vb-gallery-twentynine-viewer {
  position: fixed;
  inset: 0;
  z-index: 99999;
  display: grid;
  place-items: center;
  padding: 18px;
}

.vb-gallery-twentynine-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(15, 23, 42, 0.66);
  backdrop-filter: blur(7px);
}

.vb-gallery-twentynine-modal {
  position: relative;
  z-index: 2;
  width: min(1060px, 100%);
  overflow: hidden;
  border-radius: 34px;
  background: #ffffff;
  box-shadow: 0 34px 120px rgba(15, 23, 42, 0.38);
}

.vb-gallery-twentynine-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 16px;
  border-bottom: 1px solid rgba(148, 163, 184, 0.22);
  background: #ffffff;
}

.vb-gallery-twentynine-toolbar span {
  display: inline-flex;
  margin-bottom: 5px;
  padding: 5px 8px;
  border-radius: 999px;
  background: #eff6ff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 10px;
  font-weight: 950;
}

.vb-gallery-twentynine-toolbar strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px;
  line-height: 1.1;
  font-weight: 950;
}

.vb-gallery-twentynine-tools {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: flex-end;
}

.vb-gallery-twentynine-tools button {
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 10px 13px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-gallery-twentynine-canvas {
  display: grid;
  place-items: center;
  height: min(66vh, 620px);
  overflow: hidden;
  background:
    linear-gradient(90deg, rgba(15, 23, 42, 0.06) 1px, transparent 1px),
    linear-gradient(0deg, rgba(15, 23, 42, 0.06) 1px, transparent 1px),
    #f8fafc;
  background-size: 30px 30px;
}

.vb-gallery-twentynine-hint {
  padding: 13px 16px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 850;
  text-align: center;
}

@media (max-width: 880px) {
  .vb-gallery-twentynine-head {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-twentynine-head strong {
    justify-content: center;
    width: 100%;
  }

  .vb-gallery-twentynine-grid {
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentynine-toolbar {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-twentynine-tools {
    width: 100%;
    justify-content: flex-start;
  }
}

@media (max-width: 560px) {
  .vb-gallery-twentynine-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-twentynine-head h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-twentynine-modal {
    border-radius: 24px;
  }

  .vb-gallery-twentynine-large {
    width: 620px;
    height: 420px;
  }

  .vb-gallery-twentynine-tools button {
    flex: 1 1 auto;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-twentynine]");
  if (!gallery) return;

  const status = gallery.querySelector("[data-vb-gallery-twentynine-status]");
  const viewer = gallery.querySelector("[data-vb-gallery-twentynine-viewer]");
  const large = gallery.querySelector("[data-vb-gallery-twentynine-large]");
  const canvas = gallery.querySelector("[data-vb-gallery-twentynine-canvas]");
  const title = gallery.querySelector("[data-vb-gallery-twentynine-title]");
  const category = gallery.querySelector("[data-vb-gallery-twentynine-category]");
  const hint = gallery.querySelector("[data-vb-gallery-twentynine-hint]");
  const zoomIn = gallery.querySelector("[data-vb-gallery-twentynine-zoom-in]");
  const zoomOut = gallery.querySelector("[data-vb-gallery-twentynine-zoom-out]");
  const reset = gallery.querySelector("[data-vb-gallery-twentynine-reset]");

  let scale = 1;
  let translateX = 0;
  let translateY = 0;
  let isDragging = false;
  let startX = 0;
  let startY = 0;

  function updateTransform() {
    large.style.transform = "translate(" + translateX + "px, " + translateY + "px) scale(" + scale + ")";
    hint.textContent = "Zoom: " + Math.round(scale * 100) + "% · Drag inside the preview to pan";
  }

  function resetView() {
    scale = 1;
    translateX = 0;
    translateY = 0;
    updateTransform();
  }

  function openViewer(card) {
    const art = card.getAttribute("data-art");
    const selectedTitle = card.getAttribute("data-title");
    const selectedCategory = card.getAttribute("data-category");

    large.className = "vb-gallery-twentynine-large vb-gallery-twentynine-large-" + art;
    title.textContent = selectedTitle;
    category.textContent = selectedCategory;
    status.textContent = "Viewing: " + selectedTitle;
    viewer.hidden = false;
    document.body.style.overflow = "hidden";
    resetView();
  }

  function closeViewer() {
    viewer.hidden = true;
    document.body.style.overflow = "";
    status.textContent = "Click an image";
  }

  function changeZoom(amount) {
    scale = Math.min(3, Math.max(0.75, scale + amount));

    if (scale === 1) {
      translateX = 0;
      translateY = 0;
    }

    updateTransform();
  }

  gallery.addEventListener("click", function (event) {
    const card = event.target.closest(".vb-gallery-twentynine-card");
    const close = event.target.closest("[data-vb-gallery-twentynine-close]");

    if (card) {
      openViewer(card);
    }

    if (close) {
      closeViewer();
    }
  });

  zoomIn.addEventListener("click", function () {
    changeZoom(0.25);
  });

  zoomOut.addEventListener("click", function () {
    changeZoom(-0.25);
  });

  reset.addEventListener("click", resetView);

  canvas.addEventListener("wheel", function (event) {
    event.preventDefault();
    changeZoom(event.deltaY < 0 ? 0.15 : -0.15);
  });

  large.addEventListener("pointerdown", function (event) {
    isDragging = true;
    startX = event.clientX - translateX;
    startY = event.clientY - translateY;
    large.classList.add("is-dragging");
    large.setPointerCapture(event.pointerId);
  });

  large.addEventListener("pointermove", function (event) {
    if (!isDragging) return;

    translateX = event.clientX - startX;
    translateY = event.clientY - startY;
    updateTransform();
  });

  large.addEventListener("pointerup", function () {
    isDragging = false;
    large.classList.remove("is-dragging");
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape" &#038;&#038; !viewer.hidden) {
      closeViewer();
    }
  });

  updateTransform();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-twentynine]");
  if (!gallery) return;

  const status = gallery.querySelector("[data-vb-gallery-twentynine-status]");
  const viewer = gallery.querySelector("[data-vb-gallery-twentynine-viewer]");
  const large = gallery.querySelector("[data-vb-gallery-twentynine-large]");
  const canvas = gallery.querySelector("[data-vb-gallery-twentynine-canvas]");
  const title = gallery.querySelector("[data-vb-gallery-twentynine-title]");
  const category = gallery.querySelector("[data-vb-gallery-twentynine-category]");
  const hint = gallery.querySelector("[data-vb-gallery-twentynine-hint]");
  const zoomIn = gallery.querySelector("[data-vb-gallery-twentynine-zoom-in]");
  const zoomOut = gallery.querySelector("[data-vb-gallery-twentynine-zoom-out]");
  const reset = gallery.querySelector("[data-vb-gallery-twentynine-reset]");

  let scale = 1;
  let translateX = 0;
  let translateY = 0;
  let isDragging = false;
  let startX = 0;
  let startY = 0;

  function updateTransform() {
    large.style.transform = "translate(" + translateX + "px, " + translateY + "px) scale(" + scale + ")";
    hint.textContent = "Zoom: " + Math.round(scale * 100) + "% · Drag inside the preview to pan";
  }

  function resetView() {
    scale = 1;
    translateX = 0;
    translateY = 0;
    updateTransform();
  }

  function openViewer(card) {
    const art = card.getAttribute("data-art");
    const selectedTitle = card.getAttribute("data-title");
    const selectedCategory = card.getAttribute("data-category");

    large.className = "vb-gallery-twentynine-large vb-gallery-twentynine-large-" + art;
    title.textContent = selectedTitle;
    category.textContent = selectedCategory;
    status.textContent = "Viewing: " + selectedTitle;
    viewer.hidden = false;
    document.body.style.overflow = "hidden";
    resetView();
  }

  function closeViewer() {
    viewer.hidden = true;
    document.body.style.overflow = "";
    status.textContent = "Click an image";
  }

  function changeZoom(amount) {
    scale = Math.min(3, Math.max(0.75, scale + amount));

    if (scale === 1) {
      translateX = 0;
      translateY = 0;
    }

    updateTransform();
  }

  gallery.addEventListener("click", function (event) {
    const card = event.target.closest(".vb-gallery-twentynine-card");
    const close = event.target.closest("[data-vb-gallery-twentynine-close]");

    if (card) {
      openViewer(card);
    }

    if (close) {
      closeViewer();
    }
  });

  zoomIn.addEventListener("click", function () {
    changeZoom(0.25);
  });

  zoomOut.addEventListener("click", function () {
    changeZoom(-0.25);
  });

  reset.addEventListener("click", resetView);

  canvas.addEventListener("wheel", function (event) {
    event.preventDefault();
    changeZoom(event.deltaY &lt; 0 ? 0.15 : -0.15);
  });

  large.addEventListener("pointerdown", function (event) {
    isDragging = true;
    startX = event.clientX - translateX;
    startY = event.clientY - translateY;
    large.classList.add("is-dragging");
    large.setPointerCapture(event.pointerId);
  });

  large.addEventListener("pointermove", function (event) {
    if (!isDragging) return;

    translateX = event.clientX - startX;
    translateY = event.clientY - startY;
    updateTransform();
  });

  large.addEventListener("pointerup", function () {
    isDragging = false;
    large.classList.remove("is-dragging");
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape" && !viewer.hidden) {
      closeViewer();
    }
  });

  updateTransform();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-twentynine-demo"&gt;
  &lt;div class="vb-gallery-twentynine-shell" data-vb-gallery-twentynine&gt;
    &lt;div class="vb-gallery-twentynine-head"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 29&lt;/span&gt;
        &lt;h3&gt;Image Gallery with Zoom and Pan Viewer&lt;/h3&gt;
        &lt;p&gt;Open a CSS-generated gallery image, zoom into it, and drag the preview around with JavaScript.&lt;/p&gt;
      &lt;/div&gt;

      &lt;strong data-vb-gallery-twentynine-status&gt;Click an image&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-twentynine-grid"&gt;
      &lt;button type="button" class="vb-gallery-twentynine-card" data-title="Circuit Detail" data-category="Technical" data-art="circuit"&gt;
        &lt;div class="vb-gallery-twentynine-art vb-gallery-twentynine-art-circuit" aria-label="Circuit Detail illustration" role="img"&gt;&lt;/div&gt;
        &lt;div class="vb-gallery-twentynine-body"&gt;
          &lt;span&gt;Technical&lt;/span&gt;
          &lt;h4&gt;Circuit Detail&lt;/h4&gt;
          &lt;p&gt;Open and zoom into a technical CSS illustration.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/button&gt;

      &lt;button type="button" class="vb-gallery-twentynine-card" data-title="Product Closeup" data-category="Product" data-art="product"&gt;
        &lt;div class="vb-gallery-twentynine-art vb-gallery-twentynine-art-product" aria-label="Product Closeup illustration" role="img"&gt;&lt;/div&gt;
        &lt;div class="vb-gallery-twentynine-body"&gt;
          &lt;span&gt;Product&lt;/span&gt;
          &lt;h4&gt;Product Closeup&lt;/h4&gt;
          &lt;p&gt;Inspect a product-style CSS card in the viewer.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/button&gt;

      &lt;button type="button" class="vb-gallery-twentynine-card" data-title="Map Pattern" data-category="Map UI" data-art="map"&gt;
        &lt;div class="vb-gallery-twentynine-art vb-gallery-twentynine-art-map" aria-label="Map Pattern illustration" role="img"&gt;&lt;/div&gt;
        &lt;div class="vb-gallery-twentynine-body"&gt;
          &lt;span&gt;Map UI&lt;/span&gt;
          &lt;h4&gt;Map Pattern&lt;/h4&gt;
          &lt;p&gt;Pan around a map-style CSS visual after zooming.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/button&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-twentynine-viewer" data-vb-gallery-twentynine-viewer hidden&gt;
      &lt;div class="vb-gallery-twentynine-backdrop" data-vb-gallery-twentynine-close&gt;&lt;/div&gt;

      &lt;div class="vb-gallery-twentynine-modal"&gt;
        &lt;div class="vb-gallery-twentynine-toolbar"&gt;
          &lt;div&gt;
            &lt;span data-vb-gallery-twentynine-category&gt;Category&lt;/span&gt;
            &lt;strong data-vb-gallery-twentynine-title&gt;Gallery Image&lt;/strong&gt;
          &lt;/div&gt;

          &lt;div class="vb-gallery-twentynine-tools"&gt;
            &lt;button type="button" data-vb-gallery-twentynine-zoom-out&gt;−&lt;/button&gt;
            &lt;button type="button" data-vb-gallery-twentynine-reset&gt;Reset&lt;/button&gt;
            &lt;button type="button" data-vb-gallery-twentynine-zoom-in&gt;+&lt;/button&gt;
            &lt;button type="button" data-vb-gallery-twentynine-close&gt;Close&lt;/button&gt;
          &lt;/div&gt;
        &lt;/div&gt;

        &lt;div class="vb-gallery-twentynine-canvas" data-vb-gallery-twentynine-canvas&gt;
          &lt;div class="vb-gallery-twentynine-large" data-vb-gallery-twentynine-large&gt;&lt;/div&gt;
        &lt;/div&gt;

        &lt;div class="vb-gallery-twentynine-hint" data-vb-gallery-twentynine-hint&gt;Zoom: 100% · Drag inside the preview to pan&lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-twentynine-demo,
.vb-gallery-twentynine-demo * {
  box-sizing: border-box;
}

.vb-gallery-twentynine-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 14% 14%, rgba(34, 197, 94, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(59, 130, 246, 0.16), transparent 34%),
    linear-gradient(135deg, #f0fdf4 0%, #eff6ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(34, 197, 94, 0.22);
  box-shadow: 0 28px 80px rgba(21, 128, 61, 0.10);
}

.vb-gallery-twentynine-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-twentynine-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 24px;
}

.vb-gallery-twentynine-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-twentynine-head h3 {
  max-width: 840px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-twentynine-head p {
  max-width: 760px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-twentynine-head strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-twentynine-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
}

.vb-gallery-twentynine-card {
  overflow: hidden;
  padding: 0;
  border: 0;
  border-radius: 30px;
  background: #ffffff;
  text-align: left;
  cursor: zoom-in;
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  transition: transform 0.22s ease, box-shadow 0.22s ease;
}

.vb-gallery-twentynine-card:hover {
  transform: translateY(-6px);
  box-shadow: 0 26px 64px rgba(15, 23, 42, 0.16);
}

.vb-gallery-twentynine-art,
.vb-gallery-twentynine-large {
  position: relative;
  overflow: hidden;
  background: #111827;
}

.vb-gallery-twentynine-art {
  height: 270px;
}

.vb-gallery-twentynine-large {
  width: 780px;
  height: 520px;
  max-width: none;
  transform-origin: center center;
  cursor: grab;
  user-select: none;
}

.vb-gallery-twentynine-large.is-dragging {
  cursor: grabbing;
}

.vb-gallery-twentynine-art::before,
.vb-gallery-twentynine-art::after,
.vb-gallery-twentynine-large::before,
.vb-gallery-twentynine-large::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-twentynine-art-circuit,
.vb-gallery-twentynine-large-circuit {
  background:
    linear-gradient(90deg, rgba(34,197,94,0.18) 1px, transparent 1px),
    linear-gradient(0deg, rgba(34,197,94,0.18) 1px, transparent 1px),
    radial-gradient(circle at 25% 30%, rgba(134,239,172,0.72), transparent 12%),
    radial-gradient(circle at 74% 68%, rgba(59,130,246,0.52), transparent 14%),
    linear-gradient(135deg, #020617, #064e3b 54%, #0f172a);
  background-size: 34px 34px, 34px 34px, auto, auto, auto;
}

.vb-gallery-twentynine-art-circuit::before,
.vb-gallery-twentynine-large-circuit::before {
  left: 12%;
  top: 20%;
  width: 76%;
  height: 56%;
  border-radius: 26px;
  border: 2px solid rgba(134,239,172,0.42);
  background:
    linear-gradient(90deg, transparent 0 28%, rgba(134,239,172,0.70) 28% 30%, transparent 30% 100%),
    linear-gradient(0deg, transparent 0 48%, rgba(96,165,250,0.65) 48% 50%, transparent 50% 100%);
}

.vb-gallery-twentynine-art-circuit::after,
.vb-gallery-twentynine-large-circuit::after {
  left: 22%;
  top: 30%;
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: #86efac;
  box-shadow:
    160px 120px 0 #60a5fa,
    340px 34px 0 #86efac,
    420px 160px 0 #22c55e;
}

.vb-gallery-twentynine-art-product,
.vb-gallery-twentynine-large-product {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #e0e7ff 34%, #312e81 100%);
}

.vb-gallery-twentynine-art-product::before,
.vb-gallery-twentynine-large-product::before {
  left: 50%;
  top: 50%;
  width: 170px;
  height: 170px;
  border-radius: 34px;
  background: linear-gradient(135deg, #ffffff, #c7d2fe);
  box-shadow: 0 30px 80px rgba(49,46,129,0.34);
  transform: translate(-50%, -50%) rotate(18deg);
}

.vb-gallery-twentynine-art-product::after,
.vb-gallery-twentynine-large-product::after {
  left: 50%;
  top: 50%;
  width: 92px;
  height: 92px;
  border-radius: 24px;
  border: 5px solid rgba(79,70,229,0.50);
  transform: translate(-50%, -50%) rotate(18deg);
}

.vb-gallery-twentynine-art-map,
.vb-gallery-twentynine-large-map {
  background:
    radial-gradient(circle at 24% 34%, #fef3c7 0 7%, transparent 8%),
    radial-gradient(circle at 64% 66%, #bfdbfe 0 8%, transparent 9%),
    linear-gradient(135deg, #f8fafc, #dbeafe 46%, #bbf7d0);
}

.vb-gallery-twentynine-art-map::before,
.vb-gallery-twentynine-large-map::before {
  inset: 13%;
  border-radius: 34px;
  background:
    linear-gradient(48deg, transparent 0 46%, rgba(15,23,42,0.16) 46% 48%, transparent 48% 100%),
    linear-gradient(-28deg, transparent 0 38%, rgba(15,23,42,0.12) 38% 40%, transparent 40% 100%),
    linear-gradient(90deg, transparent 0 58%, rgba(15,23,42,0.10) 58% 60%, transparent 60% 100%);
  border: 2px solid rgba(15,23,42,0.10);
}

.vb-gallery-twentynine-art-map::after,
.vb-gallery-twentynine-large-map::after {
  left: 42%;
  top: 32%;
  width: 44px;
  height: 44px;
  border-radius: 999px 999px 999px 0;
  background: #ef4444;
  transform: rotate(-45deg);
  box-shadow: 180px 110px 0 #2563eb, -120px 140px 0 #16a34a;
}

.vb-gallery-twentynine-body {
  display: grid;
  gap: 8px;
  padding: 18px;
}

.vb-gallery-twentynine-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-twentynine-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 22px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-twentynine-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-gallery-twentynine-viewer[hidden] {
  display: none;
}

.vb-gallery-twentynine-viewer {
  position: fixed;
  inset: 0;
  z-index: 99999;
  display: grid;
  place-items: center;
  padding: 18px;
}

.vb-gallery-twentynine-backdrop {
  position: absolute;
  inset: 0;
  background: rgba(15, 23, 42, 0.66);
  backdrop-filter: blur(7px);
}

.vb-gallery-twentynine-modal {
  position: relative;
  z-index: 2;
  width: min(1060px, 100%);
  overflow: hidden;
  border-radius: 34px;
  background: #ffffff;
  box-shadow: 0 34px 120px rgba(15, 23, 42, 0.38);
}

.vb-gallery-twentynine-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 16px;
  border-bottom: 1px solid rgba(148, 163, 184, 0.22);
  background: #ffffff;
}

.vb-gallery-twentynine-toolbar span {
  display: inline-flex;
  margin-bottom: 5px;
  padding: 5px 8px;
  border-radius: 999px;
  background: #eff6ff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 10px;
  font-weight: 950;
}

.vb-gallery-twentynine-toolbar strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px;
  line-height: 1.1;
  font-weight: 950;
}

.vb-gallery-twentynine-tools {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: flex-end;
}

.vb-gallery-twentynine-tools button {
  appearance: none;
  border: 0;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  padding: 10px 13px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-gallery-twentynine-canvas {
  display: grid;
  place-items: center;
  height: min(66vh, 620px);
  overflow: hidden;
  background:
    linear-gradient(90deg, rgba(15, 23, 42, 0.06) 1px, transparent 1px),
    linear-gradient(0deg, rgba(15, 23, 42, 0.06) 1px, transparent 1px),
    #f8fafc;
  background-size: 30px 30px;
}

.vb-gallery-twentynine-hint {
  padding: 13px 16px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 850;
  text-align: center;
}

@media (max-width: 880px) {
  .vb-gallery-twentynine-head {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-twentynine-head strong {
    justify-content: center;
    width: 100%;
  }

  .vb-gallery-twentynine-grid {
    grid-template-columns: 1fr;
  }

  .vb-gallery-twentynine-toolbar {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-twentynine-tools {
    width: 100%;
    justify-content: flex-start;
  }
}

@media (max-width: 560px) {
  .vb-gallery-twentynine-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-twentynine-head h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-twentynine-modal {
    border-radius: 24px;
  }

  .vb-gallery-twentynine-large {
    width: 620px;
    height: 420px;
  }

  .vb-gallery-twentynine-tools button {
    flex: 1 1 auto;
  }
}</pre>



<p class="wp-block-paragraph">This zoom and pan image gallery is useful for product detail previews, artwork galleries, map interfaces, technical screenshots, architecture visuals, portfolio closeups, and any gallery where users need to inspect images more closely.</p>



<h2 class="wp-block-heading">30. Image Gallery with Layout Density Controller</h2>



<p class="wp-block-paragraph"><strong>An image gallery with a layout density controller</strong> lets users decide how compact or spacious the gallery should feel. This is useful for media libraries, portfolio archives, product catalogs, inspiration boards, asset dashboards, and visual browsing pages where some users want large previews while others want more images visible at once.</p>



<p class="wp-block-paragraph">This example uses JavaScript to control CSS custom properties. The density range input changes the gallery card size, spacing, preview height, and text visibility in real time. This is a different kind of JavaScript image gallery because the interaction controls the layout system itself instead of filtering or opening images.</p>



<ul class="wp-block-list">
<li>JavaScript layout density controller</li>
<li>Live CSS variable updates</li>
<li>Compact, balanced, and spacious gallery modes</li>
<li>Dynamic card size and image preview height</li>
<li>CSS-only illustrated gallery visuals</li>
</ul>



<div class="vb-gallery-thirty-demo">
  <div class="vb-gallery-thirty-shell" data-vb-gallery-thirty style="--vb-thirty-min: 250px; --vb-thirty-gap: 16px; --vb-thirty-art: 230px;">
    <div class="vb-gallery-thirty-head">
      <div>
        <span>Example 30</span>
        <h3>Image Gallery with Layout Density Controller</h3>
        <p>Use JavaScript to change gallery density, card size, spacing, and image height with CSS variables.</p>
      </div>

      <strong data-vb-gallery-thirty-label>Balanced layout</strong>
    </div>

    <div class="vb-gallery-thirty-control">
      <label for="vb-gallery-thirty-range">Gallery density</label>
      <input id="vb-gallery-thirty-range" type="range" min="1" max="3" value="2" data-vb-gallery-thirty-range>
      <div class="vb-gallery-thirty-scale">
        <span>Compact</span>
        <span>Balanced</span>
        <span>Spacious</span>
      </div>
    </div>

    <div class="vb-gallery-thirty-grid">
      <article class="vb-gallery-thirty-card">
        <div class="vb-gallery-thirty-art vb-gallery-thirty-art-orbit" aria-label="Orbit UI illustration" role="img"></div>
        <div class="vb-gallery-thirty-body">
          <span>Interface</span>
          <h4>Orbit UI</h4>
          <p>A CSS-only interface style image for adaptive gallery density.</p>
        </div>
      </article>

      <article class="vb-gallery-thirty-card">
        <div class="vb-gallery-thirty-art vb-gallery-thirty-art-studio" aria-label="Studio Object illustration" role="img"></div>
        <div class="vb-gallery-thirty-body">
          <span>Product</span>
          <h4>Studio Object</h4>
          <p>A product-style CSS illustration that changes size with the layout.</p>
        </div>
      </article>

      <article class="vb-gallery-thirty-card">
        <div class="vb-gallery-thirty-art vb-gallery-thirty-art-paper" aria-label="Paper Grid illustration" role="img"></div>
        <div class="vb-gallery-thirty-body">
          <span>Editorial</span>
          <h4>Paper Grid</h4>
          <p>An editorial CSS visual for responsive gallery card density.</p>
        </div>
      </article>

      <article class="vb-gallery-thirty-card">
        <div class="vb-gallery-thirty-art vb-gallery-thirty-art-wave" aria-label="Wave Scene illustration" role="img"></div>
        <div class="vb-gallery-thirty-body">
          <span>Abstract</span>
          <h4>Wave Scene</h4>
          <p>An abstract CSS image for testing compact and spacious views.</p>
        </div>
      </article>

      <article class="vb-gallery-thirty-card">
        <div class="vb-gallery-thirty-art vb-gallery-thirty-art-forest" aria-label="Forest Blocks illustration" role="img"></div>
        <div class="vb-gallery-thirty-body">
          <span>Nature</span>
          <h4>Forest Blocks</h4>
          <p>A CSS nature-inspired visual inside a density-aware gallery.</p>
        </div>
      </article>

      <article class="vb-gallery-thirty-card">
        <div class="vb-gallery-thirty-art vb-gallery-thirty-art-thermal" aria-label="Thermal Poster illustration" role="img"></div>
        <div class="vb-gallery-thirty-body">
          <span>Poster</span>
          <h4>Thermal Poster</h4>
          <p>A bold CSS poster card that adapts to the chosen layout density.</p>
        </div>
      </article>
    </div>
  </div>
</div>

<style>
.vb-gallery-thirty-demo,
.vb-gallery-thirty-demo * {
  box-sizing: border-box;
}

.vb-gallery-thirty-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 14% 14%, rgba(124, 58, 237, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #f5f3ff 0%, #f0f9ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(124, 58, 237, 0.20);
  box-shadow: 0 28px 80px rgba(91, 33, 182, 0.10);
}

.vb-gallery-thirty-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-thirty-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 22px;
}

.vb-gallery-thirty-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-thirty-head h3 {
  max-width: 850px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-thirty-head p {
  max-width: 760px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-thirty-head strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-thirty-control {
  margin-bottom: 22px;
  padding: 18px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.09);
}

.vb-gallery-thirty-control label {
  display: block;
  margin-bottom: 12px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-gallery-thirty-control input {
  width: 100%;
  accent-color: #7c3aed;
}

.vb-gallery-thirty-scale {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  margin-top: 10px;
}

.vb-gallery-thirty-scale span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-gallery-thirty-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(var(--vb-thirty-min), 1fr));
  gap: var(--vb-thirty-gap);
  transition: gap 0.22s ease;
}

.vb-gallery-thirty-card {
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  transition: transform 0.22s ease, border-radius 0.22s ease;
}

.vb-gallery-thirty-card:hover {
  transform: translateY(-5px);
}

.vb-gallery-thirty-art {
  position: relative;
  height: var(--vb-thirty-art);
  overflow: hidden;
  background: #111827;
  transition: height 0.22s ease;
}

.vb-gallery-thirty-art::before,
.vb-gallery-thirty-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-thirty-art-orbit {
  background:
    radial-gradient(circle at 50% 50%, rgba(255,255,255,0.90) 0 4%, transparent 5%),
    radial-gradient(circle at 50% 50%, transparent 0 24%, rgba(125,211,252,0.42) 25% 26%, transparent 27%),
    radial-gradient(circle at 50% 50%, transparent 0 38%, rgba(196,181,253,0.42) 39% 40%, transparent 41%),
    linear-gradient(135deg, #020617, #312e81 55%, #0f172a);
}

.vb-gallery-thirty-art-orbit::before {
  left: 22%;
  top: 22%;
  width: 54px;
  height: 54px;
  border-radius: 999px;
  background: #38bdf8;
  box-shadow: 240px 120px 0 #c4b5fd, 130px 20px 0 #ffffff;
}

.vb-gallery-thirty-art-orbit::after {
  left: 50%;
  top: 50%;
  width: 170px;
  height: 170px;
  border-radius: 999px;
  border: 2px dashed rgba(255,255,255,0.32);
  transform: translate(-50%, -50%) rotate(-12deg);
}

.vb-gallery-thirty-art-studio {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #e0e7ff 34%, #312e81 100%);
}

.vb-gallery-thirty-art-studio::before {
  left: 50%;
  top: 50%;
  width: 150px;
  height: 150px;
  border-radius: 34px;
  background: linear-gradient(135deg, #ffffff, #c7d2fe);
  box-shadow: 0 30px 80px rgba(49,46,129,0.34);
  transform: translate(-50%, -50%) rotate(18deg);
}

.vb-gallery-thirty-art-studio::after {
  left: 50%;
  top: 50%;
  width: 78px;
  height: 78px;
  border-radius: 24px;
  border: 5px solid rgba(79,70,229,0.50);
  transform: translate(-50%, -50%) rotate(18deg);
}

.vb-gallery-thirty-art-paper {
  background:
    linear-gradient(90deg, rgba(15,23,42,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(15,23,42,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #f8fafc, #e2e8f0);
  background-size: 26px 26px;
}

.vb-gallery-thirty-art-paper::before {
  left: 16%;
  top: 18%;
  width: 68%;
  height: 62%;
  border-radius: 24px;
  background:
    linear-gradient(90deg, #0f172a 0 18%, transparent 18%),
    linear-gradient(#64748b 0 0) 32% 28% / 48% 5px no-repeat,
    linear-gradient(#94a3b8 0 0) 32% 44% / 42% 5px no-repeat,
    linear-gradient(#cbd5e1 0 0) 32% 60% / 52% 5px no-repeat,
    #ffffff;
  box-shadow: 0 24px 70px rgba(15,23,42,0.16);
}

.vb-gallery-thirty-art-paper::after {
  right: 18%;
  bottom: 18%;
  width: 72px;
  height: 72px;
  border-radius: 18px;
  background: #38bdf8;
  transform: rotate(14deg);
}

.vb-gallery-thirty-art-wave {
  background: linear-gradient(135deg, #0f172a, #0369a1 52%, #22d3ee);
}

.vb-gallery-thirty-art-wave::before {
  left: -10%;
  right: -10%;
  bottom: 12%;
  height: 46%;
  border-radius: 50% 50% 0 0;
  background:
    radial-gradient(circle at 20% 30%, rgba(255,255,255,0.56), transparent 12%),
    radial-gradient(circle at 56% 34%, rgba(255,255,255,0.38), transparent 14%),
    linear-gradient(135deg, rgba(255,255,255,0.28), rgba(255,255,255,0.06));
}

.vb-gallery-thirty-art-wave::after {
  left: 16%;
  top: 18%;
  width: 92px;
  height: 92px;
  border-radius: 999px;
  background: rgba(255,255,255,0.34);
  filter: blur(4px);
}

.vb-gallery-thirty-art-forest {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-thirty-art-forest::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-thirty-art-forest::after {
  right: 16%;
  top: 16%;
  width: 80px;
  height: 80px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-thirty-art-thermal {
  background:
    radial-gradient(circle at 30% 30%, #fef3c7 0 10%, transparent 11%),
    radial-gradient(circle at 70% 70%, #fb7185 0 16%, transparent 17%),
    linear-gradient(135deg, #7f1d1d, #e11d48 52%, #f97316);
}

.vb-gallery-thirty-art-thermal::before {
  left: 50%;
  top: 50%;
  width: 170px;
  height: 170px;
  border-radius: 42% 58% 62% 38%;
  background: rgba(255,255,255,0.22);
  transform: translate(-50%, -50%) rotate(22deg);
  backdrop-filter: blur(5px);
}

.vb-gallery-thirty-art-thermal::after {
  left: 22%;
  bottom: 18%;
  width: 58%;
  height: 9px;
  border-radius: 999px;
  background: rgba(255,255,255,0.48);
  box-shadow: 0 24px 0 rgba(255,255,255,0.30), 0 48px 0 rgba(255,255,255,0.18);
}

.vb-gallery-thirty-body {
  display: grid;
  gap: 8px;
  padding: clamp(14px, 2vw, 18px);
}

.vb-gallery-thirty-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-thirty-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 21px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-thirty-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-gallery-thirty-shell.is-compact .vb-gallery-thirty-body p {
  display: none;
}

.vb-gallery-thirty-shell.is-compact .vb-gallery-thirty-card {
  border-radius: 22px;
}

.vb-gallery-thirty-shell.is-spacious .vb-gallery-thirty-card {
  border-radius: 34px;
}

@media (max-width: 820px) {
  .vb-gallery-thirty-head {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-thirty-head strong {
    justify-content: center;
    width: 100%;
  }
}

@media (max-width: 560px) {
  .vb-gallery-thirty-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-thirty-head h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-thirty-scale span {
    font-size: 11px;
  }
}
</style>

<script>
(function () {
  const gallery = document.querySelector("[data-vb-gallery-thirty]");
  if (!gallery) return;

  const range = gallery.querySelector("[data-vb-gallery-thirty-range]");
  const label = gallery.querySelector("[data-vb-gallery-thirty-label]");

  const modes = {
    "1": {
      label: "Compact layout",
      min: "170px",
      gap: "10px",
      art: "150px",
      className: "is-compact"
    },
    "2": {
      label: "Balanced layout",
      min: "250px",
      gap: "16px",
      art: "230px",
      className: "is-balanced"
    },
    "3": {
      label: "Spacious layout",
      min: "330px",
      gap: "22px",
      art: "320px",
      className: "is-spacious"
    }
  };

  function applyDensity(value) {
    const mode = modes[value];

    gallery.style.setProperty("--vb-thirty-min", mode.min);
    gallery.style.setProperty("--vb-thirty-gap", mode.gap);
    gallery.style.setProperty("--vb-thirty-art", mode.art);

    gallery.classList.remove("is-compact", "is-balanced", "is-spacious");
    gallery.classList.add(mode.className);

    label.textContent = mode.label;
  }

  range.addEventListener("input", function () {
    applyDensity(range.value);
  });

  applyDensity(range.value);
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const gallery = document.querySelector("[data-vb-gallery-thirty]");
  if (!gallery) return;

  const range = gallery.querySelector("[data-vb-gallery-thirty-range]");
  const label = gallery.querySelector("[data-vb-gallery-thirty-label]");

  const modes = {
    "1": {
      label: "Compact layout",
      min: "170px",
      gap: "10px",
      art: "150px",
      className: "is-compact"
    },
    "2": {
      label: "Balanced layout",
      min: "250px",
      gap: "16px",
      art: "230px",
      className: "is-balanced"
    },
    "3": {
      label: "Spacious layout",
      min: "330px",
      gap: "22px",
      art: "320px",
      className: "is-spacious"
    }
  };

  function applyDensity(value) {
    const mode = modes[value];

    gallery.style.setProperty("--vb-thirty-min", mode.min);
    gallery.style.setProperty("--vb-thirty-gap", mode.gap);
    gallery.style.setProperty("--vb-thirty-art", mode.art);

    gallery.classList.remove("is-compact", "is-balanced", "is-spacious");
    gallery.classList.add(mode.className);

    label.textContent = mode.label;
  }

  range.addEventListener("input", function () {
    applyDensity(range.value);
  });

  applyDensity(range.value);
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-gallery-thirty-demo"&gt;
  &lt;div class="vb-gallery-thirty-shell" data-vb-gallery-thirty style="--vb-thirty-min: 250px; --vb-thirty-gap: 16px; --vb-thirty-art: 230px;"&gt;
    &lt;div class="vb-gallery-thirty-head"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 30&lt;/span&gt;
        &lt;h3&gt;Image Gallery with Layout Density Controller&lt;/h3&gt;
        &lt;p&gt;Use JavaScript to change gallery density, card size, spacing, and image height with CSS variables.&lt;/p&gt;
      &lt;/div&gt;

      &lt;strong data-vb-gallery-thirty-label&gt;Balanced layout&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-thirty-control"&gt;
      &lt;label for="vb-gallery-thirty-range"&gt;Gallery density&lt;/label&gt;
      &lt;input id="vb-gallery-thirty-range" type="range" min="1" max="3" value="2" data-vb-gallery-thirty-range&gt;
      &lt;div class="vb-gallery-thirty-scale"&gt;
        &lt;span&gt;Compact&lt;/span&gt;
        &lt;span&gt;Balanced&lt;/span&gt;
        &lt;span&gt;Spacious&lt;/span&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-gallery-thirty-grid"&gt;
      &lt;article class="vb-gallery-thirty-card"&gt;
        &lt;div class="vb-gallery-thirty-art vb-gallery-thirty-art-orbit" aria-label="Orbit UI illustration" role="img"&gt;&lt;/div&gt;
        &lt;div class="vb-gallery-thirty-body"&gt;
          &lt;span&gt;Interface&lt;/span&gt;
          &lt;h4&gt;Orbit UI&lt;/h4&gt;
          &lt;p&gt;A CSS-only interface style image for adaptive gallery density.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-gallery-thirty-card"&gt;
        &lt;div class="vb-gallery-thirty-art vb-gallery-thirty-art-studio" aria-label="Studio Object illustration" role="img"&gt;&lt;/div&gt;
        &lt;div class="vb-gallery-thirty-body"&gt;
          &lt;span&gt;Product&lt;/span&gt;
          &lt;h4&gt;Studio Object&lt;/h4&gt;
          &lt;p&gt;A product-style CSS illustration that changes size with the layout.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-gallery-thirty-card"&gt;
        &lt;div class="vb-gallery-thirty-art vb-gallery-thirty-art-paper" aria-label="Paper Grid illustration" role="img"&gt;&lt;/div&gt;
        &lt;div class="vb-gallery-thirty-body"&gt;
          &lt;span&gt;Editorial&lt;/span&gt;
          &lt;h4&gt;Paper Grid&lt;/h4&gt;
          &lt;p&gt;An editorial CSS visual for responsive gallery card density.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-gallery-thirty-card"&gt;
        &lt;div class="vb-gallery-thirty-art vb-gallery-thirty-art-wave" aria-label="Wave Scene illustration" role="img"&gt;&lt;/div&gt;
        &lt;div class="vb-gallery-thirty-body"&gt;
          &lt;span&gt;Abstract&lt;/span&gt;
          &lt;h4&gt;Wave Scene&lt;/h4&gt;
          &lt;p&gt;An abstract CSS image for testing compact and spacious views.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-gallery-thirty-card"&gt;
        &lt;div class="vb-gallery-thirty-art vb-gallery-thirty-art-forest" aria-label="Forest Blocks illustration" role="img"&gt;&lt;/div&gt;
        &lt;div class="vb-gallery-thirty-body"&gt;
          &lt;span&gt;Nature&lt;/span&gt;
          &lt;h4&gt;Forest Blocks&lt;/h4&gt;
          &lt;p&gt;A CSS nature-inspired visual inside a density-aware gallery.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article class="vb-gallery-thirty-card"&gt;
        &lt;div class="vb-gallery-thirty-art vb-gallery-thirty-art-thermal" aria-label="Thermal Poster illustration" role="img"&gt;&lt;/div&gt;
        &lt;div class="vb-gallery-thirty-body"&gt;
          &lt;span&gt;Poster&lt;/span&gt;
          &lt;h4&gt;Thermal Poster&lt;/h4&gt;
          &lt;p&gt;A bold CSS poster card that adapts to the chosen layout density.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-gallery-thirty-demo,
.vb-gallery-thirty-demo * {
  box-sizing: border-box;
}

.vb-gallery-thirty-demo {
  margin: 28px 0;
  padding: clamp(18px, 4vw, 38px);
  border-radius: 38px;
  background:
    radial-gradient(circle at 14% 14%, rgba(124, 58, 237, 0.16), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(14, 165, 233, 0.16), transparent 34%),
    linear-gradient(135deg, #f5f3ff 0%, #f0f9ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(124, 58, 237, 0.20);
  box-shadow: 0 28px 80px rgba(91, 33, 182, 0.10);
}

.vb-gallery-thirty-shell {
  max-width: 1180px;
  margin: 0 auto;
}

.vb-gallery-thirty-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 22px;
}

.vb-gallery-thirty-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb-gallery-thirty-head h3 {
  max-width: 850px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.94 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-gallery-thirty-head p {
  max-width: 760px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-gallery-thirty-head strong {
  flex: 0 0 auto;
  display: inline-flex;
  padding: 11px 14px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-gallery-thirty-control {
  margin-bottom: 22px;
  padding: 18px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.09);
}

.vb-gallery-thirty-control label {
  display: block;
  margin-bottom: 12px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-gallery-thirty-control input {
  width: 100%;
  accent-color: #7c3aed;
}

.vb-gallery-thirty-scale {
  display: flex;
  justify-content: space-between;
  gap: 10px;
  margin-top: 10px;
}

.vb-gallery-thirty-scale span {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 850;
}

.vb-gallery-thirty-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(var(--vb-thirty-min), 1fr));
  gap: var(--vb-thirty-gap);
  transition: gap 0.22s ease;
}

.vb-gallery-thirty-card {
  overflow: hidden;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 18px 48px rgba(15, 23, 42, 0.10);
  transition: transform 0.22s ease, border-radius 0.22s ease;
}

.vb-gallery-thirty-card:hover {
  transform: translateY(-5px);
}

.vb-gallery-thirty-art {
  position: relative;
  height: var(--vb-thirty-art);
  overflow: hidden;
  background: #111827;
  transition: height 0.22s ease;
}

.vb-gallery-thirty-art::before,
.vb-gallery-thirty-art::after {
  content: "";
  position: absolute;
  pointer-events: none;
}

.vb-gallery-thirty-art-orbit {
  background:
    radial-gradient(circle at 50% 50%, rgba(255,255,255,0.90) 0 4%, transparent 5%),
    radial-gradient(circle at 50% 50%, transparent 0 24%, rgba(125,211,252,0.42) 25% 26%, transparent 27%),
    radial-gradient(circle at 50% 50%, transparent 0 38%, rgba(196,181,253,0.42) 39% 40%, transparent 41%),
    linear-gradient(135deg, #020617, #312e81 55%, #0f172a);
}

.vb-gallery-thirty-art-orbit::before {
  left: 22%;
  top: 22%;
  width: 54px;
  height: 54px;
  border-radius: 999px;
  background: #38bdf8;
  box-shadow: 240px 120px 0 #c4b5fd, 130px 20px 0 #ffffff;
}

.vb-gallery-thirty-art-orbit::after {
  left: 50%;
  top: 50%;
  width: 170px;
  height: 170px;
  border-radius: 999px;
  border: 2px dashed rgba(255,255,255,0.32);
  transform: translate(-50%, -50%) rotate(-12deg);
}

.vb-gallery-thirty-art-studio {
  background: radial-gradient(circle at 50% 42%, #ffffff 0%, #e0e7ff 34%, #312e81 100%);
}

.vb-gallery-thirty-art-studio::before {
  left: 50%;
  top: 50%;
  width: 150px;
  height: 150px;
  border-radius: 34px;
  background: linear-gradient(135deg, #ffffff, #c7d2fe);
  box-shadow: 0 30px 80px rgba(49,46,129,0.34);
  transform: translate(-50%, -50%) rotate(18deg);
}

.vb-gallery-thirty-art-studio::after {
  left: 50%;
  top: 50%;
  width: 78px;
  height: 78px;
  border-radius: 24px;
  border: 5px solid rgba(79,70,229,0.50);
  transform: translate(-50%, -50%) rotate(18deg);
}

.vb-gallery-thirty-art-paper {
  background:
    linear-gradient(90deg, rgba(15,23,42,0.08) 1px, transparent 1px),
    linear-gradient(0deg, rgba(15,23,42,0.08) 1px, transparent 1px),
    linear-gradient(135deg, #f8fafc, #e2e8f0);
  background-size: 26px 26px;
}

.vb-gallery-thirty-art-paper::before {
  left: 16%;
  top: 18%;
  width: 68%;
  height: 62%;
  border-radius: 24px;
  background:
    linear-gradient(90deg, #0f172a 0 18%, transparent 18%),
    linear-gradient(#64748b 0 0) 32% 28% / 48% 5px no-repeat,
    linear-gradient(#94a3b8 0 0) 32% 44% / 42% 5px no-repeat,
    linear-gradient(#cbd5e1 0 0) 32% 60% / 52% 5px no-repeat,
    #ffffff;
  box-shadow: 0 24px 70px rgba(15,23,42,0.16);
}

.vb-gallery-thirty-art-paper::after {
  right: 18%;
  bottom: 18%;
  width: 72px;
  height: 72px;
  border-radius: 18px;
  background: #38bdf8;
  transform: rotate(14deg);
}

.vb-gallery-thirty-art-wave {
  background: linear-gradient(135deg, #0f172a, #0369a1 52%, #22d3ee);
}

.vb-gallery-thirty-art-wave::before {
  left: -10%;
  right: -10%;
  bottom: 12%;
  height: 46%;
  border-radius: 50% 50% 0 0;
  background:
    radial-gradient(circle at 20% 30%, rgba(255,255,255,0.56), transparent 12%),
    radial-gradient(circle at 56% 34%, rgba(255,255,255,0.38), transparent 14%),
    linear-gradient(135deg, rgba(255,255,255,0.28), rgba(255,255,255,0.06));
}

.vb-gallery-thirty-art-wave::after {
  left: 16%;
  top: 18%;
  width: 92px;
  height: 92px;
  border-radius: 999px;
  background: rgba(255,255,255,0.34);
  filter: blur(4px);
}

.vb-gallery-thirty-art-forest {
  background: linear-gradient(180deg, #dcfce7 0%, #22c55e 54%, #052e16 100%);
}

.vb-gallery-thirty-art-forest::before {
  left: 0;
  right: 0;
  bottom: 0;
  height: 72%;
  background:
    conic-gradient(from 45deg at 18% 100%, transparent 0 25%, #052e16 0 50%, transparent 0),
    conic-gradient(from 45deg at 50% 100%, transparent 0 25%, #166534 0 50%, transparent 0),
    conic-gradient(from 45deg at 82% 100%, transparent 0 25%, #052e16 0 50%, transparent 0);
}

.vb-gallery-thirty-art-forest::after {
  right: 16%;
  top: 16%;
  width: 80px;
  height: 80px;
  border-radius: 999px;
  background: rgba(240,253,244,0.82);
  filter: blur(4px);
}

.vb-gallery-thirty-art-thermal {
  background:
    radial-gradient(circle at 30% 30%, #fef3c7 0 10%, transparent 11%),
    radial-gradient(circle at 70% 70%, #fb7185 0 16%, transparent 17%),
    linear-gradient(135deg, #7f1d1d, #e11d48 52%, #f97316);
}

.vb-gallery-thirty-art-thermal::before {
  left: 50%;
  top: 50%;
  width: 170px;
  height: 170px;
  border-radius: 42% 58% 62% 38%;
  background: rgba(255,255,255,0.22);
  transform: translate(-50%, -50%) rotate(22deg);
  backdrop-filter: blur(5px);
}

.vb-gallery-thirty-art-thermal::after {
  left: 22%;
  bottom: 18%;
  width: 58%;
  height: 9px;
  border-radius: 999px;
  background: rgba(255,255,255,0.48);
  box-shadow: 0 24px 0 rgba(255,255,255,0.30), 0 48px 0 rgba(255,255,255,0.18);
}

.vb-gallery-thirty-body {
  display: grid;
  gap: 8px;
  padding: clamp(14px, 2vw, 18px);
}

.vb-gallery-thirty-body span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 11px;
  font-weight: 950;
}

.vb-gallery-thirty-body h4 {
  margin: 0 !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 21px !important;
  line-height: 1.14 !important;
  font-weight: 950 !important;
  letter-spacing: -0.045em;
}

.vb-gallery-thirty-body p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.58;
  font-weight: 650;
}

.vb-gallery-thirty-shell.is-compact .vb-gallery-thirty-body p {
  display: none;
}

.vb-gallery-thirty-shell.is-compact .vb-gallery-thirty-card {
  border-radius: 22px;
}

.vb-gallery-thirty-shell.is-spacious .vb-gallery-thirty-card {
  border-radius: 34px;
}

@media (max-width: 820px) {
  .vb-gallery-thirty-head {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-gallery-thirty-head strong {
    justify-content: center;
    width: 100%;
  }
}

@media (max-width: 560px) {
  .vb-gallery-thirty-demo {
    padding: 16px;
    border-radius: 24px;
  }

  .vb-gallery-thirty-head h3 {
    font-size: 36px !important;
    letter-spacing: -0.055em;
  }

  .vb-gallery-thirty-scale span {
    font-size: 11px;
  }
}</pre>



<p class="wp-block-paragraph">This layout density image gallery is useful for media libraries, design inspiration boards, product catalogs, portfolio archives, asset dashboards, and responsive gallery interfaces where users should control how compact or spacious the gallery feels.</p>



<div class="vb24-js-gallery-bottom-ad">
  <a class="vb24-gallery-entityschema-wide-ad" href="https://veebilehed24.ee/en/shop/entityschema-pro/" target="_blank" rel="sponsored noopener">
    <div class="vb24-gallery-entityschema-copy">
      <span>WordPress SEO Plugin</span>
      <h2>Make Your Website Easier for Google and AI to Understand</h2>
      <p>EntitySchema Pro helps you build entity-based structured data for WordPress websites, articles, products, services, organizations, FAQs, breadcrumbs, and modern AI-readable SEO systems.</p>

      <div class="vb24-gallery-entityschema-price">
        <strong>29€</strong>
        <span><del>89€</del> Save 60€</span>
      </div>
    </div>

    <div class="vb24-gallery-entityschema-media">
      <img decoding="async" src="https://veebilehed24.ee/wp-content/uploads/2026/03/entityschema-cover-600x400.webp" width="600" height="400" alt="EntitySchema Pro WordPress structured data and entity SEO plugin" loading="lazy">
      <span>View Plugin</span>
    </div>
  </a>
</div>

<style>
.vb24-js-gallery-bottom-ad,
.vb24-js-gallery-bottom-ad * {
  box-sizing: border-box;
}

.vb24-js-gallery-bottom-ad {
  margin: 46px 0 54px;
}

.vb24-gallery-entityschema-wide-ad {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 330px;
  gap: 26px;
  align-items: center;
  padding: clamp(22px, 4vw, 34px);
  border-radius: 34px;
  background:
    radial-gradient(circle at 12% 14%, rgba(34, 211, 238, 0.26), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(168, 85, 247, 0.24), transparent 36%),
    linear-gradient(135deg, #0f172a 0%, #1e3a8a 48%, #581c87 100%) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  overflow: hidden;
  box-shadow: 0 28px 90px rgba(15, 23, 42, 0.28);
  transition: transform 0.24s ease, box-shadow 0.24s ease, filter 0.24s ease;
}

.vb24-gallery-entityschema-wide-ad:hover {
  transform: translateY(-4px);
  filter: saturate(1.08);
  box-shadow: 0 34px 110px rgba(15, 23, 42, 0.36);
}

.vb24-gallery-entityschema-copy span:first-child {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.18);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb24-gallery-entityschema-copy h2 {
  max-width: 760px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 56px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.065em;
}

.vb24-gallery-entityschema-copy p {
  max-width: 760px;
  margin: 0 0 18px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb24-gallery-entityschema-price {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 14px;
}

.vb24-gallery-entityschema-price strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 42px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb24-gallery-entityschema-price span {
  display: inline-flex;
  gap: 8px;
  align-items: center;
  padding: 9px 12px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.16);
  border: 1px solid rgba(74, 222, 128, 0.30);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb24-gallery-entityschema-price del {
  color: rgba(255,255,255,0.58) !important;
  -webkit-text-fill-color: rgba(255,255,255,0.58) !important;
  text-decoration-color: rgba(248, 113, 113, 0.95);
  text-decoration-thickness: 2px;
}

.vb24-gallery-entityschema-media {
  display: grid;
  gap: 14px;
}

.vb24-gallery-entityschema-media img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 22px;
  border: 1px solid rgba(255,255,255,0.16);
  box-shadow: 0 20px 54px rgba(2, 6, 23, 0.28);
}

.vb24-gallery-entityschema-media span {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 48px;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22d3ee, #2563eb 55%, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.30);
}

@media (max-width: 860px) {
  .vb24-gallery-entityschema-wide-ad {
    grid-template-columns: 1fr;
  }

  .vb24-gallery-entityschema-media {
    max-width: 420px;
  }
}

@media (max-width: 560px) {
  .vb24-gallery-entityschema-wide-ad {
    padding: 20px;
    border-radius: 26px;
  }

  .vb24-gallery-entityschema-copy h2 {
    font-size: 34px !important;
    letter-spacing: -0.055em;
  }
}
</style>



<h2 class="wp-block-heading" id="javascript-image-gallery-best-practices">JavaScript Image Gallery Best Practices</h2>



<p class="wp-block-paragraph">JavaScript image galleries work best when the visual design, data structure, interaction logic, accessibility, and performance choices are planned together. A gallery should not be only a decorative grid. It should help users browse images, understand categories, open previews, search content, move between items, and use the gallery comfortably on desktop and mobile screens.</p>



<p class="wp-block-paragraph">The most important best practice is to decide what the gallery should do before writing the code. A portfolio gallery may need filters and case study labels. A product image gallery may need thumbnails, zoom, variant previews, and a clear active image state. A media library may need search, tags, sorting, selection, and pagination. A photography gallery may need a lightbox, keyboard navigation, focus handling, and fullscreen viewing.</p>



<div class="vb24-js-gallery-best-grid">
  <article>
    <span>01</span>
    <h3>Keep image data organized</h3>
    <p>Use clear titles, categories, tags, descriptions, alt text, and image paths. Good data makes filtering, search, sorting, lightboxes, and dynamic rendering much easier.</p>
  </article>

  <article>
    <span>02</span>
    <h3>Scope every script</h3>
    <p>Wrap each gallery in a unique parent element and query elements inside that wrapper. This prevents one gallery from accidentally controlling another gallery on the same page.</p>
  </article>

  <article>
    <span>03</span>
    <h3>Design for mobile first</h3>
    <p>Image cards, buttons, filters, thumbnails, and modals must fit small screens. Use responsive grids, fluid image heights, and readable controls.</p>
  </article>

  <article>
    <span>04</span>
    <h3>Use meaningful interaction</h3>
    <p>JavaScript should add real value: filtering, searching, sorting, zooming, keyboard navigation, lazy loading, image selection, or saved favorites.</p>
  </article>
</div>

<style>
.vb24-js-gallery-best-grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 30px;
}

.vb24-js-gallery-best-grid article {
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 18% 10%, rgba(14, 165, 233, 0.10), transparent 32%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb24-js-gallery-best-grid span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb24-js-gallery-best-grid h3 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 19px !important;
  line-height: 1.2 !important;
  font-weight: 900 !important;
  letter-spacing: -0.035em;
}

.vb24-js-gallery-best-grid p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

@media (max-width: 980px) {
  .vb24-js-gallery-best-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .vb24-js-gallery-best-grid {
    grid-template-columns: 1fr;
  }
}
</style>



<ul class="wp-block-list">
  <li><strong>Use a reusable image data array</strong> when images need titles, categories, tags, descriptions, or dynamic rendering.</li>
  <li><strong>Use clear active states</strong> for selected filters, current thumbnails, open lightbox images, selected cards, and favorite buttons.</li>
  <li><strong>Always include an empty state</strong> for search and filter galleries when no images match the current query.</li>
  <li><strong>Use keyboard support</strong> for lightboxes, modals, image drawers, and next/previous gallery navigation.</li>
  <li><strong>Keep controls close to the gallery</strong> so users can quickly understand how filtering, searching, sorting, zooming, or switching views works.</li>
  <li><strong>Use lazy loading or pagination</strong> when a page contains many images or heavy media files.</li>
  <li><strong>Set stable image dimensions</strong> to avoid layout shifts while images are loading.</li>
  <li><strong>Do not rely only on hover</strong> because touch devices do not have hover behavior.</li>
  <li><strong>Use descriptive alt text</strong> for real images so the gallery supports accessibility and image SEO.</li>
  <li><strong>Test every gallery interaction</strong> after copying code into WordPress because themes can sometimes affect button, heading, image, or modal styles.</li>
</ul>



<p class="wp-block-paragraph">For WordPress and Gutenberg posts, it is also important to keep class names unique. If several examples use the same class names or generic IDs, one script can break another example. In this guide, every JavaScript image gallery example uses its own wrapper and scoped selectors so the examples can work together inside one long article.</p>



<h2 class="wp-block-heading" id="responsive-image-gallery-design-tips">Responsive Image Gallery Design Tips</h2>



<p class="wp-block-paragraph">A responsive image gallery should feel natural on every screen size. On desktop, users may want multi-column layouts, large previews, filters, side panels, and hover effects. On mobile, the same gallery needs larger tap targets, simpler controls, stacked cards, scrollable filters, and image previews that do not overflow the viewport.</p>



<p class="wp-block-paragraph">The safest approach is to design the gallery layout with flexible CSS grid rules, fluid image heights, and clear mobile breakpoints. Avoid fixed-width gallery cards unless they are inside a scrollable container. Keep lightbox controls reachable on mobile, and make sure close buttons, next buttons, search fields, filters, and thumbnails stay easy to tap.</p>



<div class="vb24-js-gallery-responsive-box">
  <div>
    <h3>Use flexible columns</h3>
    <p>Use <code>repeat(auto-fit, minmax(...))</code> or responsive breakpoints so image cards automatically adapt to different screen widths.</p>
  </div>

  <div>
    <h3>Control image height</h3>
    <p>Use aspect-ratio, object-fit, or CSS-generated art containers with stable heights so the gallery does not jump while loading.</p>
  </div>

  <div>
    <h3>Make filters mobile-friendly</h3>
    <p>Filter buttons can wrap, scroll horizontally, or become a stacked layout on phones. Keep tap targets large enough.</p>
  </div>

  <div>
    <h3>Test modal overflow</h3>
    <p>Lightboxes, drawers, zoom viewers, and detail panels must fit the viewport and allow scrolling when content is tall.</p>
  </div>
</div>

<style>
.vb24-js-gallery-responsive-box {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 30px;
  padding: clamp(18px, 3vw, 26px);
  border-radius: 30px;
  background:
    radial-gradient(circle at 14% 14%, rgba(99, 102, 241, 0.12), transparent 34%),
    linear-gradient(135deg, #eef2ff, #f0f9ff) !important;
  border: 1px solid rgba(99, 102, 241, 0.20);
}

.vb24-js-gallery-responsive-box div {
  padding: 20px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb24-js-gallery-responsive-box h3 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px !important;
  line-height: 1.25 !important;
  font-weight: 900 !important;
  letter-spacing: -0.035em;
}

.vb24-js-gallery-responsive-box p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb24-js-gallery-responsive-box code {
  padding: 2px 6px;
  border-radius: 7px;
  background: #f1f5f9;
  color: #1d4ed8;
  font-size: 0.92em;
}

@media (max-width: 760px) {
  .vb24-js-gallery-responsive-box {
    grid-template-columns: 1fr;
  }
}
</style>



<ul class="wp-block-list">
  <li><strong>Use one-column layouts</strong> for narrow phone screens when gallery cards contain text, buttons, or metadata.</li>
  <li><strong>Use two-column layouts carefully</strong> only when images stay readable and touch targets remain large enough.</li>
  <li><strong>Keep lightbox buttons visible</strong> so users can close the image preview without searching for controls.</li>
  <li><strong>Avoid tiny thumbnails</strong> on mobile product galleries because they become hard to tap.</li>
  <li><strong>Keep search and filter controls readable</strong> with enough padding, contrast, and spacing.</li>
  <li><strong>Test long image titles</strong> because real project names, product names, and file names can be longer than demo text.</li>
  <li><strong>Use scrollable preview areas</strong> for zoom galleries, detail drawers, and comparison tools.</li>
  <li><strong>Check horizontal overflow</strong> after adding large images, fixed modals, or wide toolbar buttons.</li>
</ul>



<h2 class="wp-block-heading" id="common-javascript-image-gallery-mistakes">Common JavaScript Image Gallery Mistakes</h2>



<p class="wp-block-paragraph">Common JavaScript image gallery mistakes usually happen when the gallery is designed only for the first visual preview and not for real content, mobile devices, accessibility, or long-term maintenance. A gallery may look good with three demo images but break when the website owner adds 40 images, long titles, multiple categories, or larger files.</p>



<p class="wp-block-paragraph">The best way to avoid gallery problems is to think about the full user flow. What happens when no filter matches? What happens when an image fails to load? Can the user close the modal with Escape? Does the gallery work with keyboard controls? Does the layout break on phones? Does the script still work when two galleries exist on the same page?</p>



<div class="vb24-js-gallery-mistakes">
  <article>
    <strong>Using unscoped selectors</strong>
    <p>Generic selectors like <code>document.querySelector(".gallery")</code> can break when the page contains more than one gallery. Always scope JavaScript to a unique wrapper.</p>
  </article>

  <article>
    <strong>Forgetting empty states</strong>
    <p>Search and filter galleries should clearly explain when no images match the current query instead of showing a blank section.</p>
  </article>

  <article>
    <strong>Ignoring keyboard users</strong>
    <p>Lightboxes, modals, drawers, and image viewers should support Escape, focus handling, and clear next or previous navigation where needed.</p>
  </article>

  <article>
    <strong>Loading too many images</strong>
    <p>Large galleries should use lazy loading, pagination, load more buttons, or infinite scroll to avoid slow pages and heavy initial loading.</p>
  </article>

  <article>
    <strong>Breaking mobile layouts</strong>
    <p>Fixed-width cards, oversized preview windows, and small buttons can make a gallery difficult to use on phones.</p>
  </article>

  <article>
    <strong>Using unclear image data</strong>
    <p>Without clear titles, categories, tags, descriptions, and alt text, gallery search, filtering, sorting, and SEO become weaker.</p>
  </article>
</div>

<style>
.vb24-js-gallery-mistakes {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 30px;
}

.vb24-js-gallery-mistakes article {
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 16% 12%, rgba(239, 68, 68, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb24-js-gallery-mistakes strong {
  display: block;
  margin-bottom: 10px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 950;
  letter-spacing: -0.03em;
}

.vb24-js-gallery-mistakes p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb24-js-gallery-mistakes code {
  padding: 2px 6px;
  border-radius: 7px;
  background: #f1f5f9;
  color: #dc2626;
  font-size: 0.92em;
}

@media (max-width: 980px) {
  .vb24-js-gallery-mistakes {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .vb24-js-gallery-mistakes {
    grid-template-columns: 1fr;
  }
}
</style>



<ul class="wp-block-list">
  <li><strong>Do not use the same ID multiple times</strong> when copying several gallery examples into one WordPress post.</li>
  <li><strong>Do not make controls too small</strong> because gallery filters, thumbnails, and close buttons must be easy to tap.</li>
  <li><strong>Do not hide important content behind hover only</strong> because touch devices do not have hover states.</li>
  <li><strong>Do not forget alt text</strong> when replacing CSS demo illustrations with real image files.</li>
  <li><strong>Do not let a lightbox trap users</strong> without a visible close button or Escape key support.</li>
  <li><strong>Do not load full-size images as thumbnails</strong> when a gallery contains many images.</li>
  <li><strong>Do not build every card manually</strong> if the gallery needs filtering, sorting, searching, or reusable data.</li>
  <li><strong>Do not ignore no-result states</strong> for filters, searches, tags, or favorites-only views.</li>
</ul>



<h2 class="wp-block-heading" id="javascript-image-gallery-faq">JavaScript Image Gallery FAQ</h2>



<p class="wp-block-paragraph">Here are common questions about JavaScript image galleries for portfolio websites, ecommerce product pages, photography galleries, real estate listings, media libraries, agency case studies, responsive landing pages, and WordPress posts.</p>



<div class="vb24-js-gallery-faq-section" data-vb24-js-gallery-faq>
  <section class="vb24-js-gallery-faq-item is-open">
    <button class="vb24-js-gallery-faq-trigger" type="button" aria-expanded="true">
      <span>What is a JavaScript image gallery?</span>
      <em></em>
    </button>
    <div class="vb24-js-gallery-faq-panel">
      <div class="vb24-js-gallery-faq-content">
        <p>A JavaScript image gallery is an interactive website component that displays multiple images and lets users browse, filter, search, sort, open, preview, zoom, select, favorite, or navigate images with dynamic behavior instead of a static image grid.</p>
      </div>
    </div>
  </section>

  <section class="vb24-js-gallery-faq-item">
    <button class="vb24-js-gallery-faq-trigger" type="button" aria-expanded="false">
      <span>Where should I use an image gallery on a website?</span>
      <em></em>
    </button>
    <div class="vb24-js-gallery-faq-panel">
      <div class="vb24-js-gallery-faq-content">
        <p>Image galleries work well on portfolio pages, photography websites, ecommerce product pages, real estate listings, travel blogs, design inspiration pages, agency case studies, media libraries, event albums, and product showcase sections.</p>
      </div>
    </div>
  </section>

  <section class="vb24-js-gallery-faq-item">
    <button class="vb24-js-gallery-faq-trigger" type="button" aria-expanded="false">
      <span>Should I use a lightbox for every gallery?</span>
      <em></em>
    </button>
    <div class="vb24-js-gallery-faq-panel">
      <div class="vb24-js-gallery-faq-content">
        <p>No. A lightbox is useful when users need a larger preview or next and previous navigation. A simple portfolio grid, product thumbnail switcher, filterable gallery, or compact media list may not always need a full overlay.</p>
      </div>
    </div>
  </section>

  <section class="vb24-js-gallery-faq-item">
    <button class="vb24-js-gallery-faq-trigger" type="button" aria-expanded="false">
      <span>How do I make a JavaScript image gallery responsive?</span>
      <em></em>
    </button>
    <div class="vb24-js-gallery-faq-panel">
      <div class="vb24-js-gallery-faq-content">
        <p>Use flexible CSS grids, fluid image dimensions, responsive breakpoints, readable button sizes, mobile-friendly filter controls, and modal styles that fit inside the viewport. Test the gallery on desktop, tablet, and phone widths.</p>
      </div>
    </div>
  </section>

  <section class="vb24-js-gallery-faq-item">
    <button class="vb24-js-gallery-faq-trigger" type="button" aria-expanded="false">
      <span>How can I improve image gallery performance?</span>
      <em></em>
    </button>
    <div class="vb24-js-gallery-faq-panel">
      <div class="vb24-js-gallery-faq-content">
        <p>Use optimized image sizes, lazy loading, thumbnails instead of full-size images, pagination, load more buttons, infinite scroll, stable image dimensions, and lightweight JavaScript. Avoid loading every large image immediately on the first page view.</p>
      </div>
    </div>
  </section>

  <section class="vb24-js-gallery-faq-item">
    <button class="vb24-js-gallery-faq-trigger" type="button" aria-expanded="false">
      <span>Can I use these image gallery examples in WordPress?</span>
      <em></em>
    </button>
    <div class="vb24-js-gallery-faq-panel">
      <div class="vb24-js-gallery-faq-content">
        <p>Yes. These examples are written with visible HTML, CSS, and JavaScript, so they can be copied into Gutenberg Custom HTML blocks or adapted into a WordPress theme, template part, shortcode, or custom plugin.</p>
      </div>
    </div>
  </section>
</div>

<style>
.vb24-js-gallery-faq-section {
  display: grid;
  gap: 12px;
  margin: 24px 0 34px;
}

.vb24-js-gallery-faq-item {
  overflow: hidden;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.08);
}

.vb24-js-gallery-faq-trigger {
  appearance: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  width: 100%;
  padding: 18px 20px;
  border: 0;
  background:
    radial-gradient(circle at 12% 14%, rgba(14, 165, 233, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  cursor: pointer;
  text-align: left;
}

.vb24-js-gallery-faq-trigger span {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 17px;
  line-height: 1.35;
  font-weight: 950;
  letter-spacing: -0.025em;
}

.vb24-js-gallery-faq-trigger em {
  position: relative;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: linear-gradient(135deg, #0ea5e9, #6366f1);
  box-shadow: 0 10px 26px rgba(99, 102, 241, 0.22);
}

.vb24-js-gallery-faq-trigger em::before,
.vb24-js-gallery-faq-trigger em::after {
  content: "";
  position: absolute;
  left: 50%;
  top: 50%;
  width: 14px;
  height: 2px;
  border-radius: 999px;
  background: #ffffff;
  transform: translate(-50%, -50%);
}

.vb24-js-gallery-faq-trigger em::after {
  transform: translate(-50%, -50%) rotate(90deg);
  transition: transform 0.2s ease;
}

.vb24-js-gallery-faq-item.is-open .vb24-js-gallery-faq-trigger em::after {
  transform: translate(-50%, -50%) rotate(0deg);
}

.vb24-js-gallery-faq-panel {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows 0.24s ease;
}

.vb24-js-gallery-faq-item.is-open .vb24-js-gallery-faq-panel {
  grid-template-rows: 1fr;
}

.vb24-js-gallery-faq-content {
  overflow: hidden;
}

.vb24-js-gallery-faq-content p {
  margin: 0 !important;
  padding: 0 20px 20px;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 15px;
  line-height: 1.72;
  font-weight: 650;
}

@media (max-width: 620px) {
  .vb24-js-gallery-faq-trigger {
    padding: 16px;
  }

  .vb24-js-gallery-faq-trigger span {
    font-size: 16px;
  }

  .vb24-js-gallery-faq-content p {
    padding: 0 16px 18px;
  }
}
</style>

<script>
(function () {
  const faq = document.querySelector("[data-vb24-js-gallery-faq]");
  if (!faq) return;

  const items = faq.querySelectorAll(".vb24-js-gallery-faq-item");

  items.forEach(function (item) {
    const trigger = item.querySelector(".vb24-js-gallery-faq-trigger");

    trigger.addEventListener("click", function () {
      const isOpen = item.classList.contains("is-open");

      items.forEach(function (otherItem) {
        otherItem.classList.remove("is-open");
        otherItem.querySelector(".vb24-js-gallery-faq-trigger").setAttribute("aria-expanded", "false");
      });

      if (!isOpen) {
        item.classList.add("is-open");
        trigger.setAttribute("aria-expanded", "true");
      }
    });
  });
})();
</script>



<h2 class="wp-block-heading" id="javascript-image-gallery-conclusion">Conclusion</h2>



<p class="wp-block-paragraph">JavaScript image galleries are useful for websites where visual content is important. They can improve portfolio pages, photography galleries, ecommerce product pages, real estate listings, travel blogs, agency case studies, media libraries, dashboards, image upload interfaces, landing pages, and product showcase sections.</p>



<p class="wp-block-paragraph">The best image gallery is not only a collection of pictures. It has a clear browsing structure, useful JavaScript behavior, responsive layout, accessible controls, optimized loading, strong visual hierarchy, and a simple way for users to explore images without confusion.</p>



<p class="wp-block-paragraph">You can use the examples in this guide as starting points for real website projects. Replace the CSS-only demo visuals with real images, connect the JavaScript data arrays to your own content, adjust the filters and tags, customize the design, and keep the gallery logic focused on what users actually need to do.</p>



<h2 class="wp-block-heading" id="related-javascript-and-css-guides">Related JavaScript and CSS Guides</h2>



<p class="wp-block-paragraph">Continue building better website sections and interactive UI components with these related JavaScript and CSS guides. These posts work well together when building full landing pages, product pages, portfolios, dashboards, navigation systems, filters, forms, and responsive website layouts.</p>



<div class="vb24-js-gallery-related">
  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-slider-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Slider Examples</strong>
    <p>Image sliders, product carousels, testimonial sliders, hero sliders, and responsive content carousel components.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-search-filter-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Search Filter Examples</strong>
    <p>Live search, card filters, product filters, FAQ search, dashboard filters, and responsive filtering UI examples.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-modal-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Modal Examples</strong>
    <p>Accessible modals, popup dialogs, confirmation windows, fullscreen overlays, and reusable modal components.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-dropdown-menu-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Dropdown Menu Examples</strong>
    <p>Custom selects, navigation dropdowns, profile menus, category dropdowns, and responsive menu components.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-accordion-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Accordion Examples</strong>
    <p>FAQ accordions, product toggles, dashboard panels, nested accordions, and responsive content expanders.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-toast-notification-examples/">
    <span>JavaScript</span>
    <strong>30 JavaScript Toast Notification Examples</strong>
    <p>Alerts, popups, UI messages, undo actions, progress notifications, and interactive toast systems.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-layouts/">
    <span>CSS</span>
    <strong>25 Modern CSS Layouts</strong>
    <p>Grid layouts, flexbox sections, bento grids, dashboards, landing pages, and responsive layout examples.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-forms/">
    <span>CSS</span>
    <strong>30 Modern CSS Forms</strong>
    <p>Contact forms, login forms, checkout forms, signup forms, validation layouts, and modern form UI examples.</p>
  </a>
</div>

<style>
.vb24-js-gallery-related {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 40px;
}

.vb24-js-gallery-related a {
  display: grid;
  gap: 10px;
  min-height: 100%;
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 16% 12%, rgba(14, 165, 233, 0.11), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  text-decoration: none !important;
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
  transition: transform 0.22s ease, border-color 0.22s ease, box-shadow 0.22s ease;
}

.vb24-js-gallery-related a:hover {
  transform: translateY(-4px);
  border-color: rgba(14, 165, 233, 0.42);
  box-shadow: 0 24px 62px rgba(15, 23, 42, 0.12);
}

.vb24-js-gallery-related span {
  display: inline-flex;
  width: fit-content;
  padding: 6px 9px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb24-js-gallery-related strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 19px;
  line-height: 1.18;
  font-weight: 950;
  letter-spacing: -0.035em;
}

.vb24-js-gallery-related p {
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.62;
  font-weight: 650;
}

@media (max-width: 1080px) {
  .vb24-js-gallery-related {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 620px) {
  .vb24-js-gallery-related {
    grid-template-columns: 1fr;
  }
}
</style>
]]></content:encoded>
					
					<wfw:commentRss>https://veebilehed24.ee/en/blog/javascript/javascript-image-gallery-examples/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>30 JavaScript Dropdown Menu Examples – Custom Select, Navigation Dropdowns &#038; UI Components</title>
		<link>https://veebilehed24.ee/en/blog/javascript/javascript-dropdown-menu-examples/</link>
					<comments>https://veebilehed24.ee/en/blog/javascript/javascript-dropdown-menu-examples/#respond</comments>
		
		<dc:creator><![CDATA[admin]]></dc:creator>
		<pubDate>Tue, 09 Jun 2026 05:33:40 +0000</pubDate>
				<category><![CDATA[Javascript]]></category>
		<guid isPermaLink="false">https://veebilehed24.ee/?p=1576</guid>

					<description><![CDATA[JavaScript dropdown menus are one of the most common interactive UI components on modern websites. They help users open navigation menus, select options, filter content, access profile actions, switch languages, browse categories, choose product variations, and reveal hidden interface controls without loading a new page. In this guide, you will find 30 JavaScript dropdown menu [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p class="wp-block-paragraph">JavaScript dropdown menus are one of the most common interactive UI components on modern websites. They help users open navigation menus, select options, filter content, access profile actions, switch languages, browse categories, choose product variations, and reveal hidden interface controls without loading a new page.</p>



<p class="wp-block-paragraph">In this guide, you will find 30 JavaScript dropdown menu examples for modern websites, including basic dropdowns, click dropdowns, custom select menus, searchable dropdowns, multi-select dropdowns, profile menus, notification dropdowns, ecommerce dropdowns, mega dropdowns, mobile navigation dropdowns, animated dropdowns, accessible dropdowns, and complete responsive dropdown UI patterns you can customize for your own projects.</p>



<p class="wp-block-paragraph">This post focuses on dropdown functionality, JavaScript interaction, open and close logic, outside click behavior, keyboard-friendly controls, responsive design, and reusable UI patterns. If you need related design inspiration, you can also explore our <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-navigation-menus/">modern CSS navigation menus</a>, <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-tabs/">modern CSS tabs</a>, <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-accordions/">modern CSS accordions</a>, and <a href="https://veebilehed24.ee/en/blog/javascript/javascript-modal-examples/">JavaScript modal examples</a>.</p>



<div class="vb24-js-dropdown-jump-box">
  <a class="vb24-js-dropdown-jump-button" href="#javascript-dropdown-menu-examples">View All 30 JavaScript Dropdown Menu Examples</a>
</div>

<style>
.vb24-js-dropdown-jump-box {
  margin: 28px 0 36px;
}

.vb24-js-dropdown-jump-button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 14px 22px;
  border-radius: 999px;
  background: linear-gradient(135deg, #06b6d4, #2563eb 52%, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 850;
  line-height: 1.2;
  text-decoration: none !important;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.28);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-js-dropdown-jump-button::after {
  content: "↓";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.18);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  line-height: 1;
}

.vb24-js-dropdown-jump-button:hover {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transform: translateY(-2px);
  filter: saturate(1.08);
  box-shadow: 0 20px 46px rgba(37, 99, 235, 0.36);
}

@media (max-width: 640px) {
  .vb24-js-dropdown-jump-button {
    width: 100%;
    padding: 14px 16px;
    font-size: 14px;
  }
}
</style>



<div class="toc-affiliate-wrap vb24-js-dropdown-toc-wrap">

  <div class="toc-left vb24-js-dropdown-toc-left">

    <div class="vb24-js-dropdown-toc-kicker">On this page</div>

    <h2>Table of Contents</h2>

    <ul class="vl24-toc vb24-js-dropdown-toc">
      <li><a href="#what-is-a-javascript-dropdown-menu">What Is a JavaScript Dropdown Menu?</a></li>
      <li><a href="#why-javascript-dropdowns-matter">Why JavaScript Dropdowns Matter</a></li>
      <li><a href="#dropdown-menu-vs-select-menu-vs-mega-menu">Dropdown Menu vs Select Menu vs Mega Menu</a></li>
      <li><a href="#what-should-a-good-javascript-dropdown-include">What Should a Good JavaScript Dropdown Include?</a></li>
      <li><a class="vb24-featured-toc-link" href="#javascript-dropdown-menu-examples">30 JavaScript Dropdown Menu Examples</a></li>
      <li><a href="#javascript-dropdown-best-practices">JavaScript Dropdown Best Practices</a></li>
      <li><a href="#responsive-dropdown-design-tips">Responsive Dropdown Design Tips</a></li>
      <li><a href="#common-javascript-dropdown-mistakes">Common JavaScript Dropdown Mistakes</a></li>
      <li><a href="#javascript-dropdown-faq">JavaScript Dropdown FAQ</a></li>
      <li><a href="#javascript-dropdown-conclusion">Conclusion</a></li>
      <li><a href="#related-javascript-and-css-guides">Related JavaScript and CSS Guides</a></li>
    </ul>

  </div>

  <div class="toc-right vb24-js-dropdown-toc-right">

    <a class="vb24-entityschema-ad-card" href="https://veebilehed24.ee/en/shop/entityschema-pro/" target="_blank" rel="sponsored noopener">
      <span class="vb24-entityschema-ad-badge">WordPress SEO Plugin</span>

      <div class="vb24-entityschema-ad-image">
        <img decoding="async" src="https://veebilehed24.ee/wp-content/uploads/2026/03/entityschema-cover-600x400.webp" width="300" height="200" alt="EntitySchema Pro WordPress structured data and entity SEO plugin" loading="lazy">
      </div>

      <div class="vb24-entityschema-ad-content">
        <h3>EntitySchema Pro</h3>
        <p>Build a real entity-based structured data system for WordPress, modern SEO, and AI-readable websites.</p>

        <div class="vb24-entityschema-ad-price">
  <div class="vb24-entityschema-ad-price-left">
    <span class="vb24-entityschema-ad-price-label">Sale price</span>
    <span class="vb24-entityschema-ad-old-price">59€</span>
  </div>

  <strong class="vb24-entityschema-ad-sale-price">29€</strong>

  <span class="vb24-entityschema-ad-save">Save 30€</span>
</div>

        <span class="vb24-entityschema-ad-button">View Plugin</span>
      </div>
    </a>

  </div>

</div>

<style>
.vb24-js-dropdown-toc-wrap {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 26px;
  align-items: stretch;
  margin: 34px 0 44px;
}

.vb24-js-dropdown-toc-left,
.vb24-js-dropdown-toc-right {
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 28px;
  background: linear-gradient(135deg, #0f172a 0%, #1e293b 100%);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.18);
}

.vb24-js-dropdown-toc-left {
  padding: 28px 30px 30px;
}

.vb24-js-dropdown-toc-kicker {
  margin-bottom: 10px;
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 13px;
  font-weight: 850;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb24-js-dropdown-toc-left h2 {
  margin: 0 0 22px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px !important;
  line-height: 1.15 !important;
  font-weight: 850 !important;
}

.vb24-js-dropdown-toc {
  display: grid !important;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 12px !important;
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb24-js-dropdown-toc li {
  margin: 0 !important;
  padding: 0 !important;
  list-style: none !important;
}

.vb24-js-dropdown-toc li::before {
  display: none !important;
  content: none !important;
}

.vb24-js-dropdown-toc a {
  display: flex;
  align-items: center;
  min-height: 54px;
  padding: 13px 15px;
  border: 1px solid rgba(148, 163, 184, 0.18);
  border-radius: 15px;
  background: rgba(255, 255, 255, 0.065);
  color: #f3f4f6 !important;
  -webkit-text-fill-color: #f3f4f6 !important;
  font-size: 15px;
  font-weight: 750;
  line-height: 1.35;
  text-decoration: none !important;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.05);
  transition: transform 0.2s ease, background 0.2s ease, border-color 0.2s ease;
}

.vb24-js-dropdown-toc a:hover {
  transform: translateY(-2px);
  border-color: rgba(14, 165, 233, 0.62);
  background: rgba(14, 165, 233, 0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb24-js-dropdown-toc .vb24-featured-toc-link {
  border-color: rgba(14, 165, 233, 0.72);
  background: linear-gradient(135deg, rgba(6, 182, 212, 0.30), rgba(37, 99, 235, 0.28), rgba(124, 58, 237, 0.26));
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb24-js-dropdown-toc-right {
  display: flex;
  align-items: stretch;
  justify-content: center;
  padding: 16px;
  overflow: hidden;
}

.vb24-entityschema-ad-card,
.vb24-entityschema-ad-card * {
  box-sizing: border-box;
}

.vb24-entityschema-ad-card {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  min-height: 100%;
  padding: 12px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 14% 12%, rgba(34, 211, 238, 0.28), transparent 34%),
    radial-gradient(circle at 86% 14%, rgba(236, 72, 153, 0.24), transparent 36%),
    linear-gradient(135deg, #111827 0%, #312e81 52%, #701a75 100%) !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  text-decoration: none !important;
  overflow: hidden;
  box-shadow: 0 20px 56px rgba(2, 6, 23, 0.32);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb24-entityschema-ad-card:hover {
  transform: translateY(-3px);
  filter: saturate(1.08);
  box-shadow: 0 26px 70px rgba(2, 6, 23, 0.42);
}

.vb24-entityschema-ad-badge {
  position: absolute;
  z-index: 3;
  top: 18px;
  left: 18px;
  display: inline-flex;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(15, 23, 42, 0.70);
  border: 1px solid rgba(255,255,255,0.22);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 11px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  backdrop-filter: blur(10px);
}

.vb24-entityschema-ad-image {
  overflow: hidden;
  border-radius: 17px;
  border: 1px solid rgba(255,255,255,0.16);
  background: rgba(255,255,255,0.08);
}

.vb24-entityschema-ad-image img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: 17px;
}

.vb24-entityschema-ad-content {
  padding: 15px 8px 4px;
}

.vb24-entityschema-ad-content h3 {
  margin: 0 0 8px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 23px !important;
  line-height: 1.12 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb24-entityschema-ad-content p {
  margin: 0 0 14px !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 13px;
  line-height: 1.5;
  font-weight: 650;
}

.vb24-entityschema-ad-price {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin: 0 0 12px;
  padding: 11px 12px;
  border-radius: 16px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.16);
}

.vb24-entityschema-ad-price-left {
  display: flex;
  flex-direction: column;
  gap: 3px;
}

.vb24-entityschema-ad-price-label {
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 11px;
  font-weight: 900;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb24-entityschema-ad-old-price {
  color: rgba(255,255,255,0.62) !important;
  -webkit-text-fill-color: rgba(255,255,255,0.62) !important;
  font-size: 15px;
  line-height: 1;
  font-weight: 850;
  text-decoration: line-through;
  text-decoration-thickness: 2px;
  text-decoration-color: rgba(248, 113, 113, 0.95);
}

.vb24-entityschema-ad-sale-price {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 31px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb24-entityschema-ad-save {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 28px;
  padding: 6px 9px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.18);
  border: 1px solid rgba(74, 222, 128, 0.34);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 11px;
  font-weight: 950;
  white-space: nowrap;
}

.vb24-entityschema-ad-button {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 43px;
  padding: 12px 14px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22d3ee, #2563eb 55%, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
  box-shadow: 0 14px 34px rgba(37, 99, 235, 0.30);
}

@media (max-width: 900px) {
  .vb24-js-dropdown-toc-wrap {
    grid-template-columns: 1fr;
  }

  .vb24-js-dropdown-toc-right {
    justify-content: flex-start;
    max-width: 360px;
  }
}

@media (max-width: 640px) {
  .vb24-js-dropdown-toc-left {
    padding: 22px 18px;
    border-radius: 22px;
  }

  .vb24-js-dropdown-toc-left h2 {
    font-size: 26px !important;
  }

  .vb24-js-dropdown-toc {
    grid-template-columns: 1fr;
  }

  .vb24-js-dropdown-toc a {
    min-height: 48px;
    font-size: 14px;
  }

  .vb24-js-dropdown-toc-right {
    max-width: 100%;
    border-radius: 22px;
  }
}
</style>



<h2 class="wp-block-heading" id="what-is-a-javascript-dropdown-menu">What Is a JavaScript Dropdown Menu?</h2>



<p class="wp-block-paragraph">A JavaScript dropdown menu is an interactive component that reveals hidden options, links, actions, filters, or content when a user clicks, taps, hovers, focuses, or selects a trigger element. Dropdowns are used in navigation bars, custom select fields, profile menus, ecommerce filters, language switchers, category menus, dashboard controls, and compact mobile interfaces.</p>



<p class="wp-block-paragraph">Unlike a static list, a dropdown responds to user interaction. JavaScript can open and close the menu, update active states, close the dropdown when users click outside, support keyboard navigation, filter options, select multiple values, animate the panel, or connect the selected option to another part of the interface.</p>



<p class="wp-block-paragraph">The best JavaScript dropdown menu examples are not only visually polished. They should be easy to use, predictable, responsive, accessible, and simple to customize. A good dropdown makes the interface feel cleaner while still keeping important options easy to find.</p>



<h2 class="wp-block-heading" id="why-javascript-dropdowns-matter">Why JavaScript Dropdowns Matter</h2>



<p class="wp-block-paragraph">JavaScript dropdowns matter because they help websites organize actions and choices without overwhelming the user. Instead of placing every link, filter, language, account action, or product option directly on the screen, a dropdown can reveal the right choices only when they are needed.</p>



<ul class="wp-block-list">
  <li><strong>They save interface space</strong> by grouping related links, actions, filters, or controls into one compact trigger.</li>
  <li><strong>They improve navigation</strong> by making menus, submenus, categories, and account actions easier to scan.</li>
  <li><strong>They support ecommerce UX</strong> by powering filters, sorting, product options, cart dropdowns, and category menus.</li>
  <li><strong>They help forms feel cleaner</strong> by replacing long option lists with custom select menus or searchable dropdowns.</li>
  <li><strong>They improve mobile layouts</strong> when large desktop menus need to become tap-friendly dropdown panels.</li>
</ul>



<p class="wp-block-paragraph">Dropdowns work especially well when users need to choose from a controlled set of options or access a small group of related actions. For example, a profile dropdown can show account settings, a notification dropdown can show recent alerts, a product filter dropdown can improve ecommerce browsing, and a navigation dropdown can keep a website header clean.</p>



<h2 class="wp-block-heading" id="dropdown-menu-vs-select-menu-vs-mega-menu">Dropdown Menu vs Select Menu vs Mega Menu</h2>



<p class="wp-block-paragraph">The terms dropdown menu, select menu, and mega menu are often used together, but they describe different interface patterns. A dropdown menu usually reveals links or actions. A select menu lets users choose one or more values. A mega menu is a larger dropdown used mainly in website navigation, often with columns, categories, icons, images, or promotional blocks.</p>



<p class="wp-block-paragraph">In real website projects, these patterns often overlap. Many users search for JavaScript dropdown examples when they also mean custom select dropdown, navigation dropdown, multi-level menu, category dropdown, profile dropdown, filter dropdown, or responsive mobile menu. That is why this guide includes several dropdown types instead of focusing on only one narrow pattern.</p>



<ul class="wp-block-list">
  <li><strong>Use a dropdown menu</strong> when you want to reveal links, profile actions, settings, notifications, or small groups of interface controls.</li>
  <li><strong>Use a custom select dropdown</strong> when users need to choose one option from a list but the native select field is too limited for the design.</li>
  <li><strong>Use a searchable dropdown</strong> when the option list is long and users need to find items quickly.</li>
  <li><strong>Use a multi-select dropdown</strong> when users need to select several filters, tags, categories, features, or preferences.</li>
  <li><strong>Use a mega menu</strong> when a website has many navigation links that need structure, columns, and visual grouping.</li>
</ul>



<h2 class="wp-block-heading" id="what-should-a-good-javascript-dropdown-include">What Should a Good JavaScript Dropdown Include?</h2>



<p class="wp-block-paragraph">A good JavaScript dropdown should make the interface easier to use, not more confusing. The trigger should be clear, the dropdown panel should open in a predictable place, active states should be visible, important options should be easy to scan, and the menu should close in a way users expect.</p>



<div class="vb24-js-dropdown-checklist">
  <div class="vb24-js-dropdown-check-item">
    <h3>Clear trigger</h3>
    <p>The button, select field, icon, or menu item should clearly show that it opens a dropdown panel.</p>
  </div>

  <div class="vb24-js-dropdown-check-item">
    <h3>Predictable close logic</h3>
    <p>The dropdown should close when users select an item, click outside, press Escape, or open another dropdown.</p>
  </div>

  <div class="vb24-js-dropdown-check-item">
    <h3>Responsive behavior</h3>
    <p>The menu should fit mobile screens, avoid viewport overflow, and remain easy to tap on small devices.</p>
  </div>

  <div class="vb24-js-dropdown-check-item">
    <h3>Accessible controls</h3>
    <p>Use buttons, ARIA attributes, focus states, keyboard support, and readable labels where the pattern needs them.</p>
  </div>
</div>

<style>
.vb24-js-dropdown-checklist {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 16px;
  margin: 24px 0 30px;
}

.vb24-js-dropdown-check-item {
  padding: 20px;
  border: 1px solid rgba(148, 163, 184, 0.22);
  border-radius: 22px;
  background: #ffffff;
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb24-js-dropdown-check-item h3 {
  margin: 0 0 10px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  line-height: 1.25;
  font-weight: 850;
}

.vb24-js-dropdown-check-item p {
  margin: 0;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 980px) {
  .vb24-js-dropdown-checklist {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-js-dropdown-checklist {
    grid-template-columns: 1fr;
  }

  .vb24-js-dropdown-check-item {
    padding: 18px;
    border-radius: 20px;
  }
}
</style>



<p class="wp-block-paragraph">Before building a dropdown, decide what the component should actually do. A navigation dropdown may need link groups and mobile behavior. A custom select dropdown may need selected value updates. A searchable dropdown may need filtering logic. A multi-select dropdown may need checkbox states. A profile dropdown may only need a small action menu with outside click closing.</p>



<ul class="wp-block-list">
  <li><strong>Use a button as the trigger</strong> when the dropdown opens actions, links, or a custom menu.</li>
  <li><strong>Show active state clearly</strong> so users know when the dropdown is open.</li>
  <li><strong>Close the dropdown on outside click</strong> to avoid panels staying open after the user moves away.</li>
  <li><strong>Support the Escape key</strong> for better keyboard interaction.</li>
  <li><strong>Keep menu items large enough</strong> for mobile tapping and touch interaction.</li>
  <li><strong>Prevent viewport overflow</strong> so the dropdown does not disappear off the edge of the screen.</li>
  <li><strong>Avoid hiding critical actions</strong> inside dropdowns that users may not notice.</li>
  <li><strong>Use unique class names</strong> to prevent conflicts when multiple examples or dropdowns exist on the same page.</li>
  <li><strong>Keep JavaScript reusable</strong> so the same pattern can support several dropdown instances.</li>
  <li><strong>Test on mobile</strong> because dropdowns often behave differently on touch screens than desktop screens.</li>
</ul>



<p class="wp-block-paragraph">You can combine JavaScript dropdowns with many other website sections. A dropdown navigation can support ideas from our <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-navigation-menus/">modern CSS navigation menus</a>, a filter dropdown can work with <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-cards/">card layouts</a>, a product dropdown can improve ecommerce sections, and dropdown actions can be paired with polished buttons from our <a href="https://veebilehed24.ee/en/blog/css-effects/20-modern-css-buttons-hover-effects-and-animations-2026/">modern CSS buttons</a> guide.</p>



<h2 class="wp-block-heading" id="javascript-dropdown-menu-examples">30 JavaScript Dropdown Menu Examples</h2>



<p class="wp-block-paragraph">Now let’s look at 30 JavaScript dropdown menu examples for real website projects. Each example uses a different dropdown layout, trigger style, interaction pattern, animation, content type, or responsive UI approach, so you can build custom select menus, navigation dropdowns, profile dropdowns, mega menus, searchable dropdowns, multi-select filters, ecommerce dropdowns, and complete responsive JavaScript dropdown sections with visible JavaScript, HTML, and CSS code.</p>



<h2 class="wp-block-heading">1. Basic JavaScript Dropdown Menu</h2>



<p class="wp-block-paragraph"><strong>A basic JavaScript dropdown menu</strong> is the best starting point for understanding how dropdown interaction works. This example uses a clean card-style trigger, a floating menu panel, active state styling, outside click closing, and Escape key support. It is simple enough for beginners but polished enough to use in real website interfaces.</p>



<p class="wp-block-paragraph">This dropdown pattern is useful for account menus, dashboard actions, small navigation menus, settings panels, quick links, and compact UI controls. The JavaScript is lightweight and easy to reuse on other dropdown components.</p>



<ul class="wp-block-list">
<li>Simple vanilla JavaScript dropdown</li>
<li>Click to open and close</li>
<li>Closes when clicking outside the menu</li>
<li>Supports Escape key closing</li>
<li>Professional card-style UI</li>
</ul>



<div class="vb-dropdown-one-demo">
  <div class="vb-dropdown-one-card" data-vb-dropdown-one>
    <div class="vb-dropdown-one-header">
      <span class="vb-dropdown-one-kicker">Example 01</span>
      <h3>Basic Dropdown Menu</h3>
      <p>Click the button to open a clean JavaScript dropdown menu with links, icons, and smooth UI behavior.</p>
    </div>

    <div class="vb-dropdown-one-menu-wrap">
      <button class="vb-dropdown-one-trigger" type="button" data-vb-dropdown-one-trigger aria-expanded="false">
        <span class="vb-dropdown-one-trigger-icon">☰</span>
        <span>Open menu</span>
        <span class="vb-dropdown-one-chevron">⌄</span>
      </button>

      <div class="vb-dropdown-one-panel" data-vb-dropdown-one-panel>
        <a href="#javascript-dropdown-menu-examples">
          <span>📁</span>
          <strong>View examples</strong>
          <small>Browse all dropdown patterns</small>
        </a>

        <a href="#what-is-a-javascript-dropdown-menu">
          <span>⚡</span>
          <strong>Learn basics</strong>
          <small>Understand dropdown logic</small>
        </a>

        <a href="#javascript-dropdown-best-practices">
          <span>✅</span>
          <strong>Best practices</strong>
          <small>Build better dropdown UX</small>
        </a>

        <a href="#related-javascript-and-css-guides">
          <span>🔗</span>
          <strong>Related guides</strong>
          <small>Explore more UI examples</small>
        </a>
      </div>
    </div>
  </div>
</div>

<style>
.vb-dropdown-one-demo,
.vb-dropdown-one-demo * {
  box-sizing: border-box;
}

.vb-dropdown-one-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 12% 16%, rgba(14, 165, 233, 0.24), transparent 34%),
    radial-gradient(circle at 88% 14%, rgba(124, 58, 237, 0.22), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #111827 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.22);
}

.vb-dropdown-one-card {
  position: relative;
  max-width: 760px;
  min-height: 430px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 28px;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
}

.vb-dropdown-one-header {
  max-width: 540px;
  margin-bottom: 34px;
}

.vb-dropdown-one-kicker {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(14, 165, 233, 0.18);
  border: 1px solid rgba(125, 211, 252, 0.30);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 13px;
  font-weight: 900;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-one-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 56px) !important;
  line-height: 1.02 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-dropdown-one-header p {
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-one-menu-wrap {
  position: relative;
  width: min(100%, 360px);
}

.vb-dropdown-one-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  min-height: 58px;
  padding: 14px 16px;
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: 18px;
  background: linear-gradient(135deg, #06b6d4, #2563eb 56%, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 900;
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 18px 44px rgba(37, 99, 235, 0.32);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb-dropdown-one-trigger:hover {
  transform: translateY(-2px);
  filter: saturate(1.08);
  box-shadow: 0 22px 54px rgba(37, 99, 235, 0.42);
}

.vb-dropdown-one-trigger-icon,
.vb-dropdown-one-chevron {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-one-chevron {
  transition: transform 0.22s ease;
}

.vb-dropdown-one-card.is-open .vb-dropdown-one-chevron {
  transform: rotate(180deg);
}

.vb-dropdown-one-panel {
  position: absolute;
  z-index: 10;
  top: calc(100% + 12px);
  left: 0;
  width: 100%;
  padding: 10px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.30);
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-one-card.is-open .vb-dropdown-one-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-one-panel a {
  display: grid;
  grid-template-columns: 38px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 13px;
  border-radius: 15px;
  text-decoration: none !important;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-one-panel a:hover {
  background: #f1f5f9;
  transform: translateX(2px);
}

.vb-dropdown-one-panel a span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 14px;
  background: #eff6ff;
  font-size: 18px;
}

.vb-dropdown-one-panel a strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  line-height: 1.2;
  font-weight: 900;
}

.vb-dropdown-one-panel a small {
  display: block;
  margin-top: 3px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 650;
}

@media (max-width: 640px) {
  .vb-dropdown-one-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-one-card {
    min-height: 460px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-one-header h3 {
    font-size: 34px !important;
  }

  .vb-dropdown-one-menu-wrap {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-one]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-one-trigger]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-one]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-one-trigger]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-one-demo"&gt;
  &lt;div class="vb-dropdown-one-card" data-vb-dropdown-one&gt;
    &lt;div class="vb-dropdown-one-header"&gt;
      &lt;span class="vb-dropdown-one-kicker"&gt;Example 01&lt;/span&gt;
      &lt;h3&gt;Basic Dropdown Menu&lt;/h3&gt;
      &lt;p&gt;Click the button to open a clean JavaScript dropdown menu with links, icons, and smooth UI behavior.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-dropdown-one-menu-wrap"&gt;
      &lt;button class="vb-dropdown-one-trigger" type="button" data-vb-dropdown-one-trigger aria-expanded="false"&gt;
        &lt;span class="vb-dropdown-one-trigger-icon"&gt;☰&lt;/span&gt;
        &lt;span&gt;Open menu&lt;/span&gt;
        &lt;span class="vb-dropdown-one-chevron"&gt;⌄&lt;/span&gt;
      &lt;/button&gt;

      &lt;div class="vb-dropdown-one-panel" data-vb-dropdown-one-panel&gt;
        &lt;a href="#javascript-dropdown-menu-examples"&gt;
          &lt;span&gt;📁&lt;/span&gt;
          &lt;strong&gt;View examples&lt;/strong&gt;
          &lt;small&gt;Browse all dropdown patterns&lt;/small&gt;
        &lt;/a&gt;

        &lt;a href="#what-is-a-javascript-dropdown-menu"&gt;
          &lt;span&gt;⚡&lt;/span&gt;
          &lt;strong&gt;Learn basics&lt;/strong&gt;
          &lt;small&gt;Understand dropdown logic&lt;/small&gt;
        &lt;/a&gt;

        &lt;a href="#javascript-dropdown-best-practices"&gt;
          &lt;span&gt;✅&lt;/span&gt;
          &lt;strong&gt;Best practices&lt;/strong&gt;
          &lt;small&gt;Build better dropdown UX&lt;/small&gt;
        &lt;/a&gt;

        &lt;a href="#related-javascript-and-css-guides"&gt;
          &lt;span&gt;🔗&lt;/span&gt;
          &lt;strong&gt;Related guides&lt;/strong&gt;
          &lt;small&gt;Explore more UI examples&lt;/small&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-one-demo,
.vb-dropdown-one-demo * {
  box-sizing: border-box;
}

.vb-dropdown-one-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 12% 16%, rgba(14, 165, 233, 0.24), transparent 34%),
    radial-gradient(circle at 88% 14%, rgba(124, 58, 237, 0.22), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #111827 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.22);
}

.vb-dropdown-one-card {
  position: relative;
  max-width: 760px;
  min-height: 430px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 28px;
  background: rgba(255, 255, 255, 0.08);
  border: 1px solid rgba(255, 255, 255, 0.14);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
}

.vb-dropdown-one-header {
  max-width: 540px;
  margin-bottom: 34px;
}

.vb-dropdown-one-kicker {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(14, 165, 233, 0.18);
  border: 1px solid rgba(125, 211, 252, 0.30);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 13px;
  font-weight: 900;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-one-header h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 56px) !important;
  line-height: 1.02 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-dropdown-one-header p {
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-one-menu-wrap {
  position: relative;
  width: min(100%, 360px);
}

.vb-dropdown-one-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  min-height: 58px;
  padding: 14px 16px;
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: 18px;
  background: linear-gradient(135deg, #06b6d4, #2563eb 56%, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 900;
  line-height: 1;
  cursor: pointer;
  box-shadow: 0 18px 44px rgba(37, 99, 235, 0.32);
  transition: transform 0.22s ease, box-shadow 0.22s ease, filter 0.22s ease;
}

.vb-dropdown-one-trigger:hover {
  transform: translateY(-2px);
  filter: saturate(1.08);
  box-shadow: 0 22px 54px rgba(37, 99, 235, 0.42);
}

.vb-dropdown-one-trigger-icon,
.vb-dropdown-one-chevron {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 30px;
  height: 30px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-one-chevron {
  transition: transform 0.22s ease;
}

.vb-dropdown-one-card.is-open .vb-dropdown-one-chevron {
  transform: rotate(180deg);
}

.vb-dropdown-one-panel {
  position: absolute;
  z-index: 10;
  top: calc(100% + 12px);
  left: 0;
  width: 100%;
  padding: 10px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.30);
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-one-card.is-open .vb-dropdown-one-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-one-panel a {
  display: grid;
  grid-template-columns: 38px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 13px;
  border-radius: 15px;
  text-decoration: none !important;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-one-panel a:hover {
  background: #f1f5f9;
  transform: translateX(2px);
}

.vb-dropdown-one-panel a span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 14px;
  background: #eff6ff;
  font-size: 18px;
}

.vb-dropdown-one-panel a strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  line-height: 1.2;
  font-weight: 900;
}

.vb-dropdown-one-panel a small {
  display: block;
  margin-top: 3px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 650;
}

@media (max-width: 640px) {
  .vb-dropdown-one-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-one-card {
    min-height: 460px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-one-header h3 {
    font-size: 34px !important;
  }

  .vb-dropdown-one-menu-wrap {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This basic JavaScript dropdown menu gives you a reusable foundation for many website components. You can adapt the same logic for profile menus, action menus, compact navigation panels, settings dropdowns, dashboard controls, and simple link menus.</p>



<h2 class="wp-block-heading">2. Custom Select Dropdown with JavaScript</h2>



<p class="wp-block-paragraph"><strong>A custom select dropdown</strong> replaces a standard select field with a more flexible and visually polished interface. This example lets users choose a website project type from a styled dropdown panel, updates the selected value, closes the menu after selection, and includes outside click and Escape key behavior.</p>



<p class="wp-block-paragraph">This pattern is useful for forms, quote request pages, onboarding screens, product configuration tools, booking forms, pricing pages, dashboards, and any interface where the native browser select field feels too limited for the design.</p>



<ul class="wp-block-list">
<li>Custom select dropdown UI</li>
<li>Updates selected value with JavaScript</li>
<li>Different visual style from the first example</li>
<li>Works without external libraries</li>
<li>Good for forms, filters, and project selection</li>
</ul>



<div class="vb-dropdown-two-demo">
  <div class="vb-dropdown-two-layout" data-vb-dropdown-two>
    <div class="vb-dropdown-two-copy">
      <span>Example 02</span>
      <h3>Choose a project type</h3>
      <p>This custom JavaScript select dropdown is designed for forms, quote requests, filters, and onboarding screens.</p>

      <div class="vb-dropdown-two-selected-preview">
        <small>Selected option</small>
        <strong data-vb-dropdown-two-preview>Business Website</strong>
      </div>
    </div>

    <div class="vb-dropdown-two-select-wrap">
      <label class="vb-dropdown-two-label" for="vb-dropdown-two-trigger">Project category</label>

      <button class="vb-dropdown-two-trigger" id="vb-dropdown-two-trigger" type="button" data-vb-dropdown-two-trigger aria-expanded="false">
        <span class="vb-dropdown-two-trigger-text" data-vb-dropdown-two-text>Business Website</span>
        <span class="vb-dropdown-two-trigger-meta">Most popular</span>
        <span class="vb-dropdown-two-arrow">⌄</span>
      </button>

      <div class="vb-dropdown-two-panel" data-vb-dropdown-two-panel>
        <button type="button" class="is-selected" data-vb-dropdown-two-option="Business Website" data-meta="Most popular">
          <span class="vb-dropdown-two-option-icon">🏢</span>
          <span>
            <strong>Business Website</strong>
            <small>Company page, service website, or local business site</small>
          </span>
        </button>

        <button type="button" data-vb-dropdown-two-option="Online Store" data-meta="Ecommerce">
          <span class="vb-dropdown-two-option-icon">🛒</span>
          <span>
            <strong>Online Store</strong>
            <small>WooCommerce, product catalog, or checkout flow</small>
          </span>
        </button>

        <button type="button" data-vb-dropdown-two-option="Landing Page" data-meta="Fast launch">
          <span class="vb-dropdown-two-option-icon">🚀</span>
          <span>
            <strong>Landing Page</strong>
            <small>Campaign page, lead generation, or product launch</small>
          </span>
        </button>

        <button type="button" data-vb-dropdown-two-option="Web App UI" data-meta="Advanced">
          <span class="vb-dropdown-two-option-icon">⚙️</span>
          <span>
            <strong>Web App UI</strong>
            <small>Dashboard, SaaS interface, or interactive product</small>
          </span>
        </button>
      </div>
    </div>
  </div>
</div>

<style>
.vb-dropdown-two-demo,
.vb-dropdown-two-demo * {
  box-sizing: border-box;
}

.vb-dropdown-two-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 30px;
  background:
    linear-gradient(135deg, #f8fafc 0%, #eef2ff 52%, #ecfeff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.12);
}

.vb-dropdown-two-layout {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(320px, 0.75fr);
  gap: 28px;
  align-items: center;
  min-height: 470px;
  max-width: 980px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 20px 60px rgba(15, 23, 42, 0.10);
  overflow: visible;
}

.vb-dropdown-two-layout::before {
  content: "";
  position: absolute;
  inset: auto auto -58px -58px;
  width: 190px;
  height: 190px;
  border-radius: 999px;
  background: linear-gradient(135deg, rgba(14, 165, 233, 0.22), rgba(124, 58, 237, 0.18));
  filter: blur(4px);
}

.vb-dropdown-two-copy {
  position: relative;
  z-index: 2;
}

.vb-dropdown-two-copy > span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-two-copy h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-dropdown-two-copy p {
  max-width: 520px;
  margin: 0 0 26px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-two-selected-preview {
  width: min(100%, 340px);
  padding: 18px;
  border-radius: 20px;
  background: linear-gradient(135deg, #0f172a, #1e293b);
  box-shadow: 0 18px 44px rgba(15, 23, 42, 0.22);
}

.vb-dropdown-two-selected-preview small {
  display: block;
  margin-bottom: 6px;
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-two-selected-preview strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  line-height: 1.1;
  font-weight: 950;
}

.vb-dropdown-two-select-wrap {
  position: relative;
  z-index: 20;
  align-self: center;
  width: 100%;
}

.vb-dropdown-two-label {
  display: block;
  margin: 0 0 10px;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-two-trigger {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto 34px;
  gap: 10px;
  align-items: center;
  width: 100%;
  min-height: 66px;
  padding: 13px 14px 13px 18px;
  border: 1px solid rgba(37, 99, 235, 0.24);
  border-radius: 20px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.12);
  cursor: pointer;
}

.vb-dropdown-two-trigger-text {
  overflow: hidden;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 950;
  line-height: 1.2;
  text-align: left;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.vb-dropdown-two-trigger-meta {
  display: inline-flex;
  justify-content: center;
  padding: 7px 10px;
  border-radius: 999px;
  background: #eef2ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 12px;
  font-weight: 900;
  white-space: nowrap;
}

.vb-dropdown-two-arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: linear-gradient(135deg, #06b6d4, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  transition: transform 0.22s ease;
}

.vb-dropdown-two-layout.is-open .vb-dropdown-two-arrow {
  transform: rotate(180deg);
}

.vb-dropdown-two-panel {
  position: absolute;
  z-index: 30;
  top: calc(100% + 12px);
  left: 0;
  right: 0;
  display: grid;
  gap: 8px;
  padding: 10px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.28);
  box-shadow: 0 28px 70px rgba(15, 23, 42, 0.22);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-two-layout.is-open .vb-dropdown-two-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.vb-dropdown-two-panel button {
  display: grid;
  grid-template-columns: 46px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  width: 100%;
  padding: 12px;
  border: 0;
  border-radius: 16px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-two-panel button:hover,
.vb-dropdown-two-panel button.is-selected {
  background: #f1f5f9;
  transform: translateX(2px);
}

.vb-dropdown-two-option-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  border-radius: 16px;
  background: linear-gradient(135deg, #dbeafe, #e0f2fe);
  font-size: 21px;
}

.vb-dropdown-two-panel strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-two-panel small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 650;
}

@media (max-width: 860px) {
  .vb-dropdown-two-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-two-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-two-layout {
    min-height: 620px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-two-copy h3 {
    font-size: 36px !important;
  }

  .vb-dropdown-two-trigger {
    grid-template-columns: minmax(0, 1fr) 34px;
  }

  .vb-dropdown-two-trigger-meta {
    display: none;
  }

  .vb-dropdown-two-panel {
    max-height: 310px;
    overflow-y: auto;
  }
}
</style>

<script>
(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-two]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-two-trigger]");
  const triggerText = dropdown.querySelector("[data-vb-dropdown-two-text]");
  const triggerMeta = dropdown.querySelector(".vb-dropdown-two-trigger-meta");
  const preview = dropdown.querySelector("[data-vb-dropdown-two-preview]");
  const options = dropdown.querySelectorAll("[data-vb-dropdown-two-option]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  options.forEach(function (option) {
    option.addEventListener("click", function () {
      const value = option.getAttribute("data-vb-dropdown-two-option");
      const meta = option.getAttribute("data-meta");

      triggerText.textContent = value;
      triggerMeta.textContent = meta;
      preview.textContent = value;

      options.forEach(function (item) {
        item.classList.remove("is-selected");
      });

      option.classList.add("is-selected");
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-two]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-two-trigger]");
  const triggerText = dropdown.querySelector("[data-vb-dropdown-two-text]");
  const triggerMeta = dropdown.querySelector(".vb-dropdown-two-trigger-meta");
  const preview = dropdown.querySelector("[data-vb-dropdown-two-preview]");
  const options = dropdown.querySelectorAll("[data-vb-dropdown-two-option]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  options.forEach(function (option) {
    option.addEventListener("click", function () {
      const value = option.getAttribute("data-vb-dropdown-two-option");
      const meta = option.getAttribute("data-meta");

      triggerText.textContent = value;
      triggerMeta.textContent = meta;
      preview.textContent = value;

      options.forEach(function (item) {
        item.classList.remove("is-selected");
      });

      option.classList.add("is-selected");
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-two-demo"&gt;
  &lt;div class="vb-dropdown-two-layout" data-vb-dropdown-two&gt;
    &lt;div class="vb-dropdown-two-copy"&gt;
      &lt;span&gt;Example 02&lt;/span&gt;
      &lt;h3&gt;Choose a project type&lt;/h3&gt;
      &lt;p&gt;This custom JavaScript select dropdown is designed for forms, quote requests, filters, and onboarding screens.&lt;/p&gt;

      &lt;div class="vb-dropdown-two-selected-preview"&gt;
        &lt;small&gt;Selected option&lt;/small&gt;
        &lt;strong data-vb-dropdown-two-preview&gt;Business Website&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-dropdown-two-select-wrap"&gt;
      &lt;label class="vb-dropdown-two-label" for="vb-dropdown-two-trigger"&gt;Project category&lt;/label&gt;

      &lt;button class="vb-dropdown-two-trigger" id="vb-dropdown-two-trigger" type="button" data-vb-dropdown-two-trigger aria-expanded="false"&gt;
        &lt;span class="vb-dropdown-two-trigger-text" data-vb-dropdown-two-text&gt;Business Website&lt;/span&gt;
        &lt;span class="vb-dropdown-two-trigger-meta"&gt;Most popular&lt;/span&gt;
        &lt;span class="vb-dropdown-two-arrow"&gt;⌄&lt;/span&gt;
      &lt;/button&gt;

      &lt;div class="vb-dropdown-two-panel" data-vb-dropdown-two-panel&gt;
        &lt;button type="button" class="is-selected" data-vb-dropdown-two-option="Business Website" data-meta="Most popular"&gt;
          &lt;span class="vb-dropdown-two-option-icon"&gt;🏢&lt;/span&gt;
          &lt;span&gt;
            &lt;strong&gt;Business Website&lt;/strong&gt;
            &lt;small&gt;Company page, service website, or local business site&lt;/small&gt;
          &lt;/span&gt;
        &lt;/button&gt;

        &lt;button type="button" data-vb-dropdown-two-option="Online Store" data-meta="Ecommerce"&gt;
          &lt;span class="vb-dropdown-two-option-icon"&gt;🛒&lt;/span&gt;
          &lt;span&gt;
            &lt;strong&gt;Online Store&lt;/strong&gt;
            &lt;small&gt;WooCommerce, product catalog, or checkout flow&lt;/small&gt;
          &lt;/span&gt;
        &lt;/button&gt;

        &lt;button type="button" data-vb-dropdown-two-option="Landing Page" data-meta="Fast launch"&gt;
          &lt;span class="vb-dropdown-two-option-icon"&gt;🚀&lt;/span&gt;
          &lt;span&gt;
            &lt;strong&gt;Landing Page&lt;/strong&gt;
            &lt;small&gt;Campaign page, lead generation, or product launch&lt;/small&gt;
          &lt;/span&gt;
        &lt;/button&gt;

        &lt;button type="button" data-vb-dropdown-two-option="Web App UI" data-meta="Advanced"&gt;
          &lt;span class="vb-dropdown-two-option-icon"&gt;⚙️&lt;/span&gt;
          &lt;span&gt;
            &lt;strong&gt;Web App UI&lt;/strong&gt;
            &lt;small&gt;Dashboard, SaaS interface, or interactive product&lt;/small&gt;
          &lt;/span&gt;
        &lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-two-demo,
.vb-dropdown-two-demo * {
  box-sizing: border-box;
}

.vb-dropdown-two-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 30px;
  background:
    linear-gradient(135deg, #f8fafc 0%, #eef2ff 52%, #ecfeff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.12);
}

.vb-dropdown-two-layout {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(320px, 0.75fr);
  gap: 28px;
  align-items: center;
  min-height: 470px;
  max-width: 980px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 20px 60px rgba(15, 23, 42, 0.10);
  overflow: visible;
}

.vb-dropdown-two-layout::before {
  content: "";
  position: absolute;
  inset: auto auto -58px -58px;
  width: 190px;
  height: 190px;
  border-radius: 999px;
  background: linear-gradient(135deg, rgba(14, 165, 233, 0.22), rgba(124, 58, 237, 0.18));
  filter: blur(4px);
}

.vb-dropdown-two-copy {
  position: relative;
  z-index: 2;
}

.vb-dropdown-two-copy &gt; span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-two-copy h3 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 62px) !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-dropdown-two-copy p {
  max-width: 520px;
  margin: 0 0 26px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-two-selected-preview {
  width: min(100%, 340px);
  padding: 18px;
  border-radius: 20px;
  background: linear-gradient(135deg, #0f172a, #1e293b);
  box-shadow: 0 18px 44px rgba(15, 23, 42, 0.22);
}

.vb-dropdown-two-selected-preview small {
  display: block;
  margin-bottom: 6px;
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-two-selected-preview strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  line-height: 1.1;
  font-weight: 950;
}

.vb-dropdown-two-select-wrap {
  position: relative;
  z-index: 20;
  align-self: center;
  width: 100%;
}

.vb-dropdown-two-label {
  display: block;
  margin: 0 0 10px;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 13px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-two-trigger {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto 34px;
  gap: 10px;
  align-items: center;
  width: 100%;
  min-height: 66px;
  padding: 13px 14px 13px 18px;
  border: 1px solid rgba(37, 99, 235, 0.24);
  border-radius: 20px;
  background: #ffffff;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.12);
  cursor: pointer;
}

.vb-dropdown-two-trigger-text {
  overflow: hidden;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 950;
  line-height: 1.2;
  text-align: left;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.vb-dropdown-two-trigger-meta {
  display: inline-flex;
  justify-content: center;
  padding: 7px 10px;
  border-radius: 999px;
  background: #eef2ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 12px;
  font-weight: 900;
  white-space: nowrap;
}

.vb-dropdown-two-arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: linear-gradient(135deg, #06b6d4, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  transition: transform 0.22s ease;
}

.vb-dropdown-two-layout.is-open .vb-dropdown-two-arrow {
  transform: rotate(180deg);
}

.vb-dropdown-two-panel {
  position: absolute;
  z-index: 30;
  top: calc(100% + 12px);
  left: 0;
  right: 0;
  display: grid;
  gap: 8px;
  padding: 10px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.28);
  box-shadow: 0 28px 70px rgba(15, 23, 42, 0.22);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-two-layout.is-open .vb-dropdown-two-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.vb-dropdown-two-panel button {
  display: grid;
  grid-template-columns: 46px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  width: 100%;
  padding: 12px;
  border: 0;
  border-radius: 16px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-two-panel button:hover,
.vb-dropdown-two-panel button.is-selected {
  background: #f1f5f9;
  transform: translateX(2px);
}

.vb-dropdown-two-option-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  border-radius: 16px;
  background: linear-gradient(135deg, #dbeafe, #e0f2fe);
  font-size: 21px;
}

.vb-dropdown-two-panel strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-two-panel small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 650;
}

@media (max-width: 860px) {
  .vb-dropdown-two-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-two-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-two-layout {
    min-height: 620px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-two-copy h3 {
    font-size: 36px !important;
  }

  .vb-dropdown-two-trigger {
    grid-template-columns: minmax(0, 1fr) 34px;
  }

  .vb-dropdown-two-trigger-meta {
    display: none;
  }

  .vb-dropdown-two-panel {
    max-height: 310px;
    overflow-y: auto;
  }
}</pre>



<p class="wp-block-paragraph">This custom select dropdown gives a form or interface more visual control than a native select field. You can reuse the same structure for quote request forms, product filters, category selectors, onboarding screens, pricing calculators, booking forms, and dashboard settings.</p>



<h2 class="wp-block-heading">3. Searchable JavaScript Dropdown</h2>



<p class="wp-block-paragraph"><strong>A searchable JavaScript dropdown</strong> is useful when a normal dropdown list becomes too long. Instead of forcing users to scroll through many options, this example lets visitors type into a search field and filter matching items instantly inside the dropdown panel.</p>



<p class="wp-block-paragraph">This pattern works well for country selectors, product categories, documentation sections, service lists, dashboard filters, tag pickers, location search fields, and any interface where users need to find one option quickly from a longer list.</p>



<ul class="wp-block-list">
<li>Search input inside the dropdown</li>
<li>Filters options with vanilla JavaScript</li>
<li>Updates selected value after clicking an option</li>
<li>Shows empty state when no result is found</li>
<li>Useful for long lists, filters, and search-style menus</li>
</ul>



<div class="vb-dropdown-three-demo">
  <div class="vb-dropdown-three-shell" data-vb-dropdown-three>
    <div class="vb-dropdown-three-visual">
      <span class="vb-dropdown-three-kicker">Example 03</span>
      <h3>Searchable Dropdown</h3>
      <p>Type inside the dropdown to filter categories instantly. This keeps large option lists clean, fast, and easier to use.</p>

      <div class="vb-dropdown-three-result-card">
        <small>Selected category</small>
        <strong data-vb-dropdown-three-preview>JavaScript Components</strong>
      </div>
    </div>

    <div class="vb-dropdown-three-control">
      <label>Choose topic</label>

      <button type="button" class="vb-dropdown-three-trigger" data-vb-dropdown-three-trigger aria-expanded="false">
        <span data-vb-dropdown-three-text>JavaScript Components</span>
        <span class="vb-dropdown-three-arrow">⌄</span>
      </button>

      <div class="vb-dropdown-three-panel" data-vb-dropdown-three-panel>
        <div class="vb-dropdown-three-search-wrap">
          <input type="text" data-vb-dropdown-three-search placeholder="Search topics..." aria-label="Search dropdown options">
        </div>

        <div class="vb-dropdown-three-options" data-vb-dropdown-three-options>
          <button type="button" class="is-selected" data-value="JavaScript Components">JavaScript Components</button>
          <button type="button" data-value="Responsive Navigation">Responsive Navigation</button>
          <button type="button" data-value="Form Validation">Form Validation</button>
          <button type="button" data-value="Modal Windows">Modal Windows</button>
          <button type="button" data-value="Image Sliders">Image Sliders</button>
          <button type="button" data-value="Dropdown Menus">Dropdown Menus</button>
          <button type="button" data-value="Tabs and Accordions">Tabs and Accordions</button>
          <button type="button" data-value="Product Filters">Product Filters</button>
          <button type="button" data-value="Dashboard UI">Dashboard UI</button>
          <button type="button" data-value="Mobile Interfaces">Mobile Interfaces</button>
        </div>

        <p class="vb-dropdown-three-empty" data-vb-dropdown-three-empty>No matching topic found.</p>
      </div>
    </div>
  </div>
</div>

<style>
.vb-dropdown-three-demo,
.vb-dropdown-three-demo * {
  box-sizing: border-box;
}

.vb-dropdown-three-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 16% 18%, rgba(16, 185, 129, 0.22), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(34, 211, 238, 0.22), transparent 34%),
    linear-gradient(135deg, #022c22 0%, #064e3b 45%, #0f172a 100%) !important;
  border: 1px solid rgba(167, 243, 208, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.24);
}

.vb-dropdown-three-shell {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(320px, 0.75fr);
  gap: 30px;
  align-items: center;
  max-width: 980px;
  min-height: 520px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.15);
  overflow: visible;
}

.vb-dropdown-three-visual {
  position: relative;
  z-index: 2;
}

.vb-dropdown-three-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(20, 184, 166, 0.20);
  border: 1px solid rgba(94, 234, 212, 0.34);
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-three-visual h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-dropdown-three-visual p {
  max-width: 540px;
  margin: 0 0 26px !important;
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-three-result-card {
  width: min(100%, 360px);
  padding: 18px;
  border-radius: 22px;
  background: rgba(15, 23, 42, 0.58);
  border: 1px solid rgba(255,255,255,0.16);
  box-shadow: 0 22px 54px rgba(2, 6, 23, 0.26);
}

.vb-dropdown-three-result-card small {
  display: block;
  margin-bottom: 7px;
  color: #99f6e4 !important;
  -webkit-text-fill-color: #99f6e4 !important;
  font-size: 12px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-three-result-card strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 23px;
  line-height: 1.15;
  font-weight: 950;
}

.vb-dropdown-three-control {
  position: relative;
  z-index: 20;
  width: 100%;
  padding: 22px;
  border-radius: 28px;
  background: #ffffff;
  box-shadow: 0 26px 70px rgba(2, 6, 23, 0.26);
}

.vb-dropdown-three-control label {
  display: block;
  margin: 0 0 10px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-three-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  min-height: 62px;
  padding: 14px 16px;
  border: 1px solid rgba(15, 118, 110, 0.20);
  border-radius: 18px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 950;
  text-align: left;
  cursor: pointer;
}

.vb-dropdown-three-arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: linear-gradient(135deg, #10b981, #0f766e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transition: transform 0.22s ease;
}

.vb-dropdown-three-shell.is-open .vb-dropdown-three-arrow {
  transform: rotate(180deg);
}

.vb-dropdown-three-panel {
  position: absolute;
  z-index: 30;
  top: calc(100% + 12px);
  left: 22px;
  right: 22px;
  padding: 12px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 28px 70px rgba(15, 23, 42, 0.24);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-three-shell.is-open .vb-dropdown-three-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.vb-dropdown-three-search-wrap {
  margin-bottom: 10px;
}

.vb-dropdown-three-search-wrap input {
  width: 100%;
  min-height: 48px;
  padding: 12px 14px;
  border: 1px solid rgba(15, 118, 110, 0.20);
  border-radius: 15px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 700;
  outline: none;
}

.vb-dropdown-three-search-wrap input:focus {
  border-color: rgba(20, 184, 166, 0.70);
  box-shadow: 0 0 0 4px rgba(20, 184, 166, 0.13);
}

.vb-dropdown-three-options {
  display: grid;
  gap: 7px;
  max-height: 280px;
  overflow-y: auto;
  padding-right: 4px;
}

.vb-dropdown-three-options button {
  width: 100%;
  padding: 12px 13px;
  border: 0;
  border-radius: 14px;
  background: transparent;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 850;
  text-align: left;
  cursor: pointer;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-three-options button:hover,
.vb-dropdown-three-options button.is-selected {
  background: #ecfdf5;
  transform: translateX(2px);
}

.vb-dropdown-three-empty {
  display: none;
  margin: 10px 0 0 !important;
  padding: 12px;
  border-radius: 14px;
  background: #fef2f2;
  color: #991b1b !important;
  -webkit-text-fill-color: #991b1b !important;
  font-size: 14px;
  line-height: 1.4;
  font-weight: 800;
}

.vb-dropdown-three-empty.is-visible {
  display: block;
}

@media (max-width: 860px) {
  .vb-dropdown-three-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-three-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-three-shell {
    min-height: 680px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-three-visual h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-three-control {
    padding: 16px;
    border-radius: 22px;
  }

  .vb-dropdown-three-panel {
    left: 16px;
    right: 16px;
  }
}
</style>

<script>
(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-three]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-three-trigger]");
  const triggerText = dropdown.querySelector("[data-vb-dropdown-three-text]");
  const preview = dropdown.querySelector("[data-vb-dropdown-three-preview]");
  const search = dropdown.querySelector("[data-vb-dropdown-three-search]");
  const options = dropdown.querySelectorAll("[data-vb-dropdown-three-option], [data-value]");
  const empty = dropdown.querySelector("[data-vb-dropdown-three-empty]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function openDropdown() {
    dropdown.classList.add("is-open");
    trigger.setAttribute("aria-expanded", "true");
    setTimeout(function () {
      search.focus();
    }, 80);
  }

  function toggleDropdown() {
    if (dropdown.classList.contains("is-open")) {
      closeDropdown();
    } else {
      openDropdown();
    }
  }

  function filterOptions() {
    const query = search.value.toLowerCase().trim();
    let visibleCount = 0;

    options.forEach(function (option) {
      const text = option.getAttribute("data-value").toLowerCase();
      const isVisible = text.includes(query);
      option.style.display = isVisible ? "block" : "none";

      if (isVisible) {
        visibleCount += 1;
      }
    });

    empty.classList.toggle("is-visible", visibleCount === 0);
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  search.addEventListener("input", filterOptions);

  options.forEach(function (option) {
    option.addEventListener("click", function () {
      const value = option.getAttribute("data-value");

      triggerText.textContent = value;
      preview.textContent = value;

      options.forEach(function (item) {
        item.classList.remove("is-selected");
      });

      option.classList.add("is-selected");
      search.value = "";
      filterOptions();
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-three]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-three-trigger]");
  const triggerText = dropdown.querySelector("[data-vb-dropdown-three-text]");
  const preview = dropdown.querySelector("[data-vb-dropdown-three-preview]");
  const search = dropdown.querySelector("[data-vb-dropdown-three-search]");
  const options = dropdown.querySelectorAll("[data-vb-dropdown-three-option], [data-value]");
  const empty = dropdown.querySelector("[data-vb-dropdown-three-empty]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function openDropdown() {
    dropdown.classList.add("is-open");
    trigger.setAttribute("aria-expanded", "true");
    setTimeout(function () {
      search.focus();
    }, 80);
  }

  function toggleDropdown() {
    if (dropdown.classList.contains("is-open")) {
      closeDropdown();
    } else {
      openDropdown();
    }
  }

  function filterOptions() {
    const query = search.value.toLowerCase().trim();
    let visibleCount = 0;

    options.forEach(function (option) {
      const text = option.getAttribute("data-value").toLowerCase();
      const isVisible = text.includes(query);
      option.style.display = isVisible ? "block" : "none";

      if (isVisible) {
        visibleCount += 1;
      }
    });

    empty.classList.toggle("is-visible", visibleCount === 0);
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  search.addEventListener("input", filterOptions);

  options.forEach(function (option) {
    option.addEventListener("click", function () {
      const value = option.getAttribute("data-value");

      triggerText.textContent = value;
      preview.textContent = value;

      options.forEach(function (item) {
        item.classList.remove("is-selected");
      });

      option.classList.add("is-selected");
      search.value = "";
      filterOptions();
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-three-demo"&gt;
  &lt;div class="vb-dropdown-three-shell" data-vb-dropdown-three&gt;
    &lt;div class="vb-dropdown-three-visual"&gt;
      &lt;span class="vb-dropdown-three-kicker"&gt;Example 03&lt;/span&gt;
      &lt;h3&gt;Searchable Dropdown&lt;/h3&gt;
      &lt;p&gt;Type inside the dropdown to filter categories instantly. This keeps large option lists clean, fast, and easier to use.&lt;/p&gt;

      &lt;div class="vb-dropdown-three-result-card"&gt;
        &lt;small&gt;Selected category&lt;/small&gt;
        &lt;strong data-vb-dropdown-three-preview&gt;JavaScript Components&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-dropdown-three-control"&gt;
      &lt;label&gt;Choose topic&lt;/label&gt;

      &lt;button type="button" class="vb-dropdown-three-trigger" data-vb-dropdown-three-trigger aria-expanded="false"&gt;
        &lt;span data-vb-dropdown-three-text&gt;JavaScript Components&lt;/span&gt;
        &lt;span class="vb-dropdown-three-arrow"&gt;⌄&lt;/span&gt;
      &lt;/button&gt;

      &lt;div class="vb-dropdown-three-panel" data-vb-dropdown-three-panel&gt;
        &lt;div class="vb-dropdown-three-search-wrap"&gt;
          &lt;input type="text" data-vb-dropdown-three-search placeholder="Search topics..." aria-label="Search dropdown options"&gt;
        &lt;/div&gt;

        &lt;div class="vb-dropdown-three-options" data-vb-dropdown-three-options&gt;
          &lt;button type="button" class="is-selected" data-value="JavaScript Components"&gt;JavaScript Components&lt;/button&gt;
          &lt;button type="button" data-value="Responsive Navigation"&gt;Responsive Navigation&lt;/button&gt;
          &lt;button type="button" data-value="Form Validation"&gt;Form Validation&lt;/button&gt;
          &lt;button type="button" data-value="Modal Windows"&gt;Modal Windows&lt;/button&gt;
          &lt;button type="button" data-value="Image Sliders"&gt;Image Sliders&lt;/button&gt;
          &lt;button type="button" data-value="Dropdown Menus"&gt;Dropdown Menus&lt;/button&gt;
          &lt;button type="button" data-value="Tabs and Accordions"&gt;Tabs and Accordions&lt;/button&gt;
          &lt;button type="button" data-value="Product Filters"&gt;Product Filters&lt;/button&gt;
          &lt;button type="button" data-value="Dashboard UI"&gt;Dashboard UI&lt;/button&gt;
          &lt;button type="button" data-value="Mobile Interfaces"&gt;Mobile Interfaces&lt;/button&gt;
        &lt;/div&gt;

        &lt;p class="vb-dropdown-three-empty" data-vb-dropdown-three-empty&gt;No matching topic found.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-three-demo,
.vb-dropdown-three-demo * {
  box-sizing: border-box;
}

.vb-dropdown-three-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 16% 18%, rgba(16, 185, 129, 0.22), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(34, 211, 238, 0.22), transparent 34%),
    linear-gradient(135deg, #022c22 0%, #064e3b 45%, #0f172a 100%) !important;
  border: 1px solid rgba(167, 243, 208, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.24);
}

.vb-dropdown-three-shell {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(320px, 0.75fr);
  gap: 30px;
  align-items: center;
  max-width: 980px;
  min-height: 520px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: rgba(255,255,255,0.09);
  border: 1px solid rgba(255,255,255,0.15);
  overflow: visible;
}

.vb-dropdown-three-visual {
  position: relative;
  z-index: 2;
}

.vb-dropdown-three-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(20, 184, 166, 0.20);
  border: 1px solid rgba(94, 234, 212, 0.34);
  color: #ccfbf1 !important;
  -webkit-text-fill-color: #ccfbf1 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-three-visual h3 {
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-dropdown-three-visual p {
  max-width: 540px;
  margin: 0 0 26px !important;
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-three-result-card {
  width: min(100%, 360px);
  padding: 18px;
  border-radius: 22px;
  background: rgba(15, 23, 42, 0.58);
  border: 1px solid rgba(255,255,255,0.16);
  box-shadow: 0 22px 54px rgba(2, 6, 23, 0.26);
}

.vb-dropdown-three-result-card small {
  display: block;
  margin-bottom: 7px;
  color: #99f6e4 !important;
  -webkit-text-fill-color: #99f6e4 !important;
  font-size: 12px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-three-result-card strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 23px;
  line-height: 1.15;
  font-weight: 950;
}

.vb-dropdown-three-control {
  position: relative;
  z-index: 20;
  width: 100%;
  padding: 22px;
  border-radius: 28px;
  background: #ffffff;
  box-shadow: 0 26px 70px rgba(2, 6, 23, 0.26);
}

.vb-dropdown-three-control label {
  display: block;
  margin: 0 0 10px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-three-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  min-height: 62px;
  padding: 14px 16px;
  border: 1px solid rgba(15, 118, 110, 0.20);
  border-radius: 18px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 950;
  text-align: left;
  cursor: pointer;
}

.vb-dropdown-three-arrow {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: linear-gradient(135deg, #10b981, #0f766e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transition: transform 0.22s ease;
}

.vb-dropdown-three-shell.is-open .vb-dropdown-three-arrow {
  transform: rotate(180deg);
}

.vb-dropdown-three-panel {
  position: absolute;
  z-index: 30;
  top: calc(100% + 12px);
  left: 22px;
  right: 22px;
  padding: 12px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 28px 70px rgba(15, 23, 42, 0.24);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-three-shell.is-open .vb-dropdown-three-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.vb-dropdown-three-search-wrap {
  margin-bottom: 10px;
}

.vb-dropdown-three-search-wrap input {
  width: 100%;
  min-height: 48px;
  padding: 12px 14px;
  border: 1px solid rgba(15, 118, 110, 0.20);
  border-radius: 15px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 700;
  outline: none;
}

.vb-dropdown-three-search-wrap input:focus {
  border-color: rgba(20, 184, 166, 0.70);
  box-shadow: 0 0 0 4px rgba(20, 184, 166, 0.13);
}

.vb-dropdown-three-options {
  display: grid;
  gap: 7px;
  max-height: 280px;
  overflow-y: auto;
  padding-right: 4px;
}

.vb-dropdown-three-options button {
  width: 100%;
  padding: 12px 13px;
  border: 0;
  border-radius: 14px;
  background: transparent;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 850;
  text-align: left;
  cursor: pointer;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-three-options button:hover,
.vb-dropdown-three-options button.is-selected {
  background: #ecfdf5;
  transform: translateX(2px);
}

.vb-dropdown-three-empty {
  display: none;
  margin: 10px 0 0 !important;
  padding: 12px;
  border-radius: 14px;
  background: #fef2f2;
  color: #991b1b !important;
  -webkit-text-fill-color: #991b1b !important;
  font-size: 14px;
  line-height: 1.4;
  font-weight: 800;
}

.vb-dropdown-three-empty.is-visible {
  display: block;
}

@media (max-width: 860px) {
  .vb-dropdown-three-shell {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-three-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-three-shell {
    min-height: 680px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-three-visual h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-three-control {
    padding: 16px;
    border-radius: 22px;
  }

  .vb-dropdown-three-panel {
    left: 16px;
    right: 16px;
  }
}</pre>



<p class="wp-block-paragraph">This searchable JavaScript dropdown is a strong pattern for longer option lists because users can type and narrow the results immediately. You can adapt it for country selectors, category filters, documentation search, product filters, dashboard menus, or tag pickers.</p>



<h2 class="wp-block-heading">4. Profile Action Dropdown Menu</h2>



<p class="wp-block-paragraph"><strong>A profile action dropdown menu</strong> is commonly used in dashboards, SaaS apps, membership websites, ecommerce accounts, admin interfaces, and web applications. It gives users quick access to account settings, billing, notifications, saved items, help, and sign-out actions without taking up much space in the header.</p>



<p class="wp-block-paragraph">This example uses a compact app-style interface with an avatar trigger, account preview, action links, notification badges, and a separate danger-style sign-out item. The design is intentionally different from the earlier dropdowns so the article has more visual variety.</p>



<ul class="wp-block-list">
<li>Profile avatar dropdown</li>
<li>Dashboard-style action menu</li>
<li>Notification badge and account preview</li>
<li>Outside click and Escape key support</li>
<li>Useful for SaaS dashboards, member areas, and ecommerce accounts</li>
</ul>



<div class="vb-dropdown-four-demo">
  <div class="vb-dropdown-four-appbar" data-vb-dropdown-four>
    <div class="vb-dropdown-four-brand">
      <span>JS</span>
      <div>
        <strong>Dropdown UI</strong>
        <small>Example 04</small>
      </div>
    </div>

    <nav class="vb-dropdown-four-nav" aria-label="Demo navigation">
      <a href="#javascript-dropdown-menu-examples">Examples</a>
      <a href="#javascript-dropdown-best-practices">Best Practices</a>
      <a href="#javascript-dropdown-faq">FAQ</a>
    </nav>

    <div class="vb-dropdown-four-profile-wrap">
      <button type="button" class="vb-dropdown-four-profile" data-vb-dropdown-four-trigger aria-expanded="false" aria-label="Open profile menu">
        <span class="vb-dropdown-four-avatar">JD</span>
        <span class="vb-dropdown-four-profile-text">
          <strong>John Designer</strong>
          <small>Pro account</small>
        </span>
        <span class="vb-dropdown-four-caret">⌄</span>
      </button>

      <div class="vb-dropdown-four-panel" data-vb-dropdown-four-panel>
        <div class="vb-dropdown-four-user">
          <span class="vb-dropdown-four-user-avatar">JD</span>
          <div>
            <strong>John Designer</strong>
            <small>john@example.com</small>
          </div>
        </div>

        <div class="vb-dropdown-four-links">
          <a href="#javascript-dropdown-menu-examples">
            <span>👤</span>
            <strong>Account overview</strong>
          </a>

          <a href="#what-should-a-good-javascript-dropdown-include">
            <span>⚙️</span>
            <strong>Interface settings</strong>
          </a>

          <a href="#responsive-dropdown-design-tips">
            <span>📱</span>
            <strong>Mobile preferences</strong>
          </a>

          <a href="#common-javascript-dropdown-mistakes">
            <span>🔔</span>
            <strong>Notifications</strong>
            <em>3</em>
          </a>
        </div>

        <div class="vb-dropdown-four-divider"></div>

        <a class="vb-dropdown-four-danger" href="#javascript-dropdown-conclusion">
          <span>↪</span>
          <strong>Sign out</strong>
        </a>
      </div>
    </div>
  </div>
</div>

<style>
.vb-dropdown-four-demo,
.vb-dropdown-four-demo * {
  box-sizing: border-box;
}

.vb-dropdown-four-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 22% 16%, rgba(248, 113, 113, 0.22), transparent 32%),
    radial-gradient(circle at 78% 20%, rgba(251, 191, 36, 0.18), transparent 34%),
    linear-gradient(135deg, #1f2937 0%, #111827 55%, #020617 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.24);
  overflow: visible;
}

.vb-dropdown-four-appbar {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 24px;
  align-items: center;
  max-width: 1040px;
  min-height: 410px;
  margin: 0 auto;
  padding: 32px;
  border-radius: 30px;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.12), rgba(255,255,255,0.06)) !important;
  border: 1px solid rgba(255,255,255,0.16);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
  overflow: visible;
}

.vb-dropdown-four-brand {
  align-self: start;
  display: flex;
  align-items: center;
  gap: 12px;
}

.vb-dropdown-four-brand > span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 16px;
  background: linear-gradient(135deg, #fb923c, #ef4444);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
  box-shadow: 0 16px 36px rgba(239, 68, 68, 0.26);
}

.vb-dropdown-four-brand strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-four-brand small {
  display: block;
  margin-top: 3px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 800;
}

.vb-dropdown-four-nav {
  align-self: start;
  display: flex;
  justify-content: center;
  gap: 10px;
}

.vb-dropdown-four-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 42px;
  padding: 10px 13px;
  border-radius: 999px;
  background: rgba(255,255,255,0.08);
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 13px;
  line-height: 1;
  font-weight: 850;
  text-decoration: none !important;
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-dropdown-four-profile-wrap {
  position: relative;
  align-self: start;
}

.vb-dropdown-four-profile {
  display: flex;
  align-items: center;
  gap: 11px;
  min-height: 58px;
  padding: 8px 10px 8px 8px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(2, 6, 23, 0.20);
}

.vb-dropdown-four-avatar,
.vb-dropdown-four-user-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: linear-gradient(135deg, #f97316, #db2777);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-dropdown-four-profile-text {
  display: grid;
  text-align: left;
}

.vb-dropdown-four-profile-text strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  line-height: 1.15;
  font-weight: 950;
}

.vb-dropdown-four-profile-text small {
  margin-top: 3px;
  color: #fecaca !important;
  -webkit-text-fill-color: #fecaca !important;
  font-size: 12px;
  line-height: 1;
  font-weight: 750;
}

.vb-dropdown-four-caret {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transition: transform 0.22s ease;
}

.vb-dropdown-four-appbar.is-open .vb-dropdown-four-caret {
  transform: rotate(180deg);
}

.vb-dropdown-four-panel {
  position: absolute;
  z-index: 40;
  top: calc(100% + 14px);
  right: 0;
  width: 330px;
  padding: 12px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 30px 80px rgba(2, 6, 23, 0.34);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-four-appbar.is-open .vb-dropdown-four-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-four-user {
  display: flex;
  gap: 12px;
  align-items: center;
  padding: 12px;
  border-radius: 18px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.22);
}

.vb-dropdown-four-user strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 15px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-four-user small {
  display: block;
  margin-top: 3px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 13px;
  line-height: 1.2;
  font-weight: 700;
}

.vb-dropdown-four-links {
  display: grid;
  gap: 6px;
  margin-top: 10px;
}

.vb-dropdown-four-links a,
.vb-dropdown-four-danger {
  display: grid;
  grid-template-columns: 38px minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  min-height: 48px;
  padding: 10px;
  border-radius: 16px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  text-decoration: none !important;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-four-links a:hover,
.vb-dropdown-four-danger:hover {
  background: #f8fafc;
  transform: translateX(2px);
}

.vb-dropdown-four-links a span,
.vb-dropdown-four-danger span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 14px;
  background: #f1f5f9;
  font-size: 17px;
}

.vb-dropdown-four-links a strong,
.vb-dropdown-four-danger strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 900;
}

.vb-dropdown-four-links a em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 24px;
  padding: 0 7px;
  border-radius: 999px;
  background: #ef4444;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-style: normal;
  font-weight: 950;
}

.vb-dropdown-four-divider {
  height: 1px;
  margin: 10px 0;
  background: #e5e7eb;
}

.vb-dropdown-four-danger {
  color: #991b1b !important;
  -webkit-text-fill-color: #991b1b !important;
}

.vb-dropdown-four-danger span {
  background: #fef2f2;
}

.vb-dropdown-four-danger strong {
  color: #991b1b !important;
  -webkit-text-fill-color: #991b1b !important;
}

@media (max-width: 880px) {
  .vb-dropdown-four-appbar {
    grid-template-columns: 1fr;
    align-items: start;
  }

  .vb-dropdown-four-nav {
    justify-content: flex-start;
    flex-wrap: wrap;
  }

  .vb-dropdown-four-profile-wrap {
    width: min(100%, 360px);
  }

  .vb-dropdown-four-profile {
    width: 100%;
    justify-content: space-between;
  }

  .vb-dropdown-four-panel {
    left: 0;
    right: auto;
    width: min(100%, 330px);
    transform-origin: top left;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-four-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-four-appbar {
    min-height: 560px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-four-nav {
    display: grid;
    width: 100%;
  }

  .vb-dropdown-four-nav a {
    justify-content: center;
  }

  .vb-dropdown-four-profile-text {
    display: none;
  }

  .vb-dropdown-four-panel {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-four]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-four-trigger]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-four]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-four-trigger]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-four-demo"&gt;
  &lt;div class="vb-dropdown-four-appbar" data-vb-dropdown-four&gt;
    &lt;div class="vb-dropdown-four-brand"&gt;
      &lt;span&gt;JS&lt;/span&gt;
      &lt;div&gt;
        &lt;strong&gt;Dropdown UI&lt;/strong&gt;
        &lt;small&gt;Example 04&lt;/small&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;nav class="vb-dropdown-four-nav" aria-label="Demo navigation"&gt;
      &lt;a href="#javascript-dropdown-menu-examples"&gt;Examples&lt;/a&gt;
      &lt;a href="#javascript-dropdown-best-practices"&gt;Best Practices&lt;/a&gt;
      &lt;a href="#javascript-dropdown-faq"&gt;FAQ&lt;/a&gt;
    &lt;/nav&gt;

    &lt;div class="vb-dropdown-four-profile-wrap"&gt;
      &lt;button type="button" class="vb-dropdown-four-profile" data-vb-dropdown-four-trigger aria-expanded="false" aria-label="Open profile menu"&gt;
        &lt;span class="vb-dropdown-four-avatar"&gt;JD&lt;/span&gt;
        &lt;span class="vb-dropdown-four-profile-text"&gt;
          &lt;strong&gt;John Designer&lt;/strong&gt;
          &lt;small&gt;Pro account&lt;/small&gt;
        &lt;/span&gt;
        &lt;span class="vb-dropdown-four-caret"&gt;⌄&lt;/span&gt;
      &lt;/button&gt;

      &lt;div class="vb-dropdown-four-panel" data-vb-dropdown-four-panel&gt;
        &lt;div class="vb-dropdown-four-user"&gt;
          &lt;span class="vb-dropdown-four-user-avatar"&gt;JD&lt;/span&gt;
          &lt;div&gt;
            &lt;strong&gt;John Designer&lt;/strong&gt;
            &lt;small&gt;john@example.com&lt;/small&gt;
          &lt;/div&gt;
        &lt;/div&gt;

        &lt;div class="vb-dropdown-four-links"&gt;
          &lt;a href="#javascript-dropdown-menu-examples"&gt;
            &lt;span&gt;👤&lt;/span&gt;
            &lt;strong&gt;Account overview&lt;/strong&gt;
          &lt;/a&gt;

          &lt;a href="#what-should-a-good-javascript-dropdown-include"&gt;
            &lt;span&gt;⚙️&lt;/span&gt;
            &lt;strong&gt;Interface settings&lt;/strong&gt;
          &lt;/a&gt;

          &lt;a href="#responsive-dropdown-design-tips"&gt;
            &lt;span&gt;📱&lt;/span&gt;
            &lt;strong&gt;Mobile preferences&lt;/strong&gt;
          &lt;/a&gt;

          &lt;a href="#common-javascript-dropdown-mistakes"&gt;
            &lt;span&gt;🔔&lt;/span&gt;
            &lt;strong&gt;Notifications&lt;/strong&gt;
            &lt;em&gt;3&lt;/em&gt;
          &lt;/a&gt;
        &lt;/div&gt;

        &lt;div class="vb-dropdown-four-divider"&gt;&lt;/div&gt;

        &lt;a class="vb-dropdown-four-danger" href="#javascript-dropdown-conclusion"&gt;
          &lt;span&gt;↪&lt;/span&gt;
          &lt;strong&gt;Sign out&lt;/strong&gt;
        &lt;/a&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-four-demo,
.vb-dropdown-four-demo * {
  box-sizing: border-box;
}

.vb-dropdown-four-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 22% 16%, rgba(248, 113, 113, 0.22), transparent 32%),
    radial-gradient(circle at 78% 20%, rgba(251, 191, 36, 0.18), transparent 34%),
    linear-gradient(135deg, #1f2937 0%, #111827 55%, #020617 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.24);
  overflow: visible;
}

.vb-dropdown-four-appbar {
  position: relative;
  z-index: 2;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 24px;
  align-items: center;
  max-width: 1040px;
  min-height: 410px;
  margin: 0 auto;
  padding: 32px;
  border-radius: 30px;
  background:
    linear-gradient(135deg, rgba(255,255,255,0.12), rgba(255,255,255,0.06)) !important;
  border: 1px solid rgba(255,255,255,0.16);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
  overflow: visible;
}

.vb-dropdown-four-brand {
  align-self: start;
  display: flex;
  align-items: center;
  gap: 12px;
}

.vb-dropdown-four-brand &gt; span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 16px;
  background: linear-gradient(135deg, #fb923c, #ef4444);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
  box-shadow: 0 16px 36px rgba(239, 68, 68, 0.26);
}

.vb-dropdown-four-brand strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-four-brand small {
  display: block;
  margin-top: 3px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 800;
}

.vb-dropdown-four-nav {
  align-self: start;
  display: flex;
  justify-content: center;
  gap: 10px;
}

.vb-dropdown-four-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 42px;
  padding: 10px 13px;
  border-radius: 999px;
  background: rgba(255,255,255,0.08);
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 13px;
  line-height: 1;
  font-weight: 850;
  text-decoration: none !important;
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-dropdown-four-profile-wrap {
  position: relative;
  align-self: start;
}

.vb-dropdown-four-profile {
  display: flex;
  align-items: center;
  gap: 11px;
  min-height: 58px;
  padding: 8px 10px 8px 8px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(2, 6, 23, 0.20);
}

.vb-dropdown-four-avatar,
.vb-dropdown-four-user-avatar {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 42px;
  height: 42px;
  border-radius: 999px;
  background: linear-gradient(135deg, #f97316, #db2777);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-dropdown-four-profile-text {
  display: grid;
  text-align: left;
}

.vb-dropdown-four-profile-text strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  line-height: 1.15;
  font-weight: 950;
}

.vb-dropdown-four-profile-text small {
  margin-top: 3px;
  color: #fecaca !important;
  -webkit-text-fill-color: #fecaca !important;
  font-size: 12px;
  line-height: 1;
  font-weight: 750;
}

.vb-dropdown-four-caret {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  transition: transform 0.22s ease;
}

.vb-dropdown-four-appbar.is-open .vb-dropdown-four-caret {
  transform: rotate(180deg);
}

.vb-dropdown-four-panel {
  position: absolute;
  z-index: 40;
  top: calc(100% + 14px);
  right: 0;
  width: 330px;
  padding: 12px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 30px 80px rgba(2, 6, 23, 0.34);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-four-appbar.is-open .vb-dropdown-four-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-four-user {
  display: flex;
  gap: 12px;
  align-items: center;
  padding: 12px;
  border-radius: 18px;
  background: #fff7ed;
  border: 1px solid rgba(251, 146, 60, 0.22);
}

.vb-dropdown-four-user strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 15px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-four-user small {
  display: block;
  margin-top: 3px;
  color: #9a3412 !important;
  -webkit-text-fill-color: #9a3412 !important;
  font-size: 13px;
  line-height: 1.2;
  font-weight: 700;
}

.vb-dropdown-four-links {
  display: grid;
  gap: 6px;
  margin-top: 10px;
}

.vb-dropdown-four-links a,
.vb-dropdown-four-danger {
  display: grid;
  grid-template-columns: 38px minmax(0, 1fr) auto;
  gap: 10px;
  align-items: center;
  min-height: 48px;
  padding: 10px;
  border-radius: 16px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  text-decoration: none !important;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-four-links a:hover,
.vb-dropdown-four-danger:hover {
  background: #f8fafc;
  transform: translateX(2px);
}

.vb-dropdown-four-links a span,
.vb-dropdown-four-danger span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 14px;
  background: #f1f5f9;
  font-size: 17px;
}

.vb-dropdown-four-links a strong,
.vb-dropdown-four-danger strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 900;
}

.vb-dropdown-four-links a em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 24px;
  padding: 0 7px;
  border-radius: 999px;
  background: #ef4444;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-style: normal;
  font-weight: 950;
}

.vb-dropdown-four-divider {
  height: 1px;
  margin: 10px 0;
  background: #e5e7eb;
}

.vb-dropdown-four-danger {
  color: #991b1b !important;
  -webkit-text-fill-color: #991b1b !important;
}

.vb-dropdown-four-danger span {
  background: #fef2f2;
}

.vb-dropdown-four-danger strong {
  color: #991b1b !important;
  -webkit-text-fill-color: #991b1b !important;
}

@media (max-width: 880px) {
  .vb-dropdown-four-appbar {
    grid-template-columns: 1fr;
    align-items: start;
  }

  .vb-dropdown-four-nav {
    justify-content: flex-start;
    flex-wrap: wrap;
  }

  .vb-dropdown-four-profile-wrap {
    width: min(100%, 360px);
  }

  .vb-dropdown-four-profile {
    width: 100%;
    justify-content: space-between;
  }

  .vb-dropdown-four-panel {
    left: 0;
    right: auto;
    width: min(100%, 330px);
    transform-origin: top left;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-four-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-four-appbar {
    min-height: 560px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-four-nav {
    display: grid;
    width: 100%;
  }

  .vb-dropdown-four-nav a {
    justify-content: center;
  }

  .vb-dropdown-four-profile-text {
    display: none;
  }

  .vb-dropdown-four-panel {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This profile action dropdown is a practical pattern for real web apps and membership websites. You can use the same structure for SaaS dashboards, WordPress user areas, ecommerce account pages, admin panels, client portals, and application headers.</p>



<h2 class="wp-block-heading">5. Notification Dropdown Menu</h2>



<p class="wp-block-paragraph"><strong>A notification dropdown menu</strong> is useful for dashboards, SaaS products, ecommerce accounts, admin panels, learning platforms, project tools, and membership websites. It lets users quickly see recent alerts without leaving the current page.</p>



<p class="wp-block-paragraph">This example includes a bell trigger, unread badge, notification cards, read/unread states, a “mark all as read” button, outside click closing, and Escape key support. The design uses a clean dashboard layout with soft shadows and a light interface style.</p>



<ul class="wp-block-list">
<li>Notification bell dropdown</li>
<li>Unread count badge</li>
<li>Mark all notifications as read</li>
<li>Read and unread visual states</li>
<li>Good for dashboards, apps, ecommerce accounts, and admin interfaces</li>
</ul>



<div class="vb-dropdown-five-demo">
  <div class="vb-dropdown-five-board" data-vb-dropdown-five>
    <div class="vb-dropdown-five-content">
      <span class="vb-dropdown-five-kicker">Example 05</span>
      <h3>Notification Dropdown</h3>
      <p>Use this JavaScript dropdown pattern to show recent alerts, messages, order updates, or dashboard notifications.</p>

      <div class="vb-dropdown-five-stats">
        <div>
          <strong data-vb-dropdown-five-count-text>3</strong>
          <span>Unread alerts</span>
        </div>
        <div>
          <strong>12</strong>
          <span>Total today</span>
        </div>
      </div>
    </div>

    <div class="vb-dropdown-five-widget">
      <div class="vb-dropdown-five-topbar">
        <div>
          <strong>Dashboard</strong>
          <small>Notification center</small>
        </div>

        <div class="vb-dropdown-five-bell-wrap">
          <button class="vb-dropdown-five-bell" type="button" data-vb-dropdown-five-trigger aria-expanded="false" aria-label="Open notifications">
            <span>🔔</span>
            <em data-vb-dropdown-five-count>3</em>
          </button>

          <div class="vb-dropdown-five-panel" data-vb-dropdown-five-panel>
            <div class="vb-dropdown-five-panel-head">
              <div>
                <strong>Notifications</strong>
                <small data-vb-dropdown-five-panel-count>3 unread messages</small>
              </div>
              <button type="button" data-vb-dropdown-five-read>Mark all read</button>
            </div>

            <div class="vb-dropdown-five-list">
              <a href="#javascript-dropdown-menu-examples" class="vb-dropdown-five-item is-unread">
                <span class="vb-dropdown-five-icon">📦</span>
                <span>
                  <strong>New order received</strong>
                  <small>Order #2048 was placed 3 minutes ago.</small>
                </span>
              </a>

              <a href="#what-is-a-javascript-dropdown-menu" class="vb-dropdown-five-item is-unread">
                <span class="vb-dropdown-five-icon">💬</span>
                <span>
                  <strong>New support message</strong>
                  <small>A customer asked about dropdown UI examples.</small>
                </span>
              </a>

              <a href="#javascript-dropdown-best-practices" class="vb-dropdown-five-item is-unread">
                <span class="vb-dropdown-five-icon">⚡</span>
                <span>
                  <strong>Performance alert</strong>
                  <small>Your latest JavaScript component loaded successfully.</small>
                </span>
              </a>

              <a href="#responsive-dropdown-design-tips" class="vb-dropdown-five-item">
                <span class="vb-dropdown-five-icon">📱</span>
                <span>
                  <strong>Mobile test complete</strong>
                  <small>Dropdown layout passed responsive preview.</small>
                </span>
              </a>
            </div>

            <a class="vb-dropdown-five-footer" href="#javascript-dropdown-faq">View all notifications</a>
          </div>
        </div>
      </div>

      <div class="vb-dropdown-five-preview">
        <div class="vb-dropdown-five-card">
          <span></span>
          <strong>Revenue update</strong>
          <p>Your dashboard can use notification dropdowns for important user actions.</p>
        </div>
        <div class="vb-dropdown-five-card">
          <span></span>
          <strong>Account activity</strong>
          <p>Show alerts, reminders, status updates, and new messages in one compact place.</p>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-dropdown-five-demo,
.vb-dropdown-five-demo * {
  box-sizing: border-box;
}

.vb-dropdown-five-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 12% 18%, rgba(59, 130, 246, 0.18), transparent 34%),
    radial-gradient(circle at 84% 16%, rgba(14, 165, 233, 0.18), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #e0f2fe 48%, #eef2ff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.12);
}

.vb-dropdown-five-board {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.8fr) minmax(360px, 1fr);
  gap: 30px;
  align-items: center;
  max-width: 1050px;
  min-height: 520px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background: rgba(255,255,255,0.74);
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 22px 66px rgba(15, 23, 42, 0.10);
  overflow: visible;
}

.vb-dropdown-five-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-five-content h3 {
  margin: 0 0 16px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-dropdown-five-content p {
  max-width: 500px;
  margin: 0 0 26px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-five-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 150px));
  gap: 14px;
}

.vb-dropdown-five-stats div {
  padding: 16px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.08);
}

.vb-dropdown-five-stats strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 30px;
  line-height: 1;
  font-weight: 950;
}

.vb-dropdown-five-stats span {
  display: block;
  margin-top: 6px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 800;
}

.vb-dropdown-five-widget {
  position: relative;
  z-index: 20;
  padding: 20px;
  border-radius: 28px;
  background: #0f172a;
  box-shadow: 0 30px 80px rgba(15, 23, 42, 0.28);
}

.vb-dropdown-five-topbar {
  position: relative;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 18px;
  padding: 14px;
  border-radius: 22px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-dropdown-five-topbar strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-five-topbar small {
  display: block;
  margin-top: 4px;
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 13px;
  font-weight: 700;
}

.vb-dropdown-five-bell-wrap {
  position: relative;
}

.vb-dropdown-five-bell {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: 18px;
  background: linear-gradient(135deg, #2563eb, #06b6d4);
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.34);
}

.vb-dropdown-five-bell span {
  font-size: 21px;
}

.vb-dropdown-five-bell em {
  position: absolute;
  top: -7px;
  right: -7px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 24px;
  padding: 0 7px;
  border-radius: 999px;
  background: #ef4444;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-style: normal;
  font-weight: 950;
  border: 2px solid #0f172a;
}

.vb-dropdown-five-bell em.is-hidden {
  display: none;
}

.vb-dropdown-five-panel {
  position: absolute;
  z-index: 50;
  top: calc(100% + 14px);
  right: 0;
  width: 360px;
  padding: 12px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 30px 80px rgba(2, 6, 23, 0.36);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-five-board.is-open .vb-dropdown-five-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-five-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 10px 10px 12px;
}

.vb-dropdown-five-panel-head strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 17px;
  font-weight: 950;
}

.vb-dropdown-five-panel-head small {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 700;
}

.vb-dropdown-five-panel-head button {
  padding: 8px 10px;
  border: 0;
  border-radius: 999px;
  background: #eff6ff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 900;
  cursor: pointer;
}

.vb-dropdown-five-list {
  display: grid;
  gap: 7px;
}

.vb-dropdown-five-item {
  position: relative;
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  padding: 11px;
  border-radius: 17px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  text-decoration: none !important;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-five-item:hover {
  background: #f8fafc;
  transform: translateX(2px);
}

.vb-dropdown-five-item.is-unread {
  background: #eff6ff;
}

.vb-dropdown-five-item.is-unread::after {
  content: "";
  position: absolute;
  top: 17px;
  right: 13px;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: #2563eb;
}

.vb-dropdown-five-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: #dbeafe;
  font-size: 18px;
}

.vb-dropdown-five-item strong {
  display: block;
  padding-right: 14px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  line-height: 1.25;
  font-weight: 950;
}

.vb-dropdown-five-item small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 650;
}

.vb-dropdown-five-footer {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 42px;
  margin-top: 10px;
  border-radius: 15px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 900;
  text-decoration: none !important;
}

.vb-dropdown-five-preview {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-dropdown-five-card {
  padding: 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-dropdown-five-card span {
  display: block;
  width: 46px;
  height: 8px;
  margin-bottom: 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #38bdf8, #2563eb);
}

.vb-dropdown-five-card strong {
  display: block;
  margin-bottom: 8px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-five-card p {
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 13px;
  line-height: 1.55;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-dropdown-five-board {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-five-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-five-board {
    min-height: 700px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-five-content h3 {
    font-size: 36px !important;
  }

  .vb-dropdown-five-preview {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-five-panel {
    right: -10px;
    width: min(86vw, 360px);
  }

  .vb-dropdown-five-panel-head {
    align-items: flex-start;
    flex-direction: column;
  }
}
</style>

<script>
(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-five]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-five-trigger]");
  const readButton = dropdown.querySelector("[data-vb-dropdown-five-read]");
  const badge = dropdown.querySelector("[data-vb-dropdown-five-count]");
  const countText = dropdown.querySelector("[data-vb-dropdown-five-count-text]");
  const panelCount = dropdown.querySelector("[data-vb-dropdown-five-panel-count]");
  const unreadItems = dropdown.querySelectorAll(".vb-dropdown-five-item.is-unread");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function markAllAsRead() {
    unreadItems.forEach(function (item) {
      item.classList.remove("is-unread");
    });

    badge.classList.add("is-hidden");
    badge.textContent = "0";
    countText.textContent = "0";
    panelCount.textContent = "No unread messages";
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  readButton.addEventListener("click", function (event) {
    event.stopPropagation();
    markAllAsRead();
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-five]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-five-trigger]");
  const readButton = dropdown.querySelector("[data-vb-dropdown-five-read]");
  const badge = dropdown.querySelector("[data-vb-dropdown-five-count]");
  const countText = dropdown.querySelector("[data-vb-dropdown-five-count-text]");
  const panelCount = dropdown.querySelector("[data-vb-dropdown-five-panel-count]");
  const unreadItems = dropdown.querySelectorAll(".vb-dropdown-five-item.is-unread");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function markAllAsRead() {
    unreadItems.forEach(function (item) {
      item.classList.remove("is-unread");
    });

    badge.classList.add("is-hidden");
    badge.textContent = "0";
    countText.textContent = "0";
    panelCount.textContent = "No unread messages";
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  readButton.addEventListener("click", function (event) {
    event.stopPropagation();
    markAllAsRead();
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-five-demo"&gt;
  &lt;div class="vb-dropdown-five-board" data-vb-dropdown-five&gt;
    &lt;div class="vb-dropdown-five-content"&gt;
      &lt;span class="vb-dropdown-five-kicker"&gt;Example 05&lt;/span&gt;
      &lt;h3&gt;Notification Dropdown&lt;/h3&gt;
      &lt;p&gt;Use this JavaScript dropdown pattern to show recent alerts, messages, order updates, or dashboard notifications.&lt;/p&gt;

      &lt;div class="vb-dropdown-five-stats"&gt;
        &lt;div&gt;
          &lt;strong data-vb-dropdown-five-count-text&gt;3&lt;/strong&gt;
          &lt;span&gt;Unread alerts&lt;/span&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;strong&gt;12&lt;/strong&gt;
          &lt;span&gt;Total today&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-dropdown-five-widget"&gt;
      &lt;div class="vb-dropdown-five-topbar"&gt;
        &lt;div&gt;
          &lt;strong&gt;Dashboard&lt;/strong&gt;
          &lt;small&gt;Notification center&lt;/small&gt;
        &lt;/div&gt;

        &lt;div class="vb-dropdown-five-bell-wrap"&gt;
          &lt;button class="vb-dropdown-five-bell" type="button" data-vb-dropdown-five-trigger aria-expanded="false" aria-label="Open notifications"&gt;
            &lt;span&gt;🔔&lt;/span&gt;
            &lt;em data-vb-dropdown-five-count&gt;3&lt;/em&gt;
          &lt;/button&gt;

          &lt;div class="vb-dropdown-five-panel" data-vb-dropdown-five-panel&gt;
            &lt;div class="vb-dropdown-five-panel-head"&gt;
              &lt;div&gt;
                &lt;strong&gt;Notifications&lt;/strong&gt;
                &lt;small data-vb-dropdown-five-panel-count&gt;3 unread messages&lt;/small&gt;
              &lt;/div&gt;
              &lt;button type="button" data-vb-dropdown-five-read&gt;Mark all read&lt;/button&gt;
            &lt;/div&gt;

            &lt;div class="vb-dropdown-five-list"&gt;
              &lt;a href="#javascript-dropdown-menu-examples" class="vb-dropdown-five-item is-unread"&gt;
                &lt;span class="vb-dropdown-five-icon"&gt;📦&lt;/span&gt;
                &lt;span&gt;
                  &lt;strong&gt;New order received&lt;/strong&gt;
                  &lt;small&gt;Order #2048 was placed 3 minutes ago.&lt;/small&gt;
                &lt;/span&gt;
              &lt;/a&gt;

              &lt;a href="#what-is-a-javascript-dropdown-menu" class="vb-dropdown-five-item is-unread"&gt;
                &lt;span class="vb-dropdown-five-icon"&gt;💬&lt;/span&gt;
                &lt;span&gt;
                  &lt;strong&gt;New support message&lt;/strong&gt;
                  &lt;small&gt;A customer asked about dropdown UI examples.&lt;/small&gt;
                &lt;/span&gt;
              &lt;/a&gt;

              &lt;a href="#javascript-dropdown-best-practices" class="vb-dropdown-five-item is-unread"&gt;
                &lt;span class="vb-dropdown-five-icon"&gt;⚡&lt;/span&gt;
                &lt;span&gt;
                  &lt;strong&gt;Performance alert&lt;/strong&gt;
                  &lt;small&gt;Your latest JavaScript component loaded successfully.&lt;/small&gt;
                &lt;/span&gt;
              &lt;/a&gt;

              &lt;a href="#responsive-dropdown-design-tips" class="vb-dropdown-five-item"&gt;
                &lt;span class="vb-dropdown-five-icon"&gt;📱&lt;/span&gt;
                &lt;span&gt;
                  &lt;strong&gt;Mobile test complete&lt;/strong&gt;
                  &lt;small&gt;Dropdown layout passed responsive preview.&lt;/small&gt;
                &lt;/span&gt;
              &lt;/a&gt;
            &lt;/div&gt;

            &lt;a class="vb-dropdown-five-footer" href="#javascript-dropdown-faq"&gt;View all notifications&lt;/a&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-five-preview"&gt;
        &lt;div class="vb-dropdown-five-card"&gt;
          &lt;span&gt;&lt;/span&gt;
          &lt;strong&gt;Revenue update&lt;/strong&gt;
          &lt;p&gt;Your dashboard can use notification dropdowns for important user actions.&lt;/p&gt;
        &lt;/div&gt;
        &lt;div class="vb-dropdown-five-card"&gt;
          &lt;span&gt;&lt;/span&gt;
          &lt;strong&gt;Account activity&lt;/strong&gt;
          &lt;p&gt;Show alerts, reminders, status updates, and new messages in one compact place.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-five-demo,
.vb-dropdown-five-demo * {
  box-sizing: border-box;
}

.vb-dropdown-five-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 12% 18%, rgba(59, 130, 246, 0.18), transparent 34%),
    radial-gradient(circle at 84% 16%, rgba(14, 165, 233, 0.18), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #e0f2fe 48%, #eef2ff 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.12);
}

.vb-dropdown-five-board {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.8fr) minmax(360px, 1fr);
  gap: 30px;
  align-items: center;
  max-width: 1050px;
  min-height: 520px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background: rgba(255,255,255,0.74);
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 22px 66px rgba(15, 23, 42, 0.10);
  overflow: visible;
}

.vb-dropdown-five-kicker {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-five-content h3 {
  margin: 0 0 16px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-dropdown-five-content p {
  max-width: 500px;
  margin: 0 0 26px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-five-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 150px));
  gap: 14px;
}

.vb-dropdown-five-stats div {
  padding: 16px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.08);
}

.vb-dropdown-five-stats strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 30px;
  line-height: 1;
  font-weight: 950;
}

.vb-dropdown-five-stats span {
  display: block;
  margin-top: 6px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 800;
}

.vb-dropdown-five-widget {
  position: relative;
  z-index: 20;
  padding: 20px;
  border-radius: 28px;
  background: #0f172a;
  box-shadow: 0 30px 80px rgba(15, 23, 42, 0.28);
}

.vb-dropdown-five-topbar {
  position: relative;
  z-index: 30;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 18px;
  padding: 14px;
  border-radius: 22px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-dropdown-five-topbar strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-five-topbar small {
  display: block;
  margin-top: 4px;
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 13px;
  font-weight: 700;
}

.vb-dropdown-five-bell-wrap {
  position: relative;
}

.vb-dropdown-five-bell {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border: 1px solid rgba(255,255,255,0.18);
  border-radius: 18px;
  background: linear-gradient(135deg, #2563eb, #06b6d4);
  cursor: pointer;
  box-shadow: 0 16px 38px rgba(37, 99, 235, 0.34);
}

.vb-dropdown-five-bell span {
  font-size: 21px;
}

.vb-dropdown-five-bell em {
  position: absolute;
  top: -7px;
  right: -7px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 24px;
  padding: 0 7px;
  border-radius: 999px;
  background: #ef4444;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-style: normal;
  font-weight: 950;
  border: 2px solid #0f172a;
}

.vb-dropdown-five-bell em.is-hidden {
  display: none;
}

.vb-dropdown-five-panel {
  position: absolute;
  z-index: 50;
  top: calc(100% + 14px);
  right: 0;
  width: 360px;
  padding: 12px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 30px 80px rgba(2, 6, 23, 0.36);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-five-board.is-open .vb-dropdown-five-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-five-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 10px 10px 12px;
}

.vb-dropdown-five-panel-head strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 17px;
  font-weight: 950;
}

.vb-dropdown-five-panel-head small {
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 700;
}

.vb-dropdown-five-panel-head button {
  padding: 8px 10px;
  border: 0;
  border-radius: 999px;
  background: #eff6ff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 900;
  cursor: pointer;
}

.vb-dropdown-five-list {
  display: grid;
  gap: 7px;
}

.vb-dropdown-five-item {
  position: relative;
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  padding: 11px;
  border-radius: 17px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  text-decoration: none !important;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-five-item:hover {
  background: #f8fafc;
  transform: translateX(2px);
}

.vb-dropdown-five-item.is-unread {
  background: #eff6ff;
}

.vb-dropdown-five-item.is-unread::after {
  content: "";
  position: absolute;
  top: 17px;
  right: 13px;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: #2563eb;
}

.vb-dropdown-five-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: #dbeafe;
  font-size: 18px;
}

.vb-dropdown-five-item strong {
  display: block;
  padding-right: 14px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  line-height: 1.25;
  font-weight: 950;
}

.vb-dropdown-five-item small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  line-height: 1.35;
  font-weight: 650;
}

.vb-dropdown-five-footer {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 42px;
  margin-top: 10px;
  border-radius: 15px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 900;
  text-decoration: none !important;
}

.vb-dropdown-five-preview {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
}

.vb-dropdown-five-card {
  padding: 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-dropdown-five-card span {
  display: block;
  width: 46px;
  height: 8px;
  margin-bottom: 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #38bdf8, #2563eb);
}

.vb-dropdown-five-card strong {
  display: block;
  margin-bottom: 8px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-five-card p {
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 13px;
  line-height: 1.55;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-dropdown-five-board {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-five-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-five-board {
    min-height: 700px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-five-content h3 {
    font-size: 36px !important;
  }

  .vb-dropdown-five-preview {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-five-panel {
    right: -10px;
    width: min(86vw, 360px);
  }

  .vb-dropdown-five-panel-head {
    align-items: flex-start;
    flex-direction: column;
  }
}</pre>



<p class="wp-block-paragraph">This notification dropdown is a practical UI component for real product dashboards and user accounts. You can adapt the same structure for order alerts, customer messages, admin updates, SaaS notifications, system warnings, or member activity feeds.</p>



<h2 class="wp-block-heading">6. Multi-Select Filter Dropdown</h2>



<p class="wp-block-paragraph"><strong>A multi-select filter dropdown</strong> lets users choose several options from one compact menu. This is especially useful for ecommerce filters, blog category filters, portfolio tags, job boards, product comparison tools, dashboards, and listing pages where users need to combine multiple criteria.</p>



<p class="wp-block-paragraph">This example uses checkbox-style filter chips, a live selected count, removable selected tags, a clear button, and JavaScript state updates. The layout feels more like a modern product filter panel than a simple menu dropdown.</p>



<ul class="wp-block-list">
<li>Multi-select dropdown with checkboxes</li>
<li>Live selected filter count</li>
<li>Selected tags displayed below the trigger</li>
<li>Clear all selected filters button</li>
<li>Useful for ecommerce, blogs, portfolios, directories, and dashboards</li>
</ul>



<div class="vb-dropdown-six-demo">
  <div class="vb-dropdown-six-shop" data-vb-dropdown-six>
    <div class="vb-dropdown-six-header">
      <span>Example 06</span>
      <h3>Multi-Select Filter Dropdown</h3>
      <p>Select several product filters from one dropdown and show active filter tags instantly.</p>
    </div>

    <div class="vb-dropdown-six-products">
      <div class="vb-dropdown-six-filterbar">
        <div class="vb-dropdown-six-filter-wrap">
          <button type="button" class="vb-dropdown-six-trigger" data-vb-dropdown-six-trigger aria-expanded="false">
            <span>
              <strong>Product filters</strong>
              <small data-vb-dropdown-six-summary>0 filters selected</small>
            </span>
            <em>⌄</em>
          </button>

          <div class="vb-dropdown-six-panel" data-vb-dropdown-six-panel>
            <div class="vb-dropdown-six-panel-head">
              <strong>Filter products</strong>
              <button type="button" data-vb-dropdown-six-clear>Clear all</button>
            </div>

            <label class="vb-dropdown-six-option">
              <input type="checkbox" value="Bestseller">
              <span>Bestseller</span>
            </label>

            <label class="vb-dropdown-six-option">
              <input type="checkbox" value="Discount">
              <span>Discount</span>
            </label>

            <label class="vb-dropdown-six-option">
              <input type="checkbox" value="New Arrival">
              <span>New Arrival</span>
            </label>

            <label class="vb-dropdown-six-option">
              <input type="checkbox" value="Free Shipping">
              <span>Free Shipping</span>
            </label>

            <label class="vb-dropdown-six-option">
              <input type="checkbox" value="Premium">
              <span>Premium</span>
            </label>

            <label class="vb-dropdown-six-option">
              <input type="checkbox" value="In Stock">
              <span>In Stock</span>
            </label>
          </div>
        </div>
      </div>

      <div class="vb-dropdown-six-tags" data-vb-dropdown-six-tags>
        <span>No active filters yet</span>
      </div>

      <div class="vb-dropdown-six-grid">
        <div>
          <small>Product Card</small>
          <strong>Smart UI Kit</strong>
          <p>Use filters to narrow product collections and improve browsing.</p>
        </div>

        <div>
          <small>Product Card</small>
          <strong>Dashboard Pack</strong>
          <p>Multi-select dropdowns are useful for complex listing pages.</p>
        </div>

        <div>
          <small>Product Card</small>
          <strong>Component Bundle</strong>
          <p>Selected tags help users see which filters are active.</p>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-dropdown-six-demo,
.vb-dropdown-six-demo * {
  box-sizing: border-box;
}

.vb-dropdown-six-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 18% 16%, rgba(168, 85, 247, 0.20), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(236, 72, 153, 0.18), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #fdf2f8 50%, #fff7ed 100%) !important;
  border: 1px solid rgba(216, 180, 254, 0.34);
  box-shadow: 0 24px 70px rgba(88, 28, 135, 0.12);
}

.vb-dropdown-six-shop {
  position: relative;
  max-width: 1040px;
  min-height: 560px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(216, 180, 254, 0.30);
  box-shadow: 0 24px 70px rgba(88, 28, 135, 0.14);
  overflow: visible;
}

.vb-dropdown-six-header {
  max-width: 760px;
  margin-bottom: 28px;
}

.vb-dropdown-six-header > span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-six-header h3 {
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-dropdown-six-header p {
  max-width: 600px;
  margin: 0 !important;
  color: #6b7280 !important;
  -webkit-text-fill-color: #6b7280 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-six-products {
  position: relative;
  z-index: 20;
  padding: 22px;
  border-radius: 28px;
  background: #f9fafb;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-dropdown-six-filterbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 16px;
}

.vb-dropdown-six-filter-wrap {
  position: relative;
  width: min(100%, 360px);
}

.vb-dropdown-six-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  width: 100%;
  min-height: 68px;
  padding: 13px 14px 13px 18px;
  border: 1px solid rgba(168, 85, 247, 0.24);
  border-radius: 20px;
  background: #ffffff;
  box-shadow: 0 16px 38px rgba(88, 28, 135, 0.10);
  cursor: pointer;
  text-align: left;
}

.vb-dropdown-six-trigger strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 15px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-six-trigger small {
  display: block;
  margin-top: 5px;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 13px;
  line-height: 1.2;
  font-weight: 850;
}

.vb-dropdown-six-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 38px;
  height: 38px;
  border-radius: 999px;
  background: linear-gradient(135deg, #a855f7, #ec4899);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  font-weight: 950;
  transition: transform 0.22s ease;
}

.vb-dropdown-six-shop.is-open .vb-dropdown-six-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-six-panel {
  position: absolute;
  z-index: 40;
  top: calc(100% + 12px);
  left: 0;
  width: 100%;
  padding: 12px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(216, 180, 254, 0.45);
  box-shadow: 0 28px 70px rgba(88, 28, 135, 0.24);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-six-shop.is-open .vb-dropdown-six-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.vb-dropdown-six-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 10px;
  padding: 4px 4px 10px;
  border-bottom: 1px solid #f3e8ff;
}

.vb-dropdown-six-panel-head strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-six-panel-head button {
  border: 0;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  padding: 8px 10px;
  font-size: 12px;
  font-weight: 900;
  cursor: pointer;
}

.vb-dropdown-six-option {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  padding: 10px;
  border-radius: 14px;
  cursor: pointer;
  transition: background 0.18s ease;
}

.vb-dropdown-six-option:hover {
  background: #faf5ff;
}

.vb-dropdown-six-option input {
  width: 18px;
  height: 18px;
  accent-color: #a855f7;
}

.vb-dropdown-six-option span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-dropdown-six-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
  min-height: 42px;
  margin-bottom: 18px;
}

.vb-dropdown-six-tags span,
.vb-dropdown-six-tags button {
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  padding: 8px 11px;
  border-radius: 999px;
  background: #ffffff;
  border: 1px solid rgba(216, 180, 254, 0.55);
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-dropdown-six-tags button {
  cursor: pointer;
}

.vb-dropdown-six-tags button::after {
  content: "×";
  margin-left: 8px;
  font-size: 16px;
  line-height: 1;
  font-weight: 950;
}

.vb-dropdown-six-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.vb-dropdown-six-grid div {
  min-height: 160px;
  padding: 18px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 20% 14%, rgba(236, 72, 153, 0.14), transparent 34%),
    linear-gradient(135deg, #ffffff, #faf5ff) !important;
  border: 1px solid rgba(216, 180, 254, 0.35);
  box-shadow: 0 16px 40px rgba(88, 28, 135, 0.08);
}

.vb-dropdown-six-grid small {
  display: inline-flex;
  margin-bottom: 18px;
  color: #a21caf !important;
  -webkit-text-fill-color: #a21caf !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-dropdown-six-grid strong {
  display: block;
  margin-bottom: 8px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-dropdown-six-grid p {
  margin: 0 !important;
  color: #6b7280 !important;
  -webkit-text-fill-color: #6b7280 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

@media (max-width: 860px) {
  .vb-dropdown-six-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-six-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-six-shop {
    min-height: 780px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-six-header h3 {
    font-size: 36px !important;
  }

  .vb-dropdown-six-products {
    padding: 16px;
  }

  .vb-dropdown-six-filter-wrap {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-six]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-six-trigger]");
  const checkboxes = dropdown.querySelectorAll(".vb-dropdown-six-option input");
  const summary = dropdown.querySelector("[data-vb-dropdown-six-summary]");
  const tags = dropdown.querySelector("[data-vb-dropdown-six-tags]");
  const clearButton = dropdown.querySelector("[data-vb-dropdown-six-clear]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function getSelectedValues() {
    return Array.from(checkboxes)
      .filter(function (checkbox) {
        return checkbox.checked;
      })
      .map(function (checkbox) {
        return checkbox.value;
      });
  }

  function updateSelectedTags() {
    const selectedValues = getSelectedValues();

    summary.textContent = selectedValues.length === 1
      ? "1 filter selected"
      : selectedValues.length + " filters selected";

    tags.innerHTML = "";

    if (selectedValues.length === 0) {
      const empty = document.createElement("span");
      empty.textContent = "No active filters yet";
      tags.appendChild(empty);
      return;
    }

    selectedValues.forEach(function (value) {
      const tag = document.createElement("button");
      tag.type = "button";
      tag.textContent = value;
      tag.setAttribute("data-remove-filter", value);
      tags.appendChild(tag);
    });
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  checkboxes.forEach(function (checkbox) {
    checkbox.addEventListener("change", updateSelectedTags);
  });

  clearButton.addEventListener("click", function (event) {
    event.stopPropagation();

    checkboxes.forEach(function (checkbox) {
      checkbox.checked = false;
    });

    updateSelectedTags();
  });

  tags.addEventListener("click", function (event) {
    const button = event.target.closest("[data-remove-filter]");
    if (!button) return;

    const value = button.getAttribute("data-remove-filter");

    checkboxes.forEach(function (checkbox) {
      if (checkbox.value === value) {
        checkbox.checked = false;
      }
    });

    updateSelectedTags();
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });

  updateSelectedTags();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-six]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-six-trigger]");
  const checkboxes = dropdown.querySelectorAll(".vb-dropdown-six-option input");
  const summary = dropdown.querySelector("[data-vb-dropdown-six-summary]");
  const tags = dropdown.querySelector("[data-vb-dropdown-six-tags]");
  const clearButton = dropdown.querySelector("[data-vb-dropdown-six-clear]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function getSelectedValues() {
    return Array.from(checkboxes)
      .filter(function (checkbox) {
        return checkbox.checked;
      })
      .map(function (checkbox) {
        return checkbox.value;
      });
  }

  function updateSelectedTags() {
    const selectedValues = getSelectedValues();

    summary.textContent = selectedValues.length === 1
      ? "1 filter selected"
      : selectedValues.length + " filters selected";

    tags.innerHTML = "";

    if (selectedValues.length === 0) {
      const empty = document.createElement("span");
      empty.textContent = "No active filters yet";
      tags.appendChild(empty);
      return;
    }

    selectedValues.forEach(function (value) {
      const tag = document.createElement("button");
      tag.type = "button";
      tag.textContent = value;
      tag.setAttribute("data-remove-filter", value);
      tags.appendChild(tag);
    });
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  checkboxes.forEach(function (checkbox) {
    checkbox.addEventListener("change", updateSelectedTags);
  });

  clearButton.addEventListener("click", function (event) {
    event.stopPropagation();

    checkboxes.forEach(function (checkbox) {
      checkbox.checked = false;
    });

    updateSelectedTags();
  });

  tags.addEventListener("click", function (event) {
    const button = event.target.closest("[data-remove-filter]");
    if (!button) return;

    const value = button.getAttribute("data-remove-filter");

    checkboxes.forEach(function (checkbox) {
      if (checkbox.value === value) {
        checkbox.checked = false;
      }
    });

    updateSelectedTags();
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });

  updateSelectedTags();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-six-demo"&gt;
  &lt;div class="vb-dropdown-six-shop" data-vb-dropdown-six&gt;
    &lt;div class="vb-dropdown-six-header"&gt;
      &lt;span&gt;Example 06&lt;/span&gt;
      &lt;h3&gt;Multi-Select Filter Dropdown&lt;/h3&gt;
      &lt;p&gt;Select several product filters from one dropdown and show active filter tags instantly.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-dropdown-six-products"&gt;
      &lt;div class="vb-dropdown-six-filterbar"&gt;
        &lt;div class="vb-dropdown-six-filter-wrap"&gt;
          &lt;button type="button" class="vb-dropdown-six-trigger" data-vb-dropdown-six-trigger aria-expanded="false"&gt;
            &lt;span&gt;
              &lt;strong&gt;Product filters&lt;/strong&gt;
              &lt;small data-vb-dropdown-six-summary&gt;0 filters selected&lt;/small&gt;
            &lt;/span&gt;
            &lt;em&gt;⌄&lt;/em&gt;
          &lt;/button&gt;

          &lt;div class="vb-dropdown-six-panel" data-vb-dropdown-six-panel&gt;
            &lt;div class="vb-dropdown-six-panel-head"&gt;
              &lt;strong&gt;Filter products&lt;/strong&gt;
              &lt;button type="button" data-vb-dropdown-six-clear&gt;Clear all&lt;/button&gt;
            &lt;/div&gt;

            &lt;label class="vb-dropdown-six-option"&gt;
              &lt;input type="checkbox" value="Bestseller"&gt;
              &lt;span&gt;Bestseller&lt;/span&gt;
            &lt;/label&gt;

            &lt;label class="vb-dropdown-six-option"&gt;
              &lt;input type="checkbox" value="Discount"&gt;
              &lt;span&gt;Discount&lt;/span&gt;
            &lt;/label&gt;

            &lt;label class="vb-dropdown-six-option"&gt;
              &lt;input type="checkbox" value="New Arrival"&gt;
              &lt;span&gt;New Arrival&lt;/span&gt;
            &lt;/label&gt;

            &lt;label class="vb-dropdown-six-option"&gt;
              &lt;input type="checkbox" value="Free Shipping"&gt;
              &lt;span&gt;Free Shipping&lt;/span&gt;
            &lt;/label&gt;

            &lt;label class="vb-dropdown-six-option"&gt;
              &lt;input type="checkbox" value="Premium"&gt;
              &lt;span&gt;Premium&lt;/span&gt;
            &lt;/label&gt;

            &lt;label class="vb-dropdown-six-option"&gt;
              &lt;input type="checkbox" value="In Stock"&gt;
              &lt;span&gt;In Stock&lt;/span&gt;
            &lt;/label&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-six-tags" data-vb-dropdown-six-tags&gt;
        &lt;span&gt;No active filters yet&lt;/span&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-six-grid"&gt;
        &lt;div&gt;
          &lt;small&gt;Product Card&lt;/small&gt;
          &lt;strong&gt;Smart UI Kit&lt;/strong&gt;
          &lt;p&gt;Use filters to narrow product collections and improve browsing.&lt;/p&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;small&gt;Product Card&lt;/small&gt;
          &lt;strong&gt;Dashboard Pack&lt;/strong&gt;
          &lt;p&gt;Multi-select dropdowns are useful for complex listing pages.&lt;/p&gt;
        &lt;/div&gt;

        &lt;div&gt;
          &lt;small&gt;Product Card&lt;/small&gt;
          &lt;strong&gt;Component Bundle&lt;/strong&gt;
          &lt;p&gt;Selected tags help users see which filters are active.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-six-demo,
.vb-dropdown-six-demo * {
  box-sizing: border-box;
}

.vb-dropdown-six-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 18% 16%, rgba(168, 85, 247, 0.20), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(236, 72, 153, 0.18), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #fdf2f8 50%, #fff7ed 100%) !important;
  border: 1px solid rgba(216, 180, 254, 0.34);
  box-shadow: 0 24px 70px rgba(88, 28, 135, 0.12);
}

.vb-dropdown-six-shop {
  position: relative;
  max-width: 1040px;
  min-height: 560px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(216, 180, 254, 0.30);
  box-shadow: 0 24px 70px rgba(88, 28, 135, 0.14);
  overflow: visible;
}

.vb-dropdown-six-header {
  max-width: 760px;
  margin-bottom: 28px;
}

.vb-dropdown-six-header &gt; span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-six-header h3 {
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(34px, 5vw, 64px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-dropdown-six-header p {
  max-width: 600px;
  margin: 0 !important;
  color: #6b7280 !important;
  -webkit-text-fill-color: #6b7280 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-six-products {
  position: relative;
  z-index: 20;
  padding: 22px;
  border-radius: 28px;
  background: #f9fafb;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-dropdown-six-filterbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 16px;
}

.vb-dropdown-six-filter-wrap {
  position: relative;
  width: min(100%, 360px);
}

.vb-dropdown-six-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  width: 100%;
  min-height: 68px;
  padding: 13px 14px 13px 18px;
  border: 1px solid rgba(168, 85, 247, 0.24);
  border-radius: 20px;
  background: #ffffff;
  box-shadow: 0 16px 38px rgba(88, 28, 135, 0.10);
  cursor: pointer;
  text-align: left;
}

.vb-dropdown-six-trigger strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 15px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-six-trigger small {
  display: block;
  margin-top: 5px;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 13px;
  line-height: 1.2;
  font-weight: 850;
}

.vb-dropdown-six-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 38px;
  height: 38px;
  border-radius: 999px;
  background: linear-gradient(135deg, #a855f7, #ec4899);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  font-weight: 950;
  transition: transform 0.22s ease;
}

.vb-dropdown-six-shop.is-open .vb-dropdown-six-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-six-panel {
  position: absolute;
  z-index: 40;
  top: calc(100% + 12px);
  left: 0;
  width: 100%;
  padding: 12px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(216, 180, 254, 0.45);
  box-shadow: 0 28px 70px rgba(88, 28, 135, 0.24);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-six-shop.is-open .vb-dropdown-six-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.vb-dropdown-six-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 10px;
  padding: 4px 4px 10px;
  border-bottom: 1px solid #f3e8ff;
}

.vb-dropdown-six-panel-head strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-six-panel-head button {
  border: 0;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  padding: 8px 10px;
  font-size: 12px;
  font-weight: 900;
  cursor: pointer;
}

.vb-dropdown-six-option {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 44px;
  padding: 10px;
  border-radius: 14px;
  cursor: pointer;
  transition: background 0.18s ease;
}

.vb-dropdown-six-option:hover {
  background: #faf5ff;
}

.vb-dropdown-six-option input {
  width: 18px;
  height: 18px;
  accent-color: #a855f7;
}

.vb-dropdown-six-option span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-dropdown-six-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
  min-height: 42px;
  margin-bottom: 18px;
}

.vb-dropdown-six-tags span,
.vb-dropdown-six-tags button {
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  padding: 8px 11px;
  border-radius: 999px;
  background: #ffffff;
  border: 1px solid rgba(216, 180, 254, 0.55);
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 13px;
  font-weight: 850;
}

.vb-dropdown-six-tags button {
  cursor: pointer;
}

.vb-dropdown-six-tags button::after {
  content: "×";
  margin-left: 8px;
  font-size: 16px;
  line-height: 1;
  font-weight: 950;
}

.vb-dropdown-six-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.vb-dropdown-six-grid div {
  min-height: 160px;
  padding: 18px;
  border-radius: 22px;
  background:
    radial-gradient(circle at 20% 14%, rgba(236, 72, 153, 0.14), transparent 34%),
    linear-gradient(135deg, #ffffff, #faf5ff) !important;
  border: 1px solid rgba(216, 180, 254, 0.35);
  box-shadow: 0 16px 40px rgba(88, 28, 135, 0.08);
}

.vb-dropdown-six-grid small {
  display: inline-flex;
  margin-bottom: 18px;
  color: #a21caf !important;
  -webkit-text-fill-color: #a21caf !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-dropdown-six-grid strong {
  display: block;
  margin-bottom: 8px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-dropdown-six-grid p {
  margin: 0 !important;
  color: #6b7280 !important;
  -webkit-text-fill-color: #6b7280 !important;
  font-size: 14px;
  line-height: 1.55;
  font-weight: 650;
}

@media (max-width: 860px) {
  .vb-dropdown-six-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-six-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-six-shop {
    min-height: 780px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-six-header h3 {
    font-size: 36px !important;
  }

  .vb-dropdown-six-products {
    padding: 16px;
  }

  .vb-dropdown-six-filter-wrap {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This multi-select filter dropdown is ideal for ecommerce and listing interfaces because it keeps many filters inside one compact control. You can reuse it for product categories, blog tags, portfolio filters, job board requirements, dashboard segments, or directory search filters.</p>



<h2 class="wp-block-heading">7. Multi-Level Navigation Dropdown</h2>



<p class="wp-block-paragraph"><strong>A multi-level navigation dropdown</strong> is useful when a website has nested pages, service groups, product categories, documentation sections, or deeper navigation paths. Instead of showing every link at once, the dropdown lets users move through organized levels step by step.</p>



<p class="wp-block-paragraph">This example uses a polished navigation bar, a services dropdown, a second-level submenu, active hover states, click-based submenu switching, outside click closing, and Escape key support. It is designed for business websites, SaaS websites, ecommerce category menus, agency pages, and documentation-style navigation.</p>



<ul class="wp-block-list">
<li>Multi-level dropdown navigation</li>
<li>Click-based submenu switching</li>
<li>Second-level category panel</li>
<li>Outside click and Escape key support</li>
<li>Useful for business websites, ecommerce stores, SaaS sites, and documentation menus</li>
</ul>



<div class="vb-dropdown-seven-demo">
  <div class="vb-dropdown-seven-site" data-vb-dropdown-seven>
    <header class="vb-dropdown-seven-nav">
      <a class="vb-dropdown-seven-logo" href="#javascript-dropdown-menu-examples">
        <span>V</span>
        <strong>Vertex UI</strong>
      </a>

      <nav class="vb-dropdown-seven-links" aria-label="Example navigation">
        <a href="#what-is-a-javascript-dropdown-menu">Home</a>

        <div class="vb-dropdown-seven-menu-wrap">
          <button type="button" class="vb-dropdown-seven-trigger" data-vb-dropdown-seven-trigger aria-expanded="false">
            Services
            <span>⌄</span>
          </button>

          <div class="vb-dropdown-seven-panel" data-vb-dropdown-seven-panel>
            <div class="vb-dropdown-seven-primary">
              <button type="button" class="is-active" data-vb-dropdown-seven-tab="websites">
                <span>🌐</span>
                <strong>Websites</strong>
                <small>Design and development</small>
              </button>

              <button type="button" data-vb-dropdown-seven-tab="marketing">
                <span>📣</span>
                <strong>Marketing</strong>
                <small>SEO and campaigns</small>
              </button>

              <button type="button" data-vb-dropdown-seven-tab="apps">
                <span>⚙️</span>
                <strong>Apps</strong>
                <small>Dashboards and tools</small>
              </button>
            </div>

            <div class="vb-dropdown-seven-secondary">
              <div class="vb-dropdown-seven-sub is-active" data-vb-dropdown-seven-content="websites">
                <div class="vb-dropdown-seven-sub-head">
                  <strong>Website services</strong>
                  <small>Build pages that convert visitors into customers.</small>
                </div>

                <a href="#javascript-dropdown-menu-examples">
                  <span>01</span>
                  <strong>Business Website</strong>
                  <small>Modern company websites and service pages</small>
                </a>

                <a href="#why-javascript-dropdowns-matter">
                  <span>02</span>
                  <strong>Landing Page</strong>
                  <small>Campaign pages, lead forms, and product launches</small>
                </a>

                <a href="#responsive-dropdown-design-tips">
                  <span>03</span>
                  <strong>Responsive Redesign</strong>
                  <small>Mobile-first layout and UI improvements</small>
                </a>
              </div>

              <div class="vb-dropdown-seven-sub" data-vb-dropdown-seven-content="marketing">
                <div class="vb-dropdown-seven-sub-head">
                  <strong>Marketing services</strong>
                  <small>Improve visibility, content structure, and conversions.</small>
                </div>

                <a href="#javascript-dropdown-best-practices">
                  <span>01</span>
                  <strong>SEO Strategy</strong>
                  <small>Technical SEO, content planning, and structure</small>
                </a>

                <a href="#common-javascript-dropdown-mistakes">
                  <span>02</span>
                  <strong>Conversion Audit</strong>
                  <small>Improve CTA placement and user journeys</small>
                </a>

                <a href="#related-javascript-and-css-guides">
                  <span>03</span>
                  <strong>Content System</strong>
                  <small>Reusable guides, posts, and landing content</small>
                </a>
              </div>

              <div class="vb-dropdown-seven-sub" data-vb-dropdown-seven-content="apps">
                <div class="vb-dropdown-seven-sub-head">
                  <strong>App services</strong>
                  <small>Create interactive tools, dashboards, and custom UI.</small>
                </div>

                <a href="#dropdown-menu-vs-select-menu-vs-mega-menu">
                  <span>01</span>
                  <strong>Dashboard UI</strong>
                  <small>Admin panels, SaaS dashboards, and analytics</small>
                </a>

                <a href="#what-should-a-good-javascript-dropdown-include">
                  <span>02</span>
                  <strong>Custom Components</strong>
                  <small>Dropdowns, modals, filters, sliders, and forms</small>
                </a>

                <a href="#javascript-dropdown-faq">
                  <span>03</span>
                  <strong>Automation Tools</strong>
                  <small>Internal tools and workflow systems</small>
                </a>
              </div>
            </div>
          </div>
        </div>

        <a href="#javascript-dropdown-best-practices">Work</a>
        <a href="#javascript-dropdown-faq">FAQ</a>
      </nav>

      <a class="vb-dropdown-seven-cta" href="#javascript-dropdown-menu-examples">Get Started</a>
    </header>

    <section class="vb-dropdown-seven-hero">
      <span>Example 07</span>
      <h3>Multi-Level Navigation Dropdown</h3>
      <p>This menu uses JavaScript to switch between second-level dropdown content panels while keeping the navigation clean and structured.</p>
    </section>
  </div>
</div>

<style>
.vb-dropdown-seven-demo,
.vb-dropdown-seven-demo * {
  box-sizing: border-box;
}

.vb-dropdown-seven-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(14, 165, 233, 0.20), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(59, 130, 246, 0.20), transparent 34%),
    linear-gradient(135deg, #e0f2fe 0%, #eff6ff 48%, #ffffff 100%) !important;
  border: 1px solid rgba(147, 197, 253, 0.34);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.12);
}

.vb-dropdown-seven-site {
  position: relative;
  max-width: 1080px;
  min-height: 560px;
  margin: 0 auto;
  padding: 24px;
  border-radius: 30px;
  background:
    linear-gradient(135deg, #ffffff 0%, #f8fafc 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.12);
  overflow: visible;
}

.vb-dropdown-seven-nav {
  position: relative;
  z-index: 40;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 22px;
  align-items: center;
  padding: 14px;
  border-radius: 24px;
  background: #0f172a;
  box-shadow: 0 20px 50px rgba(15, 23, 42, 0.24);
}

.vb-dropdown-seven-logo {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none !important;
}

.vb-dropdown-seven-logo span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: linear-gradient(135deg, #06b6d4, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-seven-logo strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-dropdown-seven-links {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.vb-dropdown-seven-links > a,
.vb-dropdown-seven-trigger {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 42px;
  padding: 10px 13px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 14px;
  line-height: 1;
  font-weight: 850;
  text-decoration: none !important;
  cursor: pointer;
  transition: background 0.18s ease, color 0.18s ease;
}

.vb-dropdown-seven-links > a:hover,
.vb-dropdown-seven-trigger:hover,
.vb-dropdown-seven-site.is-open .vb-dropdown-seven-trigger {
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-seven-trigger span {
  transition: transform 0.2s ease;
}

.vb-dropdown-seven-site.is-open .vb-dropdown-seven-trigger span {
  transform: rotate(180deg);
}

.vb-dropdown-seven-menu-wrap {
  position: relative;
}

.vb-dropdown-seven-panel {
  position: absolute;
  z-index: 50;
  top: calc(100% + 16px);
  left: 50%;
  display: grid;
  grid-template-columns: 280px minmax(360px, 1fr);
  gap: 12px;
  width: min(760px, 88vw);
  padding: 12px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.30);
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, 12px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-seven-site.is-open .vb-dropdown-seven-panel {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0) scale(1);
}

.vb-dropdown-seven-primary {
  display: grid;
  gap: 8px;
  padding: 8px;
  border-radius: 20px;
  background: #f8fafc;
}

.vb-dropdown-seven-primary button {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  width: 100%;
  padding: 12px;
  border: 0;
  border-radius: 16px;
  background: transparent;
  text-align: left;
  cursor: pointer;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-seven-primary button:hover,
.vb-dropdown-seven-primary button.is-active {
  background: #ffffff;
  transform: translateX(2px);
  box-shadow: 0 12px 28px rgba(15, 23, 42, 0.08);
}

.vb-dropdown-seven-primary button span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: #dbeafe;
  font-size: 19px;
}

.vb-dropdown-seven-primary button strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-seven-primary button small {
  display: block;
  margin-top: 3px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.3;
  font-weight: 700;
}

.vb-dropdown-seven-secondary {
  position: relative;
  min-height: 290px;
  padding: 18px;
  border-radius: 20px;
  background:
    radial-gradient(circle at 16% 12%, rgba(14, 165, 233, 0.13), transparent 32%),
    linear-gradient(135deg, #f8fafc, #eff6ff) !important;
  overflow: hidden;
}

.vb-dropdown-seven-sub {
  display: none;
}

.vb-dropdown-seven-sub.is-active {
  display: block;
}

.vb-dropdown-seven-sub-head {
  margin-bottom: 14px;
}

.vb-dropdown-seven-sub-head strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-seven-sub-head small {
  display: block;
  margin-top: 6px;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 650;
}

.vb-dropdown-seven-sub a {
  display: grid;
  grid-template-columns: 38px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 12px;
  border-radius: 16px;
  text-decoration: none !important;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-seven-sub a:hover {
  background: #ffffff;
  transform: translateX(2px);
}

.vb-dropdown-seven-sub a span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 14px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-dropdown-seven-sub a strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-seven-sub a small {
  display: block;
  margin-top: 3px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 650;
}

.vb-dropdown-seven-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 42px;
  padding: 10px 15px;
  border-radius: 999px;
  background: linear-gradient(135deg, #06b6d4, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
  box-shadow: 0 16px 34px rgba(37, 99, 235, 0.30);
  white-space: nowrap;
}

.vb-dropdown-seven-hero {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 420px;
  padding: 44px 18px 18px;
}

.vb-dropdown-seven-hero > span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-seven-hero h3 {
  max-width: 720px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 6vw, 72px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-seven-hero p {
  max-width: 640px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-dropdown-seven-nav {
    grid-template-columns: 1fr;
    align-items: start;
  }

  .vb-dropdown-seven-links {
    justify-content: flex-start;
    flex-wrap: wrap;
  }

  .vb-dropdown-seven-panel {
    left: 0;
    grid-template-columns: 1fr;
    width: min(90vw, 640px);
    transform: translate(0, 12px) scale(0.98);
  }

  .vb-dropdown-seven-site.is-open .vb-dropdown-seven-panel {
    transform: translate(0, 0) scale(1);
  }
}

@media (max-width: 640px) {
  .vb-dropdown-seven-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-seven-site {
    min-height: 760px;
    padding: 18px;
    border-radius: 22px;
  }

  .vb-dropdown-seven-nav {
    padding: 12px;
    border-radius: 20px;
  }

  .vb-dropdown-seven-links {
    display: grid;
    width: 100%;
  }

  .vb-dropdown-seven-links > a,
  .vb-dropdown-seven-trigger,
  .vb-dropdown-seven-cta {
    width: 100%;
    justify-content: center;
  }

  .vb-dropdown-seven-menu-wrap {
    width: 100%;
  }

  .vb-dropdown-seven-panel {
    width: 100%;
    max-height: 470px;
    overflow-y: auto;
  }

  .vb-dropdown-seven-hero h3 {
    font-size: 38px !important;
  }
}
</style>

<script>
(function () {
  const menu = document.querySelector("[data-vb-dropdown-seven]");
  if (!menu) return;

  const trigger = menu.querySelector("[data-vb-dropdown-seven-trigger]");
  const tabs = menu.querySelectorAll("[data-vb-dropdown-seven-tab]");
  const contents = menu.querySelectorAll("[data-vb-dropdown-seven-content]");

  function closeMenu() {
    menu.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleMenu() {
    const isOpen = menu.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function showTab(tabName) {
    tabs.forEach(function (tab) {
      tab.classList.toggle("is-active", tab.getAttribute("data-vb-dropdown-seven-tab") === tabName);
    });

    contents.forEach(function (content) {
      content.classList.toggle("is-active", content.getAttribute("data-vb-dropdown-seven-content") === tabName);
    });
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleMenu();
  });

  tabs.forEach(function (tab) {
    tab.addEventListener("click", function (event) {
      event.stopPropagation();
      showTab(tab.getAttribute("data-vb-dropdown-seven-tab"));
    });
  });

  document.addEventListener("click", function (event) {
    if (!menu.contains(event.target)) {
      closeMenu();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeMenu();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const menu = document.querySelector("[data-vb-dropdown-seven]");
  if (!menu) return;

  const trigger = menu.querySelector("[data-vb-dropdown-seven-trigger]");
  const tabs = menu.querySelectorAll("[data-vb-dropdown-seven-tab]");
  const contents = menu.querySelectorAll("[data-vb-dropdown-seven-content]");

  function closeMenu() {
    menu.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleMenu() {
    const isOpen = menu.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function showTab(tabName) {
    tabs.forEach(function (tab) {
      tab.classList.toggle("is-active", tab.getAttribute("data-vb-dropdown-seven-tab") === tabName);
    });

    contents.forEach(function (content) {
      content.classList.toggle("is-active", content.getAttribute("data-vb-dropdown-seven-content") === tabName);
    });
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleMenu();
  });

  tabs.forEach(function (tab) {
    tab.addEventListener("click", function (event) {
      event.stopPropagation();
      showTab(tab.getAttribute("data-vb-dropdown-seven-tab"));
    });
  });

  document.addEventListener("click", function (event) {
    if (!menu.contains(event.target)) {
      closeMenu();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeMenu();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-seven-demo"&gt;
  &lt;div class="vb-dropdown-seven-site" data-vb-dropdown-seven&gt;
    &lt;header class="vb-dropdown-seven-nav"&gt;
      &lt;a class="vb-dropdown-seven-logo" href="#javascript-dropdown-menu-examples"&gt;
        &lt;span&gt;V&lt;/span&gt;
        &lt;strong&gt;Vertex UI&lt;/strong&gt;
      &lt;/a&gt;

      &lt;nav class="vb-dropdown-seven-links" aria-label="Example navigation"&gt;
        &lt;a href="#what-is-a-javascript-dropdown-menu"&gt;Home&lt;/a&gt;

        &lt;div class="vb-dropdown-seven-menu-wrap"&gt;
          &lt;button type="button" class="vb-dropdown-seven-trigger" data-vb-dropdown-seven-trigger aria-expanded="false"&gt;
            Services
            &lt;span&gt;⌄&lt;/span&gt;
          &lt;/button&gt;

          &lt;div class="vb-dropdown-seven-panel" data-vb-dropdown-seven-panel&gt;
            &lt;div class="vb-dropdown-seven-primary"&gt;
              &lt;button type="button" class="is-active" data-vb-dropdown-seven-tab="websites"&gt;
                &lt;span&gt;🌐&lt;/span&gt;
                &lt;strong&gt;Websites&lt;/strong&gt;
                &lt;small&gt;Design and development&lt;/small&gt;
              &lt;/button&gt;

              &lt;button type="button" data-vb-dropdown-seven-tab="marketing"&gt;
                &lt;span&gt;📣&lt;/span&gt;
                &lt;strong&gt;Marketing&lt;/strong&gt;
                &lt;small&gt;SEO and campaigns&lt;/small&gt;
              &lt;/button&gt;

              &lt;button type="button" data-vb-dropdown-seven-tab="apps"&gt;
                &lt;span&gt;⚙️&lt;/span&gt;
                &lt;strong&gt;Apps&lt;/strong&gt;
                &lt;small&gt;Dashboards and tools&lt;/small&gt;
              &lt;/button&gt;
            &lt;/div&gt;

            &lt;div class="vb-dropdown-seven-secondary"&gt;
              &lt;div class="vb-dropdown-seven-sub is-active" data-vb-dropdown-seven-content="websites"&gt;
                &lt;div class="vb-dropdown-seven-sub-head"&gt;
                  &lt;strong&gt;Website services&lt;/strong&gt;
                  &lt;small&gt;Build pages that convert visitors into customers.&lt;/small&gt;
                &lt;/div&gt;

                &lt;a href="#javascript-dropdown-menu-examples"&gt;
                  &lt;span&gt;01&lt;/span&gt;
                  &lt;strong&gt;Business Website&lt;/strong&gt;
                  &lt;small&gt;Modern company websites and service pages&lt;/small&gt;
                &lt;/a&gt;

                &lt;a href="#why-javascript-dropdowns-matter"&gt;
                  &lt;span&gt;02&lt;/span&gt;
                  &lt;strong&gt;Landing Page&lt;/strong&gt;
                  &lt;small&gt;Campaign pages, lead forms, and product launches&lt;/small&gt;
                &lt;/a&gt;

                &lt;a href="#responsive-dropdown-design-tips"&gt;
                  &lt;span&gt;03&lt;/span&gt;
                  &lt;strong&gt;Responsive Redesign&lt;/strong&gt;
                  &lt;small&gt;Mobile-first layout and UI improvements&lt;/small&gt;
                &lt;/a&gt;
              &lt;/div&gt;

              &lt;div class="vb-dropdown-seven-sub" data-vb-dropdown-seven-content="marketing"&gt;
                &lt;div class="vb-dropdown-seven-sub-head"&gt;
                  &lt;strong&gt;Marketing services&lt;/strong&gt;
                  &lt;small&gt;Improve visibility, content structure, and conversions.&lt;/small&gt;
                &lt;/div&gt;

                &lt;a href="#javascript-dropdown-best-practices"&gt;
                  &lt;span&gt;01&lt;/span&gt;
                  &lt;strong&gt;SEO Strategy&lt;/strong&gt;
                  &lt;small&gt;Technical SEO, content planning, and structure&lt;/small&gt;
                &lt;/a&gt;

                &lt;a href="#common-javascript-dropdown-mistakes"&gt;
                  &lt;span&gt;02&lt;/span&gt;
                  &lt;strong&gt;Conversion Audit&lt;/strong&gt;
                  &lt;small&gt;Improve CTA placement and user journeys&lt;/small&gt;
                &lt;/a&gt;

                &lt;a href="#related-javascript-and-css-guides"&gt;
                  &lt;span&gt;03&lt;/span&gt;
                  &lt;strong&gt;Content System&lt;/strong&gt;
                  &lt;small&gt;Reusable guides, posts, and landing content&lt;/small&gt;
                &lt;/a&gt;
              &lt;/div&gt;

              &lt;div class="vb-dropdown-seven-sub" data-vb-dropdown-seven-content="apps"&gt;
                &lt;div class="vb-dropdown-seven-sub-head"&gt;
                  &lt;strong&gt;App services&lt;/strong&gt;
                  &lt;small&gt;Create interactive tools, dashboards, and custom UI.&lt;/small&gt;
                &lt;/div&gt;

                &lt;a href="#dropdown-menu-vs-select-menu-vs-mega-menu"&gt;
                  &lt;span&gt;01&lt;/span&gt;
                  &lt;strong&gt;Dashboard UI&lt;/strong&gt;
                  &lt;small&gt;Admin panels, SaaS dashboards, and analytics&lt;/small&gt;
                &lt;/a&gt;

                &lt;a href="#what-should-a-good-javascript-dropdown-include"&gt;
                  &lt;span&gt;02&lt;/span&gt;
                  &lt;strong&gt;Custom Components&lt;/strong&gt;
                  &lt;small&gt;Dropdowns, modals, filters, sliders, and forms&lt;/small&gt;
                &lt;/a&gt;

                &lt;a href="#javascript-dropdown-faq"&gt;
                  &lt;span&gt;03&lt;/span&gt;
                  &lt;strong&gt;Automation Tools&lt;/strong&gt;
                  &lt;small&gt;Internal tools and workflow systems&lt;/small&gt;
                &lt;/a&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;

        &lt;a href="#javascript-dropdown-best-practices"&gt;Work&lt;/a&gt;
        &lt;a href="#javascript-dropdown-faq"&gt;FAQ&lt;/a&gt;
      &lt;/nav&gt;

      &lt;a class="vb-dropdown-seven-cta" href="#javascript-dropdown-menu-examples"&gt;Get Started&lt;/a&gt;
    &lt;/header&gt;

    &lt;section class="vb-dropdown-seven-hero"&gt;
      &lt;span&gt;Example 07&lt;/span&gt;
      &lt;h3&gt;Multi-Level Navigation Dropdown&lt;/h3&gt;
      &lt;p&gt;This menu uses JavaScript to switch between second-level dropdown content panels while keeping the navigation clean and structured.&lt;/p&gt;
    &lt;/section&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-seven-demo,
.vb-dropdown-seven-demo * {
  box-sizing: border-box;
}

.vb-dropdown-seven-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(14, 165, 233, 0.20), transparent 34%),
    radial-gradient(circle at 88% 18%, rgba(59, 130, 246, 0.20), transparent 34%),
    linear-gradient(135deg, #e0f2fe 0%, #eff6ff 48%, #ffffff 100%) !important;
  border: 1px solid rgba(147, 197, 253, 0.34);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.12);
}

.vb-dropdown-seven-site {
  position: relative;
  max-width: 1080px;
  min-height: 560px;
  margin: 0 auto;
  padding: 24px;
  border-radius: 30px;
  background:
    linear-gradient(135deg, #ffffff 0%, #f8fafc 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.12);
  overflow: visible;
}

.vb-dropdown-seven-nav {
  position: relative;
  z-index: 40;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 22px;
  align-items: center;
  padding: 14px;
  border-radius: 24px;
  background: #0f172a;
  box-shadow: 0 20px 50px rgba(15, 23, 42, 0.24);
}

.vb-dropdown-seven-logo {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none !important;
}

.vb-dropdown-seven-logo span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: linear-gradient(135deg, #06b6d4, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-seven-logo strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-dropdown-seven-links {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.vb-dropdown-seven-links &gt; a,
.vb-dropdown-seven-trigger {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 42px;
  padding: 10px 13px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 14px;
  line-height: 1;
  font-weight: 850;
  text-decoration: none !important;
  cursor: pointer;
  transition: background 0.18s ease, color 0.18s ease;
}

.vb-dropdown-seven-links &gt; a:hover,
.vb-dropdown-seven-trigger:hover,
.vb-dropdown-seven-site.is-open .vb-dropdown-seven-trigger {
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-seven-trigger span {
  transition: transform 0.2s ease;
}

.vb-dropdown-seven-site.is-open .vb-dropdown-seven-trigger span {
  transform: rotate(180deg);
}

.vb-dropdown-seven-menu-wrap {
  position: relative;
}

.vb-dropdown-seven-panel {
  position: absolute;
  z-index: 50;
  top: calc(100% + 16px);
  left: 50%;
  display: grid;
  grid-template-columns: 280px minmax(360px, 1fr);
  gap: 12px;
  width: min(760px, 88vw);
  padding: 12px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.30);
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, 12px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-seven-site.is-open .vb-dropdown-seven-panel {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0) scale(1);
}

.vb-dropdown-seven-primary {
  display: grid;
  gap: 8px;
  padding: 8px;
  border-radius: 20px;
  background: #f8fafc;
}

.vb-dropdown-seven-primary button {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  width: 100%;
  padding: 12px;
  border: 0;
  border-radius: 16px;
  background: transparent;
  text-align: left;
  cursor: pointer;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-seven-primary button:hover,
.vb-dropdown-seven-primary button.is-active {
  background: #ffffff;
  transform: translateX(2px);
  box-shadow: 0 12px 28px rgba(15, 23, 42, 0.08);
}

.vb-dropdown-seven-primary button span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: #dbeafe;
  font-size: 19px;
}

.vb-dropdown-seven-primary button strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-seven-primary button small {
  display: block;
  margin-top: 3px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.3;
  font-weight: 700;
}

.vb-dropdown-seven-secondary {
  position: relative;
  min-height: 290px;
  padding: 18px;
  border-radius: 20px;
  background:
    radial-gradient(circle at 16% 12%, rgba(14, 165, 233, 0.13), transparent 32%),
    linear-gradient(135deg, #f8fafc, #eff6ff) !important;
  overflow: hidden;
}

.vb-dropdown-seven-sub {
  display: none;
}

.vb-dropdown-seven-sub.is-active {
  display: block;
}

.vb-dropdown-seven-sub-head {
  margin-bottom: 14px;
}

.vb-dropdown-seven-sub-head strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 20px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-seven-sub-head small {
  display: block;
  margin-top: 6px;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 14px;
  line-height: 1.45;
  font-weight: 650;
}

.vb-dropdown-seven-sub a {
  display: grid;
  grid-template-columns: 38px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 12px;
  border-radius: 16px;
  text-decoration: none !important;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-seven-sub a:hover {
  background: #ffffff;
  transform: translateX(2px);
}

.vb-dropdown-seven-sub a span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 14px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-dropdown-seven-sub a strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-seven-sub a small {
  display: block;
  margin-top: 3px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 650;
}

.vb-dropdown-seven-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 42px;
  padding: 10px 15px;
  border-radius: 999px;
  background: linear-gradient(135deg, #06b6d4, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
  box-shadow: 0 16px 34px rgba(37, 99, 235, 0.30);
  white-space: nowrap;
}

.vb-dropdown-seven-hero {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 420px;
  padding: 44px 18px 18px;
}

.vb-dropdown-seven-hero &gt; span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-seven-hero h3 {
  max-width: 720px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 6vw, 72px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-seven-hero p {
  max-width: 640px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-dropdown-seven-nav {
    grid-template-columns: 1fr;
    align-items: start;
  }

  .vb-dropdown-seven-links {
    justify-content: flex-start;
    flex-wrap: wrap;
  }

  .vb-dropdown-seven-panel {
    left: 0;
    grid-template-columns: 1fr;
    width: min(90vw, 640px);
    transform: translate(0, 12px) scale(0.98);
  }

  .vb-dropdown-seven-site.is-open .vb-dropdown-seven-panel {
    transform: translate(0, 0) scale(1);
  }
}

@media (max-width: 640px) {
  .vb-dropdown-seven-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-seven-site {
    min-height: 760px;
    padding: 18px;
    border-radius: 22px;
  }

  .vb-dropdown-seven-nav {
    padding: 12px;
    border-radius: 20px;
  }

  .vb-dropdown-seven-links {
    display: grid;
    width: 100%;
  }

  .vb-dropdown-seven-links &gt; a,
  .vb-dropdown-seven-trigger,
  .vb-dropdown-seven-cta {
    width: 100%;
    justify-content: center;
  }

  .vb-dropdown-seven-menu-wrap {
    width: 100%;
  }

  .vb-dropdown-seven-panel {
    width: 100%;
    max-height: 470px;
    overflow-y: auto;
  }

  .vb-dropdown-seven-hero h3 {
    font-size: 38px !important;
  }
}</pre>



<p class="wp-block-paragraph">This multi-level navigation dropdown is a useful pattern for websites with deeper page structures. You can adapt it for service menus, product categories, documentation sections, resource hubs, ecommerce departments, or SaaS feature navigation.</p>



<h2 class="wp-block-heading">8. Shopping Cart Dropdown</h2>



<p class="wp-block-paragraph"><strong>A shopping cart dropdown</strong> gives ecommerce users a fast way to preview selected products without leaving the current page. It can show product names, prices, quantities, subtotal information, checkout links, and quick item controls inside a compact header dropdown.</p>



<p class="wp-block-paragraph">This example includes a cart button, item count badge, product rows, quantity controls, removable items, subtotal calculation, empty cart state, outside click closing, and Escape key support. It is useful for ecommerce stores, product landing pages, WooCommerce-style interfaces, and custom checkout flows.</p>



<ul class="wp-block-list">
<li>Shopping cart dropdown preview</li>
<li>Quantity increase and decrease buttons</li>
<li>Remove product from dropdown cart</li>
<li>Live subtotal and item count updates</li>
<li>Useful for ecommerce stores, product pages, and checkout interfaces</li>
</ul>



<div class="vb-dropdown-eight-demo">
  <div class="vb-dropdown-eight-store" data-vb-dropdown-eight>
    <div class="vb-dropdown-eight-top">
      <div class="vb-dropdown-eight-brand">
        <span>SHOP</span>
        <div>
          <strong>Nova Store</strong>
          <small>Example 08</small>
        </div>
      </div>

      <div class="vb-dropdown-eight-cart-wrap">
        <button type="button" class="vb-dropdown-eight-cart-button" data-vb-dropdown-eight-trigger aria-expanded="false">
          <span>🛒</span>
          <strong>Cart</strong>
          <em data-vb-dropdown-eight-count>3</em>
        </button>

        <div class="vb-dropdown-eight-panel" data-vb-dropdown-eight-panel>
          <div class="vb-dropdown-eight-panel-head">
            <div>
              <strong>Your cart</strong>
              <small data-vb-dropdown-eight-summary>3 items selected</small>
            </div>
          </div>

          <div class="vb-dropdown-eight-items" data-vb-dropdown-eight-items>
            <div class="vb-dropdown-eight-item" data-price="49" data-qty="1">
              <div class="vb-dropdown-eight-thumb vb-dropdown-eight-thumb-a"></div>
              <div class="vb-dropdown-eight-info">
                <strong>Dropdown UI Kit</strong>
                <small>€49 each</small>
                <div class="vb-dropdown-eight-qty">
                  <button type="button" data-action="minus">−</button>
                  <span data-qty-label>1</span>
                  <button type="button" data-action="plus">+</button>
                </div>
              </div>
              <button type="button" class="vb-dropdown-eight-remove" data-action="remove">×</button>
            </div>

            <div class="vb-dropdown-eight-item" data-price="29" data-qty="1">
              <div class="vb-dropdown-eight-thumb vb-dropdown-eight-thumb-b"></div>
              <div class="vb-dropdown-eight-info">
                <strong>Component Pack</strong>
                <small>€29 each</small>
                <div class="vb-dropdown-eight-qty">
                  <button type="button" data-action="minus">−</button>
                  <span data-qty-label>1</span>
                  <button type="button" data-action="plus">+</button>
                </div>
              </div>
              <button type="button" class="vb-dropdown-eight-remove" data-action="remove">×</button>
            </div>

            <div class="vb-dropdown-eight-item" data-price="19" data-qty="1">
              <div class="vb-dropdown-eight-thumb vb-dropdown-eight-thumb-c"></div>
              <div class="vb-dropdown-eight-info">
                <strong>Micro Animation Set</strong>
                <small>€19 each</small>
                <div class="vb-dropdown-eight-qty">
                  <button type="button" data-action="minus">−</button>
                  <span data-qty-label>1</span>
                  <button type="button" data-action="plus">+</button>
                </div>
              </div>
              <button type="button" class="vb-dropdown-eight-remove" data-action="remove">×</button>
            </div>
          </div>

          <div class="vb-dropdown-eight-empty" data-vb-dropdown-eight-empty>
            <strong>Your cart is empty</strong>
            <small>Add products to see them here.</small>
          </div>

          <div class="vb-dropdown-eight-total">
            <span>Subtotal</span>
            <strong data-vb-dropdown-eight-total>€97</strong>
          </div>

          <div class="vb-dropdown-eight-actions">
            <a href="#javascript-dropdown-menu-examples">View Cart</a>
            <a href="#javascript-dropdown-conclusion">Checkout</a>
          </div>
        </div>
      </div>
    </div>

    <section class="vb-dropdown-eight-hero">
      <div>
        <span>Ecommerce UI</span>
        <h3>Shopping Cart Dropdown</h3>
        <p>Preview cart items, update quantities, remove products, and calculate subtotal with JavaScript.</p>
      </div>

      <div class="vb-dropdown-eight-product-grid">
        <article>
          <span></span>
          <strong>UI Kit</strong>
          <small>€49</small>
        </article>
        <article>
          <span></span>
          <strong>Components</strong>
          <small>€29</small>
        </article>
        <article>
          <span></span>
          <strong>Animations</strong>
          <small>€19</small>
        </article>
      </div>
    </section>
  </div>
</div>

<style>
.vb-dropdown-eight-demo,
.vb-dropdown-eight-demo * {
  box-sizing: border-box;
}

.vb-dropdown-eight-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 16% 16%, rgba(251, 146, 60, 0.22), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(244, 63, 94, 0.18), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #fff1f2 52%, #ffffff 100%) !important;
  border: 1px solid rgba(251, 146, 60, 0.30);
  box-shadow: 0 24px 70px rgba(124, 45, 18, 0.12);
}

.vb-dropdown-eight-store {
  position: relative;
  max-width: 1080px;
  min-height: 560px;
  margin: 0 auto;
  padding: 24px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(251, 146, 60, 0.24);
  box-shadow: 0 24px 70px rgba(124, 45, 18, 0.12);
  overflow: visible;
}

.vb-dropdown-eight-top {
  position: relative;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  padding: 14px;
  border-radius: 24px;
  background: #111827;
  box-shadow: 0 20px 50px rgba(15, 23, 42, 0.24);
}

.vb-dropdown-eight-brand {
  display: flex;
  align-items: center;
  gap: 12px;
}

.vb-dropdown-eight-brand > span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 58px;
  height: 42px;
  padding: 0 12px;
  border-radius: 15px;
  background: linear-gradient(135deg, #fb923c, #f43f5e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
}

.vb-dropdown-eight-brand strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-eight-brand small {
  display: block;
  margin-top: 3px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  line-height: 1;
  font-weight: 750;
}

.vb-dropdown-eight-cart-wrap {
  position: relative;
}

.vb-dropdown-eight-cart-button {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: 48px;
  padding: 10px 14px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  cursor: pointer;
}

.vb-dropdown-eight-cart-button span,
.vb-dropdown-eight-cart-button strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-eight-cart-button strong {
  font-size: 14px;
  font-weight: 950;
}

.vb-dropdown-eight-cart-button em {
  position: absolute;
  top: -8px;
  right: -6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 24px;
  padding: 0 7px;
  border-radius: 999px;
  background: #f43f5e;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-style: normal;
  font-weight: 950;
  border: 2px solid #111827;
}

.vb-dropdown-eight-cart-button em.is-hidden {
  display: none;
}

.vb-dropdown-eight-panel {
  position: absolute;
  z-index: 50;
  top: calc(100% + 14px);
  right: 0;
  width: 390px;
  padding: 14px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.32);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-eight-store.is-open .vb-dropdown-eight-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-eight-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 8px 8px 12px;
}

.vb-dropdown-eight-panel-head strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-dropdown-eight-panel-head small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 700;
}

.vb-dropdown-eight-items {
  display: grid;
  gap: 10px;
  max-height: 330px;
  overflow-y: auto;
  padding-right: 4px;
}

.vb-dropdown-eight-item {
  position: relative;
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr) 32px;
  gap: 12px;
  align-items: center;
  padding: 10px;
  border-radius: 18px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.18);
}

.vb-dropdown-eight-thumb {
  width: 56px;
  height: 56px;
  border-radius: 17px;
}

.vb-dropdown-eight-thumb-a {
  background: linear-gradient(135deg, #fb923c, #f43f5e);
}

.vb-dropdown-eight-thumb-b {
  background: linear-gradient(135deg, #06b6d4, #2563eb);
}

.vb-dropdown-eight-thumb-c {
  background: linear-gradient(135deg, #a855f7, #ec4899);
}

.vb-dropdown-eight-info strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  line-height: 1.25;
  font-weight: 950;
}

.vb-dropdown-eight-info small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 750;
}

.vb-dropdown-eight-qty {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 9px;
  padding: 5px;
  border-radius: 999px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-dropdown-eight-qty button,
.vb-dropdown-eight-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  cursor: pointer;
}

.vb-dropdown-eight-qty button {
  width: 24px;
  height: 24px;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-eight-qty span {
  min-width: 18px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 13px;
  font-weight: 950;
  text-align: center;
}

.vb-dropdown-eight-remove {
  width: 30px;
  height: 30px;
  border-radius: 999px;
  background: #fee2e2;
  color: #991b1b !important;
  -webkit-text-fill-color: #991b1b !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-dropdown-eight-empty {
  display: none;
  padding: 28px 16px;
  border-radius: 20px;
  background: #f8fafc;
  text-align: center;
}

.vb-dropdown-eight-empty.is-visible {
  display: block;
}

.vb-dropdown-eight-empty strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 17px;
  font-weight: 950;
}

.vb-dropdown-eight-empty small {
  display: block;
  margin-top: 5px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 700;
}

.vb-dropdown-eight-total {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-top: 12px;
  padding: 14px;
  border-radius: 18px;
  background: #111827;
}

.vb-dropdown-eight-total span,
.vb-dropdown-eight-total strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-eight-total span {
  font-size: 13px;
  font-weight: 850;
}

.vb-dropdown-eight-total strong {
  font-size: 22px;
  line-height: 1;
  font-weight: 950;
}

.vb-dropdown-eight-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-top: 10px;
}

.vb-dropdown-eight-actions a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
}

.vb-dropdown-eight-actions a:first-child {
  background: #f8fafc;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-dropdown-eight-actions a:last-child {
  background: linear-gradient(135deg, #fb923c, #f43f5e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-eight-hero {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(320px, 0.9fr);
  gap: 28px;
  align-items: end;
  min-height: 430px;
  padding: 52px 12px 12px;
}

.vb-dropdown-eight-hero > div:first-child > span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-eight-hero h3 {
  max-width: 620px;
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 6vw, 72px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-eight-hero p {
  max-width: 560px;
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-eight-product-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-dropdown-eight-product-grid article {
  min-height: 170px;
  padding: 16px;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb-dropdown-eight-product-grid article span {
  display: block;
  width: 100%;
  height: 72px;
  margin-bottom: 14px;
  border-radius: 16px;
  background: linear-gradient(135deg, #fb923c, #f43f5e);
}

.vb-dropdown-eight-product-grid article:nth-child(2) span {
  background: linear-gradient(135deg, #06b6d4, #2563eb);
}

.vb-dropdown-eight-product-grid article:nth-child(3) span {
  background: linear-gradient(135deg, #a855f7, #ec4899);
}

.vb-dropdown-eight-product-grid strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 15px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-eight-product-grid small {
  display: block;
  margin-top: 6px;
  color: #f43f5e !important;
  -webkit-text-fill-color: #f43f5e !important;
  font-size: 13px;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vb-dropdown-eight-hero {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-eight-product-grid {
    max-width: 520px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-eight-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-eight-store {
    min-height: 820px;
    padding: 18px;
    border-radius: 22px;
  }

  .vb-dropdown-eight-top {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-dropdown-eight-cart-wrap {
    width: 100%;
  }

  .vb-dropdown-eight-cart-button {
    width: 100%;
    justify-content: center;
  }

  .vb-dropdown-eight-panel {
    left: 0;
    right: auto;
    width: 100%;
    transform-origin: top left;
  }

  .vb-dropdown-eight-product-grid {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-eight-hero h3 {
    font-size: 38px !important;
  }
}
</style>

<script>
(function () {
  const cart = document.querySelector("[data-vb-dropdown-eight]");
  if (!cart) return;

  const trigger = cart.querySelector("[data-vb-dropdown-eight-trigger]");
  const itemsWrap = cart.querySelector("[data-vb-dropdown-eight-items]");
  const count = cart.querySelector("[data-vb-dropdown-eight-count]");
  const summary = cart.querySelector("[data-vb-dropdown-eight-summary]");
  const total = cart.querySelector("[data-vb-dropdown-eight-total]");
  const empty = cart.querySelector("[data-vb-dropdown-eight-empty]");

  function closeCart() {
    cart.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleCart() {
    const isOpen = cart.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function updateCart() {
    const items = itemsWrap.querySelectorAll(".vb-dropdown-eight-item");
    let itemCount = 0;
    let subtotal = 0;

    items.forEach(function (item) {
      const price = Number(item.getAttribute("data-price"));
      const qty = Number(item.getAttribute("data-qty"));
      const qtyLabel = item.querySelector("[data-qty-label]");

      itemCount += qty;
      subtotal += price * qty;
      qtyLabel.textContent = qty;
    });

    count.textContent = itemCount;
    summary.textContent = itemCount === 1 ? "1 item selected" : itemCount + " items selected";
    total.textContent = "€" + subtotal;

    count.classList.toggle("is-hidden", itemCount === 0);
    empty.classList.toggle("is-visible", itemCount === 0);
    itemsWrap.style.display = itemCount === 0 ? "none" : "grid";
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleCart();
  });

  itemsWrap.addEventListener("click", function (event) {
    const button = event.target.closest("button");
    if (!button) return;

    const item = button.closest(".vb-dropdown-eight-item");
    if (!item) return;

    const action = button.getAttribute("data-action");
    let qty = Number(item.getAttribute("data-qty"));

    if (action === "plus") {
      qty += 1;
      item.setAttribute("data-qty", String(qty));
    }

    if (action === "minus") {
      qty = Math.max(1, qty - 1);
      item.setAttribute("data-qty", String(qty));
    }

    if (action === "remove") {
      item.remove();
    }

    updateCart();
  });

  document.addEventListener("click", function (event) {
    if (!cart.contains(event.target)) {
      closeCart();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeCart();
    }
  });

  updateCart();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const cart = document.querySelector("[data-vb-dropdown-eight]");
  if (!cart) return;

  const trigger = cart.querySelector("[data-vb-dropdown-eight-trigger]");
  const itemsWrap = cart.querySelector("[data-vb-dropdown-eight-items]");
  const count = cart.querySelector("[data-vb-dropdown-eight-count]");
  const summary = cart.querySelector("[data-vb-dropdown-eight-summary]");
  const total = cart.querySelector("[data-vb-dropdown-eight-total]");
  const empty = cart.querySelector("[data-vb-dropdown-eight-empty]");

  function closeCart() {
    cart.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleCart() {
    const isOpen = cart.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function updateCart() {
    const items = itemsWrap.querySelectorAll(".vb-dropdown-eight-item");
    let itemCount = 0;
    let subtotal = 0;

    items.forEach(function (item) {
      const price = Number(item.getAttribute("data-price"));
      const qty = Number(item.getAttribute("data-qty"));
      const qtyLabel = item.querySelector("[data-qty-label]");

      itemCount += qty;
      subtotal += price * qty;
      qtyLabel.textContent = qty;
    });

    count.textContent = itemCount;
    summary.textContent = itemCount === 1 ? "1 item selected" : itemCount + " items selected";
    total.textContent = "€" + subtotal;

    count.classList.toggle("is-hidden", itemCount === 0);
    empty.classList.toggle("is-visible", itemCount === 0);
    itemsWrap.style.display = itemCount === 0 ? "none" : "grid";
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleCart();
  });

  itemsWrap.addEventListener("click", function (event) {
    const button = event.target.closest("button");
    if (!button) return;

    const item = button.closest(".vb-dropdown-eight-item");
    if (!item) return;

    const action = button.getAttribute("data-action");
    let qty = Number(item.getAttribute("data-qty"));

    if (action === "plus") {
      qty += 1;
      item.setAttribute("data-qty", String(qty));
    }

    if (action === "minus") {
      qty = Math.max(1, qty - 1);
      item.setAttribute("data-qty", String(qty));
    }

    if (action === "remove") {
      item.remove();
    }

    updateCart();
  });

  document.addEventListener("click", function (event) {
    if (!cart.contains(event.target)) {
      closeCart();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeCart();
    }
  });

  updateCart();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-eight-demo"&gt;
  &lt;div class="vb-dropdown-eight-store" data-vb-dropdown-eight&gt;
    &lt;div class="vb-dropdown-eight-top"&gt;
      &lt;div class="vb-dropdown-eight-brand"&gt;
        &lt;span&gt;SHOP&lt;/span&gt;
        &lt;div&gt;
          &lt;strong&gt;Nova Store&lt;/strong&gt;
          &lt;small&gt;Example 08&lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-eight-cart-wrap"&gt;
        &lt;button type="button" class="vb-dropdown-eight-cart-button" data-vb-dropdown-eight-trigger aria-expanded="false"&gt;
          &lt;span&gt;🛒&lt;/span&gt;
          &lt;strong&gt;Cart&lt;/strong&gt;
          &lt;em data-vb-dropdown-eight-count&gt;3&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-dropdown-eight-panel" data-vb-dropdown-eight-panel&gt;
          &lt;div class="vb-dropdown-eight-panel-head"&gt;
            &lt;div&gt;
              &lt;strong&gt;Your cart&lt;/strong&gt;
              &lt;small data-vb-dropdown-eight-summary&gt;3 items selected&lt;/small&gt;
            &lt;/div&gt;
          &lt;/div&gt;

          &lt;div class="vb-dropdown-eight-items" data-vb-dropdown-eight-items&gt;
            &lt;div class="vb-dropdown-eight-item" data-price="49" data-qty="1"&gt;
              &lt;div class="vb-dropdown-eight-thumb vb-dropdown-eight-thumb-a"&gt;&lt;/div&gt;
              &lt;div class="vb-dropdown-eight-info"&gt;
                &lt;strong&gt;Dropdown UI Kit&lt;/strong&gt;
                &lt;small&gt;€49 each&lt;/small&gt;
                &lt;div class="vb-dropdown-eight-qty"&gt;
                  &lt;button type="button" data-action="minus"&gt;−&lt;/button&gt;
                  &lt;span data-qty-label&gt;1&lt;/span&gt;
                  &lt;button type="button" data-action="plus"&gt;+&lt;/button&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;button type="button" class="vb-dropdown-eight-remove" data-action="remove"&gt;×&lt;/button&gt;
            &lt;/div&gt;

            &lt;div class="vb-dropdown-eight-item" data-price="29" data-qty="1"&gt;
              &lt;div class="vb-dropdown-eight-thumb vb-dropdown-eight-thumb-b"&gt;&lt;/div&gt;
              &lt;div class="vb-dropdown-eight-info"&gt;
                &lt;strong&gt;Component Pack&lt;/strong&gt;
                &lt;small&gt;€29 each&lt;/small&gt;
                &lt;div class="vb-dropdown-eight-qty"&gt;
                  &lt;button type="button" data-action="minus"&gt;−&lt;/button&gt;
                  &lt;span data-qty-label&gt;1&lt;/span&gt;
                  &lt;button type="button" data-action="plus"&gt;+&lt;/button&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;button type="button" class="vb-dropdown-eight-remove" data-action="remove"&gt;×&lt;/button&gt;
            &lt;/div&gt;

            &lt;div class="vb-dropdown-eight-item" data-price="19" data-qty="1"&gt;
              &lt;div class="vb-dropdown-eight-thumb vb-dropdown-eight-thumb-c"&gt;&lt;/div&gt;
              &lt;div class="vb-dropdown-eight-info"&gt;
                &lt;strong&gt;Micro Animation Set&lt;/strong&gt;
                &lt;small&gt;€19 each&lt;/small&gt;
                &lt;div class="vb-dropdown-eight-qty"&gt;
                  &lt;button type="button" data-action="minus"&gt;−&lt;/button&gt;
                  &lt;span data-qty-label&gt;1&lt;/span&gt;
                  &lt;button type="button" data-action="plus"&gt;+&lt;/button&gt;
                &lt;/div&gt;
              &lt;/div&gt;
              &lt;button type="button" class="vb-dropdown-eight-remove" data-action="remove"&gt;×&lt;/button&gt;
            &lt;/div&gt;
          &lt;/div&gt;

          &lt;div class="vb-dropdown-eight-empty" data-vb-dropdown-eight-empty&gt;
            &lt;strong&gt;Your cart is empty&lt;/strong&gt;
            &lt;small&gt;Add products to see them here.&lt;/small&gt;
          &lt;/div&gt;

          &lt;div class="vb-dropdown-eight-total"&gt;
            &lt;span&gt;Subtotal&lt;/span&gt;
            &lt;strong data-vb-dropdown-eight-total&gt;€97&lt;/strong&gt;
          &lt;/div&gt;

          &lt;div class="vb-dropdown-eight-actions"&gt;
            &lt;a href="#javascript-dropdown-menu-examples"&gt;View Cart&lt;/a&gt;
            &lt;a href="#javascript-dropdown-conclusion"&gt;Checkout&lt;/a&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;section class="vb-dropdown-eight-hero"&gt;
      &lt;div&gt;
        &lt;span&gt;Ecommerce UI&lt;/span&gt;
        &lt;h3&gt;Shopping Cart Dropdown&lt;/h3&gt;
        &lt;p&gt;Preview cart items, update quantities, remove products, and calculate subtotal with JavaScript.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-eight-product-grid"&gt;
        &lt;article&gt;
          &lt;span&gt;&lt;/span&gt;
          &lt;strong&gt;UI Kit&lt;/strong&gt;
          &lt;small&gt;€49&lt;/small&gt;
        &lt;/article&gt;
        &lt;article&gt;
          &lt;span&gt;&lt;/span&gt;
          &lt;strong&gt;Components&lt;/strong&gt;
          &lt;small&gt;€29&lt;/small&gt;
        &lt;/article&gt;
        &lt;article&gt;
          &lt;span&gt;&lt;/span&gt;
          &lt;strong&gt;Animations&lt;/strong&gt;
          &lt;small&gt;€19&lt;/small&gt;
        &lt;/article&gt;
      &lt;/div&gt;
    &lt;/section&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-eight-demo,
.vb-dropdown-eight-demo * {
  box-sizing: border-box;
}

.vb-dropdown-eight-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 16% 16%, rgba(251, 146, 60, 0.22), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(244, 63, 94, 0.18), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #fff1f2 52%, #ffffff 100%) !important;
  border: 1px solid rgba(251, 146, 60, 0.30);
  box-shadow: 0 24px 70px rgba(124, 45, 18, 0.12);
}

.vb-dropdown-eight-store {
  position: relative;
  max-width: 1080px;
  min-height: 560px;
  margin: 0 auto;
  padding: 24px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(251, 146, 60, 0.24);
  box-shadow: 0 24px 70px rgba(124, 45, 18, 0.12);
  overflow: visible;
}

.vb-dropdown-eight-top {
  position: relative;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  padding: 14px;
  border-radius: 24px;
  background: #111827;
  box-shadow: 0 20px 50px rgba(15, 23, 42, 0.24);
}

.vb-dropdown-eight-brand {
  display: flex;
  align-items: center;
  gap: 12px;
}

.vb-dropdown-eight-brand &gt; span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 58px;
  height: 42px;
  padding: 0 12px;
  border-radius: 15px;
  background: linear-gradient(135deg, #fb923c, #f43f5e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
}

.vb-dropdown-eight-brand strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-eight-brand small {
  display: block;
  margin-top: 3px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  line-height: 1;
  font-weight: 750;
}

.vb-dropdown-eight-cart-wrap {
  position: relative;
}

.vb-dropdown-eight-cart-button {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: 48px;
  padding: 10px 14px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  cursor: pointer;
}

.vb-dropdown-eight-cart-button span,
.vb-dropdown-eight-cart-button strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-eight-cart-button strong {
  font-size: 14px;
  font-weight: 950;
}

.vb-dropdown-eight-cart-button em {
  position: absolute;
  top: -8px;
  right: -6px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 24px;
  padding: 0 7px;
  border-radius: 999px;
  background: #f43f5e;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-style: normal;
  font-weight: 950;
  border: 2px solid #111827;
}

.vb-dropdown-eight-cart-button em.is-hidden {
  display: none;
}

.vb-dropdown-eight-panel {
  position: absolute;
  z-index: 50;
  top: calc(100% + 14px);
  right: 0;
  width: 390px;
  padding: 14px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.32);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-eight-store.is-open .vb-dropdown-eight-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-eight-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 8px 8px 12px;
}

.vb-dropdown-eight-panel-head strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-dropdown-eight-panel-head small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 700;
}

.vb-dropdown-eight-items {
  display: grid;
  gap: 10px;
  max-height: 330px;
  overflow-y: auto;
  padding-right: 4px;
}

.vb-dropdown-eight-item {
  position: relative;
  display: grid;
  grid-template-columns: 56px minmax(0, 1fr) 32px;
  gap: 12px;
  align-items: center;
  padding: 10px;
  border-radius: 18px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.18);
}

.vb-dropdown-eight-thumb {
  width: 56px;
  height: 56px;
  border-radius: 17px;
}

.vb-dropdown-eight-thumb-a {
  background: linear-gradient(135deg, #fb923c, #f43f5e);
}

.vb-dropdown-eight-thumb-b {
  background: linear-gradient(135deg, #06b6d4, #2563eb);
}

.vb-dropdown-eight-thumb-c {
  background: linear-gradient(135deg, #a855f7, #ec4899);
}

.vb-dropdown-eight-info strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  line-height: 1.25;
  font-weight: 950;
}

.vb-dropdown-eight-info small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 750;
}

.vb-dropdown-eight-qty {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: 9px;
  padding: 5px;
  border-radius: 999px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
}

.vb-dropdown-eight-qty button,
.vb-dropdown-eight-remove {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  cursor: pointer;
}

.vb-dropdown-eight-qty button {
  width: 24px;
  height: 24px;
  border-radius: 999px;
  background: #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-eight-qty span {
  min-width: 18px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 13px;
  font-weight: 950;
  text-align: center;
}

.vb-dropdown-eight-remove {
  width: 30px;
  height: 30px;
  border-radius: 999px;
  background: #fee2e2;
  color: #991b1b !important;
  -webkit-text-fill-color: #991b1b !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-dropdown-eight-empty {
  display: none;
  padding: 28px 16px;
  border-radius: 20px;
  background: #f8fafc;
  text-align: center;
}

.vb-dropdown-eight-empty.is-visible {
  display: block;
}

.vb-dropdown-eight-empty strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 17px;
  font-weight: 950;
}

.vb-dropdown-eight-empty small {
  display: block;
  margin-top: 5px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 700;
}

.vb-dropdown-eight-total {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-top: 12px;
  padding: 14px;
  border-radius: 18px;
  background: #111827;
}

.vb-dropdown-eight-total span,
.vb-dropdown-eight-total strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-eight-total span {
  font-size: 13px;
  font-weight: 850;
}

.vb-dropdown-eight-total strong {
  font-size: 22px;
  line-height: 1;
  font-weight: 950;
}

.vb-dropdown-eight-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-top: 10px;
}

.vb-dropdown-eight-actions a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  border-radius: 999px;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
}

.vb-dropdown-eight-actions a:first-child {
  background: #f8fafc;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
}

.vb-dropdown-eight-actions a:last-child {
  background: linear-gradient(135deg, #fb923c, #f43f5e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-eight-hero {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(320px, 0.9fr);
  gap: 28px;
  align-items: end;
  min-height: 430px;
  padding: 52px 12px 12px;
}

.vb-dropdown-eight-hero &gt; div:first-child &gt; span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-eight-hero h3 {
  max-width: 620px;
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 6vw, 72px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-eight-hero p {
  max-width: 560px;
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-eight-product-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 12px;
}

.vb-dropdown-eight-product-grid article {
  min-height: 170px;
  padding: 16px;
  border-radius: 22px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb-dropdown-eight-product-grid article span {
  display: block;
  width: 100%;
  height: 72px;
  margin-bottom: 14px;
  border-radius: 16px;
  background: linear-gradient(135deg, #fb923c, #f43f5e);
}

.vb-dropdown-eight-product-grid article:nth-child(2) span {
  background: linear-gradient(135deg, #06b6d4, #2563eb);
}

.vb-dropdown-eight-product-grid article:nth-child(3) span {
  background: linear-gradient(135deg, #a855f7, #ec4899);
}

.vb-dropdown-eight-product-grid strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 15px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-eight-product-grid small {
  display: block;
  margin-top: 6px;
  color: #f43f5e !important;
  -webkit-text-fill-color: #f43f5e !important;
  font-size: 13px;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vb-dropdown-eight-hero {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-eight-product-grid {
    max-width: 520px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-eight-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-eight-store {
    min-height: 820px;
    padding: 18px;
    border-radius: 22px;
  }

  .vb-dropdown-eight-top {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-dropdown-eight-cart-wrap {
    width: 100%;
  }

  .vb-dropdown-eight-cart-button {
    width: 100%;
    justify-content: center;
  }

  .vb-dropdown-eight-panel {
    left: 0;
    right: auto;
    width: 100%;
    transform-origin: top left;
  }

  .vb-dropdown-eight-product-grid {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-eight-hero h3 {
    font-size: 38px !important;
  }
}</pre>



<p class="wp-block-paragraph">This shopping cart dropdown is a useful ecommerce pattern because it gives visitors a quick cart preview without interrupting their browsing flow. You can adapt it for WooCommerce-style mini carts, custom product pages, checkout previews, digital product stores, and landing pages with product bundles.</p>



<h2 class="wp-block-heading">9. Language Selector Dropdown</h2>



<p class="wp-block-paragraph"><strong>A language selector dropdown</strong> is useful for multilingual websites, SaaS products, ecommerce stores, documentation platforms, travel websites, international service pages, and global landing pages. It lets users switch the visible interface language from a compact dropdown in the header.</p>



<p class="wp-block-paragraph">This example uses a premium glass-style header card, flag-style language options, selected language preview, active state styling, outside click closing, and Escape key support. The JavaScript updates the selected language text and highlights the active option.</p>



<ul class="wp-block-list">
<li>Language selector dropdown</li>
<li>Updates selected language with JavaScript</li>
<li>Flag-style option layout</li>
<li>Outside click and Escape key support</li>
<li>Useful for multilingual websites, SaaS apps, ecommerce stores, and documentation pages</li>
</ul>



<div class="vb-dropdown-nine-demo">
  <div class="vb-dropdown-nine-panel" data-vb-dropdown-nine>
    <div class="vb-dropdown-nine-bg-shape vb-dropdown-nine-bg-one"></div>
    <div class="vb-dropdown-nine-bg-shape vb-dropdown-nine-bg-two"></div>

    <header class="vb-dropdown-nine-header">
      <a class="vb-dropdown-nine-brand" href="#javascript-dropdown-menu-examples">
        <span>G</span>
        <strong>Global UI</strong>
      </a>

      <nav class="vb-dropdown-nine-nav" aria-label="Demo navigation">
        <a href="#what-is-a-javascript-dropdown-menu">Product</a>
        <a href="#javascript-dropdown-best-practices">Resources</a>
        <a href="#javascript-dropdown-faq">Support</a>
      </nav>

      <div class="vb-dropdown-nine-lang-wrap">
        <button type="button" class="vb-dropdown-nine-trigger" data-vb-dropdown-nine-trigger aria-expanded="false">
          <span class="vb-dropdown-nine-flag" data-vb-dropdown-nine-flag>🇺🇸</span>
          <span data-vb-dropdown-nine-text>English</span>
          <em>⌄</em>
        </button>

        <div class="vb-dropdown-nine-menu" data-vb-dropdown-nine-menu>
          <button type="button" class="is-active" data-lang="English" data-flag="🇺🇸">
            <span>🇺🇸</span>
            <strong>English</strong>
            <small>United States</small>
          </button>

          <button type="button" data-lang="Deutsch" data-flag="🇩🇪">
            <span>🇩🇪</span>
            <strong>Deutsch</strong>
            <small>Germany</small>
          </button>

          <button type="button" data-lang="Français" data-flag="🇫🇷">
            <span>🇫🇷</span>
            <strong>Français</strong>
            <small>France</small>
          </button>

          <button type="button" data-lang="Español" data-flag="🇪🇸">
            <span>🇪🇸</span>
            <strong>Español</strong>
            <small>Spain</small>
          </button>

          <button type="button" data-lang="Eesti" data-flag="🇪🇪">
            <span>🇪🇪</span>
            <strong>Eesti</strong>
            <small>Estonia</small>
          </button>
        </div>
      </div>
    </header>

    <section class="vb-dropdown-nine-hero">
      <span>Example 09</span>
      <h3>Language Selector Dropdown</h3>
      <p>This JavaScript dropdown updates the selected language and gives users a polished way to switch between localized website versions.</p>

      <div class="vb-dropdown-nine-current">
        <small>Current language</small>
        <strong data-vb-dropdown-nine-preview>🇺🇸 English</strong>
      </div>
    </section>
  </div>
</div>

<style>
.vb-dropdown-nine-demo,
.vb-dropdown-nine-demo * {
  box-sizing: border-box;
}

.vb-dropdown-nine-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 16%, rgba(56, 189, 248, 0.22), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(129, 140, 248, 0.22), transparent 34%),
    linear-gradient(135deg, #020617 0%, #0f172a 48%, #1e1b4b 100%) !important;
  border: 1px solid rgba(125, 211, 252, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.26);
}

.vb-dropdown-nine-panel {
  position: relative;
  max-width: 1080px;
  min-height: 560px;
  margin: 0 auto;
  padding: 24px;
  border-radius: 30px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.14);
  overflow: visible;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
}

.vb-dropdown-nine-bg-shape {
  position: absolute;
  border-radius: 999px;
  filter: blur(6px);
  opacity: 0.8;
  pointer-events: none;
}

.vb-dropdown-nine-bg-one {
  top: 110px;
  right: 90px;
  width: 170px;
  height: 170px;
  background: rgba(14, 165, 233, 0.26);
}

.vb-dropdown-nine-bg-two {
  left: 70px;
  bottom: 70px;
  width: 220px;
  height: 220px;
  background: rgba(168, 85, 247, 0.20);
}

.vb-dropdown-nine-header {
  position: relative;
  z-index: 40;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 22px;
  align-items: center;
  padding: 14px;
  border-radius: 24px;
  background: rgba(15, 23, 42, 0.72);
  border: 1px solid rgba(255,255,255,0.12);
  backdrop-filter: blur(16px);
  box-shadow: 0 24px 60px rgba(2, 6, 23, 0.28);
}

.vb-dropdown-nine-brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none !important;
}

.vb-dropdown-nine-brand span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: linear-gradient(135deg, #38bdf8, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-nine-brand strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-dropdown-nine-nav {
  display: flex;
  justify-content: center;
  gap: 8px;
}

.vb-dropdown-nine-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  padding: 10px 13px;
  border-radius: 999px;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 13px;
  line-height: 1;
  font-weight: 850;
  text-decoration: none !important;
}

.vb-dropdown-nine-nav a:hover {
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-nine-lang-wrap {
  position: relative;
}

.vb-dropdown-nine-trigger {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: 46px;
  padding: 9px 12px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  cursor: pointer;
}

.vb-dropdown-nine-trigger span {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-dropdown-nine-flag {
  font-size: 19px !important;
}

.vb-dropdown-nine-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 25px;
  height: 25px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-nine-panel.is-open .vb-dropdown-nine-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-nine-menu {
  position: absolute;
  z-index: 50;
  top: calc(100% + 14px);
  right: 0;
  display: grid;
  gap: 7px;
  width: 280px;
  padding: 10px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 30px 80px rgba(2, 6, 23, 0.34);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-nine-panel.is-open .vb-dropdown-nine-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-nine-menu button {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  width: 100%;
  padding: 11px;
  border: 0;
  border-radius: 16px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-nine-menu button:hover,
.vb-dropdown-nine-menu button.is-active {
  background: #eff6ff;
  transform: translateX(2px);
}

.vb-dropdown-nine-menu button > span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: #f8fafc;
  font-size: 22px;
}

.vb-dropdown-nine-menu strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-nine-menu small {
  display: block;
  margin-top: 3px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.3;
  font-weight: 700;
}

.vb-dropdown-nine-hero {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 430px;
  padding: 52px 18px 18px;
}

.vb-dropdown-nine-hero > span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(14, 165, 233, 0.18);
  border: 1px solid rgba(125, 211, 252, 0.28);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-nine-hero h3 {
  max-width: 720px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 6vw, 78px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-nine-hero p {
  max-width: 660px;
  margin: 0 0 24px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-nine-current {
  width: min(100%, 320px);
  padding: 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-dropdown-nine-current small {
  display: block;
  margin-bottom: 6px;
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-nine-current strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  line-height: 1.1;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vb-dropdown-nine-header {
    grid-template-columns: 1fr;
    align-items: start;
  }

  .vb-dropdown-nine-nav {
    justify-content: flex-start;
    flex-wrap: wrap;
  }

  .vb-dropdown-nine-lang-wrap {
    width: min(100%, 320px);
  }

  .vb-dropdown-nine-trigger {
    width: 100%;
    justify-content: space-between;
  }

  .vb-dropdown-nine-menu {
    left: 0;
    right: auto;
    transform-origin: top left;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-nine-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-nine-panel {
    min-height: 740px;
    padding: 18px;
    border-radius: 22px;
  }

  .vb-dropdown-nine-nav {
    display: grid;
    width: 100%;
  }

  .vb-dropdown-nine-nav a {
    justify-content: center;
    background: rgba(255,255,255,0.06);
  }

  .vb-dropdown-nine-menu {
    width: 100%;
  }

  .vb-dropdown-nine-hero h3 {
    font-size: 38px !important;
  }
}
</style>

<script>
(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-nine]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-nine-trigger]");
  const text = dropdown.querySelector("[data-vb-dropdown-nine-text]");
  const flag = dropdown.querySelector("[data-vb-dropdown-nine-flag]");
  const preview = dropdown.querySelector("[data-vb-dropdown-nine-preview]");
  const options = dropdown.querySelectorAll("[data-lang]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  options.forEach(function (option) {
    option.addEventListener("click", function () {
      const selectedLanguage = option.getAttribute("data-lang");
      const selectedFlag = option.getAttribute("data-flag");

      text.textContent = selectedLanguage;
      flag.textContent = selectedFlag;
      preview.textContent = selectedFlag + " " + selectedLanguage;

      options.forEach(function (item) {
        item.classList.remove("is-active");
      });

      option.classList.add("is-active");
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-nine]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-nine-trigger]");
  const text = dropdown.querySelector("[data-vb-dropdown-nine-text]");
  const flag = dropdown.querySelector("[data-vb-dropdown-nine-flag]");
  const preview = dropdown.querySelector("[data-vb-dropdown-nine-preview]");
  const options = dropdown.querySelectorAll("[data-lang]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  options.forEach(function (option) {
    option.addEventListener("click", function () {
      const selectedLanguage = option.getAttribute("data-lang");
      const selectedFlag = option.getAttribute("data-flag");

      text.textContent = selectedLanguage;
      flag.textContent = selectedFlag;
      preview.textContent = selectedFlag + " " + selectedLanguage;

      options.forEach(function (item) {
        item.classList.remove("is-active");
      });

      option.classList.add("is-active");
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-nine-demo"&gt;
  &lt;div class="vb-dropdown-nine-panel" data-vb-dropdown-nine&gt;
    &lt;div class="vb-dropdown-nine-bg-shape vb-dropdown-nine-bg-one"&gt;&lt;/div&gt;
    &lt;div class="vb-dropdown-nine-bg-shape vb-dropdown-nine-bg-two"&gt;&lt;/div&gt;

    &lt;header class="vb-dropdown-nine-header"&gt;
      &lt;a class="vb-dropdown-nine-brand" href="#javascript-dropdown-menu-examples"&gt;
        &lt;span&gt;G&lt;/span&gt;
        &lt;strong&gt;Global UI&lt;/strong&gt;
      &lt;/a&gt;

      &lt;nav class="vb-dropdown-nine-nav" aria-label="Demo navigation"&gt;
        &lt;a href="#what-is-a-javascript-dropdown-menu"&gt;Product&lt;/a&gt;
        &lt;a href="#javascript-dropdown-best-practices"&gt;Resources&lt;/a&gt;
        &lt;a href="#javascript-dropdown-faq"&gt;Support&lt;/a&gt;
      &lt;/nav&gt;

      &lt;div class="vb-dropdown-nine-lang-wrap"&gt;
        &lt;button type="button" class="vb-dropdown-nine-trigger" data-vb-dropdown-nine-trigger aria-expanded="false"&gt;
          &lt;span class="vb-dropdown-nine-flag" data-vb-dropdown-nine-flag&gt;🇺🇸&lt;/span&gt;
          &lt;span data-vb-dropdown-nine-text&gt;English&lt;/span&gt;
          &lt;em&gt;⌄&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-dropdown-nine-menu" data-vb-dropdown-nine-menu&gt;
          &lt;button type="button" class="is-active" data-lang="English" data-flag="🇺🇸"&gt;
            &lt;span&gt;🇺🇸&lt;/span&gt;
            &lt;strong&gt;English&lt;/strong&gt;
            &lt;small&gt;United States&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-lang="Deutsch" data-flag="🇩🇪"&gt;
            &lt;span&gt;🇩🇪&lt;/span&gt;
            &lt;strong&gt;Deutsch&lt;/strong&gt;
            &lt;small&gt;Germany&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-lang="Français" data-flag="🇫🇷"&gt;
            &lt;span&gt;🇫🇷&lt;/span&gt;
            &lt;strong&gt;Français&lt;/strong&gt;
            &lt;small&gt;France&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-lang="Español" data-flag="🇪🇸"&gt;
            &lt;span&gt;🇪🇸&lt;/span&gt;
            &lt;strong&gt;Español&lt;/strong&gt;
            &lt;small&gt;Spain&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-lang="Eesti" data-flag="🇪🇪"&gt;
            &lt;span&gt;🇪🇪&lt;/span&gt;
            &lt;strong&gt;Eesti&lt;/strong&gt;
            &lt;small&gt;Estonia&lt;/small&gt;
          &lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/header&gt;

    &lt;section class="vb-dropdown-nine-hero"&gt;
      &lt;span&gt;Example 09&lt;/span&gt;
      &lt;h3&gt;Language Selector Dropdown&lt;/h3&gt;
      &lt;p&gt;This JavaScript dropdown updates the selected language and gives users a polished way to switch between localized website versions.&lt;/p&gt;

      &lt;div class="vb-dropdown-nine-current"&gt;
        &lt;small&gt;Current language&lt;/small&gt;
        &lt;strong data-vb-dropdown-nine-preview&gt;🇺🇸 English&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/section&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-nine-demo,
.vb-dropdown-nine-demo * {
  box-sizing: border-box;
}

.vb-dropdown-nine-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 16%, rgba(56, 189, 248, 0.22), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(129, 140, 248, 0.22), transparent 34%),
    linear-gradient(135deg, #020617 0%, #0f172a 48%, #1e1b4b 100%) !important;
  border: 1px solid rgba(125, 211, 252, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.26);
}

.vb-dropdown-nine-panel {
  position: relative;
  max-width: 1080px;
  min-height: 560px;
  margin: 0 auto;
  padding: 24px;
  border-radius: 30px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.14);
  overflow: visible;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
}

.vb-dropdown-nine-bg-shape {
  position: absolute;
  border-radius: 999px;
  filter: blur(6px);
  opacity: 0.8;
  pointer-events: none;
}

.vb-dropdown-nine-bg-one {
  top: 110px;
  right: 90px;
  width: 170px;
  height: 170px;
  background: rgba(14, 165, 233, 0.26);
}

.vb-dropdown-nine-bg-two {
  left: 70px;
  bottom: 70px;
  width: 220px;
  height: 220px;
  background: rgba(168, 85, 247, 0.20);
}

.vb-dropdown-nine-header {
  position: relative;
  z-index: 40;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 22px;
  align-items: center;
  padding: 14px;
  border-radius: 24px;
  background: rgba(15, 23, 42, 0.72);
  border: 1px solid rgba(255,255,255,0.12);
  backdrop-filter: blur(16px);
  box-shadow: 0 24px 60px rgba(2, 6, 23, 0.28);
}

.vb-dropdown-nine-brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none !important;
}

.vb-dropdown-nine-brand span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: linear-gradient(135deg, #38bdf8, #6366f1);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-nine-brand strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-dropdown-nine-nav {
  display: flex;
  justify-content: center;
  gap: 8px;
}

.vb-dropdown-nine-nav a {
  display: inline-flex;
  align-items: center;
  min-height: 40px;
  padding: 10px 13px;
  border-radius: 999px;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 13px;
  line-height: 1;
  font-weight: 850;
  text-decoration: none !important;
}

.vb-dropdown-nine-nav a:hover {
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-nine-lang-wrap {
  position: relative;
}

.vb-dropdown-nine-trigger {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: 46px;
  padding: 9px 12px;
  border: 1px solid rgba(255,255,255,0.14);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  cursor: pointer;
}

.vb-dropdown-nine-trigger span {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 900;
}

.vb-dropdown-nine-flag {
  font-size: 19px !important;
}

.vb-dropdown-nine-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 25px;
  height: 25px;
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-nine-panel.is-open .vb-dropdown-nine-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-nine-menu {
  position: absolute;
  z-index: 50;
  top: calc(100% + 14px);
  right: 0;
  display: grid;
  gap: 7px;
  width: 280px;
  padding: 10px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 30px 80px rgba(2, 6, 23, 0.34);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-nine-panel.is-open .vb-dropdown-nine-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-nine-menu button {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  width: 100%;
  padding: 11px;
  border: 0;
  border-radius: 16px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-nine-menu button:hover,
.vb-dropdown-nine-menu button.is-active {
  background: #eff6ff;
  transform: translateX(2px);
}

.vb-dropdown-nine-menu button &gt; span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: #f8fafc;
  font-size: 22px;
}

.vb-dropdown-nine-menu strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-nine-menu small {
  display: block;
  margin-top: 3px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.3;
  font-weight: 700;
}

.vb-dropdown-nine-hero {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 430px;
  padding: 52px 18px 18px;
}

.vb-dropdown-nine-hero &gt; span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(14, 165, 233, 0.18);
  border: 1px solid rgba(125, 211, 252, 0.28);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-nine-hero h3 {
  max-width: 720px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(38px, 6vw, 78px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-nine-hero p {
  max-width: 660px;
  margin: 0 0 24px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-nine-current {
  width: min(100%, 320px);
  padding: 18px;
  border-radius: 22px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-dropdown-nine-current small {
  display: block;
  margin-bottom: 6px;
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-nine-current strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  line-height: 1.1;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vb-dropdown-nine-header {
    grid-template-columns: 1fr;
    align-items: start;
  }

  .vb-dropdown-nine-nav {
    justify-content: flex-start;
    flex-wrap: wrap;
  }

  .vb-dropdown-nine-lang-wrap {
    width: min(100%, 320px);
  }

  .vb-dropdown-nine-trigger {
    width: 100%;
    justify-content: space-between;
  }

  .vb-dropdown-nine-menu {
    left: 0;
    right: auto;
    transform-origin: top left;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-nine-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-nine-panel {
    min-height: 740px;
    padding: 18px;
    border-radius: 22px;
  }

  .vb-dropdown-nine-nav {
    display: grid;
    width: 100%;
  }

  .vb-dropdown-nine-nav a {
    justify-content: center;
    background: rgba(255,255,255,0.06);
  }

  .vb-dropdown-nine-menu {
    width: 100%;
  }

  .vb-dropdown-nine-hero h3 {
    font-size: 38px !important;
  }
}</pre>



<p class="wp-block-paragraph">This language selector dropdown is a useful pattern for international websites because it keeps localization controls visible without taking up too much space. You can adapt it for multilingual blogs, documentation sites, SaaS apps, ecommerce stores, booking platforms, and global landing pages.</p>



<h2 class="wp-block-heading">10. Currency Selector Dropdown</h2>



<p class="wp-block-paragraph"><strong>A currency selector dropdown</strong> helps ecommerce stores, travel websites, booking platforms, SaaS pricing pages, digital product shops, and marketplace interfaces display pricing in a way that feels more relevant to international users.</p>



<p class="wp-block-paragraph">This example uses a compact pricing card, currency options, live product price conversion, selected currency preview, outside click closing, and Escape key support. It is a demo conversion pattern, but the same UI can be connected to real exchange rates or ecommerce pricing logic.</p>



<ul class="wp-block-list">
<li>Currency selector dropdown</li>
<li>Updates selected currency with JavaScript</li>
<li>Demo price conversion logic</li>
<li>Clean pricing card layout</li>
<li>Useful for ecommerce, pricing pages, booking sites, and global product pages</li>
</ul>



<div class="vb-dropdown-ten-demo">
  <div class="vb-dropdown-ten-pricing" data-vb-dropdown-ten>
    <div class="vb-dropdown-ten-copy">
      <span>Example 10</span>
      <h3>Currency Selector Dropdown</h3>
      <p>Select a currency and update the product price instantly. This is useful for international ecommerce stores and pricing pages.</p>
    </div>

    <div class="vb-dropdown-ten-card">
      <div class="vb-dropdown-ten-card-top">
        <div>
          <small>Digital Product</small>
          <strong>JavaScript UI Bundle</strong>
        </div>

        <div class="vb-dropdown-ten-select-wrap">
          <button type="button" class="vb-dropdown-ten-trigger" data-vb-dropdown-ten-trigger aria-expanded="false">
            <span data-vb-dropdown-ten-code>EUR</span>
            <em>⌄</em>
          </button>

          <div class="vb-dropdown-ten-menu" data-vb-dropdown-ten-menu>
            <button type="button" class="is-active" data-code="EUR" data-symbol="€" data-rate="1">
              <span>€</span>
              <strong>EUR</strong>
              <small>Euro</small>
            </button>

            <button type="button" data-code="USD" data-symbol="$" data-rate="1.09">
              <span>$</span>
              <strong>USD</strong>
              <small>US Dollar</small>
            </button>

            <button type="button" data-code="GBP" data-symbol="£" data-rate="0.86">
              <span>£</span>
              <strong>GBP</strong>
              <small>British Pound</small>
            </button>

            <button type="button" data-code="CAD" data-symbol="C$" data-rate="1.48">
              <span>C$</span>
              <strong>CAD</strong>
              <small>Canadian Dollar</small>
            </button>
          </div>
        </div>
      </div>

      <div class="vb-dropdown-ten-price">
        <small>Current price</small>
        <strong data-vb-dropdown-ten-price>€49</strong>
      </div>

      <div class="vb-dropdown-ten-features">
        <span>Reusable dropdown components</span>
        <span>Copy-paste ready code examples</span>
        <span>Responsive UI patterns</span>
      </div>

      <a href="#javascript-dropdown-menu-examples">View examples</a>
    </div>
  </div>
</div>

<style>
.vb-dropdown-ten-demo,
.vb-dropdown-ten-demo * {
  box-sizing: border-box;
}

.vb-dropdown-ten-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 18% 14%, rgba(34, 197, 94, 0.20), transparent 34%),
    radial-gradient(circle at 84% 16%, rgba(250, 204, 21, 0.18), transparent 34%),
    linear-gradient(135deg, #f7fee7 0%, #ecfdf5 52%, #ffffff 100%) !important;
  border: 1px solid rgba(187, 247, 208, 0.50);
  box-shadow: 0 24px 70px rgba(21, 128, 61, 0.12);
}

.vb-dropdown-ten-pricing {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(330px, 0.72fr);
  gap: 32px;
  align-items: center;
  max-width: 1040px;
  min-height: 560px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(187, 247, 208, 0.60);
  box-shadow: 0 24px 70px rgba(21, 128, 61, 0.12);
  overflow: visible;
}

.vb-dropdown-ten-copy > span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-ten-copy h3 {
  max-width: 680px;
  margin: 0 0 16px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-ten-copy p {
  max-width: 560px;
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-ten-card {
  position: relative;
  z-index: 30;
  padding: 22px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 20% 16%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #14532d 100%) !important;
  box-shadow: 0 30px 80px rgba(20, 83, 45, 0.28);
}

.vb-dropdown-ten-card-top {
  position: relative;
  z-index: 40;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 28px;
}

.vb-dropdown-ten-card-top small {
  display: block;
  margin-bottom: 6px;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-ten-card-top strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 23px;
  line-height: 1.12;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-dropdown-ten-select-wrap {
  position: relative;
  flex: 0 0 auto;
}

.vb-dropdown-ten-trigger {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 42px;
  padding: 8px 10px 8px 13px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  cursor: pointer;
}

.vb-dropdown-ten-trigger span {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-dropdown-ten-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-ten-pricing.is-open .vb-dropdown-ten-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-ten-menu {
  position: absolute;
  z-index: 60;
  top: calc(100% + 12px);
  right: 0;
  display: grid;
  gap: 7px;
  width: 230px;
  padding: 9px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 30px 80px rgba(2, 6, 23, 0.34);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-ten-pricing.is-open .vb-dropdown-ten-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-ten-menu button {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  width: 100%;
  padding: 10px;
  border: 0;
  border-radius: 15px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-ten-menu button:hover,
.vb-dropdown-ten-menu button.is-active {
  background: #f0fdf4;
  transform: translateX(2px);
}

.vb-dropdown-ten-menu button > span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-dropdown-ten-menu strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-ten-menu small {
  display: block;
  margin-top: 3px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.3;
  font-weight: 700;
}

.vb-dropdown-ten-price {
  margin-bottom: 24px;
  padding: 22px;
  border-radius: 24px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-dropdown-ten-price small {
  display: block;
  margin-bottom: 8px;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-ten-price strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 58px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.08em;
}

.vb-dropdown-ten-features {
  display: grid;
  gap: 10px;
  margin-bottom: 18px;
}

.vb-dropdown-ten-features span {
  display: flex;
  align-items: center;
  gap: 9px;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 14px;
  line-height: 1.4;
  font-weight: 750;
}

.vb-dropdown-ten-features span::before {
  content: "✓";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.24);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-dropdown-ten-card > a {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22c55e, #84cc16);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  text-decoration: none !important;
  box-shadow: 0 18px 40px rgba(34, 197, 94, 0.26);
}

@media (max-width: 860px) {
  .vb-dropdown-ten-pricing {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-ten-card {
    max-width: 440px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-ten-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-ten-pricing {
    min-height: 700px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-ten-copy h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-ten-card {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-ten-card-top {
    flex-direction: column;
  }

  .vb-dropdown-ten-select-wrap {
    width: 100%;
  }

  .vb-dropdown-ten-trigger {
    width: 100%;
    justify-content: space-between;
  }

  .vb-dropdown-ten-menu {
    left: 0;
    right: auto;
    width: 100%;
    transform-origin: top left;
  }

  .vb-dropdown-ten-price strong {
    font-size: 48px;
  }
}
</style>

<script>
(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-ten]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-ten-trigger]");
  const code = dropdown.querySelector("[data-vb-dropdown-ten-code]");
  const price = dropdown.querySelector("[data-vb-dropdown-ten-price]");
  const options = dropdown.querySelectorAll("[data-code]");
  const basePrice = 49;

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function updateCurrency(option) {
    const selectedCode = option.getAttribute("data-code");
    const selectedSymbol = option.getAttribute("data-symbol");
    const selectedRate = Number(option.getAttribute("data-rate"));
    const convertedPrice = Math.round(basePrice * selectedRate);

    code.textContent = selectedCode;
    price.textContent = selectedSymbol + convertedPrice;

    options.forEach(function (item) {
      item.classList.remove("is-active");
    });

    option.classList.add("is-active");
    closeDropdown();
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  options.forEach(function (option) {
    option.addEventListener("click", function () {
      updateCurrency(option);
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-ten]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-ten-trigger]");
  const code = dropdown.querySelector("[data-vb-dropdown-ten-code]");
  const price = dropdown.querySelector("[data-vb-dropdown-ten-price]");
  const options = dropdown.querySelectorAll("[data-code]");
  const basePrice = 49;

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function updateCurrency(option) {
    const selectedCode = option.getAttribute("data-code");
    const selectedSymbol = option.getAttribute("data-symbol");
    const selectedRate = Number(option.getAttribute("data-rate"));
    const convertedPrice = Math.round(basePrice * selectedRate);

    code.textContent = selectedCode;
    price.textContent = selectedSymbol + convertedPrice;

    options.forEach(function (item) {
      item.classList.remove("is-active");
    });

    option.classList.add("is-active");
    closeDropdown();
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  options.forEach(function (option) {
    option.addEventListener("click", function () {
      updateCurrency(option);
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-ten-demo"&gt;
  &lt;div class="vb-dropdown-ten-pricing" data-vb-dropdown-ten&gt;
    &lt;div class="vb-dropdown-ten-copy"&gt;
      &lt;span&gt;Example 10&lt;/span&gt;
      &lt;h3&gt;Currency Selector Dropdown&lt;/h3&gt;
      &lt;p&gt;Select a currency and update the product price instantly. This is useful for international ecommerce stores and pricing pages.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-dropdown-ten-card"&gt;
      &lt;div class="vb-dropdown-ten-card-top"&gt;
        &lt;div&gt;
          &lt;small&gt;Digital Product&lt;/small&gt;
          &lt;strong&gt;JavaScript UI Bundle&lt;/strong&gt;
        &lt;/div&gt;

        &lt;div class="vb-dropdown-ten-select-wrap"&gt;
          &lt;button type="button" class="vb-dropdown-ten-trigger" data-vb-dropdown-ten-trigger aria-expanded="false"&gt;
            &lt;span data-vb-dropdown-ten-code&gt;EUR&lt;/span&gt;
            &lt;em&gt;⌄&lt;/em&gt;
          &lt;/button&gt;

          &lt;div class="vb-dropdown-ten-menu" data-vb-dropdown-ten-menu&gt;
            &lt;button type="button" class="is-active" data-code="EUR" data-symbol="€" data-rate="1"&gt;
              &lt;span&gt;€&lt;/span&gt;
              &lt;strong&gt;EUR&lt;/strong&gt;
              &lt;small&gt;Euro&lt;/small&gt;
            &lt;/button&gt;

            &lt;button type="button" data-code="USD" data-symbol="$" data-rate="1.09"&gt;
              &lt;span&gt;$&lt;/span&gt;
              &lt;strong&gt;USD&lt;/strong&gt;
              &lt;small&gt;US Dollar&lt;/small&gt;
            &lt;/button&gt;

            &lt;button type="button" data-code="GBP" data-symbol="£" data-rate="0.86"&gt;
              &lt;span&gt;£&lt;/span&gt;
              &lt;strong&gt;GBP&lt;/strong&gt;
              &lt;small&gt;British Pound&lt;/small&gt;
            &lt;/button&gt;

            &lt;button type="button" data-code="CAD" data-symbol="C$" data-rate="1.48"&gt;
              &lt;span&gt;C$&lt;/span&gt;
              &lt;strong&gt;CAD&lt;/strong&gt;
              &lt;small&gt;Canadian Dollar&lt;/small&gt;
            &lt;/button&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-ten-price"&gt;
        &lt;small&gt;Current price&lt;/small&gt;
        &lt;strong data-vb-dropdown-ten-price&gt;€49&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-ten-features"&gt;
        &lt;span&gt;Reusable dropdown components&lt;/span&gt;
        &lt;span&gt;Copy-paste ready code examples&lt;/span&gt;
        &lt;span&gt;Responsive UI patterns&lt;/span&gt;
      &lt;/div&gt;

      &lt;a href="#javascript-dropdown-menu-examples"&gt;View examples&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-ten-demo,
.vb-dropdown-ten-demo * {
  box-sizing: border-box;
}

.vb-dropdown-ten-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 18% 14%, rgba(34, 197, 94, 0.20), transparent 34%),
    radial-gradient(circle at 84% 16%, rgba(250, 204, 21, 0.18), transparent 34%),
    linear-gradient(135deg, #f7fee7 0%, #ecfdf5 52%, #ffffff 100%) !important;
  border: 1px solid rgba(187, 247, 208, 0.50);
  box-shadow: 0 24px 70px rgba(21, 128, 61, 0.12);
}

.vb-dropdown-ten-pricing {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(330px, 0.72fr);
  gap: 32px;
  align-items: center;
  max-width: 1040px;
  min-height: 560px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(187, 247, 208, 0.60);
  box-shadow: 0 24px 70px rgba(21, 128, 61, 0.12);
  overflow: visible;
}

.vb-dropdown-ten-copy &gt; span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-ten-copy h3 {
  max-width: 680px;
  margin: 0 0 16px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-ten-copy p {
  max-width: 560px;
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-ten-card {
  position: relative;
  z-index: 30;
  padding: 22px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 20% 16%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #0f172a 0%, #14532d 100%) !important;
  box-shadow: 0 30px 80px rgba(20, 83, 45, 0.28);
}

.vb-dropdown-ten-card-top {
  position: relative;
  z-index: 40;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 18px;
  margin-bottom: 28px;
}

.vb-dropdown-ten-card-top small {
  display: block;
  margin-bottom: 6px;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-ten-card-top strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 23px;
  line-height: 1.12;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-dropdown-ten-select-wrap {
  position: relative;
  flex: 0 0 auto;
}

.vb-dropdown-ten-trigger {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 42px;
  padding: 8px 10px 8px 13px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  background: rgba(255,255,255,0.12);
  cursor: pointer;
}

.vb-dropdown-ten-trigger span {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-dropdown-ten-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-ten-pricing.is-open .vb-dropdown-ten-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-ten-menu {
  position: absolute;
  z-index: 60;
  top: calc(100% + 12px);
  right: 0;
  display: grid;
  gap: 7px;
  width: 230px;
  padding: 9px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 30px 80px rgba(2, 6, 23, 0.34);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-ten-pricing.is-open .vb-dropdown-ten-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-ten-menu button {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  width: 100%;
  padding: 10px;
  border: 0;
  border-radius: 15px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-ten-menu button:hover,
.vb-dropdown-ten-menu button.is-active {
  background: #f0fdf4;
  transform: translateX(2px);
}

.vb-dropdown-ten-menu button &gt; span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: #dcfce7;
  color: #166534 !important;
  -webkit-text-fill-color: #166534 !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-dropdown-ten-menu strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-ten-menu small {
  display: block;
  margin-top: 3px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.3;
  font-weight: 700;
}

.vb-dropdown-ten-price {
  margin-bottom: 24px;
  padding: 22px;
  border-radius: 24px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-dropdown-ten-price small {
  display: block;
  margin-bottom: 8px;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-ten-price strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 58px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.08em;
}

.vb-dropdown-ten-features {
  display: grid;
  gap: 10px;
  margin-bottom: 18px;
}

.vb-dropdown-ten-features span {
  display: flex;
  align-items: center;
  gap: 9px;
  color: #dcfce7 !important;
  -webkit-text-fill-color: #dcfce7 !important;
  font-size: 14px;
  line-height: 1.4;
  font-weight: 750;
}

.vb-dropdown-ten-features span::before {
  content: "✓";
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  border-radius: 999px;
  background: rgba(34, 197, 94, 0.24);
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-dropdown-ten-card &gt; a {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22c55e, #84cc16);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  text-decoration: none !important;
  box-shadow: 0 18px 40px rgba(34, 197, 94, 0.26);
}

@media (max-width: 860px) {
  .vb-dropdown-ten-pricing {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-ten-card {
    max-width: 440px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-ten-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-ten-pricing {
    min-height: 700px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-ten-copy h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-ten-card {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-ten-card-top {
    flex-direction: column;
  }

  .vb-dropdown-ten-select-wrap {
    width: 100%;
  }

  .vb-dropdown-ten-trigger {
    width: 100%;
    justify-content: space-between;
  }

  .vb-dropdown-ten-menu {
    left: 0;
    right: auto;
    width: 100%;
    transform-origin: top left;
  }

  .vb-dropdown-ten-price strong {
    font-size: 48px;
  }
}</pre>



<p class="wp-block-paragraph">This currency selector dropdown is useful for global ecommerce and pricing interfaces. You can connect the same UI to real exchange rates, WooCommerce currency switchers, SaaS pricing plans, travel booking forms, or international product landing pages.</p>



<h2 class="wp-block-heading">11. Icon Action Dropdown Menu</h2>



<p class="wp-block-paragraph"><strong>An icon action dropdown menu</strong> is useful when a card, table row, dashboard widget, product item, or project panel needs compact actions without taking up too much space. Instead of showing every action as a visible button, users can open a small menu from a three-dot icon.</p>



<p class="wp-block-paragraph">This example uses a modern project card layout with a three-dot trigger, floating action menu, active status change, small feedback message, outside click closing, and Escape key support. It works well for admin panels, SaaS dashboards, project management tools, file managers, content lists, and ecommerce product rows.</p>



<ul class="wp-block-list">
<li>Three-dot icon dropdown</li>
<li>Compact action menu for cards and rows</li>
<li>JavaScript updates the visible project status</li>
<li>Outside click and Escape key support</li>
<li>Useful for dashboards, project cards, tables, file managers, and admin screens</li>
</ul>



<div class="vb-dropdown-eleven-demo">
  <div class="vb-dropdown-eleven-workspace" data-vb-dropdown-eleven>
    <div class="vb-dropdown-eleven-intro">
      <span>Example 11</span>
      <h3>Icon Action Dropdown</h3>
      <p>Use a three-dot dropdown when each card or table row needs compact actions such as edit, duplicate, archive, share, or delete.</p>
    </div>

    <div class="vb-dropdown-eleven-card">
      <div class="vb-dropdown-eleven-card-top">
        <div class="vb-dropdown-eleven-icon">UI</div>

        <div class="vb-dropdown-eleven-menu-wrap">
          <button type="button" class="vb-dropdown-eleven-trigger" data-vb-dropdown-eleven-trigger aria-expanded="false" aria-label="Open card actions">
            <span></span>
            <span></span>
            <span></span>
          </button>

          <div class="vb-dropdown-eleven-menu" data-vb-dropdown-eleven-menu>
            <button type="button" data-vb-dropdown-eleven-action="Edit project">
              <span>✏️</span>
              <strong>Edit project</strong>
            </button>

            <button type="button" data-vb-dropdown-eleven-action="Duplicate project">
              <span>📄</span>
              <strong>Duplicate</strong>
            </button>

            <button type="button" data-vb-dropdown-eleven-action="Shared project">
              <span>🔗</span>
              <strong>Share link</strong>
            </button>

            <button type="button" data-vb-dropdown-eleven-action="Archived project">
              <span>📦</span>
              <strong>Archive</strong>
            </button>

            <button type="button" class="vb-dropdown-eleven-danger" data-vb-dropdown-eleven-action="Delete option opened">
              <span>🗑️</span>
              <strong>Delete</strong>
            </button>
          </div>
        </div>
      </div>

      <div class="vb-dropdown-eleven-body">
        <small>Active project</small>
        <h4>Dropdown Component System</h4>
        <p>A reusable JavaScript dropdown menu system for modern website cards, admin rows, and dashboard actions.</p>

        <div class="vb-dropdown-eleven-meta">
          <span>Status: <strong data-vb-dropdown-eleven-status>Ready</strong></span>
          <span>Updated today</span>
        </div>

        <div class="vb-dropdown-eleven-feedback" data-vb-dropdown-eleven-feedback>
          Choose an action from the dropdown menu.
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-dropdown-eleven-demo,
.vb-dropdown-eleven-demo * {
  box-sizing: border-box;
}

.vb-dropdown-eleven-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 16%, rgba(99, 102, 241, 0.22), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(217, 70, 239, 0.18), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #faf5ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(199, 210, 254, 0.50);
  box-shadow: 0 24px 70px rgba(67, 56, 202, 0.12);
}

.vb-dropdown-eleven-workspace {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(340px, 0.72fr);
  gap: 32px;
  align-items: center;
  max-width: 1040px;
  min-height: 560px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(199, 210, 254, 0.44);
  box-shadow: 0 24px 70px rgba(67, 56, 202, 0.12);
  overflow: visible;
}

.vb-dropdown-eleven-intro > span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #e0e7ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-eleven-intro h3 {
  max-width: 660px;
  margin: 0 0 16px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-eleven-intro p {
  max-width: 560px;
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-eleven-card {
  position: relative;
  z-index: 20;
  padding: 22px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 14%, rgba(129, 140, 248, 0.16), transparent 34%),
    linear-gradient(135deg, #111827 0%, #312e81 100%) !important;
  box-shadow: 0 30px 80px rgba(49, 46, 129, 0.28);
}

.vb-dropdown-eleven-card-top {
  position: relative;
  z-index: 40;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 52px;
}

.vb-dropdown-eleven-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 58px;
  height: 58px;
  border-radius: 20px;
  background: linear-gradient(135deg, #818cf8, #d946ef);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
  box-shadow: 0 18px 42px rgba(129, 140, 248, 0.30);
}

.vb-dropdown-eleven-menu-wrap {
  position: relative;
}

.vb-dropdown-eleven-trigger {
  display: inline-grid;
  place-items: center;
  gap: 4px;
  width: 46px;
  height: 46px;
  padding: 12px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 16px;
  background: rgba(255,255,255,0.12);
  cursor: pointer;
}

.vb-dropdown-eleven-trigger span {
  display: block;
  width: 5px;
  height: 5px;
  border-radius: 999px;
  background: #ffffff;
}

.vb-dropdown-eleven-menu {
  position: absolute;
  z-index: 60;
  top: calc(100% + 12px);
  right: 0;
  display: grid;
  gap: 6px;
  width: 230px;
  padding: 9px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 30px 80px rgba(2, 6, 23, 0.34);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-eleven-workspace.is-open .vb-dropdown-eleven-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-eleven-menu button {
  display: grid;
  grid-template-columns: 38px minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  width: 100%;
  min-height: 46px;
  padding: 9px;
  border: 0;
  border-radius: 15px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-eleven-menu button:hover {
  background: #f8fafc;
  transform: translateX(2px);
}

.vb-dropdown-eleven-menu button span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 14px;
  background: #eef2ff;
  font-size: 17px;
}

.vb-dropdown-eleven-menu button strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 900;
}

.vb-dropdown-eleven-menu .vb-dropdown-eleven-danger:hover {
  background: #fef2f2;
}

.vb-dropdown-eleven-menu .vb-dropdown-eleven-danger span {
  background: #fee2e2;
}

.vb-dropdown-eleven-menu .vb-dropdown-eleven-danger strong {
  color: #991b1b !important;
  -webkit-text-fill-color: #991b1b !important;
}

.vb-dropdown-eleven-body small {
  display: inline-flex;
  margin-bottom: 12px;
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-eleven-body h4 {
  margin: 0 0 12px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 32px !important;
  line-height: 1.05 !important;
  font-weight: 950 !important;
  letter-spacing: -0.05em;
}

.vb-dropdown-eleven-body p {
  margin: 0 0 18px !important;
  color: #ddd6fe !important;
  -webkit-text-fill-color: #ddd6fe !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-dropdown-eleven-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
  margin-bottom: 14px;
}

.vb-dropdown-eleven-meta span {
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  padding: 8px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ede9fe !important;
  -webkit-text-fill-color: #ede9fe !important;
  font-size: 12px;
  line-height: 1;
  font-weight: 850;
}

.vb-dropdown-eleven-meta strong {
  margin-left: 4px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-eleven-feedback {
  padding: 13px;
  border-radius: 16px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 13px;
  line-height: 1.45;
  font-weight: 750;
}

@media (max-width: 860px) {
  .vb-dropdown-eleven-workspace {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-eleven-card {
    max-width: 430px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-eleven-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-eleven-workspace {
    min-height: 700px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-eleven-intro h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-eleven-card {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-eleven-menu {
    right: -8px;
    width: min(82vw, 230px);
  }
}
</style>

<script>
(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-eleven]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-eleven-trigger]");
  const actionButtons = dropdown.querySelectorAll("[data-vb-dropdown-eleven-action]");
  const feedback = dropdown.querySelector("[data-vb-dropdown-eleven-feedback]");
  const status = dropdown.querySelector("[data-vb-dropdown-eleven-status]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  actionButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      const action = button.getAttribute("data-vb-dropdown-eleven-action");
      feedback.textContent = "Selected action: " + action + ".";
      status.textContent = action;
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-eleven]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-eleven-trigger]");
  const actionButtons = dropdown.querySelectorAll("[data-vb-dropdown-eleven-action]");
  const feedback = dropdown.querySelector("[data-vb-dropdown-eleven-feedback]");
  const status = dropdown.querySelector("[data-vb-dropdown-eleven-status]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  actionButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      const action = button.getAttribute("data-vb-dropdown-eleven-action");
      feedback.textContent = "Selected action: " + action + ".";
      status.textContent = action;
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-eleven-demo"&gt;
  &lt;div class="vb-dropdown-eleven-workspace" data-vb-dropdown-eleven&gt;
    &lt;div class="vb-dropdown-eleven-intro"&gt;
      &lt;span&gt;Example 11&lt;/span&gt;
      &lt;h3&gt;Icon Action Dropdown&lt;/h3&gt;
      &lt;p&gt;Use a three-dot dropdown when each card or table row needs compact actions such as edit, duplicate, archive, share, or delete.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-dropdown-eleven-card"&gt;
      &lt;div class="vb-dropdown-eleven-card-top"&gt;
        &lt;div class="vb-dropdown-eleven-icon"&gt;UI&lt;/div&gt;

        &lt;div class="vb-dropdown-eleven-menu-wrap"&gt;
          &lt;button type="button" class="vb-dropdown-eleven-trigger" data-vb-dropdown-eleven-trigger aria-expanded="false" aria-label="Open card actions"&gt;
            &lt;span&gt;&lt;/span&gt;
            &lt;span&gt;&lt;/span&gt;
            &lt;span&gt;&lt;/span&gt;
          &lt;/button&gt;

          &lt;div class="vb-dropdown-eleven-menu" data-vb-dropdown-eleven-menu&gt;
            &lt;button type="button" data-vb-dropdown-eleven-action="Edit project"&gt;
              &lt;span&gt;✏️&lt;/span&gt;
              &lt;strong&gt;Edit project&lt;/strong&gt;
            &lt;/button&gt;

            &lt;button type="button" data-vb-dropdown-eleven-action="Duplicate project"&gt;
              &lt;span&gt;📄&lt;/span&gt;
              &lt;strong&gt;Duplicate&lt;/strong&gt;
            &lt;/button&gt;

            &lt;button type="button" data-vb-dropdown-eleven-action="Shared project"&gt;
              &lt;span&gt;🔗&lt;/span&gt;
              &lt;strong&gt;Share link&lt;/strong&gt;
            &lt;/button&gt;

            &lt;button type="button" data-vb-dropdown-eleven-action="Archived project"&gt;
              &lt;span&gt;📦&lt;/span&gt;
              &lt;strong&gt;Archive&lt;/strong&gt;
            &lt;/button&gt;

            &lt;button type="button" class="vb-dropdown-eleven-danger" data-vb-dropdown-eleven-action="Delete option opened"&gt;
              &lt;span&gt;🗑️&lt;/span&gt;
              &lt;strong&gt;Delete&lt;/strong&gt;
            &lt;/button&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-eleven-body"&gt;
        &lt;small&gt;Active project&lt;/small&gt;
        &lt;h4&gt;Dropdown Component System&lt;/h4&gt;
        &lt;p&gt;A reusable JavaScript dropdown menu system for modern website cards, admin rows, and dashboard actions.&lt;/p&gt;

        &lt;div class="vb-dropdown-eleven-meta"&gt;
          &lt;span&gt;Status: &lt;strong data-vb-dropdown-eleven-status&gt;Ready&lt;/strong&gt;&lt;/span&gt;
          &lt;span&gt;Updated today&lt;/span&gt;
        &lt;/div&gt;

        &lt;div class="vb-dropdown-eleven-feedback" data-vb-dropdown-eleven-feedback&gt;
          Choose an action from the dropdown menu.
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-eleven-demo,
.vb-dropdown-eleven-demo * {
  box-sizing: border-box;
}

.vb-dropdown-eleven-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 16%, rgba(99, 102, 241, 0.22), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(217, 70, 239, 0.18), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #faf5ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(199, 210, 254, 0.50);
  box-shadow: 0 24px 70px rgba(67, 56, 202, 0.12);
}

.vb-dropdown-eleven-workspace {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(340px, 0.72fr);
  gap: 32px;
  align-items: center;
  max-width: 1040px;
  min-height: 560px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(199, 210, 254, 0.44);
  box-shadow: 0 24px 70px rgba(67, 56, 202, 0.12);
  overflow: visible;
}

.vb-dropdown-eleven-intro &gt; span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #e0e7ff;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-eleven-intro h3 {
  max-width: 660px;
  margin: 0 0 16px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-eleven-intro p {
  max-width: 560px;
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-eleven-card {
  position: relative;
  z-index: 20;
  padding: 22px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 14%, rgba(129, 140, 248, 0.16), transparent 34%),
    linear-gradient(135deg, #111827 0%, #312e81 100%) !important;
  box-shadow: 0 30px 80px rgba(49, 46, 129, 0.28);
}

.vb-dropdown-eleven-card-top {
  position: relative;
  z-index: 40;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 52px;
}

.vb-dropdown-eleven-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 58px;
  height: 58px;
  border-radius: 20px;
  background: linear-gradient(135deg, #818cf8, #d946ef);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
  box-shadow: 0 18px 42px rgba(129, 140, 248, 0.30);
}

.vb-dropdown-eleven-menu-wrap {
  position: relative;
}

.vb-dropdown-eleven-trigger {
  display: inline-grid;
  place-items: center;
  gap: 4px;
  width: 46px;
  height: 46px;
  padding: 12px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 16px;
  background: rgba(255,255,255,0.12);
  cursor: pointer;
}

.vb-dropdown-eleven-trigger span {
  display: block;
  width: 5px;
  height: 5px;
  border-radius: 999px;
  background: #ffffff;
}

.vb-dropdown-eleven-menu {
  position: absolute;
  z-index: 60;
  top: calc(100% + 12px);
  right: 0;
  display: grid;
  gap: 6px;
  width: 230px;
  padding: 9px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 30px 80px rgba(2, 6, 23, 0.34);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-eleven-workspace.is-open .vb-dropdown-eleven-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-eleven-menu button {
  display: grid;
  grid-template-columns: 38px minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  width: 100%;
  min-height: 46px;
  padding: 9px;
  border: 0;
  border-radius: 15px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-eleven-menu button:hover {
  background: #f8fafc;
  transform: translateX(2px);
}

.vb-dropdown-eleven-menu button span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 14px;
  background: #eef2ff;
  font-size: 17px;
}

.vb-dropdown-eleven-menu button strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 900;
}

.vb-dropdown-eleven-menu .vb-dropdown-eleven-danger:hover {
  background: #fef2f2;
}

.vb-dropdown-eleven-menu .vb-dropdown-eleven-danger span {
  background: #fee2e2;
}

.vb-dropdown-eleven-menu .vb-dropdown-eleven-danger strong {
  color: #991b1b !important;
  -webkit-text-fill-color: #991b1b !important;
}

.vb-dropdown-eleven-body small {
  display: inline-flex;
  margin-bottom: 12px;
  color: #c7d2fe !important;
  -webkit-text-fill-color: #c7d2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-eleven-body h4 {
  margin: 0 0 12px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 32px !important;
  line-height: 1.05 !important;
  font-weight: 950 !important;
  letter-spacing: -0.05em;
}

.vb-dropdown-eleven-body p {
  margin: 0 0 18px !important;
  color: #ddd6fe !important;
  -webkit-text-fill-color: #ddd6fe !important;
  font-size: 15px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-dropdown-eleven-meta {
  display: flex;
  flex-wrap: wrap;
  gap: 9px;
  margin-bottom: 14px;
}

.vb-dropdown-eleven-meta span {
  display: inline-flex;
  align-items: center;
  min-height: 34px;
  padding: 8px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ede9fe !important;
  -webkit-text-fill-color: #ede9fe !important;
  font-size: 12px;
  line-height: 1;
  font-weight: 850;
}

.vb-dropdown-eleven-meta strong {
  margin-left: 4px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-eleven-feedback {
  padding: 13px;
  border-radius: 16px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.14);
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 13px;
  line-height: 1.45;
  font-weight: 750;
}

@media (max-width: 860px) {
  .vb-dropdown-eleven-workspace {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-eleven-card {
    max-width: 430px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-eleven-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-eleven-workspace {
    min-height: 700px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-eleven-intro h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-eleven-card {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-eleven-menu {
    right: -8px;
    width: min(82vw, 230px);
  }
}</pre>



<p class="wp-block-paragraph">This icon action dropdown is a practical pattern for modern admin interfaces because it keeps actions available without cluttering the UI. You can reuse it in content tables, dashboard cards, product lists, project boards, media libraries, file managers, and user management screens.</p>



<h2 class="wp-block-heading">12. Dropdown Menu with Images</h2>



<p class="wp-block-paragraph"><strong>A dropdown menu with images</strong> is useful when menu options need stronger visual context. Instead of using only text labels, this dropdown uses image-style thumbnails, titles, descriptions, and selected preview content to make each option easier to understand.</p>



<p class="wp-block-paragraph">This pattern works well for portfolio categories, product collections, destination selectors, service packages, template libraries, featured content menus, gallery filters, and visual navigation sections. The JavaScript updates the preview card whenever a dropdown option is selected.</p>



<ul class="wp-block-list">
<li>Dropdown options with image-style thumbnails</li>
<li>Selected option updates the preview card</li>
<li>Strong visual navigation layout</li>
<li>Outside click and Escape key support</li>
<li>Useful for product collections, portfolios, galleries, destinations, and template libraries</li>
</ul>



<div class="vb-dropdown-twelve-demo">
  <div class="vb-dropdown-twelve-gallery" data-vb-dropdown-twelve>
    <div class="vb-dropdown-twelve-preview">
      <div class="vb-dropdown-twelve-image vb-dropdown-twelve-image-a" data-vb-dropdown-twelve-image></div>

      <div class="vb-dropdown-twelve-preview-content">
        <span>Example 12</span>
        <h3 data-vb-dropdown-twelve-title>Portfolio Templates</h3>
        <p data-vb-dropdown-twelve-desc>Choose a visual category from the image dropdown and update the selected preview card instantly.</p>
      </div>
    </div>

    <div class="vb-dropdown-twelve-control">
      <label>Choose collection</label>

      <button type="button" class="vb-dropdown-twelve-trigger" data-vb-dropdown-twelve-trigger aria-expanded="false">
        <span data-vb-dropdown-twelve-current>Portfolio Templates</span>
        <em>⌄</em>
      </button>

      <div class="vb-dropdown-twelve-menu" data-vb-dropdown-twelve-menu>
        <button type="button" class="is-active" data-title="Portfolio Templates" data-desc="Choose a visual category from the image dropdown and update the selected preview card instantly." data-image="a">
          <span class="vb-dropdown-twelve-thumb vb-dropdown-twelve-thumb-a"></span>
          <span>
            <strong>Portfolio Templates</strong>
            <small>Creative layouts for designers and agencies</small>
          </span>
        </button>

        <button type="button" data-title="Product Collections" data-desc="Use image dropdowns to help users browse ecommerce collections with more visual context." data-image="b">
          <span class="vb-dropdown-twelve-thumb vb-dropdown-twelve-thumb-b"></span>
          <span>
            <strong>Product Collections</strong>
            <small>Visual ecommerce categories and featured items</small>
          </span>
        </button>

        <button type="button" data-title="Travel Destinations" data-desc="Image dropdowns are useful when users choose destinations, hotels, tours, or travel packages." data-image="c">
          <span class="vb-dropdown-twelve-thumb vb-dropdown-twelve-thumb-c"></span>
          <span>
            <strong>Travel Destinations</strong>
            <small>Destination cards, booking filters, and trip ideas</small>
          </span>
        </button>

        <button type="button" data-title="SaaS UI Sections" data-desc="Use visual dropdown options for template libraries, dashboard sections, and component pickers." data-image="d">
          <span class="vb-dropdown-twelve-thumb vb-dropdown-twelve-thumb-d"></span>
          <span>
            <strong>SaaS UI Sections</strong>
            <small>Dashboard blocks, app screens, and UI components</small>
          </span>
        </button>
      </div>
    </div>
  </div>
</div>

<style>
.vb-dropdown-twelve-demo,
.vb-dropdown-twelve-demo * {
  box-sizing: border-box;
}

.vb-dropdown-twelve-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 16% 18%, rgba(236, 72, 153, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(251, 146, 60, 0.18), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #fff7ed 52%, #ffffff 100%) !important;
  border: 1px solid rgba(251, 207, 232, 0.50);
  box-shadow: 0 24px 70px rgba(190, 24, 93, 0.12);
}

.vb-dropdown-twelve-gallery {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(330px, 0.72fr);
  gap: 32px;
  align-items: center;
  max-width: 1040px;
  min-height: 580px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(251, 207, 232, 0.55);
  box-shadow: 0 24px 70px rgba(190, 24, 93, 0.12);
  overflow: visible;
}

.vb-dropdown-twelve-preview {
  overflow: hidden;
  border-radius: 30px;
  background: #111827;
  box-shadow: 0 30px 80px rgba(15, 23, 42, 0.20);
}

.vb-dropdown-twelve-image {
  min-height: 310px;
  position: relative;
  overflow: hidden;
}

.vb-dropdown-twelve-image::before,
.vb-dropdown-twelve-image::after {
  content: "";
  position: absolute;
  border-radius: 999px;
  background: rgba(255,255,255,0.24);
}

.vb-dropdown-twelve-image::before {
  width: 170px;
  height: 170px;
  top: 42px;
  left: 42px;
}

.vb-dropdown-twelve-image::after {
  width: 220px;
  height: 220px;
  right: -40px;
  bottom: -50px;
}

.vb-dropdown-twelve-image-a {
  background: linear-gradient(135deg, #ec4899, #8b5cf6 55%, #2563eb) !important;
}

.vb-dropdown-twelve-image-b {
  background: linear-gradient(135deg, #fb923c, #f43f5e 55%, #7c2d12) !important;
}

.vb-dropdown-twelve-image-c {
  background: linear-gradient(135deg, #14b8a6, #06b6d4 55%, #1d4ed8) !important;
}

.vb-dropdown-twelve-image-d {
  background: linear-gradient(135deg, #0f172a, #4338ca 55%, #a855f7) !important;
}

.vb-dropdown-twelve-preview-content {
  padding: 28px;
}

.vb-dropdown-twelve-preview-content span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(236, 72, 153, 0.16);
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-twelve-preview-content h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 54px) !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-dropdown-twelve-preview-content p {
  margin: 0 !important;
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-dropdown-twelve-control {
  position: relative;
  z-index: 30;
  width: 100%;
}

.vb-dropdown-twelve-control label {
  display: block;
  margin: 0 0 10px;
  color: #9f1239 !important;
  -webkit-text-fill-color: #9f1239 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twelve-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  min-height: 64px;
  padding: 14px 16px;
  border: 1px solid rgba(244, 114, 182, 0.34);
  border-radius: 20px;
  background: #ffffff;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  box-shadow: 0 18px 44px rgba(190, 24, 93, 0.12);
  cursor: pointer;
  text-align: left;
}

.vb-dropdown-twelve-trigger span {
  overflow: hidden;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 16px;
  font-weight: 950;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.vb-dropdown-twelve-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  background: linear-gradient(135deg, #ec4899, #fb923c);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-twelve-gallery.is-open .vb-dropdown-twelve-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-twelve-menu {
  position: absolute;
  z-index: 60;
  top: calc(100% + 12px);
  left: 0;
  right: 0;
  display: grid;
  gap: 8px;
  padding: 10px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(244, 114, 182, 0.32);
  box-shadow: 0 30px 80px rgba(190, 24, 93, 0.24);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-twelve-gallery.is-open .vb-dropdown-twelve-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.vb-dropdown-twelve-menu button {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  width: 100%;
  padding: 10px;
  border: 0;
  border-radius: 17px;
  background: transparent;
  text-align: left;
  cursor: pointer;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-twelve-menu button:hover,
.vb-dropdown-twelve-menu button.is-active {
  background: #fff1f2;
  transform: translateX(2px);
}

.vb-dropdown-twelve-thumb {
  display: block;
  width: 64px;
  height: 54px;
  border-radius: 16px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.24);
}

.vb-dropdown-twelve-thumb-a {
  background: linear-gradient(135deg, #ec4899, #8b5cf6);
}

.vb-dropdown-twelve-thumb-b {
  background: linear-gradient(135deg, #fb923c, #f43f5e);
}

.vb-dropdown-twelve-thumb-c {
  background: linear-gradient(135deg, #14b8a6, #06b6d4);
}

.vb-dropdown-twelve-thumb-d {
  background: linear-gradient(135deg, #0f172a, #a855f7);
}

.vb-dropdown-twelve-menu strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-twelve-menu small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 700;
}

@media (max-width: 860px) {
  .vb-dropdown-twelve-gallery {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-twelve-control {
    max-width: 440px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-twelve-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twelve-gallery {
    min-height: 760px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-twelve-preview-content {
    padding: 22px;
  }

  .vb-dropdown-twelve-image {
    min-height: 240px;
  }

  .vb-dropdown-twelve-menu {
    max-height: 360px;
    overflow-y: auto;
  }
}
</style>

<script>
(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-twelve]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-twelve-trigger]");
  const current = dropdown.querySelector("[data-vb-dropdown-twelve-current]");
  const title = dropdown.querySelector("[data-vb-dropdown-twelve-title]");
  const desc = dropdown.querySelector("[data-vb-dropdown-twelve-desc]");
  const image = dropdown.querySelector("[data-vb-dropdown-twelve-image]");
  const options = dropdown.querySelectorAll("[data-title]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function updatePreview(option) {
    const selectedTitle = option.getAttribute("data-title");
    const selectedDesc = option.getAttribute("data-desc");
    const selectedImage = option.getAttribute("data-image");

    current.textContent = selectedTitle;
    title.textContent = selectedTitle;
    desc.textContent = selectedDesc;

    image.className = "vb-dropdown-twelve-image vb-dropdown-twelve-image-" + selectedImage;

    options.forEach(function (item) {
      item.classList.remove("is-active");
    });

    option.classList.add("is-active");
    closeDropdown();
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  options.forEach(function (option) {
    option.addEventListener("click", function () {
      updatePreview(option);
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-twelve]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-twelve-trigger]");
  const current = dropdown.querySelector("[data-vb-dropdown-twelve-current]");
  const title = dropdown.querySelector("[data-vb-dropdown-twelve-title]");
  const desc = dropdown.querySelector("[data-vb-dropdown-twelve-desc]");
  const image = dropdown.querySelector("[data-vb-dropdown-twelve-image]");
  const options = dropdown.querySelectorAll("[data-title]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function updatePreview(option) {
    const selectedTitle = option.getAttribute("data-title");
    const selectedDesc = option.getAttribute("data-desc");
    const selectedImage = option.getAttribute("data-image");

    current.textContent = selectedTitle;
    title.textContent = selectedTitle;
    desc.textContent = selectedDesc;

    image.className = "vb-dropdown-twelve-image vb-dropdown-twelve-image-" + selectedImage;

    options.forEach(function (item) {
      item.classList.remove("is-active");
    });

    option.classList.add("is-active");
    closeDropdown();
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  options.forEach(function (option) {
    option.addEventListener("click", function () {
      updatePreview(option);
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-twelve-demo"&gt;
  &lt;div class="vb-dropdown-twelve-gallery" data-vb-dropdown-twelve&gt;
    &lt;div class="vb-dropdown-twelve-preview"&gt;
      &lt;div class="vb-dropdown-twelve-image vb-dropdown-twelve-image-a" data-vb-dropdown-twelve-image&gt;&lt;/div&gt;

      &lt;div class="vb-dropdown-twelve-preview-content"&gt;
        &lt;span&gt;Example 12&lt;/span&gt;
        &lt;h3 data-vb-dropdown-twelve-title&gt;Portfolio Templates&lt;/h3&gt;
        &lt;p data-vb-dropdown-twelve-desc&gt;Choose a visual category from the image dropdown and update the selected preview card instantly.&lt;/p&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-dropdown-twelve-control"&gt;
      &lt;label&gt;Choose collection&lt;/label&gt;

      &lt;button type="button" class="vb-dropdown-twelve-trigger" data-vb-dropdown-twelve-trigger aria-expanded="false"&gt;
        &lt;span data-vb-dropdown-twelve-current&gt;Portfolio Templates&lt;/span&gt;
        &lt;em&gt;⌄&lt;/em&gt;
      &lt;/button&gt;

      &lt;div class="vb-dropdown-twelve-menu" data-vb-dropdown-twelve-menu&gt;
        &lt;button type="button" class="is-active" data-title="Portfolio Templates" data-desc="Choose a visual category from the image dropdown and update the selected preview card instantly." data-image="a"&gt;
          &lt;span class="vb-dropdown-twelve-thumb vb-dropdown-twelve-thumb-a"&gt;&lt;/span&gt;
          &lt;span&gt;
            &lt;strong&gt;Portfolio Templates&lt;/strong&gt;
            &lt;small&gt;Creative layouts for designers and agencies&lt;/small&gt;
          &lt;/span&gt;
        &lt;/button&gt;

        &lt;button type="button" data-title="Product Collections" data-desc="Use image dropdowns to help users browse ecommerce collections with more visual context." data-image="b"&gt;
          &lt;span class="vb-dropdown-twelve-thumb vb-dropdown-twelve-thumb-b"&gt;&lt;/span&gt;
          &lt;span&gt;
            &lt;strong&gt;Product Collections&lt;/strong&gt;
            &lt;small&gt;Visual ecommerce categories and featured items&lt;/small&gt;
          &lt;/span&gt;
        &lt;/button&gt;

        &lt;button type="button" data-title="Travel Destinations" data-desc="Image dropdowns are useful when users choose destinations, hotels, tours, or travel packages." data-image="c"&gt;
          &lt;span class="vb-dropdown-twelve-thumb vb-dropdown-twelve-thumb-c"&gt;&lt;/span&gt;
          &lt;span&gt;
            &lt;strong&gt;Travel Destinations&lt;/strong&gt;
            &lt;small&gt;Destination cards, booking filters, and trip ideas&lt;/small&gt;
          &lt;/span&gt;
        &lt;/button&gt;

        &lt;button type="button" data-title="SaaS UI Sections" data-desc="Use visual dropdown options for template libraries, dashboard sections, and component pickers." data-image="d"&gt;
          &lt;span class="vb-dropdown-twelve-thumb vb-dropdown-twelve-thumb-d"&gt;&lt;/span&gt;
          &lt;span&gt;
            &lt;strong&gt;SaaS UI Sections&lt;/strong&gt;
            &lt;small&gt;Dashboard blocks, app screens, and UI components&lt;/small&gt;
          &lt;/span&gt;
        &lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-twelve-demo,
.vb-dropdown-twelve-demo * {
  box-sizing: border-box;
}

.vb-dropdown-twelve-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 16% 18%, rgba(236, 72, 153, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(251, 146, 60, 0.18), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #fff7ed 52%, #ffffff 100%) !important;
  border: 1px solid rgba(251, 207, 232, 0.50);
  box-shadow: 0 24px 70px rgba(190, 24, 93, 0.12);
}

.vb-dropdown-twelve-gallery {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.95fr) minmax(330px, 0.72fr);
  gap: 32px;
  align-items: center;
  max-width: 1040px;
  min-height: 580px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(251, 207, 232, 0.55);
  box-shadow: 0 24px 70px rgba(190, 24, 93, 0.12);
  overflow: visible;
}

.vb-dropdown-twelve-preview {
  overflow: hidden;
  border-radius: 30px;
  background: #111827;
  box-shadow: 0 30px 80px rgba(15, 23, 42, 0.20);
}

.vb-dropdown-twelve-image {
  min-height: 310px;
  position: relative;
  overflow: hidden;
}

.vb-dropdown-twelve-image::before,
.vb-dropdown-twelve-image::after {
  content: "";
  position: absolute;
  border-radius: 999px;
  background: rgba(255,255,255,0.24);
}

.vb-dropdown-twelve-image::before {
  width: 170px;
  height: 170px;
  top: 42px;
  left: 42px;
}

.vb-dropdown-twelve-image::after {
  width: 220px;
  height: 220px;
  right: -40px;
  bottom: -50px;
}

.vb-dropdown-twelve-image-a {
  background: linear-gradient(135deg, #ec4899, #8b5cf6 55%, #2563eb) !important;
}

.vb-dropdown-twelve-image-b {
  background: linear-gradient(135deg, #fb923c, #f43f5e 55%, #7c2d12) !important;
}

.vb-dropdown-twelve-image-c {
  background: linear-gradient(135deg, #14b8a6, #06b6d4 55%, #1d4ed8) !important;
}

.vb-dropdown-twelve-image-d {
  background: linear-gradient(135deg, #0f172a, #4338ca 55%, #a855f7) !important;
}

.vb-dropdown-twelve-preview-content {
  padding: 28px;
}

.vb-dropdown-twelve-preview-content span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(236, 72, 153, 0.16);
  color: #fbcfe8 !important;
  -webkit-text-fill-color: #fbcfe8 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-twelve-preview-content h3 {
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(32px, 5vw, 54px) !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.07em;
}

.vb-dropdown-twelve-preview-content p {
  margin: 0 !important;
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 15px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-dropdown-twelve-control {
  position: relative;
  z-index: 30;
  width: 100%;
}

.vb-dropdown-twelve-control label {
  display: block;
  margin: 0 0 10px;
  color: #9f1239 !important;
  -webkit-text-fill-color: #9f1239 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twelve-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  min-height: 64px;
  padding: 14px 16px;
  border: 1px solid rgba(244, 114, 182, 0.34);
  border-radius: 20px;
  background: #ffffff;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  box-shadow: 0 18px 44px rgba(190, 24, 93, 0.12);
  cursor: pointer;
  text-align: left;
}

.vb-dropdown-twelve-trigger span {
  overflow: hidden;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 16px;
  font-weight: 950;
  white-space: nowrap;
  text-overflow: ellipsis;
}

.vb-dropdown-twelve-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  background: linear-gradient(135deg, #ec4899, #fb923c);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-twelve-gallery.is-open .vb-dropdown-twelve-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-twelve-menu {
  position: absolute;
  z-index: 60;
  top: calc(100% + 12px);
  left: 0;
  right: 0;
  display: grid;
  gap: 8px;
  padding: 10px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(244, 114, 182, 0.32);
  box-shadow: 0 30px 80px rgba(190, 24, 93, 0.24);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-twelve-gallery.is-open .vb-dropdown-twelve-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.vb-dropdown-twelve-menu button {
  display: grid;
  grid-template-columns: 64px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  width: 100%;
  padding: 10px;
  border: 0;
  border-radius: 17px;
  background: transparent;
  text-align: left;
  cursor: pointer;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-twelve-menu button:hover,
.vb-dropdown-twelve-menu button.is-active {
  background: #fff1f2;
  transform: translateX(2px);
}

.vb-dropdown-twelve-thumb {
  display: block;
  width: 64px;
  height: 54px;
  border-radius: 16px;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.24);
}

.vb-dropdown-twelve-thumb-a {
  background: linear-gradient(135deg, #ec4899, #8b5cf6);
}

.vb-dropdown-twelve-thumb-b {
  background: linear-gradient(135deg, #fb923c, #f43f5e);
}

.vb-dropdown-twelve-thumb-c {
  background: linear-gradient(135deg, #14b8a6, #06b6d4);
}

.vb-dropdown-twelve-thumb-d {
  background: linear-gradient(135deg, #0f172a, #a855f7);
}

.vb-dropdown-twelve-menu strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-twelve-menu small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 700;
}

@media (max-width: 860px) {
  .vb-dropdown-twelve-gallery {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-twelve-control {
    max-width: 440px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-twelve-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twelve-gallery {
    min-height: 760px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-twelve-preview-content {
    padding: 22px;
  }

  .vb-dropdown-twelve-image {
    min-height: 240px;
  }

  .vb-dropdown-twelve-menu {
    max-height: 360px;
    overflow-y: auto;
  }
}</pre>



<p class="wp-block-paragraph">This dropdown with images makes selection more visual and easier to understand. You can adapt it for template libraries, ecommerce collections, portfolio categories, travel destinations, visual filters, gallery menus, and service package selectors.</p>



<h2 class="wp-block-heading">13. Category Filter Dropdown</h2>



<p class="wp-block-paragraph"><strong>A category filter dropdown</strong> is useful for blogs, portfolios, ecommerce sections, resource libraries, documentation hubs, tutorials, case studies, and card-based content grids. It lets users choose one category from a dropdown and instantly filter the visible items.</p>



<p class="wp-block-paragraph">This example includes a category dropdown, active category state, live result count, filtered content cards, outside click closing, and Escape key support. It uses JavaScript to show only the cards that match the selected category.</p>



<ul class="wp-block-list">
<li>Category filter dropdown</li>
<li>Filters visible cards with JavaScript</li>
<li>Updates selected category and result count</li>
<li>Works without external libraries</li>
<li>Useful for blogs, portfolios, product grids, resource libraries, and case study sections</li>
</ul>



<div class="vb-dropdown-thirteen-demo">
  <div class="vb-dropdown-thirteen-board" data-vb-dropdown-thirteen>
    <div class="vb-dropdown-thirteen-head">
      <div>
        <span>Example 13</span>
        <h3>Category Filter Dropdown</h3>
        <p>Choose a content category and filter the visible cards instantly with vanilla JavaScript.</p>
      </div>

      <div class="vb-dropdown-thirteen-control">
        <button type="button" class="vb-dropdown-thirteen-trigger" data-vb-dropdown-thirteen-trigger aria-expanded="false">
          <span data-vb-dropdown-thirteen-current>All categories</span>
          <em>⌄</em>
        </button>

        <div class="vb-dropdown-thirteen-menu" data-vb-dropdown-thirteen-menu>
          <button type="button" class="is-active" data-filter="all">All categories</button>
          <button type="button" data-filter="javascript">JavaScript</button>
          <button type="button" data-filter="css">CSS</button>
          <button type="button" data-filter="ui">UI Design</button>
          <button type="button" data-filter="seo">SEO</button>
        </div>
      </div>
    </div>

    <div class="vb-dropdown-thirteen-count">
      <strong data-vb-dropdown-thirteen-count>6</strong>
      <span>items visible</span>
    </div>

    <div class="vb-dropdown-thirteen-grid" data-vb-dropdown-thirteen-grid>
      <article data-category="javascript">
        <small>JavaScript</small>
        <h4>Dropdown Menu Logic</h4>
        <p>Build click, outside close, and Escape key behavior for dropdown components.</p>
      </article>

      <article data-category="css">
        <small>CSS</small>
        <h4>Modern Card Layout</h4>
        <p>Create responsive card sections with spacing, shadows, and flexible grids.</p>
      </article>

      <article data-category="ui">
        <small>UI Design</small>
        <h4>Dashboard Interface</h4>
        <p>Design clean dashboard cards, actions, controls, and visual hierarchy.</p>
      </article>

      <article data-category="seo">
        <small>SEO</small>
        <h4>Structured Content</h4>
        <p>Plan article sections, headings, internal links, and search-friendly content.</p>
      </article>

      <article data-category="javascript">
        <small>JavaScript</small>
        <h4>Filter Components</h4>
        <p>Use data attributes to show and hide cards based on selected category.</p>
      </article>

      <article data-category="css">
        <small>CSS</small>
        <h4>Responsive Grid</h4>
        <p>Make content cards adapt from desktop grids to mobile-friendly layouts.</p>
      </article>
    </div>
  </div>
</div>

<style>
.vb-dropdown-thirteen-demo,
.vb-dropdown-thirteen-demo * {
  box-sizing: border-box;
}

.vb-dropdown-thirteen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(59, 130, 246, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(20, 184, 166, 0.18), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #ecfeff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(125, 211, 252, 0.36);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.11);
}

.vb-dropdown-thirteen-board {
  position: relative;
  max-width: 1080px;
  min-height: 620px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
  overflow: visible;
}

.vb-dropdown-thirteen-head {
  position: relative;
  z-index: 40;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 320px);
  gap: 28px;
  align-items: end;
  margin-bottom: 22px;
}

.vb-dropdown-thirteen-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #cffafe;
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-thirteen-head h3 {
  max-width: 720px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-thirteen-head p {
  max-width: 640px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-thirteen-control {
  position: relative;
  z-index: 50;
  width: 100%;
}

.vb-dropdown-thirteen-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  min-height: 62px;
  padding: 14px 16px;
  border: 1px solid rgba(14, 116, 144, 0.20);
  border-radius: 20px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  box-shadow: 0 16px 38px rgba(14, 116, 144, 0.10);
  cursor: pointer;
  text-align: left;
}

.vb-dropdown-thirteen-trigger span {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-thirteen-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  background: linear-gradient(135deg, #06b6d4, #0f766e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-thirteen-board.is-open .vb-dropdown-thirteen-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-thirteen-menu {
  position: absolute;
  z-index: 60;
  top: calc(100% + 12px);
  left: 0;
  right: 0;
  display: grid;
  gap: 7px;
  padding: 10px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 30px 80px rgba(15, 23, 42, 0.22);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-thirteen-board.is-open .vb-dropdown-thirteen-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.vb-dropdown-thirteen-menu button {
  width: 100%;
  min-height: 44px;
  padding: 10px 12px;
  border: 0;
  border-radius: 14px;
  background: transparent;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 850;
  text-align: left;
  cursor: pointer;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-thirteen-menu button:hover,
.vb-dropdown-thirteen-menu button.is-active {
  background: #ecfeff;
  transform: translateX(2px);
}

.vb-dropdown-thirteen-count {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 18px;
  padding: 11px 14px;
  border-radius: 999px;
  background: #0f172a;
}

.vb-dropdown-thirteen-count strong,
.vb-dropdown-thirteen-count span {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-thirteen-count strong {
  font-size: 20px;
  line-height: 1;
  font-weight: 950;
}

.vb-dropdown-thirteen-count span {
  font-size: 13px;
  font-weight: 850;
}

.vb-dropdown-thirteen-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.vb-dropdown-thirteen-grid article {
  min-height: 190px;
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 16% 14%, rgba(14, 165, 233, 0.12), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
  transition: transform 0.2s ease, opacity 0.2s ease;
}

.vb-dropdown-thirteen-grid article.is-hidden {
  display: none;
}

.vb-dropdown-thirteen-grid small {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #ecfeff;
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 12px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-dropdown-thirteen-grid h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 21px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-dropdown-thirteen-grid p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-dropdown-thirteen-head {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-thirteen-control {
    max-width: 360px;
  }

  .vb-dropdown-thirteen-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-dropdown-thirteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-thirteen-board {
    min-height: 780px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-thirteen-head h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-thirteen-control,
  .vb-dropdown-thirteen-grid {
    width: 100%;
  }

  .vb-dropdown-thirteen-grid {
    grid-template-columns: 1fr;
  }
}
</style>

<script>
(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-thirteen]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-thirteen-trigger]");
  const current = dropdown.querySelector("[data-vb-dropdown-thirteen-current]");
  const buttons = dropdown.querySelectorAll("[data-filter]");
  const cards = dropdown.querySelectorAll("[data-category]");
  const count = dropdown.querySelector("[data-vb-dropdown-thirteen-count]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function filterCards(filterValue, label) {
    let visibleCount = 0;

    cards.forEach(function (card) {
      const category = card.getAttribute("data-category");
      const shouldShow = filterValue === "all" || category === filterValue;

      card.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visibleCount += 1;
      }
    });

    count.textContent = visibleCount;
    current.textContent = label;
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      const filterValue = button.getAttribute("data-filter");
      const label = button.textContent.trim();

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      filterCards(filterValue, label);
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-thirteen]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-thirteen-trigger]");
  const current = dropdown.querySelector("[data-vb-dropdown-thirteen-current]");
  const buttons = dropdown.querySelectorAll("[data-filter]");
  const cards = dropdown.querySelectorAll("[data-category]");
  const count = dropdown.querySelector("[data-vb-dropdown-thirteen-count]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function filterCards(filterValue, label) {
    let visibleCount = 0;

    cards.forEach(function (card) {
      const category = card.getAttribute("data-category");
      const shouldShow = filterValue === "all" || category === filterValue;

      card.classList.toggle("is-hidden", !shouldShow);

      if (shouldShow) {
        visibleCount += 1;
      }
    });

    count.textContent = visibleCount;
    current.textContent = label;
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  buttons.forEach(function (button) {
    button.addEventListener("click", function () {
      const filterValue = button.getAttribute("data-filter");
      const label = button.textContent.trim();

      buttons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      filterCards(filterValue, label);
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-thirteen-demo"&gt;
  &lt;div class="vb-dropdown-thirteen-board" data-vb-dropdown-thirteen&gt;
    &lt;div class="vb-dropdown-thirteen-head"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 13&lt;/span&gt;
        &lt;h3&gt;Category Filter Dropdown&lt;/h3&gt;
        &lt;p&gt;Choose a content category and filter the visible cards instantly with vanilla JavaScript.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-thirteen-control"&gt;
        &lt;button type="button" class="vb-dropdown-thirteen-trigger" data-vb-dropdown-thirteen-trigger aria-expanded="false"&gt;
          &lt;span data-vb-dropdown-thirteen-current&gt;All categories&lt;/span&gt;
          &lt;em&gt;⌄&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-dropdown-thirteen-menu" data-vb-dropdown-thirteen-menu&gt;
          &lt;button type="button" class="is-active" data-filter="all"&gt;All categories&lt;/button&gt;
          &lt;button type="button" data-filter="javascript"&gt;JavaScript&lt;/button&gt;
          &lt;button type="button" data-filter="css"&gt;CSS&lt;/button&gt;
          &lt;button type="button" data-filter="ui"&gt;UI Design&lt;/button&gt;
          &lt;button type="button" data-filter="seo"&gt;SEO&lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-dropdown-thirteen-count"&gt;
      &lt;strong data-vb-dropdown-thirteen-count&gt;6&lt;/strong&gt;
      &lt;span&gt;items visible&lt;/span&gt;
    &lt;/div&gt;

    &lt;div class="vb-dropdown-thirteen-grid" data-vb-dropdown-thirteen-grid&gt;
      &lt;article data-category="javascript"&gt;
        &lt;small&gt;JavaScript&lt;/small&gt;
        &lt;h4&gt;Dropdown Menu Logic&lt;/h4&gt;
        &lt;p&gt;Build click, outside close, and Escape key behavior for dropdown components.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-category="css"&gt;
        &lt;small&gt;CSS&lt;/small&gt;
        &lt;h4&gt;Modern Card Layout&lt;/h4&gt;
        &lt;p&gt;Create responsive card sections with spacing, shadows, and flexible grids.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-category="ui"&gt;
        &lt;small&gt;UI Design&lt;/small&gt;
        &lt;h4&gt;Dashboard Interface&lt;/h4&gt;
        &lt;p&gt;Design clean dashboard cards, actions, controls, and visual hierarchy.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-category="seo"&gt;
        &lt;small&gt;SEO&lt;/small&gt;
        &lt;h4&gt;Structured Content&lt;/h4&gt;
        &lt;p&gt;Plan article sections, headings, internal links, and search-friendly content.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-category="javascript"&gt;
        &lt;small&gt;JavaScript&lt;/small&gt;
        &lt;h4&gt;Filter Components&lt;/h4&gt;
        &lt;p&gt;Use data attributes to show and hide cards based on selected category.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article data-category="css"&gt;
        &lt;small&gt;CSS&lt;/small&gt;
        &lt;h4&gt;Responsive Grid&lt;/h4&gt;
        &lt;p&gt;Make content cards adapt from desktop grids to mobile-friendly layouts.&lt;/p&gt;
      &lt;/article&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-thirteen-demo,
.vb-dropdown-thirteen-demo * {
  box-sizing: border-box;
}

.vb-dropdown-thirteen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(59, 130, 246, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(20, 184, 166, 0.18), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #ecfeff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(125, 211, 252, 0.36);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.11);
}

.vb-dropdown-thirteen-board {
  position: relative;
  max-width: 1080px;
  min-height: 620px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
  overflow: visible;
}

.vb-dropdown-thirteen-head {
  position: relative;
  z-index: 40;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 320px);
  gap: 28px;
  align-items: end;
  margin-bottom: 22px;
}

.vb-dropdown-thirteen-head span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #cffafe;
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-thirteen-head h3 {
  max-width: 720px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-thirteen-head p {
  max-width: 640px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-thirteen-control {
  position: relative;
  z-index: 50;
  width: 100%;
}

.vb-dropdown-thirteen-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  min-height: 62px;
  padding: 14px 16px;
  border: 1px solid rgba(14, 116, 144, 0.20);
  border-radius: 20px;
  background: #f8fafc;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  box-shadow: 0 16px 38px rgba(14, 116, 144, 0.10);
  cursor: pointer;
  text-align: left;
}

.vb-dropdown-thirteen-trigger span {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-thirteen-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  background: linear-gradient(135deg, #06b6d4, #0f766e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-thirteen-board.is-open .vb-dropdown-thirteen-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-thirteen-menu {
  position: absolute;
  z-index: 60;
  top: calc(100% + 12px);
  left: 0;
  right: 0;
  display: grid;
  gap: 7px;
  padding: 10px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 30px 80px rgba(15, 23, 42, 0.22);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-thirteen-board.is-open .vb-dropdown-thirteen-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.vb-dropdown-thirteen-menu button {
  width: 100%;
  min-height: 44px;
  padding: 10px 12px;
  border: 0;
  border-radius: 14px;
  background: transparent;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 850;
  text-align: left;
  cursor: pointer;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-thirteen-menu button:hover,
.vb-dropdown-thirteen-menu button.is-active {
  background: #ecfeff;
  transform: translateX(2px);
}

.vb-dropdown-thirteen-count {
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 18px;
  padding: 11px 14px;
  border-radius: 999px;
  background: #0f172a;
}

.vb-dropdown-thirteen-count strong,
.vb-dropdown-thirteen-count span {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-thirteen-count strong {
  font-size: 20px;
  line-height: 1;
  font-weight: 950;
}

.vb-dropdown-thirteen-count span {
  font-size: 13px;
  font-weight: 850;
}

.vb-dropdown-thirteen-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.vb-dropdown-thirteen-grid article {
  min-height: 190px;
  padding: 20px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 16% 14%, rgba(14, 165, 233, 0.12), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
  transition: transform 0.2s ease, opacity 0.2s ease;
}

.vb-dropdown-thirteen-grid article.is-hidden {
  display: none;
}

.vb-dropdown-thirteen-grid small {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #ecfeff;
  color: #0e7490 !important;
  -webkit-text-fill-color: #0e7490 !important;
  font-size: 12px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-dropdown-thirteen-grid h4 {
  margin: 0 0 10px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 21px !important;
  line-height: 1.15 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-dropdown-thirteen-grid p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

@media (max-width: 900px) {
  .vb-dropdown-thirteen-head {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-thirteen-control {
    max-width: 360px;
  }

  .vb-dropdown-thirteen-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb-dropdown-thirteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-thirteen-board {
    min-height: 780px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-thirteen-head h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-thirteen-control,
  .vb-dropdown-thirteen-grid {
    width: 100%;
  }

  .vb-dropdown-thirteen-grid {
    grid-template-columns: 1fr;
  }
}</pre>



<p class="wp-block-paragraph">This category filter dropdown is useful for any page where visitors need to browse grouped content without reloading the page. You can adapt it for blog categories, portfolio filters, ecommerce collections, case studies, resource cards, tutorials, and documentation hubs.</p>



<h2 class="wp-block-heading">14. Sort By Dropdown Menu</h2>



<p class="wp-block-paragraph"><strong>A sort by dropdown menu</strong> helps users reorder visible items based on price, popularity, rating, date, or alphabetical order. It is one of the most useful dropdown patterns for ecommerce stores, directories, job boards, blog archives, marketplace pages, and product comparison sections.</p>



<p class="wp-block-paragraph">This example uses a product-style listing layout with a sort dropdown, active option state, live sorting, updated label text, outside click closing, and Escape key support. The JavaScript reorders product cards based on data attributes.</p>



<ul class="wp-block-list">
<li>Sort by dropdown for listing pages</li>
<li>Sorts cards by price, rating, and name</li>
<li>Updates selected sort label</li>
<li>Uses data attributes for simple JavaScript sorting</li>
<li>Useful for ecommerce, directories, blogs, job boards, and marketplace interfaces</li>
</ul>



<div class="vb-dropdown-fourteen-demo">
  <div class="vb-dropdown-fourteen-listing" data-vb-dropdown-fourteen>
    <div class="vb-dropdown-fourteen-top">
      <div>
        <span>Example 14</span>
        <h3>Sort By Dropdown</h3>
        <p>Sort product cards by price, rating, or name using a compact JavaScript dropdown menu.</p>
      </div>

      <div class="vb-dropdown-fourteen-sort-wrap">
        <button type="button" class="vb-dropdown-fourteen-trigger" data-vb-dropdown-fourteen-trigger aria-expanded="false">
          <span data-vb-dropdown-fourteen-current>Sort: Featured</span>
          <em>⌄</em>
        </button>

        <div class="vb-dropdown-fourteen-menu" data-vb-dropdown-fourteen-menu>
          <button type="button" class="is-active" data-sort="featured">Featured</button>
          <button type="button" data-sort="price-low">Price: Low to High</button>
          <button type="button" data-sort="price-high">Price: High to Low</button>
          <button type="button" data-sort="rating">Highest Rated</button>
          <button type="button" data-sort="name">Name A–Z</button>
        </div>
      </div>
    </div>

    <div class="vb-dropdown-fourteen-products" data-vb-dropdown-fourteen-products>
      <article data-name="Analytics Dashboard" data-price="79" data-rating="4.9" data-featured="1">
        <div class="vb-dropdown-fourteen-product-art vb-dropdown-fourteen-art-a"></div>
        <small>Dashboard</small>
        <h4>Analytics Dashboard</h4>
        <div class="vb-dropdown-fourteen-product-meta">
          <strong>€79</strong>
          <span>4.9 rating</span>
        </div>
      </article>

      <article data-name="Booking UI Kit" data-price="49" data-rating="4.7" data-featured="2">
        <div class="vb-dropdown-fourteen-product-art vb-dropdown-fourteen-art-b"></div>
        <small>UI Kit</small>
        <h4>Booking UI Kit</h4>
        <div class="vb-dropdown-fourteen-product-meta">
          <strong>€49</strong>
          <span>4.7 rating</span>
        </div>
      </article>

      <article data-name="Checkout Components" data-price="39" data-rating="4.8" data-featured="3">
        <div class="vb-dropdown-fourteen-product-art vb-dropdown-fourteen-art-c"></div>
        <small>Ecommerce</small>
        <h4>Checkout Components</h4>
        <div class="vb-dropdown-fourteen-product-meta">
          <strong>€39</strong>
          <span>4.8 rating</span>
        </div>
      </article>

      <article data-name="Dropdown Bundle" data-price="29" data-rating="4.6" data-featured="4">
        <div class="vb-dropdown-fourteen-product-art vb-dropdown-fourteen-art-d"></div>
        <small>Components</small>
        <h4>Dropdown Bundle</h4>
        <div class="vb-dropdown-fourteen-product-meta">
          <strong>€29</strong>
          <span>4.6 rating</span>
        </div>
      </article>
    </div>
  </div>
</div>

<style>
.vb-dropdown-fourteen-demo,
.vb-dropdown-fourteen-demo * {
  box-sizing: border-box;
}

.vb-dropdown-fourteen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 15% 17%, rgba(251, 146, 60, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(234, 179, 8, 0.18), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fff7ed 52%, #ffffff 100%) !important;
  border: 1px solid rgba(253, 186, 116, 0.42);
  box-shadow: 0 24px 70px rgba(124, 45, 18, 0.11);
}

.vb-dropdown-fourteen-listing {
  position: relative;
  max-width: 1080px;
  min-height: 620px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(253, 186, 116, 0.30);
  box-shadow: 0 24px 70px rgba(124, 45, 18, 0.12);
  overflow: visible;
}

.vb-dropdown-fourteen-top {
  position: relative;
  z-index: 40;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 320px);
  gap: 28px;
  align-items: end;
  margin-bottom: 24px;
}

.vb-dropdown-fourteen-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-fourteen-top h3 {
  max-width: 720px;
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-fourteen-top p {
  max-width: 640px;
  margin: 0 !important;
  color: #6b7280 !important;
  -webkit-text-fill-color: #6b7280 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-fourteen-sort-wrap {
  position: relative;
  z-index: 50;
  width: 100%;
}

.vb-dropdown-fourteen-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  min-height: 62px;
  padding: 14px 16px;
  border: 1px solid rgba(249, 115, 22, 0.24);
  border-radius: 20px;
  background: #fff7ed;
  box-shadow: 0 16px 38px rgba(249, 115, 22, 0.12);
  cursor: pointer;
  text-align: left;
}

.vb-dropdown-fourteen-trigger span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-fourteen-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  background: linear-gradient(135deg, #fb923c, #f59e0b);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-fourteen-listing.is-open .vb-dropdown-fourteen-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-fourteen-menu {
  position: absolute;
  z-index: 60;
  top: calc(100% + 12px);
  left: 0;
  right: 0;
  display: grid;
  gap: 7px;
  padding: 10px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(253, 186, 116, 0.42);
  box-shadow: 0 30px 80px rgba(124, 45, 18, 0.22);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-fourteen-listing.is-open .vb-dropdown-fourteen-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.vb-dropdown-fourteen-menu button {
  width: 100%;
  min-height: 44px;
  padding: 10px 12px;
  border: 0;
  border-radius: 14px;
  background: transparent;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 850;
  text-align: left;
  cursor: pointer;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-fourteen-menu button:hover,
.vb-dropdown-fourteen-menu button.is-active {
  background: #fff7ed;
  transform: translateX(2px);
}

.vb-dropdown-fourteen-products {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-dropdown-fourteen-products article {
  min-height: 300px;
  padding: 16px;
  border-radius: 24px;
  background: #f9fafb;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
  transition: transform 0.2s ease;
}

.vb-dropdown-fourteen-products article:hover {
  transform: translateY(-3px);
}

.vb-dropdown-fourteen-product-art {
  height: 130px;
  margin-bottom: 16px;
  border-radius: 19px;
  position: relative;
  overflow: hidden;
}

.vb-dropdown-fourteen-product-art::before,
.vb-dropdown-fourteen-product-art::after {
  content: "";
  position: absolute;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
}

.vb-dropdown-fourteen-product-art::before {
  width: 70px;
  height: 70px;
  top: 22px;
  left: 18px;
}

.vb-dropdown-fourteen-product-art::after {
  width: 110px;
  height: 110px;
  right: -28px;
  bottom: -28px;
}

.vb-dropdown-fourteen-art-a {
  background: linear-gradient(135deg, #0f172a, #2563eb) !important;
}

.vb-dropdown-fourteen-art-b {
  background: linear-gradient(135deg, #fb923c, #f43f5e) !important;
}

.vb-dropdown-fourteen-art-c {
  background: linear-gradient(135deg, #14b8a6, #0f766e) !important;
}

.vb-dropdown-fourteen-art-d {
  background: linear-gradient(135deg, #8b5cf6, #ec4899) !important;
}

.vb-dropdown-fourteen-products small {
  display: inline-flex;
  margin-bottom: 12px;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-dropdown-fourteen-products h4 {
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 19px !important;
  line-height: 1.16 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-dropdown-fourteen-product-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: auto;
}

.vb-dropdown-fourteen-product-meta strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px;
  line-height: 1;
  font-weight: 950;
}

.vb-dropdown-fourteen-product-meta span {
  color: #f59e0b !important;
  -webkit-text-fill-color: #f59e0b !important;
  font-size: 13px;
  font-weight: 900;
}

@media (max-width: 980px) {
  .vb-dropdown-fourteen-products {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-dropdown-fourteen-top {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-fourteen-sort-wrap {
    max-width: 360px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-fourteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-fourteen-listing {
    min-height: 900px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-fourteen-top h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-fourteen-products {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-fourteen-sort-wrap {
    width: 100%;
  }
}
</style>

<script>
(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-fourteen]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-fourteen-trigger]");
  const current = dropdown.querySelector("[data-vb-dropdown-fourteen-current]");
  const menuButtons = dropdown.querySelectorAll("[data-sort]");
  const productWrap = dropdown.querySelector("[data-vb-dropdown-fourteen-products]");
  const originalItems = Array.from(productWrap.querySelectorAll("article"));

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function sortProducts(sortType) {
    const items = Array.from(productWrap.querySelectorAll("article"));

    items.sort(function (a, b) {
      if (sortType === "price-low") {
        return Number(a.dataset.price) - Number(b.dataset.price);
      }

      if (sortType === "price-high") {
        return Number(b.dataset.price) - Number(a.dataset.price);
      }

      if (sortType === "rating") {
        return Number(b.dataset.rating) - Number(a.dataset.rating);
      }

      if (sortType === "name") {
        return a.dataset.name.localeCompare(b.dataset.name);
      }

      return Number(a.dataset.featured) - Number(b.dataset.featured);
    });

    if (sortType === "featured") {
      originalItems.forEach(function (item) {
        productWrap.appendChild(item);
      });
      return;
    }

    items.forEach(function (item) {
      productWrap.appendChild(item);
    });
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  menuButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      const sortType = button.getAttribute("data-sort");
      const label = button.textContent.trim();

      menuButtons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      current.textContent = "Sort: " + label;
      sortProducts(sortType);
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-fourteen]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-fourteen-trigger]");
  const current = dropdown.querySelector("[data-vb-dropdown-fourteen-current]");
  const menuButtons = dropdown.querySelectorAll("[data-sort]");
  const productWrap = dropdown.querySelector("[data-vb-dropdown-fourteen-products]");
  const originalItems = Array.from(productWrap.querySelectorAll("article"));

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function sortProducts(sortType) {
    const items = Array.from(productWrap.querySelectorAll("article"));

    items.sort(function (a, b) {
      if (sortType === "price-low") {
        return Number(a.dataset.price) - Number(b.dataset.price);
      }

      if (sortType === "price-high") {
        return Number(b.dataset.price) - Number(a.dataset.price);
      }

      if (sortType === "rating") {
        return Number(b.dataset.rating) - Number(a.dataset.rating);
      }

      if (sortType === "name") {
        return a.dataset.name.localeCompare(b.dataset.name);
      }

      return Number(a.dataset.featured) - Number(b.dataset.featured);
    });

    if (sortType === "featured") {
      originalItems.forEach(function (item) {
        productWrap.appendChild(item);
      });
      return;
    }

    items.forEach(function (item) {
      productWrap.appendChild(item);
    });
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  menuButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      const sortType = button.getAttribute("data-sort");
      const label = button.textContent.trim();

      menuButtons.forEach(function (item) {
        item.classList.remove("is-active");
      });

      button.classList.add("is-active");
      current.textContent = "Sort: " + label;
      sortProducts(sortType);
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-fourteen-demo"&gt;
  &lt;div class="vb-dropdown-fourteen-listing" data-vb-dropdown-fourteen&gt;
    &lt;div class="vb-dropdown-fourteen-top"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 14&lt;/span&gt;
        &lt;h3&gt;Sort By Dropdown&lt;/h3&gt;
        &lt;p&gt;Sort product cards by price, rating, or name using a compact JavaScript dropdown menu.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-fourteen-sort-wrap"&gt;
        &lt;button type="button" class="vb-dropdown-fourteen-trigger" data-vb-dropdown-fourteen-trigger aria-expanded="false"&gt;
          &lt;span data-vb-dropdown-fourteen-current&gt;Sort: Featured&lt;/span&gt;
          &lt;em&gt;⌄&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-dropdown-fourteen-menu" data-vb-dropdown-fourteen-menu&gt;
          &lt;button type="button" class="is-active" data-sort="featured"&gt;Featured&lt;/button&gt;
          &lt;button type="button" data-sort="price-low"&gt;Price: Low to High&lt;/button&gt;
          &lt;button type="button" data-sort="price-high"&gt;Price: High to Low&lt;/button&gt;
          &lt;button type="button" data-sort="rating"&gt;Highest Rated&lt;/button&gt;
          &lt;button type="button" data-sort="name"&gt;Name A–Z&lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-dropdown-fourteen-products" data-vb-dropdown-fourteen-products&gt;
      &lt;article data-name="Analytics Dashboard" data-price="79" data-rating="4.9" data-featured="1"&gt;
        &lt;div class="vb-dropdown-fourteen-product-art vb-dropdown-fourteen-art-a"&gt;&lt;/div&gt;
        &lt;small&gt;Dashboard&lt;/small&gt;
        &lt;h4&gt;Analytics Dashboard&lt;/h4&gt;
        &lt;div class="vb-dropdown-fourteen-product-meta"&gt;
          &lt;strong&gt;€79&lt;/strong&gt;
          &lt;span&gt;4.9 rating&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-name="Booking UI Kit" data-price="49" data-rating="4.7" data-featured="2"&gt;
        &lt;div class="vb-dropdown-fourteen-product-art vb-dropdown-fourteen-art-b"&gt;&lt;/div&gt;
        &lt;small&gt;UI Kit&lt;/small&gt;
        &lt;h4&gt;Booking UI Kit&lt;/h4&gt;
        &lt;div class="vb-dropdown-fourteen-product-meta"&gt;
          &lt;strong&gt;€49&lt;/strong&gt;
          &lt;span&gt;4.7 rating&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-name="Checkout Components" data-price="39" data-rating="4.8" data-featured="3"&gt;
        &lt;div class="vb-dropdown-fourteen-product-art vb-dropdown-fourteen-art-c"&gt;&lt;/div&gt;
        &lt;small&gt;Ecommerce&lt;/small&gt;
        &lt;h4&gt;Checkout Components&lt;/h4&gt;
        &lt;div class="vb-dropdown-fourteen-product-meta"&gt;
          &lt;strong&gt;€39&lt;/strong&gt;
          &lt;span&gt;4.8 rating&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;

      &lt;article data-name="Dropdown Bundle" data-price="29" data-rating="4.6" data-featured="4"&gt;
        &lt;div class="vb-dropdown-fourteen-product-art vb-dropdown-fourteen-art-d"&gt;&lt;/div&gt;
        &lt;small&gt;Components&lt;/small&gt;
        &lt;h4&gt;Dropdown Bundle&lt;/h4&gt;
        &lt;div class="vb-dropdown-fourteen-product-meta"&gt;
          &lt;strong&gt;€29&lt;/strong&gt;
          &lt;span&gt;4.6 rating&lt;/span&gt;
        &lt;/div&gt;
      &lt;/article&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-fourteen-demo,
.vb-dropdown-fourteen-demo * {
  box-sizing: border-box;
}

.vb-dropdown-fourteen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 15% 17%, rgba(251, 146, 60, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(234, 179, 8, 0.18), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fff7ed 52%, #ffffff 100%) !important;
  border: 1px solid rgba(253, 186, 116, 0.42);
  box-shadow: 0 24px 70px rgba(124, 45, 18, 0.11);
}

.vb-dropdown-fourteen-listing {
  position: relative;
  max-width: 1080px;
  min-height: 620px;
  margin: 0 auto;
  padding: 34px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(253, 186, 116, 0.30);
  box-shadow: 0 24px 70px rgba(124, 45, 18, 0.12);
  overflow: visible;
}

.vb-dropdown-fourteen-top {
  position: relative;
  z-index: 40;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 320px);
  gap: 28px;
  align-items: end;
  margin-bottom: 24px;
}

.vb-dropdown-fourteen-top span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-fourteen-top h3 {
  max-width: 720px;
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 68px) !important;
  line-height: 0.98 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-fourteen-top p {
  max-width: 640px;
  margin: 0 !important;
  color: #6b7280 !important;
  -webkit-text-fill-color: #6b7280 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-fourteen-sort-wrap {
  position: relative;
  z-index: 50;
  width: 100%;
}

.vb-dropdown-fourteen-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  min-height: 62px;
  padding: 14px 16px;
  border: 1px solid rgba(249, 115, 22, 0.24);
  border-radius: 20px;
  background: #fff7ed;
  box-shadow: 0 16px 38px rgba(249, 115, 22, 0.12);
  cursor: pointer;
  text-align: left;
}

.vb-dropdown-fourteen-trigger span {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-fourteen-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  background: linear-gradient(135deg, #fb923c, #f59e0b);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-fourteen-listing.is-open .vb-dropdown-fourteen-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-fourteen-menu {
  position: absolute;
  z-index: 60;
  top: calc(100% + 12px);
  left: 0;
  right: 0;
  display: grid;
  gap: 7px;
  padding: 10px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(253, 186, 116, 0.42);
  box-shadow: 0 30px 80px rgba(124, 45, 18, 0.22);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px);
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-fourteen-listing.is-open .vb-dropdown-fourteen-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
}

.vb-dropdown-fourteen-menu button {
  width: 100%;
  min-height: 44px;
  padding: 10px 12px;
  border: 0;
  border-radius: 14px;
  background: transparent;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 850;
  text-align: left;
  cursor: pointer;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-fourteen-menu button:hover,
.vb-dropdown-fourteen-menu button.is-active {
  background: #fff7ed;
  transform: translateX(2px);
}

.vb-dropdown-fourteen-products {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 14px;
}

.vb-dropdown-fourteen-products article {
  min-height: 300px;
  padding: 16px;
  border-radius: 24px;
  background: #f9fafb;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
  transition: transform 0.2s ease;
}

.vb-dropdown-fourteen-products article:hover {
  transform: translateY(-3px);
}

.vb-dropdown-fourteen-product-art {
  height: 130px;
  margin-bottom: 16px;
  border-radius: 19px;
  position: relative;
  overflow: hidden;
}

.vb-dropdown-fourteen-product-art::before,
.vb-dropdown-fourteen-product-art::after {
  content: "";
  position: absolute;
  border-radius: 999px;
  background: rgba(255,255,255,0.26);
}

.vb-dropdown-fourteen-product-art::before {
  width: 70px;
  height: 70px;
  top: 22px;
  left: 18px;
}

.vb-dropdown-fourteen-product-art::after {
  width: 110px;
  height: 110px;
  right: -28px;
  bottom: -28px;
}

.vb-dropdown-fourteen-art-a {
  background: linear-gradient(135deg, #0f172a, #2563eb) !important;
}

.vb-dropdown-fourteen-art-b {
  background: linear-gradient(135deg, #fb923c, #f43f5e) !important;
}

.vb-dropdown-fourteen-art-c {
  background: linear-gradient(135deg, #14b8a6, #0f766e) !important;
}

.vb-dropdown-fourteen-art-d {
  background: linear-gradient(135deg, #8b5cf6, #ec4899) !important;
}

.vb-dropdown-fourteen-products small {
  display: inline-flex;
  margin-bottom: 12px;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-dropdown-fourteen-products h4 {
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 19px !important;
  line-height: 1.16 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb-dropdown-fourteen-product-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: auto;
}

.vb-dropdown-fourteen-product-meta strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px;
  line-height: 1;
  font-weight: 950;
}

.vb-dropdown-fourteen-product-meta span {
  color: #f59e0b !important;
  -webkit-text-fill-color: #f59e0b !important;
  font-size: 13px;
  font-weight: 900;
}

@media (max-width: 980px) {
  .vb-dropdown-fourteen-products {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .vb-dropdown-fourteen-top {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-fourteen-sort-wrap {
    max-width: 360px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-fourteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-fourteen-listing {
    min-height: 900px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-fourteen-top h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-fourteen-products {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-fourteen-sort-wrap {
    width: 100%;
  }
}</pre>



<p class="wp-block-paragraph">This sort by dropdown is a practical listing-page pattern because it lets users control how items are ordered. You can adapt it for WooCommerce product grids, blog archives, job listings, directories, marketplaces, course libraries, and comparison pages.</p>



<h2 class="wp-block-heading">15. Mega Dropdown Menu</h2>



<p class="wp-block-paragraph"><strong>A mega dropdown menu</strong> is useful for websites that have many important navigation links but still need a clean header. Instead of showing a long vertical dropdown, a mega menu can organize links into columns, feature blocks, categories, icons, and highlighted calls to action.</p>



<p class="wp-block-paragraph">This example uses a wide JavaScript mega dropdown with columns, featured sections, link groups, a promotional card, outside click closing, and Escape key support. It is a practical pattern for SaaS websites, ecommerce stores, agencies, documentation hubs, and content-heavy websites.</p>



<ul class="wp-block-list">
<li>Large mega dropdown menu</li>
<li>Column-based navigation layout</li>
<li>Featured card inside the dropdown</li>
<li>Outside click and Escape key support</li>
<li>Useful for SaaS websites, ecommerce stores, agencies, directories, and resource hubs</li>
</ul>



<div class="vb-dropdown-fifteen-demo">
  <div class="vb-dropdown-fifteen-page" data-vb-dropdown-fifteen>
    <header class="vb-dropdown-fifteen-header">
      <a class="vb-dropdown-fifteen-logo" href="#javascript-dropdown-menu-examples">
        <span>M</span>
        <strong>MegaFlow</strong>
      </a>

      <nav class="vb-dropdown-fifteen-nav" aria-label="Mega menu demo navigation">
        <a href="#what-is-a-javascript-dropdown-menu">Home</a>

        <div class="vb-dropdown-fifteen-wrap">
          <button type="button" class="vb-dropdown-fifteen-trigger" data-vb-dropdown-fifteen-trigger aria-expanded="false">
            Solutions
            <span>⌄</span>
          </button>

          <div class="vb-dropdown-fifteen-menu" data-vb-dropdown-fifteen-menu>
            <div class="vb-dropdown-fifteen-column">
              <h4>Build</h4>
              <a href="#javascript-dropdown-menu-examples">
                <span>⚡</span>
                <strong>JavaScript Components</strong>
                <small>Dropdowns, modals, sliders, and UI logic</small>
              </a>
              <a href="#why-javascript-dropdowns-matter">
                <span>🎨</span>
                <strong>Frontend Design</strong>
                <small>Responsive layouts and polished interfaces</small>
              </a>
              <a href="#what-should-a-good-javascript-dropdown-include">
                <span>🧩</span>
                <strong>Reusable UI Blocks</strong>
                <small>Components for real website projects</small>
              </a>
            </div>

            <div class="vb-dropdown-fifteen-column">
              <h4>Grow</h4>
              <a href="#javascript-dropdown-best-practices">
                <span>📈</span>
                <strong>SEO Content</strong>
                <small>Guides, structure, headings, and internal links</small>
              </a>
              <a href="#common-javascript-dropdown-mistakes">
                <span>🛒</span>
                <strong>Ecommerce UX</strong>
                <small>Product filters, carts, sorting, and menus</small>
              </a>
              <a href="#responsive-dropdown-design-tips">
                <span>📱</span>
                <strong>Mobile Experience</strong>
                <small>Touch-friendly dropdowns and navigation</small>
              </a>
            </div>

            <div class="vb-dropdown-fifteen-feature">
              <span>Featured</span>
              <h4>Complete dropdown UI system</h4>
              <p>Use mega dropdowns when your header needs more structure than a small menu can provide.</p>
              <a href="#javascript-dropdown-faq">Explore guide</a>
            </div>
          </div>
        </div>

        <a href="#javascript-dropdown-best-practices">Resources</a>
        <a href="#javascript-dropdown-faq">FAQ</a>
      </nav>

      <a class="vb-dropdown-fifteen-cta" href="#javascript-dropdown-menu-examples">View Examples</a>
    </header>

    <section class="vb-dropdown-fifteen-hero">
      <span>Example 15</span>
      <h3>Mega Dropdown Menu</h3>
      <p>A wide dropdown menu for websites that need columns, grouped links, featured blocks, and strong navigation structure.</p>
    </section>
  </div>
</div>

<style>
.vb-dropdown-fifteen-demo,
.vb-dropdown-fifteen-demo * {
  box-sizing: border-box;
}

.vb-dropdown-fifteen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(168, 85, 247, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(14, 165, 233, 0.18), transparent 34%),
    linear-gradient(135deg, #f5f3ff 0%, #ecfeff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(196, 181, 253, 0.40);
  box-shadow: 0 24px 70px rgba(76, 29, 149, 0.12);
}

.vb-dropdown-fifteen-page {
  position: relative;
  max-width: 1120px;
  min-height: 600px;
  margin: 0 auto;
  padding: 24px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 80% 80%, rgba(14, 165, 233, 0.12), transparent 32%),
    linear-gradient(135deg, #ffffff 0%, #f8fafc 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
  overflow: visible;
}

.vb-dropdown-fifteen-header {
  position: relative;
  z-index: 50;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 22px;
  align-items: center;
  padding: 14px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 20px 50px rgba(15, 23, 42, 0.12);
}

.vb-dropdown-fifteen-logo {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none !important;
}

.vb-dropdown-fifteen-logo span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: linear-gradient(135deg, #7c3aed, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-fifteen-logo strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-dropdown-fifteen-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.vb-dropdown-fifteen-nav > a,
.vb-dropdown-fifteen-trigger {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 42px;
  padding: 10px 13px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  line-height: 1;
  font-weight: 850;
  text-decoration: none !important;
  cursor: pointer;
  transition: background 0.18s ease, color 0.18s ease;
}

.vb-dropdown-fifteen-nav > a:hover,
.vb-dropdown-fifteen-trigger:hover,
.vb-dropdown-fifteen-page.is-open .vb-dropdown-fifteen-trigger {
  background: #f1f5f9;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
}

.vb-dropdown-fifteen-trigger span {
  transition: transform 0.2s ease;
}

.vb-dropdown-fifteen-page.is-open .vb-dropdown-fifteen-trigger span {
  transform: rotate(180deg);
}

.vb-dropdown-fifteen-wrap {
  position: relative;
}

.vb-dropdown-fifteen-menu {
  position: absolute;
  z-index: 70;
  top: calc(100% + 16px);
  left: 50%;
  display: grid;
  grid-template-columns: 1fr 1fr 280px;
  gap: 14px;
  width: min(900px, 90vw);
  padding: 14px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 34px 90px rgba(15, 23, 42, 0.24);
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, 14px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-fifteen-page.is-open .vb-dropdown-fifteen-menu {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0) scale(1);
}

.vb-dropdown-fifteen-column {
  padding: 12px;
  border-radius: 22px;
  background: #f8fafc;
}

.vb-dropdown-fifteen-column h4 {
  margin: 0 0 10px !important;
  padding: 0 4px;
  color: #4c1d95 !important;
  -webkit-text-fill-color: #4c1d95 !important;
  font-size: 13px !important;
  font-weight: 950 !important;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-fifteen-column a {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  padding: 12px;
  border-radius: 17px;
  text-decoration: none !important;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-fifteen-column a:hover {
  background: #ffffff;
  transform: translateX(2px);
  box-shadow: 0 12px 28px rgba(15, 23, 42, 0.08);
}

.vb-dropdown-fifteen-column a span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: #ede9fe;
  font-size: 18px;
}

.vb-dropdown-fifteen-column a strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-fifteen-column a small {
  display: block;
  margin-top: 3px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 650;
}

.vb-dropdown-fifteen-feature {
  padding: 22px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 16% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #4c1d95, #1d4ed8 58%, #0e7490) !important;
  box-shadow: 0 22px 54px rgba(29, 78, 216, 0.20);
}

.vb-dropdown-fifteen-feature > span {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-fifteen-feature h4 {
  margin: 0 0 10px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 25px !important;
  line-height: 1.05 !important;
  font-weight: 950 !important;
  letter-spacing: -0.05em;
}

.vb-dropdown-fifteen-feature p {
  margin: 0 0 18px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 13px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-dropdown-fifteen-feature a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 42px;
  padding: 10px 14px;
  border-radius: 999px;
  background: #ffffff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
}

.vb-dropdown-fifteen-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 42px;
  padding: 10px 15px;
  border-radius: 999px;
  background: linear-gradient(135deg, #7c3aed, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
  white-space: nowrap;
  box-shadow: 0 16px 34px rgba(124, 58, 237, 0.24);
}

.vb-dropdown-fifteen-hero {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 450px;
  padding: 54px 18px 18px;
}

.vb-dropdown-fifteen-hero > span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-fifteen-hero h3 {
  max-width: 740px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(38px, 6vw, 76px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-fifteen-hero p {
  max-width: 640px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 960px) {
  .vb-dropdown-fifteen-header {
    grid-template-columns: 1fr;
    align-items: start;
  }

  .vb-dropdown-fifteen-nav {
    justify-content: flex-start;
    flex-wrap: wrap;
  }

  .vb-dropdown-fifteen-menu {
    left: 0;
    grid-template-columns: 1fr;
    width: min(90vw, 620px);
    max-height: 520px;
    overflow-y: auto;
    transform: translate(0, 14px) scale(0.98);
  }

  .vb-dropdown-fifteen-page.is-open .vb-dropdown-fifteen-menu {
    transform: translate(0, 0) scale(1);
  }
}

@media (max-width: 640px) {
  .vb-dropdown-fifteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-fifteen-page {
    min-height: 780px;
    padding: 18px;
    border-radius: 22px;
  }

  .vb-dropdown-fifteen-nav {
    display: grid;
    width: 100%;
  }

  .vb-dropdown-fifteen-wrap,
  .vb-dropdown-fifteen-trigger,
  .vb-dropdown-fifteen-nav > a,
  .vb-dropdown-fifteen-cta {
    width: 100%;
    justify-content: center;
  }

  .vb-dropdown-fifteen-menu {
    width: 100%;
  }

  .vb-dropdown-fifteen-hero h3 {
    font-size: 38px !important;
  }
}
</style>

<script>
(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-fifteen]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-fifteen-trigger]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-fifteen]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-fifteen-trigger]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-fifteen-demo"&gt;
  &lt;div class="vb-dropdown-fifteen-page" data-vb-dropdown-fifteen&gt;
    &lt;header class="vb-dropdown-fifteen-header"&gt;
      &lt;a class="vb-dropdown-fifteen-logo" href="#javascript-dropdown-menu-examples"&gt;
        &lt;span&gt;M&lt;/span&gt;
        &lt;strong&gt;MegaFlow&lt;/strong&gt;
      &lt;/a&gt;

      &lt;nav class="vb-dropdown-fifteen-nav" aria-label="Mega menu demo navigation"&gt;
        &lt;a href="#what-is-a-javascript-dropdown-menu"&gt;Home&lt;/a&gt;

        &lt;div class="vb-dropdown-fifteen-wrap"&gt;
          &lt;button type="button" class="vb-dropdown-fifteen-trigger" data-vb-dropdown-fifteen-trigger aria-expanded="false"&gt;
            Solutions
            &lt;span&gt;⌄&lt;/span&gt;
          &lt;/button&gt;

          &lt;div class="vb-dropdown-fifteen-menu" data-vb-dropdown-fifteen-menu&gt;
            &lt;div class="vb-dropdown-fifteen-column"&gt;
              &lt;h4&gt;Build&lt;/h4&gt;
              &lt;a href="#javascript-dropdown-menu-examples"&gt;
                &lt;span&gt;⚡&lt;/span&gt;
                &lt;strong&gt;JavaScript Components&lt;/strong&gt;
                &lt;small&gt;Dropdowns, modals, sliders, and UI logic&lt;/small&gt;
              &lt;/a&gt;
              &lt;a href="#why-javascript-dropdowns-matter"&gt;
                &lt;span&gt;🎨&lt;/span&gt;
                &lt;strong&gt;Frontend Design&lt;/strong&gt;
                &lt;small&gt;Responsive layouts and polished interfaces&lt;/small&gt;
              &lt;/a&gt;
              &lt;a href="#what-should-a-good-javascript-dropdown-include"&gt;
                &lt;span&gt;🧩&lt;/span&gt;
                &lt;strong&gt;Reusable UI Blocks&lt;/strong&gt;
                &lt;small&gt;Components for real website projects&lt;/small&gt;
              &lt;/a&gt;
            &lt;/div&gt;

            &lt;div class="vb-dropdown-fifteen-column"&gt;
              &lt;h4&gt;Grow&lt;/h4&gt;
              &lt;a href="#javascript-dropdown-best-practices"&gt;
                &lt;span&gt;📈&lt;/span&gt;
                &lt;strong&gt;SEO Content&lt;/strong&gt;
                &lt;small&gt;Guides, structure, headings, and internal links&lt;/small&gt;
              &lt;/a&gt;
              &lt;a href="#common-javascript-dropdown-mistakes"&gt;
                &lt;span&gt;🛒&lt;/span&gt;
                &lt;strong&gt;Ecommerce UX&lt;/strong&gt;
                &lt;small&gt;Product filters, carts, sorting, and menus&lt;/small&gt;
              &lt;/a&gt;
              &lt;a href="#responsive-dropdown-design-tips"&gt;
                &lt;span&gt;📱&lt;/span&gt;
                &lt;strong&gt;Mobile Experience&lt;/strong&gt;
                &lt;small&gt;Touch-friendly dropdowns and navigation&lt;/small&gt;
              &lt;/a&gt;
            &lt;/div&gt;

            &lt;div class="vb-dropdown-fifteen-feature"&gt;
              &lt;span&gt;Featured&lt;/span&gt;
              &lt;h4&gt;Complete dropdown UI system&lt;/h4&gt;
              &lt;p&gt;Use mega dropdowns when your header needs more structure than a small menu can provide.&lt;/p&gt;
              &lt;a href="#javascript-dropdown-faq"&gt;Explore guide&lt;/a&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;

        &lt;a href="#javascript-dropdown-best-practices"&gt;Resources&lt;/a&gt;
        &lt;a href="#javascript-dropdown-faq"&gt;FAQ&lt;/a&gt;
      &lt;/nav&gt;

      &lt;a class="vb-dropdown-fifteen-cta" href="#javascript-dropdown-menu-examples"&gt;View Examples&lt;/a&gt;
    &lt;/header&gt;

    &lt;section class="vb-dropdown-fifteen-hero"&gt;
      &lt;span&gt;Example 15&lt;/span&gt;
      &lt;h3&gt;Mega Dropdown Menu&lt;/h3&gt;
      &lt;p&gt;A wide dropdown menu for websites that need columns, grouped links, featured blocks, and strong navigation structure.&lt;/p&gt;
    &lt;/section&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-fifteen-demo,
.vb-dropdown-fifteen-demo * {
  box-sizing: border-box;
}

.vb-dropdown-fifteen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(168, 85, 247, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(14, 165, 233, 0.18), transparent 34%),
    linear-gradient(135deg, #f5f3ff 0%, #ecfeff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(196, 181, 253, 0.40);
  box-shadow: 0 24px 70px rgba(76, 29, 149, 0.12);
}

.vb-dropdown-fifteen-page {
  position: relative;
  max-width: 1120px;
  min-height: 600px;
  margin: 0 auto;
  padding: 24px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 80% 80%, rgba(14, 165, 233, 0.12), transparent 32%),
    linear-gradient(135deg, #ffffff 0%, #f8fafc 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
  overflow: visible;
}

.vb-dropdown-fifteen-header {
  position: relative;
  z-index: 50;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 22px;
  align-items: center;
  padding: 14px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 20px 50px rgba(15, 23, 42, 0.12);
}

.vb-dropdown-fifteen-logo {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none !important;
}

.vb-dropdown-fifteen-logo span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: linear-gradient(135deg, #7c3aed, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-fifteen-logo strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 950;
  white-space: nowrap;
}

.vb-dropdown-fifteen-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.vb-dropdown-fifteen-nav &gt; a,
.vb-dropdown-fifteen-trigger {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 42px;
  padding: 10px 13px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: #334155 !important;
  -webkit-text-fill-color: #334155 !important;
  font-size: 14px;
  line-height: 1;
  font-weight: 850;
  text-decoration: none !important;
  cursor: pointer;
  transition: background 0.18s ease, color 0.18s ease;
}

.vb-dropdown-fifteen-nav &gt; a:hover,
.vb-dropdown-fifteen-trigger:hover,
.vb-dropdown-fifteen-page.is-open .vb-dropdown-fifteen-trigger {
  background: #f1f5f9;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
}

.vb-dropdown-fifteen-trigger span {
  transition: transform 0.2s ease;
}

.vb-dropdown-fifteen-page.is-open .vb-dropdown-fifteen-trigger span {
  transform: rotate(180deg);
}

.vb-dropdown-fifteen-wrap {
  position: relative;
}

.vb-dropdown-fifteen-menu {
  position: absolute;
  z-index: 70;
  top: calc(100% + 16px);
  left: 50%;
  display: grid;
  grid-template-columns: 1fr 1fr 280px;
  gap: 14px;
  width: min(900px, 90vw);
  padding: 14px;
  border-radius: 28px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 34px 90px rgba(15, 23, 42, 0.24);
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, 14px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-fifteen-page.is-open .vb-dropdown-fifteen-menu {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0) scale(1);
}

.vb-dropdown-fifteen-column {
  padding: 12px;
  border-radius: 22px;
  background: #f8fafc;
}

.vb-dropdown-fifteen-column h4 {
  margin: 0 0 10px !important;
  padding: 0 4px;
  color: #4c1d95 !important;
  -webkit-text-fill-color: #4c1d95 !important;
  font-size: 13px !important;
  font-weight: 950 !important;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-fifteen-column a {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  padding: 12px;
  border-radius: 17px;
  text-decoration: none !important;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-fifteen-column a:hover {
  background: #ffffff;
  transform: translateX(2px);
  box-shadow: 0 12px 28px rgba(15, 23, 42, 0.08);
}

.vb-dropdown-fifteen-column a span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: #ede9fe;
  font-size: 18px;
}

.vb-dropdown-fifteen-column a strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-fifteen-column a small {
  display: block;
  margin-top: 3px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 650;
}

.vb-dropdown-fifteen-feature {
  padding: 22px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 16% 18%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #4c1d95, #1d4ed8 58%, #0e7490) !important;
  box-shadow: 0 22px 54px rgba(29, 78, 216, 0.20);
}

.vb-dropdown-fifteen-feature &gt; span {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.16);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-fifteen-feature h4 {
  margin: 0 0 10px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 25px !important;
  line-height: 1.05 !important;
  font-weight: 950 !important;
  letter-spacing: -0.05em;
}

.vb-dropdown-fifteen-feature p {
  margin: 0 0 18px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 13px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-dropdown-fifteen-feature a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 42px;
  padding: 10px 14px;
  border-radius: 999px;
  background: #ffffff;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
}

.vb-dropdown-fifteen-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 42px;
  padding: 10px 15px;
  border-radius: 999px;
  background: linear-gradient(135deg, #7c3aed, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
  white-space: nowrap;
  box-shadow: 0 16px 34px rgba(124, 58, 237, 0.24);
}

.vb-dropdown-fifteen-hero {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 450px;
  padding: 54px 18px 18px;
}

.vb-dropdown-fifteen-hero &gt; span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ede9fe;
  color: #6d28d9 !important;
  -webkit-text-fill-color: #6d28d9 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-fifteen-hero h3 {
  max-width: 740px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(38px, 6vw, 76px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-fifteen-hero p {
  max-width: 640px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

@media (max-width: 960px) {
  .vb-dropdown-fifteen-header {
    grid-template-columns: 1fr;
    align-items: start;
  }

  .vb-dropdown-fifteen-nav {
    justify-content: flex-start;
    flex-wrap: wrap;
  }

  .vb-dropdown-fifteen-menu {
    left: 0;
    grid-template-columns: 1fr;
    width: min(90vw, 620px);
    max-height: 520px;
    overflow-y: auto;
    transform: translate(0, 14px) scale(0.98);
  }

  .vb-dropdown-fifteen-page.is-open .vb-dropdown-fifteen-menu {
    transform: translate(0, 0) scale(1);
  }
}

@media (max-width: 640px) {
  .vb-dropdown-fifteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-fifteen-page {
    min-height: 780px;
    padding: 18px;
    border-radius: 22px;
  }

  .vb-dropdown-fifteen-nav {
    display: grid;
    width: 100%;
  }

  .vb-dropdown-fifteen-wrap,
  .vb-dropdown-fifteen-trigger,
  .vb-dropdown-fifteen-nav &gt; a,
  .vb-dropdown-fifteen-cta {
    width: 100%;
    justify-content: center;
  }

  .vb-dropdown-fifteen-menu {
    width: 100%;
  }

  .vb-dropdown-fifteen-hero h3 {
    font-size: 38px !important;
  }
}</pre>



<p class="wp-block-paragraph">This mega dropdown menu is a strong pattern for websites that need more navigation depth without overwhelming the header. You can adapt it for SaaS features, ecommerce departments, agency services, documentation sections, course libraries, product categories, and resource hubs.</p>



<h2 class="wp-block-heading">16. Mobile Hamburger Dropdown Navigation</h2>



<p class="wp-block-paragraph"><strong>A mobile hamburger dropdown navigation</strong> is one of the most common JavaScript menu patterns for responsive websites. It lets small screens keep a clean header while still giving users access to important links, account actions, and call-to-action buttons.</p>



<p class="wp-block-paragraph">This example uses a mobile-style phone preview, animated hamburger button, slide-down navigation panel, active menu state, CTA button, outside click closing, and Escape key support. It is useful for business websites, portfolios, SaaS landing pages, ecommerce stores, and WordPress themes.</p>



<ul class="wp-block-list">
<li>Mobile hamburger dropdown menu</li>
<li>Animated open and close state</li>
<li>Slide-down navigation panel</li>
<li>Outside click and Escape key support</li>
<li>Useful for responsive websites, landing pages, ecommerce stores, and WordPress themes</li>
</ul>



<div class="vb-dropdown-sixteen-demo">
  <div class="vb-dropdown-sixteen-stage" data-vb-dropdown-sixteen>
    <div class="vb-dropdown-sixteen-copy">
      <span>Example 16</span>
      <h3>Mobile Hamburger Dropdown</h3>
      <p>Open the hamburger button to reveal a responsive dropdown navigation panel inside a mobile website header.</p>
    </div>

    <div class="vb-dropdown-sixteen-phone">
      <header class="vb-dropdown-sixteen-phone-header">
        <a class="vb-dropdown-sixteen-phone-logo" href="#javascript-dropdown-menu-examples">FlowApp</a>

        <button type="button" class="vb-dropdown-sixteen-hamburger" data-vb-dropdown-sixteen-trigger aria-expanded="false" aria-label="Open mobile menu">
          <span></span>
          <span></span>
          <span></span>
        </button>
      </header>

      <nav class="vb-dropdown-sixteen-menu" data-vb-dropdown-sixteen-menu aria-label="Mobile dropdown navigation">
        <a href="#what-is-a-javascript-dropdown-menu">
          <span>01</span>
          <strong>Overview</strong>
        </a>

        <a href="#javascript-dropdown-menu-examples">
          <span>02</span>
          <strong>Examples</strong>
        </a>

        <a href="#javascript-dropdown-best-practices">
          <span>03</span>
          <strong>Best Practices</strong>
        </a>

        <a href="#responsive-dropdown-design-tips">
          <span>04</span>
          <strong>Responsive Tips</strong>
        </a>

        <a class="vb-dropdown-sixteen-menu-cta" href="#javascript-dropdown-faq">Read FAQ</a>
      </nav>

      <section class="vb-dropdown-sixteen-screen">
        <span>Mobile UI</span>
        <h4>Responsive menu with JavaScript</h4>
        <p>This dropdown navigation keeps small screens clean while still giving users quick access to important links.</p>

        <div class="vb-dropdown-sixteen-dots">
          <span></span>
          <span></span>
          <span></span>
        </div>
      </section>
    </div>
  </div>
</div>

<style>
.vb-dropdown-sixteen-demo,
.vb-dropdown-sixteen-demo * {
  box-sizing: border-box;
}

.vb-dropdown-sixteen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 18% 16%, rgba(244, 63, 94, 0.18), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(59, 130, 246, 0.18), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #eff6ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(251, 207, 232, 0.42);
  box-shadow: 0 24px 70px rgba(136, 19, 55, 0.11);
}

.vb-dropdown-sixteen-stage {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(320px, 390px);
  gap: 34px;
  align-items: center;
  max-width: 1040px;
  min-height: 650px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(251, 207, 232, 0.46);
  box-shadow: 0 24px 70px rgba(136, 19, 55, 0.10);
  overflow: visible;
}

.vb-dropdown-sixteen-copy > span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-sixteen-copy h3 {
  max-width: 680px;
  margin: 0 0 16px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-sixteen-copy p {
  max-width: 560px;
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-sixteen-phone {
  position: relative;
  z-index: 20;
  min-height: 560px;
  padding: 16px;
  border-radius: 38px;
  background: #111827;
  border: 8px solid #020617;
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.32);
  overflow: visible;
}

.vb-dropdown-sixteen-phone-header {
  position: relative;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 14px;
  border-radius: 25px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-dropdown-sixteen-phone-logo {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  line-height: 1;
  font-weight: 950;
  text-decoration: none !important;
}

.vb-dropdown-sixteen-hamburger {
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 44px;
  height: 44px;
  padding: 0 12px;
  border: 0;
  border-radius: 16px;
  background: linear-gradient(135deg, #f43f5e, #3b82f6);
  cursor: pointer;
}

.vb-dropdown-sixteen-hamburger span {
  display: block;
  width: 100%;
  height: 2px;
  border-radius: 999px;
  background: #ffffff;
  transition: transform 0.22s ease, opacity 0.22s ease;
}

.vb-dropdown-sixteen-stage.is-open .vb-dropdown-sixteen-hamburger span:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}

.vb-dropdown-sixteen-stage.is-open .vb-dropdown-sixteen-hamburger span:nth-child(2) {
  opacity: 0;
}

.vb-dropdown-sixteen-stage.is-open .vb-dropdown-sixteen-hamburger span:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

.vb-dropdown-sixteen-menu {
  position: absolute;
  z-index: 50;
  top: 86px;
  left: 16px;
  right: 16px;
  display: grid;
  gap: 8px;
  padding: 12px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 80px rgba(2, 6, 23, 0.34);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-12px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.22s ease, visibility 0.22s ease, transform 0.22s ease;
}

.vb-dropdown-sixteen-stage.is-open .vb-dropdown-sixteen-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-sixteen-menu a {
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  min-height: 52px;
  padding: 10px;
  border-radius: 17px;
  text-decoration: none !important;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-sixteen-menu a:hover {
  background: #f8fafc;
  transform: translateX(2px);
}

.vb-dropdown-sixteen-menu a span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 15px;
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-dropdown-sixteen-menu a strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 15px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-sixteen-menu .vb-dropdown-sixteen-menu-cta {
  display: flex;
  justify-content: center;
  min-height: 46px;
  margin-top: 4px;
  border-radius: 999px;
  background: linear-gradient(135deg, #f43f5e, #3b82f6);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-dropdown-sixteen-screen {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 430px;
  padding: 34px 14px 14px;
}

.vb-dropdown-sixteen-screen > span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 12px;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(244, 63, 94, 0.18);
  color: #fecdd3 !important;
  -webkit-text-fill-color: #fecdd3 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-sixteen-screen h4 {
  margin: 0 0 12px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-dropdown-sixteen-screen p {
  margin: 0 0 22px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 14px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-dropdown-sixteen-dots {
  display: flex;
  gap: 8px;
}

.vb-dropdown-sixteen-dots span {
  width: 42px;
  height: 8px;
  border-radius: 999px;
  background: rgba(255,255,255,0.18);
}

.vb-dropdown-sixteen-dots span:first-child {
  background: linear-gradient(135deg, #f43f5e, #3b82f6);
}

@media (max-width: 860px) {
  .vb-dropdown-sixteen-stage {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-sixteen-phone {
    max-width: 390px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-sixteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-sixteen-stage {
    min-height: 820px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-sixteen-copy h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-sixteen-phone {
    width: 100%;
    min-height: 540px;
    border-width: 6px;
    border-radius: 30px;
  }
}
</style>

<script>
(function () {
  const menu = document.querySelector("[data-vb-dropdown-sixteen]");
  if (!menu) return;

  const trigger = menu.querySelector("[data-vb-dropdown-sixteen-trigger]");

  function closeMenu() {
    menu.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleMenu() {
    const isOpen = menu.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleMenu();
  });

  document.addEventListener("click", function (event) {
    if (!menu.contains(event.target)) {
      closeMenu();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeMenu();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const menu = document.querySelector("[data-vb-dropdown-sixteen]");
  if (!menu) return;

  const trigger = menu.querySelector("[data-vb-dropdown-sixteen-trigger]");

  function closeMenu() {
    menu.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleMenu() {
    const isOpen = menu.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleMenu();
  });

  document.addEventListener("click", function (event) {
    if (!menu.contains(event.target)) {
      closeMenu();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeMenu();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-sixteen-demo"&gt;
  &lt;div class="vb-dropdown-sixteen-stage" data-vb-dropdown-sixteen&gt;
    &lt;div class="vb-dropdown-sixteen-copy"&gt;
      &lt;span&gt;Example 16&lt;/span&gt;
      &lt;h3&gt;Mobile Hamburger Dropdown&lt;/h3&gt;
      &lt;p&gt;Open the hamburger button to reveal a responsive dropdown navigation panel inside a mobile website header.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-dropdown-sixteen-phone"&gt;
      &lt;header class="vb-dropdown-sixteen-phone-header"&gt;
        &lt;a class="vb-dropdown-sixteen-phone-logo" href="#javascript-dropdown-menu-examples"&gt;FlowApp&lt;/a&gt;

        &lt;button type="button" class="vb-dropdown-sixteen-hamburger" data-vb-dropdown-sixteen-trigger aria-expanded="false" aria-label="Open mobile menu"&gt;
          &lt;span&gt;&lt;/span&gt;
          &lt;span&gt;&lt;/span&gt;
          &lt;span&gt;&lt;/span&gt;
        &lt;/button&gt;
      &lt;/header&gt;

      &lt;nav class="vb-dropdown-sixteen-menu" data-vb-dropdown-sixteen-menu aria-label="Mobile dropdown navigation"&gt;
        &lt;a href="#what-is-a-javascript-dropdown-menu"&gt;
          &lt;span&gt;01&lt;/span&gt;
          &lt;strong&gt;Overview&lt;/strong&gt;
        &lt;/a&gt;

        &lt;a href="#javascript-dropdown-menu-examples"&gt;
          &lt;span&gt;02&lt;/span&gt;
          &lt;strong&gt;Examples&lt;/strong&gt;
        &lt;/a&gt;

        &lt;a href="#javascript-dropdown-best-practices"&gt;
          &lt;span&gt;03&lt;/span&gt;
          &lt;strong&gt;Best Practices&lt;/strong&gt;
        &lt;/a&gt;

        &lt;a href="#responsive-dropdown-design-tips"&gt;
          &lt;span&gt;04&lt;/span&gt;
          &lt;strong&gt;Responsive Tips&lt;/strong&gt;
        &lt;/a&gt;

        &lt;a class="vb-dropdown-sixteen-menu-cta" href="#javascript-dropdown-faq"&gt;Read FAQ&lt;/a&gt;
      &lt;/nav&gt;

      &lt;section class="vb-dropdown-sixteen-screen"&gt;
        &lt;span&gt;Mobile UI&lt;/span&gt;
        &lt;h4&gt;Responsive menu with JavaScript&lt;/h4&gt;
        &lt;p&gt;This dropdown navigation keeps small screens clean while still giving users quick access to important links.&lt;/p&gt;

        &lt;div class="vb-dropdown-sixteen-dots"&gt;
          &lt;span&gt;&lt;/span&gt;
          &lt;span&gt;&lt;/span&gt;
          &lt;span&gt;&lt;/span&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-sixteen-demo,
.vb-dropdown-sixteen-demo * {
  box-sizing: border-box;
}

.vb-dropdown-sixteen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 18% 16%, rgba(244, 63, 94, 0.18), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(59, 130, 246, 0.18), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #eff6ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(251, 207, 232, 0.42);
  box-shadow: 0 24px 70px rgba(136, 19, 55, 0.11);
}

.vb-dropdown-sixteen-stage {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(320px, 390px);
  gap: 34px;
  align-items: center;
  max-width: 1040px;
  min-height: 650px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(251, 207, 232, 0.46);
  box-shadow: 0 24px 70px rgba(136, 19, 55, 0.10);
  overflow: visible;
}

.vb-dropdown-sixteen-copy &gt; span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-sixteen-copy h3 {
  max-width: 680px;
  margin: 0 0 16px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-sixteen-copy p {
  max-width: 560px;
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-sixteen-phone {
  position: relative;
  z-index: 20;
  min-height: 560px;
  padding: 16px;
  border-radius: 38px;
  background: #111827;
  border: 8px solid #020617;
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.32);
  overflow: visible;
}

.vb-dropdown-sixteen-phone-header {
  position: relative;
  z-index: 60;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 14px;
  border-radius: 25px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-dropdown-sixteen-phone-logo {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  line-height: 1;
  font-weight: 950;
  text-decoration: none !important;
}

.vb-dropdown-sixteen-hamburger {
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 44px;
  height: 44px;
  padding: 0 12px;
  border: 0;
  border-radius: 16px;
  background: linear-gradient(135deg, #f43f5e, #3b82f6);
  cursor: pointer;
}

.vb-dropdown-sixteen-hamburger span {
  display: block;
  width: 100%;
  height: 2px;
  border-radius: 999px;
  background: #ffffff;
  transition: transform 0.22s ease, opacity 0.22s ease;
}

.vb-dropdown-sixteen-stage.is-open .vb-dropdown-sixteen-hamburger span:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}

.vb-dropdown-sixteen-stage.is-open .vb-dropdown-sixteen-hamburger span:nth-child(2) {
  opacity: 0;
}

.vb-dropdown-sixteen-stage.is-open .vb-dropdown-sixteen-hamburger span:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

.vb-dropdown-sixteen-menu {
  position: absolute;
  z-index: 50;
  top: 86px;
  left: 16px;
  right: 16px;
  display: grid;
  gap: 8px;
  padding: 12px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 30px 80px rgba(2, 6, 23, 0.34);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-12px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.22s ease, visibility 0.22s ease, transform 0.22s ease;
}

.vb-dropdown-sixteen-stage.is-open .vb-dropdown-sixteen-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-sixteen-menu a {
  display: grid;
  grid-template-columns: 40px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  min-height: 52px;
  padding: 10px;
  border-radius: 17px;
  text-decoration: none !important;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-sixteen-menu a:hover {
  background: #f8fafc;
  transform: translateX(2px);
}

.vb-dropdown-sixteen-menu a span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 15px;
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-dropdown-sixteen-menu a strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 15px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-sixteen-menu .vb-dropdown-sixteen-menu-cta {
  display: flex;
  justify-content: center;
  min-height: 46px;
  margin-top: 4px;
  border-radius: 999px;
  background: linear-gradient(135deg, #f43f5e, #3b82f6);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-dropdown-sixteen-screen {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 430px;
  padding: 34px 14px 14px;
}

.vb-dropdown-sixteen-screen &gt; span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 12px;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(244, 63, 94, 0.18);
  color: #fecdd3 !important;
  -webkit-text-fill-color: #fecdd3 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-sixteen-screen h4 {
  margin: 0 0 12px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-dropdown-sixteen-screen p {
  margin: 0 0 22px !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 14px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-dropdown-sixteen-dots {
  display: flex;
  gap: 8px;
}

.vb-dropdown-sixteen-dots span {
  width: 42px;
  height: 8px;
  border-radius: 999px;
  background: rgba(255,255,255,0.18);
}

.vb-dropdown-sixteen-dots span:first-child {
  background: linear-gradient(135deg, #f43f5e, #3b82f6);
}

@media (max-width: 860px) {
  .vb-dropdown-sixteen-stage {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-sixteen-phone {
    max-width: 390px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-sixteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-sixteen-stage {
    min-height: 820px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-sixteen-copy h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-sixteen-phone {
    width: 100%;
    min-height: 540px;
    border-width: 6px;
    border-radius: 30px;
  }
}</pre>



<p class="wp-block-paragraph">This mobile hamburger dropdown is one of the most reusable responsive navigation patterns. You can adapt it for WordPress themes, landing pages, ecommerce stores, SaaS sites, portfolio websites, and mobile-first web apps.</p>



<h2 class="wp-block-heading">17. Autocomplete Search Dropdown</h2>



<p class="wp-block-paragraph"><strong>An autocomplete search dropdown</strong> helps users find pages, products, categories, documentation entries, services, or search suggestions faster. As the user types, JavaScript filters the available suggestions and displays matching results inside a dropdown panel.</p>



<p class="wp-block-paragraph">This example includes a search input, live suggestion filtering, result count, selected result preview, empty state, keyboard-friendly Escape closing, and outside click closing. It is useful for search bars, ecommerce product search, documentation search, dashboard command search, and website navigation.</p>



<ul class="wp-block-list">
<li>Autocomplete dropdown search</li>
<li>Filters suggestions while typing</li>
<li>Updates selected result preview</li>
<li>Shows empty state when no matches exist</li>
<li>Useful for website search, product search, docs search, and app navigation</li>
</ul>



<div class="vb-dropdown-seventeen-demo">
  <div class="vb-dropdown-seventeen-search" data-vb-dropdown-seventeen>
    <div class="vb-dropdown-seventeen-copy">
      <span>Example 17</span>
      <h3>Autocomplete Search Dropdown</h3>
      <p>Start typing inside the search field and JavaScript will filter the dropdown suggestions instantly.</p>

      <div class="vb-dropdown-seventeen-selected">
        <small>Selected result</small>
        <strong data-vb-dropdown-seventeen-selected>No result selected yet</strong>
      </div>
    </div>

    <div class="vb-dropdown-seventeen-box">
      <label for="vb-dropdown-seventeen-input">Search components</label>

      <div class="vb-dropdown-seventeen-input-wrap">
        <span>⌕</span>
        <input id="vb-dropdown-seventeen-input" type="text" data-vb-dropdown-seventeen-input placeholder="Try typing: dropdown, modal, slider..." autocomplete="off">
      </div>

      <div class="vb-dropdown-seventeen-panel" data-vb-dropdown-seventeen-panel>
        <div class="vb-dropdown-seventeen-panel-head">
          <strong>Suggestions</strong>
          <small data-vb-dropdown-seventeen-count>6 results</small>
        </div>

        <div class="vb-dropdown-seventeen-results" data-vb-dropdown-seventeen-results>
          <button type="button" data-search-title="Dropdown Menu" data-search-category="JavaScript UI">
            <span>DM</span>
            <strong>Dropdown Menu</strong>
            <small>JavaScript UI</small>
          </button>

          <button type="button" data-search-title="Modal Window" data-search-category="JavaScript Component">
            <span>MW</span>
            <strong>Modal Window</strong>
            <small>JavaScript Component</small>
          </button>

          <button type="button" data-search-title="Image Slider" data-search-category="Carousel UI">
            <span>IS</span>
            <strong>Image Slider</strong>
            <small>Carousel UI</small>
          </button>

          <button type="button" data-search-title="Form Validation" data-search-category="Form UX">
            <span>FV</span>
            <strong>Form Validation</strong>
            <small>Form UX</small>
          </button>

          <button type="button" data-search-title="Product Filter" data-search-category="Ecommerce UI">
            <span>PF</span>
            <strong>Product Filter</strong>
            <small>Ecommerce UI</small>
          </button>

          <button type="button" data-search-title="Mobile Navigation" data-search-category="Responsive Menu">
            <span>MN</span>
            <strong>Mobile Navigation</strong>
            <small>Responsive Menu</small>
          </button>
        </div>

        <div class="vb-dropdown-seventeen-empty" data-vb-dropdown-seventeen-empty>
          <strong>No results found</strong>
          <small>Try another keyword or search term.</small>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-dropdown-seventeen-demo,
.vb-dropdown-seventeen-demo * {
  box-sizing: border-box;
}

.vb-dropdown-seventeen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(14, 165, 233, 0.22), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(99, 102, 241, 0.20), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(147, 197, 253, 0.46);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.12);
}

.vb-dropdown-seventeen-search {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(340px, 0.78fr);
  gap: 34px;
  align-items: center;
  max-width: 1040px;
  min-height: 620px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(147, 197, 253, 0.34);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.12);
  overflow: visible;
}

.vb-dropdown-seventeen-copy > span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-seventeen-copy h3 {
  max-width: 680px;
  margin: 0 0 16px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-seventeen-copy p {
  max-width: 560px;
  margin: 0 0 26px !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-seventeen-selected {
  width: min(100%, 380px);
  padding: 18px;
  border-radius: 22px;
  background: #0f172a;
  box-shadow: 0 22px 54px rgba(15, 23, 42, 0.22);
}

.vb-dropdown-seventeen-selected small {
  display: block;
  margin-bottom: 7px;
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-seventeen-selected strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1.15;
  font-weight: 950;
}

.vb-dropdown-seventeen-box {
  position: relative;
  z-index: 30;
  padding: 22px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 16%, rgba(59, 130, 246, 0.14), transparent 34%),
    linear-gradient(135deg, #0f172a, #1e3a8a) !important;
  box-shadow: 0 30px 80px rgba(30, 64, 175, 0.28);
}

.vb-dropdown-seventeen-box label {
  display: block;
  margin: 0 0 10px;
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-seventeen-input-wrap {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  min-height: 62px;
  padding: 9px 14px 9px 10px;
  border-radius: 20px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
}

.vb-dropdown-seventeen-input-wrap span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-dropdown-seventeen-input-wrap input {
  width: 100%;
  border: 0;
  outline: none;
  background: transparent;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 850;
}

.vb-dropdown-seventeen-input-wrap input::placeholder {
  color: rgba(255,255,255,0.68);
  -webkit-text-fill-color: rgba(255,255,255,0.68);
}

.vb-dropdown-seventeen-panel {
  position: absolute;
  z-index: 60;
  top: calc(100% + 12px);
  left: 22px;
  right: 22px;
  padding: 12px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 30px 80px rgba(2, 6, 23, 0.34);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-seventeen-search.is-open .vb-dropdown-seventeen-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-seventeen-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 8px 8px 12px;
  border-bottom: 1px solid #e5e7eb;
  margin-bottom: 8px;
}

.vb-dropdown-seventeen-panel-head strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-seventeen-panel-head small {
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 12px;
  font-weight: 900;
}

.vb-dropdown-seventeen-results {
  display: grid;
  gap: 7px;
  max-height: 310px;
  overflow-y: auto;
  padding-right: 4px;
}

.vb-dropdown-seventeen-results button {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  width: 100%;
  padding: 10px;
  border: 0;
  border-radius: 16px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-seventeen-results button:hover {
  background: #eff6ff;
  transform: translateX(2px);
}

.vb-dropdown-seventeen-results button span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-dropdown-seventeen-results button strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-seventeen-results button small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.3;
  font-weight: 700;
}

.vb-dropdown-seventeen-results button.is-hidden {
  display: none;
}

.vb-dropdown-seventeen-empty {
  display: none;
  padding: 22px 14px;
  border-radius: 18px;
  background: #f8fafc;
  text-align: center;
}

.vb-dropdown-seventeen-empty.is-visible {
  display: block;
}

.vb-dropdown-seventeen-empty strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-seventeen-empty small {
  display: block;
  margin-top: 5px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 700;
}

@media (max-width: 860px) {
  .vb-dropdown-seventeen-search {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-seventeen-box {
    max-width: 460px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-seventeen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-seventeen-search {
    min-height: 760px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-seventeen-copy h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-seventeen-box {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-seventeen-panel {
    left: 18px;
    right: 18px;
  }
}
</style>

<script>
(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-seventeen]");
  if (!dropdown) return;

  const input = dropdown.querySelector("[data-vb-dropdown-seventeen-input]");
  const results = dropdown.querySelectorAll("[data-search-title]");
  const count = dropdown.querySelector("[data-vb-dropdown-seventeen-count]");
  const empty = dropdown.querySelector("[data-vb-dropdown-seventeen-empty]");
  const selected = dropdown.querySelector("[data-vb-dropdown-seventeen-selected]");

  function openDropdown() {
    dropdown.classList.add("is-open");
  }

  function closeDropdown() {
    dropdown.classList.remove("is-open");
  }

  function filterResults() {
    const query = input.value.toLowerCase().trim();
    let visibleCount = 0;

    results.forEach(function (result) {
      const title = result.getAttribute("data-search-title").toLowerCase();
      const category = result.getAttribute("data-search-category").toLowerCase();
      const match = title.includes(query) || category.includes(query);

      result.classList.toggle("is-hidden", !match);

      if (match) {
        visibleCount += 1;
      }
    });

    count.textContent = visibleCount === 1 ? "1 result" : visibleCount + " results";
    empty.classList.toggle("is-visible", visibleCount === 0);
  }

  input.addEventListener("focus", function () {
    openDropdown();
    filterResults();
  });

  input.addEventListener("input", function () {
    openDropdown();
    filterResults();
  });

  results.forEach(function (result) {
    result.addEventListener("click", function () {
      const title = result.getAttribute("data-search-title");
      const category = result.getAttribute("data-search-category");

      input.value = title;
      selected.textContent = title + " — " + category;
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
      input.blur();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-seventeen]");
  if (!dropdown) return;

  const input = dropdown.querySelector("[data-vb-dropdown-seventeen-input]");
  const results = dropdown.querySelectorAll("[data-search-title]");
  const count = dropdown.querySelector("[data-vb-dropdown-seventeen-count]");
  const empty = dropdown.querySelector("[data-vb-dropdown-seventeen-empty]");
  const selected = dropdown.querySelector("[data-vb-dropdown-seventeen-selected]");

  function openDropdown() {
    dropdown.classList.add("is-open");
  }

  function closeDropdown() {
    dropdown.classList.remove("is-open");
  }

  function filterResults() {
    const query = input.value.toLowerCase().trim();
    let visibleCount = 0;

    results.forEach(function (result) {
      const title = result.getAttribute("data-search-title").toLowerCase();
      const category = result.getAttribute("data-search-category").toLowerCase();
      const match = title.includes(query) || category.includes(query);

      result.classList.toggle("is-hidden", !match);

      if (match) {
        visibleCount += 1;
      }
    });

    count.textContent = visibleCount === 1 ? "1 result" : visibleCount + " results";
    empty.classList.toggle("is-visible", visibleCount === 0);
  }

  input.addEventListener("focus", function () {
    openDropdown();
    filterResults();
  });

  input.addEventListener("input", function () {
    openDropdown();
    filterResults();
  });

  results.forEach(function (result) {
    result.addEventListener("click", function () {
      const title = result.getAttribute("data-search-title");
      const category = result.getAttribute("data-search-category");

      input.value = title;
      selected.textContent = title + " — " + category;
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
      input.blur();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-seventeen-demo"&gt;
  &lt;div class="vb-dropdown-seventeen-search" data-vb-dropdown-seventeen&gt;
    &lt;div class="vb-dropdown-seventeen-copy"&gt;
      &lt;span&gt;Example 17&lt;/span&gt;
      &lt;h3&gt;Autocomplete Search Dropdown&lt;/h3&gt;
      &lt;p&gt;Start typing inside the search field and JavaScript will filter the dropdown suggestions instantly.&lt;/p&gt;

      &lt;div class="vb-dropdown-seventeen-selected"&gt;
        &lt;small&gt;Selected result&lt;/small&gt;
        &lt;strong data-vb-dropdown-seventeen-selected&gt;No result selected yet&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-dropdown-seventeen-box"&gt;
      &lt;label for="vb-dropdown-seventeen-input"&gt;Search components&lt;/label&gt;

      &lt;div class="vb-dropdown-seventeen-input-wrap"&gt;
        &lt;span&gt;⌕&lt;/span&gt;
        &lt;input id="vb-dropdown-seventeen-input" type="text" data-vb-dropdown-seventeen-input placeholder="Try typing: dropdown, modal, slider..." autocomplete="off"&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-seventeen-panel" data-vb-dropdown-seventeen-panel&gt;
        &lt;div class="vb-dropdown-seventeen-panel-head"&gt;
          &lt;strong&gt;Suggestions&lt;/strong&gt;
          &lt;small data-vb-dropdown-seventeen-count&gt;6 results&lt;/small&gt;
        &lt;/div&gt;

        &lt;div class="vb-dropdown-seventeen-results" data-vb-dropdown-seventeen-results&gt;
          &lt;button type="button" data-search-title="Dropdown Menu" data-search-category="JavaScript UI"&gt;
            &lt;span&gt;DM&lt;/span&gt;
            &lt;strong&gt;Dropdown Menu&lt;/strong&gt;
            &lt;small&gt;JavaScript UI&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-search-title="Modal Window" data-search-category="JavaScript Component"&gt;
            &lt;span&gt;MW&lt;/span&gt;
            &lt;strong&gt;Modal Window&lt;/strong&gt;
            &lt;small&gt;JavaScript Component&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-search-title="Image Slider" data-search-category="Carousel UI"&gt;
            &lt;span&gt;IS&lt;/span&gt;
            &lt;strong&gt;Image Slider&lt;/strong&gt;
            &lt;small&gt;Carousel UI&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-search-title="Form Validation" data-search-category="Form UX"&gt;
            &lt;span&gt;FV&lt;/span&gt;
            &lt;strong&gt;Form Validation&lt;/strong&gt;
            &lt;small&gt;Form UX&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-search-title="Product Filter" data-search-category="Ecommerce UI"&gt;
            &lt;span&gt;PF&lt;/span&gt;
            &lt;strong&gt;Product Filter&lt;/strong&gt;
            &lt;small&gt;Ecommerce UI&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-search-title="Mobile Navigation" data-search-category="Responsive Menu"&gt;
            &lt;span&gt;MN&lt;/span&gt;
            &lt;strong&gt;Mobile Navigation&lt;/strong&gt;
            &lt;small&gt;Responsive Menu&lt;/small&gt;
          &lt;/button&gt;
        &lt;/div&gt;

        &lt;div class="vb-dropdown-seventeen-empty" data-vb-dropdown-seventeen-empty&gt;
          &lt;strong&gt;No results found&lt;/strong&gt;
          &lt;small&gt;Try another keyword or search term.&lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-seventeen-demo,
.vb-dropdown-seventeen-demo * {
  box-sizing: border-box;
}

.vb-dropdown-seventeen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(14, 165, 233, 0.22), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(99, 102, 241, 0.20), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(147, 197, 253, 0.46);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.12);
}

.vb-dropdown-seventeen-search {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(340px, 0.78fr);
  gap: 34px;
  align-items: center;
  max-width: 1040px;
  min-height: 620px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(147, 197, 253, 0.34);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.12);
  overflow: visible;
}

.vb-dropdown-seventeen-copy &gt; span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-seventeen-copy h3 {
  max-width: 680px;
  margin: 0 0 16px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-seventeen-copy p {
  max-width: 560px;
  margin: 0 0 26px !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-seventeen-selected {
  width: min(100%, 380px);
  padding: 18px;
  border-radius: 22px;
  background: #0f172a;
  box-shadow: 0 22px 54px rgba(15, 23, 42, 0.22);
}

.vb-dropdown-seventeen-selected small {
  display: block;
  margin-bottom: 7px;
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-seventeen-selected strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1.15;
  font-weight: 950;
}

.vb-dropdown-seventeen-box {
  position: relative;
  z-index: 30;
  padding: 22px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 16%, rgba(59, 130, 246, 0.14), transparent 34%),
    linear-gradient(135deg, #0f172a, #1e3a8a) !important;
  box-shadow: 0 30px 80px rgba(30, 64, 175, 0.28);
}

.vb-dropdown-seventeen-box label {
  display: block;
  margin: 0 0 10px;
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-seventeen-input-wrap {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  min-height: 62px;
  padding: 9px 14px 9px 10px;
  border-radius: 20px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.16);
}

.vb-dropdown-seventeen-input-wrap span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  font-weight: 950;
}

.vb-dropdown-seventeen-input-wrap input {
  width: 100%;
  border: 0;
  outline: none;
  background: transparent;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 850;
}

.vb-dropdown-seventeen-input-wrap input::placeholder {
  color: rgba(255,255,255,0.68);
  -webkit-text-fill-color: rgba(255,255,255,0.68);
}

.vb-dropdown-seventeen-panel {
  position: absolute;
  z-index: 60;
  top: calc(100% + 12px);
  left: 22px;
  right: 22px;
  padding: 12px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 30px 80px rgba(2, 6, 23, 0.34);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-seventeen-search.is-open .vb-dropdown-seventeen-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-seventeen-panel-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 8px 8px 12px;
  border-bottom: 1px solid #e5e7eb;
  margin-bottom: 8px;
}

.vb-dropdown-seventeen-panel-head strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-seventeen-panel-head small {
  color: #2563eb !important;
  -webkit-text-fill-color: #2563eb !important;
  font-size: 12px;
  font-weight: 900;
}

.vb-dropdown-seventeen-results {
  display: grid;
  gap: 7px;
  max-height: 310px;
  overflow-y: auto;
  padding-right: 4px;
}

.vb-dropdown-seventeen-results button {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  width: 100%;
  padding: 10px;
  border: 0;
  border-radius: 16px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-seventeen-results button:hover {
  background: #eff6ff;
  transform: translateX(2px);
}

.vb-dropdown-seventeen-results button span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 12px;
  font-weight: 950;
}

.vb-dropdown-seventeen-results button strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-seventeen-results button small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.3;
  font-weight: 700;
}

.vb-dropdown-seventeen-results button.is-hidden {
  display: none;
}

.vb-dropdown-seventeen-empty {
  display: none;
  padding: 22px 14px;
  border-radius: 18px;
  background: #f8fafc;
  text-align: center;
}

.vb-dropdown-seventeen-empty.is-visible {
  display: block;
}

.vb-dropdown-seventeen-empty strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-seventeen-empty small {
  display: block;
  margin-top: 5px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 700;
}

@media (max-width: 860px) {
  .vb-dropdown-seventeen-search {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-seventeen-box {
    max-width: 460px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-seventeen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-seventeen-search {
    min-height: 760px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-seventeen-copy h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-seventeen-box {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-seventeen-panel {
    left: 18px;
    right: 18px;
  }
}</pre>



<p class="wp-block-paragraph">This autocomplete dropdown is a strong pattern for search-heavy interfaces. You can adapt it for product search, blog search, documentation search, app navigation, location search, service search, and dashboard quick find tools.</p>



<h2 class="wp-block-heading">18. Command Palette Dropdown</h2>



<p class="wp-block-paragraph"><strong>A command palette dropdown</strong> is a modern app-style menu that lets users quickly run actions, navigate sections, open settings, or search interface commands. It is common in SaaS products, dashboards, admin panels, developer tools, productivity apps, and advanced web applications.</p>



<p class="wp-block-paragraph">This example uses a keyboard-style trigger button, command search input, filtered command list, selected command feedback, empty state, outside click closing, and Escape key support. The design is intentionally darker and more app-like to create variety from the previous examples.</p>



<ul class="wp-block-list">
<li>Modern command palette dropdown</li>
<li>Searchable command list</li>
<li>Updates selected command feedback</li>
<li>Dark app-style interface</li>
<li>Useful for dashboards, SaaS apps, admin panels, developer tools, and productivity interfaces</li>
</ul>



<div class="vb-dropdown-eighteen-demo">
  <div class="vb-dropdown-eighteen-app" data-vb-dropdown-eighteen>
    <div class="vb-dropdown-eighteen-sidebar">
      <span>APP</span>
      <a href="#javascript-dropdown-menu-examples">Dashboard</a>
      <a href="#javascript-dropdown-best-practices">Projects</a>
      <a href="#responsive-dropdown-design-tips">Settings</a>
    </div>

    <main class="vb-dropdown-eighteen-main">
      <div class="vb-dropdown-eighteen-top">
        <div>
          <span>Example 18</span>
          <h3>Command Palette Dropdown</h3>
          <p>Open a searchable command menu and select an action from the dropdown list.</p>
        </div>

        <button type="button" class="vb-dropdown-eighteen-open" data-vb-dropdown-eighteen-trigger aria-expanded="false">
          <span>⌘</span>
          Open commands
          <em>K</em>
        </button>
      </div>

      <div class="vb-dropdown-eighteen-status">
        <small>Last selected command</small>
        <strong data-vb-dropdown-eighteen-status>No command selected yet</strong>
      </div>
    </main>

    <div class="vb-dropdown-eighteen-overlay" data-vb-dropdown-eighteen-overlay>
      <div class="vb-dropdown-eighteen-palette" data-vb-dropdown-eighteen-palette>
        <div class="vb-dropdown-eighteen-search">
          <span>⌕</span>
          <input type="text" data-vb-dropdown-eighteen-input placeholder="Search commands..." autocomplete="off">
        </div>

        <div class="vb-dropdown-eighteen-list" data-vb-dropdown-eighteen-list>
          <button type="button" data-command="Create new project" data-keyword="create project new">
            <span>＋</span>
            <strong>Create new project</strong>
            <small>Start a new workspace item</small>
          </button>

          <button type="button" data-command="Open dashboard" data-keyword="open dashboard analytics">
            <span>⌂</span>
            <strong>Open dashboard</strong>
            <small>Go to dashboard overview</small>
          </button>

          <button type="button" data-command="Search documentation" data-keyword="search docs documentation help">
            <span>?</span>
            <strong>Search documentation</strong>
            <small>Find guides and answers</small>
          </button>

          <button type="button" data-command="Toggle dark mode" data-keyword="toggle dark mode theme">
            <span>◐</span>
            <strong>Toggle dark mode</strong>
            <small>Switch interface appearance</small>
          </button>

          <button type="button" data-command="Invite team member" data-keyword="invite team member user">
            <span>👥</span>
            <strong>Invite team member</strong>
            <small>Add someone to this workspace</small>
          </button>

          <button type="button" data-command="Open account settings" data-keyword="settings account profile">
            <span>⚙</span>
            <strong>Open account settings</strong>
            <small>Manage profile and preferences</small>
          </button>
        </div>

        <div class="vb-dropdown-eighteen-empty" data-vb-dropdown-eighteen-empty>
          <strong>No command found</strong>
          <small>Try another keyword.</small>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-dropdown-eighteen-demo,
.vb-dropdown-eighteen-demo * {
  box-sizing: border-box;
}

.vb-dropdown-eighteen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 18% 16%, rgba(34, 211, 238, 0.18), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(168, 85, 247, 0.20), transparent 34%),
    linear-gradient(135deg, #020617 0%, #111827 52%, #1e1b4b 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.18);
  box-shadow: 0 24px 70px rgba(2, 6, 23, 0.28);
}

.vb-dropdown-eighteen-app {
  position: relative;
  display: grid;
  grid-template-columns: 210px minmax(0, 1fr);
  gap: 18px;
  max-width: 1080px;
  min-height: 620px;
  margin: 0 auto;
  padding: 18px;
  border-radius: 30px;
  background: rgba(255,255,255,0.07);
  border: 1px solid rgba(255,255,255,0.12);
  overflow: hidden;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
}

.vb-dropdown-eighteen-sidebar {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 18px;
  border-radius: 24px;
  background: rgba(15, 23, 42, 0.72);
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-dropdown-eighteen-sidebar > span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 12px;
  padding: 8px 10px;
  border-radius: 999px;
  background: rgba(34, 211, 238, 0.16);
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.1em;
}

.vb-dropdown-eighteen-sidebar a {
  display: flex;
  align-items: center;
  min-height: 42px;
  padding: 10px 12px;
  border-radius: 14px;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 14px;
  font-weight: 850;
  text-decoration: none !important;
}

.vb-dropdown-eighteen-sidebar a:hover {
  background: rgba(255,255,255,0.08);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-eighteen-main {
  position: relative;
  padding: 30px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 80% 15%, rgba(34, 211, 238, 0.12), transparent 34%),
    linear-gradient(135deg, rgba(15, 23, 42, 0.86), rgba(30, 41, 59, 0.58)) !important;
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-dropdown-eighteen-top {
  display: flex;
  justify-content: space-between;
  gap: 24px;
  align-items: flex-start;
}

.vb-dropdown-eighteen-top > div > span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(168, 85, 247, 0.18);
  color: #e9d5ff !important;
  -webkit-text-fill-color: #e9d5ff !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-eighteen-top h3 {
  max-width: 660px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-eighteen-top p {
  max-width: 560px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-eighteen-open {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: 48px;
  padding: 9px 12px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 900;
  cursor: pointer;
  white-space: nowrap;
}

.vb-dropdown-eighteen-open span,
.vb-dropdown-eighteen-open em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  font-weight: 950;
}

.vb-dropdown-eighteen-status {
  position: absolute;
  left: 30px;
  right: 30px;
  bottom: 30px;
  padding: 20px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-dropdown-eighteen-status small {
  display: block;
  margin-bottom: 6px;
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-eighteen-status strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-eighteen-overlay {
  position: absolute;
  z-index: 80;
  inset: 0;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 70px 22px 22px;
  background: rgba(2, 6, 23, 0.62);
  backdrop-filter: blur(12px);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.22s ease, visibility 0.22s ease;
}

.vb-dropdown-eighteen-app.is-open .vb-dropdown-eighteen-overlay {
  opacity: 1;
  visibility: visible;
}

.vb-dropdown-eighteen-palette {
  width: min(100%, 620px);
  padding: 14px;
  border-radius: 26px;
  background: #0f172a;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 40px 100px rgba(2, 6, 23, 0.56);
  transform: translateY(16px) scale(0.98);
  transition: transform 0.22s ease;
}

.vb-dropdown-eighteen-app.is-open .vb-dropdown-eighteen-palette {
  transform: translateY(0) scale(1);
}

.vb-dropdown-eighteen-search {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  min-height: 58px;
  padding: 8px 12px 8px 8px;
  border-radius: 20px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
  margin-bottom: 10px;
}

.vb-dropdown-eighteen-search span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: rgba(34, 211, 238, 0.14);
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 19px;
  font-weight: 950;
}

.vb-dropdown-eighteen-search input {
  width: 100%;
  border: 0;
  outline: none;
  background: transparent;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 850;
}

.vb-dropdown-eighteen-search input::placeholder {
  color: rgba(255,255,255,0.62);
  -webkit-text-fill-color: rgba(255,255,255,0.62);
}

.vb-dropdown-eighteen-list {
  display: grid;
  gap: 7px;
  max-height: 360px;
  overflow-y: auto;
  padding-right: 4px;
}

.vb-dropdown-eighteen-list button {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  width: 100%;
  padding: 11px;
  border: 0;
  border-radius: 17px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-eighteen-list button:hover {
  background: rgba(255,255,255,0.08);
  transform: translateX(2px);
}

.vb-dropdown-eighteen-list button.is-hidden {
  display: none;
}

.vb-dropdown-eighteen-list button span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-eighteen-list button strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-eighteen-list button small {
  display: block;
  margin-top: 4px;
  color: #94a3b8 !important;
  -webkit-text-fill-color: #94a3b8 !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 700;
}

.vb-dropdown-eighteen-empty {
  display: none;
  padding: 24px 14px;
  border-radius: 18px;
  background: rgba(255,255,255,0.07);
  text-align: center;
}

.vb-dropdown-eighteen-empty.is-visible {
  display: block;
}

.vb-dropdown-eighteen-empty strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-eighteen-empty small {
  display: block;
  margin-top: 5px;
  color: #94a3b8 !important;
  -webkit-text-fill-color: #94a3b8 !important;
  font-size: 13px;
  font-weight: 700;
}

@media (max-width: 860px) {
  .vb-dropdown-eighteen-app {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-eighteen-sidebar {
    display: none;
  }

  .vb-dropdown-eighteen-main {
    min-height: 560px;
  }

  .vb-dropdown-eighteen-top {
    flex-direction: column;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-eighteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-eighteen-app {
    min-height: 700px;
    border-radius: 22px;
  }

  .vb-dropdown-eighteen-main {
    padding: 22px;
    border-radius: 20px;
  }

  .vb-dropdown-eighteen-top h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-eighteen-status {
    left: 22px;
    right: 22px;
    bottom: 22px;
  }

  .vb-dropdown-eighteen-overlay {
    padding-top: 40px;
  }
}
</style>

<script>
(function () {
  const app = document.querySelector("[data-vb-dropdown-eighteen]");
  if (!app) return;

  const trigger = app.querySelector("[data-vb-dropdown-eighteen-trigger]");
  const overlay = app.querySelector("[data-vb-dropdown-eighteen-overlay]");
  const palette = app.querySelector("[data-vb-dropdown-eighteen-palette]");
  const input = app.querySelector("[data-vb-dropdown-eighteen-input]");
  const commands = app.querySelectorAll("[data-command]");
  const empty = app.querySelector("[data-vb-dropdown-eighteen-empty]");
  const status = app.querySelector("[data-vb-dropdown-eighteen-status]");

  function openPalette() {
    app.classList.add("is-open");
    trigger.setAttribute("aria-expanded", "true");

    setTimeout(function () {
      input.focus();
    }, 80);
  }

  function closePalette() {
    app.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
    input.value = "";
    filterCommands();
  }

  function filterCommands() {
    const query = input.value.toLowerCase().trim();
    let visibleCount = 0;

    commands.forEach(function (command) {
      const keywords = command.getAttribute("data-keyword").toLowerCase();
      const title = command.getAttribute("data-command").toLowerCase();
      const match = title.includes(query) || keywords.includes(query);

      command.classList.toggle("is-hidden", !match);

      if (match) {
        visibleCount += 1;
      }
    });

    empty.classList.toggle("is-visible", visibleCount === 0);
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    openPalette();
  });

  input.addEventListener("input", filterCommands);

  commands.forEach(function (command) {
    command.addEventListener("click", function () {
      status.textContent = command.getAttribute("data-command");
      closePalette();
    });
  });

  overlay.addEventListener("click", function (event) {
    if (!palette.contains(event.target)) {
      closePalette();
    }
  });

  document.addEventListener("keydown", function (event) {
    if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "k") {
      event.preventDefault();
      openPalette();
    }

    if (event.key === "Escape") {
      closePalette();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const app = document.querySelector("[data-vb-dropdown-eighteen]");
  if (!app) return;

  const trigger = app.querySelector("[data-vb-dropdown-eighteen-trigger]");
  const overlay = app.querySelector("[data-vb-dropdown-eighteen-overlay]");
  const palette = app.querySelector("[data-vb-dropdown-eighteen-palette]");
  const input = app.querySelector("[data-vb-dropdown-eighteen-input]");
  const commands = app.querySelectorAll("[data-command]");
  const empty = app.querySelector("[data-vb-dropdown-eighteen-empty]");
  const status = app.querySelector("[data-vb-dropdown-eighteen-status]");

  function openPalette() {
    app.classList.add("is-open");
    trigger.setAttribute("aria-expanded", "true");

    setTimeout(function () {
      input.focus();
    }, 80);
  }

  function closePalette() {
    app.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
    input.value = "";
    filterCommands();
  }

  function filterCommands() {
    const query = input.value.toLowerCase().trim();
    let visibleCount = 0;

    commands.forEach(function (command) {
      const keywords = command.getAttribute("data-keyword").toLowerCase();
      const title = command.getAttribute("data-command").toLowerCase();
      const match = title.includes(query) || keywords.includes(query);

      command.classList.toggle("is-hidden", !match);

      if (match) {
        visibleCount += 1;
      }
    });

    empty.classList.toggle("is-visible", visibleCount === 0);
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    openPalette();
  });

  input.addEventListener("input", filterCommands);

  commands.forEach(function (command) {
    command.addEventListener("click", function () {
      status.textContent = command.getAttribute("data-command");
      closePalette();
    });
  });

  overlay.addEventListener("click", function (event) {
    if (!palette.contains(event.target)) {
      closePalette();
    }
  });

  document.addEventListener("keydown", function (event) {
    if ((event.ctrlKey || event.metaKey) && event.key.toLowerCase() === "k") {
      event.preventDefault();
      openPalette();
    }

    if (event.key === "Escape") {
      closePalette();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-eighteen-demo"&gt;
  &lt;div class="vb-dropdown-eighteen-app" data-vb-dropdown-eighteen&gt;
    &lt;div class="vb-dropdown-eighteen-sidebar"&gt;
      &lt;span&gt;APP&lt;/span&gt;
      &lt;a href="#javascript-dropdown-menu-examples"&gt;Dashboard&lt;/a&gt;
      &lt;a href="#javascript-dropdown-best-practices"&gt;Projects&lt;/a&gt;
      &lt;a href="#responsive-dropdown-design-tips"&gt;Settings&lt;/a&gt;
    &lt;/div&gt;

    &lt;main class="vb-dropdown-eighteen-main"&gt;
      &lt;div class="vb-dropdown-eighteen-top"&gt;
        &lt;div&gt;
          &lt;span&gt;Example 18&lt;/span&gt;
          &lt;h3&gt;Command Palette Dropdown&lt;/h3&gt;
          &lt;p&gt;Open a searchable command menu and select an action from the dropdown list.&lt;/p&gt;
        &lt;/div&gt;

        &lt;button type="button" class="vb-dropdown-eighteen-open" data-vb-dropdown-eighteen-trigger aria-expanded="false"&gt;
          &lt;span&gt;⌘&lt;/span&gt;
          Open commands
          &lt;em&gt;K&lt;/em&gt;
        &lt;/button&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-eighteen-status"&gt;
        &lt;small&gt;Last selected command&lt;/small&gt;
        &lt;strong data-vb-dropdown-eighteen-status&gt;No command selected yet&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/main&gt;

    &lt;div class="vb-dropdown-eighteen-overlay" data-vb-dropdown-eighteen-overlay&gt;
      &lt;div class="vb-dropdown-eighteen-palette" data-vb-dropdown-eighteen-palette&gt;
        &lt;div class="vb-dropdown-eighteen-search"&gt;
          &lt;span&gt;⌕&lt;/span&gt;
          &lt;input type="text" data-vb-dropdown-eighteen-input placeholder="Search commands..." autocomplete="off"&gt;
        &lt;/div&gt;

        &lt;div class="vb-dropdown-eighteen-list" data-vb-dropdown-eighteen-list&gt;
          &lt;button type="button" data-command="Create new project" data-keyword="create project new"&gt;
            &lt;span&gt;＋&lt;/span&gt;
            &lt;strong&gt;Create new project&lt;/strong&gt;
            &lt;small&gt;Start a new workspace item&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-command="Open dashboard" data-keyword="open dashboard analytics"&gt;
            &lt;span&gt;⌂&lt;/span&gt;
            &lt;strong&gt;Open dashboard&lt;/strong&gt;
            &lt;small&gt;Go to dashboard overview&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-command="Search documentation" data-keyword="search docs documentation help"&gt;
            &lt;span&gt;?&lt;/span&gt;
            &lt;strong&gt;Search documentation&lt;/strong&gt;
            &lt;small&gt;Find guides and answers&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-command="Toggle dark mode" data-keyword="toggle dark mode theme"&gt;
            &lt;span&gt;◐&lt;/span&gt;
            &lt;strong&gt;Toggle dark mode&lt;/strong&gt;
            &lt;small&gt;Switch interface appearance&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-command="Invite team member" data-keyword="invite team member user"&gt;
            &lt;span&gt;👥&lt;/span&gt;
            &lt;strong&gt;Invite team member&lt;/strong&gt;
            &lt;small&gt;Add someone to this workspace&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-command="Open account settings" data-keyword="settings account profile"&gt;
            &lt;span&gt;⚙&lt;/span&gt;
            &lt;strong&gt;Open account settings&lt;/strong&gt;
            &lt;small&gt;Manage profile and preferences&lt;/small&gt;
          &lt;/button&gt;
        &lt;/div&gt;

        &lt;div class="vb-dropdown-eighteen-empty" data-vb-dropdown-eighteen-empty&gt;
          &lt;strong&gt;No command found&lt;/strong&gt;
          &lt;small&gt;Try another keyword.&lt;/small&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-eighteen-demo,
.vb-dropdown-eighteen-demo * {
  box-sizing: border-box;
}

.vb-dropdown-eighteen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 18% 16%, rgba(34, 211, 238, 0.18), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(168, 85, 247, 0.20), transparent 34%),
    linear-gradient(135deg, #020617 0%, #111827 52%, #1e1b4b 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.18);
  box-shadow: 0 24px 70px rgba(2, 6, 23, 0.28);
}

.vb-dropdown-eighteen-app {
  position: relative;
  display: grid;
  grid-template-columns: 210px minmax(0, 1fr);
  gap: 18px;
  max-width: 1080px;
  min-height: 620px;
  margin: 0 auto;
  padding: 18px;
  border-radius: 30px;
  background: rgba(255,255,255,0.07);
  border: 1px solid rgba(255,255,255,0.12);
  overflow: hidden;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
}

.vb-dropdown-eighteen-sidebar {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 18px;
  border-radius: 24px;
  background: rgba(15, 23, 42, 0.72);
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-dropdown-eighteen-sidebar &gt; span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 12px;
  padding: 8px 10px;
  border-radius: 999px;
  background: rgba(34, 211, 238, 0.16);
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.1em;
}

.vb-dropdown-eighteen-sidebar a {
  display: flex;
  align-items: center;
  min-height: 42px;
  padding: 10px 12px;
  border-radius: 14px;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 14px;
  font-weight: 850;
  text-decoration: none !important;
}

.vb-dropdown-eighteen-sidebar a:hover {
  background: rgba(255,255,255,0.08);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-eighteen-main {
  position: relative;
  padding: 30px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 80% 15%, rgba(34, 211, 238, 0.12), transparent 34%),
    linear-gradient(135deg, rgba(15, 23, 42, 0.86), rgba(30, 41, 59, 0.58)) !important;
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-dropdown-eighteen-top {
  display: flex;
  justify-content: space-between;
  gap: 24px;
  align-items: flex-start;
}

.vb-dropdown-eighteen-top &gt; div &gt; span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(168, 85, 247, 0.18);
  color: #e9d5ff !important;
  -webkit-text-fill-color: #e9d5ff !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-eighteen-top h3 {
  max-width: 660px;
  margin: 0 0 16px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-eighteen-top p {
  max-width: 560px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-eighteen-open {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: 48px;
  padding: 9px 12px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 900;
  cursor: pointer;
  white-space: nowrap;
}

.vb-dropdown-eighteen-open span,
.vb-dropdown-eighteen-open em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  font-weight: 950;
}

.vb-dropdown-eighteen-status {
  position: absolute;
  left: 30px;
  right: 30px;
  bottom: 30px;
  padding: 20px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-dropdown-eighteen-status small {
  display: block;
  margin-bottom: 6px;
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-eighteen-status strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-eighteen-overlay {
  position: absolute;
  z-index: 80;
  inset: 0;
  display: flex;
  align-items: flex-start;
  justify-content: center;
  padding: 70px 22px 22px;
  background: rgba(2, 6, 23, 0.62);
  backdrop-filter: blur(12px);
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.22s ease, visibility 0.22s ease;
}

.vb-dropdown-eighteen-app.is-open .vb-dropdown-eighteen-overlay {
  opacity: 1;
  visibility: visible;
}

.vb-dropdown-eighteen-palette {
  width: min(100%, 620px);
  padding: 14px;
  border-radius: 26px;
  background: #0f172a;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 40px 100px rgba(2, 6, 23, 0.56);
  transform: translateY(16px) scale(0.98);
  transition: transform 0.22s ease;
}

.vb-dropdown-eighteen-app.is-open .vb-dropdown-eighteen-palette {
  transform: translateY(0) scale(1);
}

.vb-dropdown-eighteen-search {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  min-height: 58px;
  padding: 8px 12px 8px 8px;
  border-radius: 20px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
  margin-bottom: 10px;
}

.vb-dropdown-eighteen-search span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: rgba(34, 211, 238, 0.14);
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 19px;
  font-weight: 950;
}

.vb-dropdown-eighteen-search input {
  width: 100%;
  border: 0;
  outline: none;
  background: transparent;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 850;
}

.vb-dropdown-eighteen-search input::placeholder {
  color: rgba(255,255,255,0.62);
  -webkit-text-fill-color: rgba(255,255,255,0.62);
}

.vb-dropdown-eighteen-list {
  display: grid;
  gap: 7px;
  max-height: 360px;
  overflow-y: auto;
  padding-right: 4px;
}

.vb-dropdown-eighteen-list button {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  width: 100%;
  padding: 11px;
  border: 0;
  border-radius: 17px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-eighteen-list button:hover {
  background: rgba(255,255,255,0.08);
  transform: translateX(2px);
}

.vb-dropdown-eighteen-list button.is-hidden {
  display: none;
}

.vb-dropdown-eighteen-list button span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-eighteen-list button strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-eighteen-list button small {
  display: block;
  margin-top: 4px;
  color: #94a3b8 !important;
  -webkit-text-fill-color: #94a3b8 !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 700;
}

.vb-dropdown-eighteen-empty {
  display: none;
  padding: 24px 14px;
  border-radius: 18px;
  background: rgba(255,255,255,0.07);
  text-align: center;
}

.vb-dropdown-eighteen-empty.is-visible {
  display: block;
}

.vb-dropdown-eighteen-empty strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-eighteen-empty small {
  display: block;
  margin-top: 5px;
  color: #94a3b8 !important;
  -webkit-text-fill-color: #94a3b8 !important;
  font-size: 13px;
  font-weight: 700;
}

@media (max-width: 860px) {
  .vb-dropdown-eighteen-app {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-eighteen-sidebar {
    display: none;
  }

  .vb-dropdown-eighteen-main {
    min-height: 560px;
  }

  .vb-dropdown-eighteen-top {
    flex-direction: column;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-eighteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-eighteen-app {
    min-height: 700px;
    border-radius: 22px;
  }

  .vb-dropdown-eighteen-main {
    padding: 22px;
    border-radius: 20px;
  }

  .vb-dropdown-eighteen-top h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-eighteen-status {
    left: 22px;
    right: 22px;
    bottom: 22px;
  }

  .vb-dropdown-eighteen-overlay {
    padding-top: 40px;
  }
}</pre>



<p class="wp-block-paragraph">This command palette dropdown is a modern pattern for advanced web applications. You can adapt it for SaaS dashboards, admin panels, developer tools, productivity apps, WordPress plugin interfaces, CRM systems, and internal business tools.</p>



<h2 class="wp-block-heading">19. User Profile Dropdown Menu</h2>



<p class="wp-block-paragraph"><strong>A user profile dropdown menu</strong> is a common pattern for dashboards, SaaS apps, ecommerce accounts, membership websites, admin panels, and logged-in user interfaces. It gives users fast access to profile settings, billing, saved items, notifications, and logout actions.</p>



<p class="wp-block-paragraph">This example includes an avatar trigger, account links, plan status, selected action feedback, outside click closing, and Escape key support. The design uses a polished dark dashboard style with a compact floating account menu.</p>



<ul class="wp-block-list">
<li>User avatar dropdown menu</li>
<li>Account, billing, settings, and logout links</li>
<li>Selected action feedback with JavaScript</li>
<li>Outside click and Escape key support</li>
<li>Useful for SaaS apps, dashboards, ecommerce accounts, and membership websites</li>
</ul>



<div class="vb-dropdown-nineteen-demo">
  <div class="vb-dropdown-nineteen-dashboard" data-vb-dropdown-nineteen>
    <aside class="vb-dropdown-nineteen-sidebar">
      <span>USER</span>
      <a href="#javascript-dropdown-menu-examples">Overview</a>
      <a href="#javascript-dropdown-best-practices">Projects</a>
      <a href="#responsive-dropdown-design-tips">Settings</a>
    </aside>

    <main class="vb-dropdown-nineteen-main">
      <header class="vb-dropdown-nineteen-header">
        <div>
          <span>Example 19</span>
          <h3>User Profile Dropdown</h3>
        </div>

        <div class="vb-dropdown-nineteen-profile-wrap">
          <button type="button" class="vb-dropdown-nineteen-trigger" data-vb-dropdown-nineteen-trigger aria-expanded="false" aria-label="Open profile menu">
            <span>JD</span>
            <strong>Jordan</strong>
            <em>⌄</em>
          </button>

          <div class="vb-dropdown-nineteen-menu" data-vb-dropdown-nineteen-menu>
            <div class="vb-dropdown-nineteen-user">
              <span>JD</span>
              <div>
                <strong>Jordan Davis</strong>
                <small>jordan@example.com</small>
              </div>
            </div>

            <div class="vb-dropdown-nineteen-plan">
              <small>Current plan</small>
              <strong>Pro Workspace</strong>
            </div>

            <button type="button" data-profile-action="Open profile settings">
              <span>👤</span>
              <strong>Profile settings</strong>
            </button>

            <button type="button" data-profile-action="Open billing page">
              <span>💳</span>
              <strong>Billing</strong>
            </button>

            <button type="button" data-profile-action="Open saved items">
              <span>⭐</span>
              <strong>Saved items</strong>
            </button>

            <button type="button" data-profile-action="Open notifications">
              <span>🔔</span>
              <strong>Notifications</strong>
            </button>

            <button type="button" class="vb-dropdown-nineteen-danger" data-profile-action="Logout selected">
              <span>↪</span>
              <strong>Logout</strong>
            </button>
          </div>
        </div>
      </header>

      <section class="vb-dropdown-nineteen-content">
        <p>Open the avatar menu to display account actions inside a compact JavaScript dropdown.</p>

        <div class="vb-dropdown-nineteen-feedback">
          <small>Selected action</small>
          <strong data-vb-dropdown-nineteen-feedback>No action selected yet</strong>
        </div>
      </section>
    </main>
  </div>
</div>

<style>
.vb-dropdown-nineteen-demo,
.vb-dropdown-nineteen-demo * {
  box-sizing: border-box;
}

.vb-dropdown-nineteen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(56, 189, 248, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(168, 85, 247, 0.18), transparent 34%),
    linear-gradient(135deg, #020617 0%, #111827 52%, #312e81 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.18);
  box-shadow: 0 24px 70px rgba(2, 6, 23, 0.30);
}

.vb-dropdown-nineteen-dashboard {
  position: relative;
  display: grid;
  grid-template-columns: 210px minmax(0, 1fr);
  gap: 18px;
  max-width: 1080px;
  min-height: 620px;
  margin: 0 auto;
  padding: 18px;
  border-radius: 30px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
  overflow: visible;
}

.vb-dropdown-nineteen-sidebar {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 18px;
  border-radius: 24px;
  background: rgba(15, 23, 42, 0.78);
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-dropdown-nineteen-sidebar > span {
  width: fit-content;
  margin-bottom: 12px;
  padding: 8px 10px;
  border-radius: 999px;
  background: rgba(56, 189, 248, 0.16);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.1em;
}

.vb-dropdown-nineteen-sidebar a {
  display: flex;
  align-items: center;
  min-height: 42px;
  padding: 10px 12px;
  border-radius: 14px;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 14px;
  font-weight: 850;
  text-decoration: none !important;
}

.vb-dropdown-nineteen-sidebar a:hover {
  background: rgba(255,255,255,0.08);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-nineteen-main {
  position: relative;
  padding: 24px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 80% 15%, rgba(56, 189, 248, 0.12), transparent 34%),
    linear-gradient(135deg, rgba(15, 23, 42, 0.90), rgba(30, 41, 59, 0.68)) !important;
  border: 1px solid rgba(255,255,255,0.10);
  overflow: visible;
}

.vb-dropdown-nineteen-header {
  position: relative;
  z-index: 50;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
}

.vb-dropdown-nineteen-header > div:first-child > span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(168, 85, 247, 0.18);
  color: #e9d5ff !important;
  -webkit-text-fill-color: #e9d5ff !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-nineteen-header h3 {
  max-width: 660px;
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-nineteen-profile-wrap {
  position: relative;
  z-index: 70;
}

.vb-dropdown-nineteen-trigger {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: 52px;
  padding: 8px 12px 8px 8px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  cursor: pointer;
}

.vb-dropdown-nineteen-trigger span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 999px;
  background: linear-gradient(135deg, #38bdf8, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-dropdown-nineteen-trigger strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-dropdown-nineteen-trigger em {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-nineteen-dashboard.is-open .vb-dropdown-nineteen-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-nineteen-menu {
  position: absolute;
  z-index: 80;
  top: calc(100% + 12px);
  right: 0;
  display: grid;
  gap: 7px;
  width: 300px;
  padding: 12px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.38);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-nineteen-dashboard.is-open .vb-dropdown-nineteen-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-nineteen-user {
  display: grid;
  grid-template-columns: 48px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 10px;
  border-radius: 18px;
  background: #f8fafc;
}

.vb-dropdown-nineteen-user > span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 17px;
  background: linear-gradient(135deg, #38bdf8, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-dropdown-nineteen-user strong,
.vb-dropdown-nineteen-plan strong,
.vb-dropdown-nineteen-menu button strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
}

.vb-dropdown-nineteen-user strong {
  display: block;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-nineteen-user small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 700;
}

.vb-dropdown-nineteen-plan {
  padding: 13px;
  border-radius: 18px;
  background: #eef2ff;
}

.vb-dropdown-nineteen-plan small {
  display: block;
  margin-bottom: 5px;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-nineteen-plan strong {
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-nineteen-menu button {
  display: grid;
  grid-template-columns: 38px minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  width: 100%;
  min-height: 46px;
  padding: 9px;
  border: 0;
  border-radius: 15px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-nineteen-menu button:hover {
  background: #f8fafc;
  transform: translateX(2px);
}

.vb-dropdown-nineteen-menu button span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 14px;
  background: #eef2ff;
  font-size: 16px;
}

.vb-dropdown-nineteen-menu button strong {
  font-size: 14px;
  font-weight: 900;
}

.vb-dropdown-nineteen-menu .vb-dropdown-nineteen-danger:hover {
  background: #fef2f2;
}

.vb-dropdown-nineteen-menu .vb-dropdown-nineteen-danger span {
  background: #fee2e2;
}

.vb-dropdown-nineteen-menu .vb-dropdown-nineteen-danger strong {
  color: #991b1b !important;
  -webkit-text-fill-color: #991b1b !important;
}

.vb-dropdown-nineteen-content {
  position: absolute;
  left: 24px;
  right: 24px;
  bottom: 24px;
}

.vb-dropdown-nineteen-content p {
  max-width: 560px;
  margin: 0 0 22px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-dropdown-nineteen-feedback {
  padding: 20px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-dropdown-nineteen-feedback small {
  display: block;
  margin-bottom: 6px;
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-nineteen-feedback strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1.2;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-dropdown-nineteen-dashboard {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-nineteen-sidebar {
    display: none;
  }

  .vb-dropdown-nineteen-main {
    min-height: 560px;
  }

  .vb-dropdown-nineteen-header {
    flex-direction: column;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-nineteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-nineteen-dashboard {
    min-height: 700px;
    border-radius: 22px;
  }

  .vb-dropdown-nineteen-main {
    padding: 20px;
    border-radius: 20px;
  }

  .vb-dropdown-nineteen-header h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-nineteen-menu {
    left: 0;
    right: auto;
    width: min(100%, 300px);
    transform-origin: top left;
  }

  .vb-dropdown-nineteen-content {
    left: 20px;
    right: 20px;
    bottom: 20px;
  }
}
</style>

<script>
(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-nineteen]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-nineteen-trigger]");
  const actions = dropdown.querySelectorAll("[data-profile-action]");
  const feedback = dropdown.querySelector("[data-vb-dropdown-nineteen-feedback]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  actions.forEach(function (action) {
    action.addEventListener("click", function () {
      feedback.textContent = action.getAttribute("data-profile-action");
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-nineteen]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-nineteen-trigger]");
  const actions = dropdown.querySelectorAll("[data-profile-action]");
  const feedback = dropdown.querySelector("[data-vb-dropdown-nineteen-feedback]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  actions.forEach(function (action) {
    action.addEventListener("click", function () {
      feedback.textContent = action.getAttribute("data-profile-action");
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-nineteen-demo"&gt;
  &lt;div class="vb-dropdown-nineteen-dashboard" data-vb-dropdown-nineteen&gt;
    &lt;aside class="vb-dropdown-nineteen-sidebar"&gt;
      &lt;span&gt;USER&lt;/span&gt;
      &lt;a href="#javascript-dropdown-menu-examples"&gt;Overview&lt;/a&gt;
      &lt;a href="#javascript-dropdown-best-practices"&gt;Projects&lt;/a&gt;
      &lt;a href="#responsive-dropdown-design-tips"&gt;Settings&lt;/a&gt;
    &lt;/aside&gt;

    &lt;main class="vb-dropdown-nineteen-main"&gt;
      &lt;header class="vb-dropdown-nineteen-header"&gt;
        &lt;div&gt;
          &lt;span&gt;Example 19&lt;/span&gt;
          &lt;h3&gt;User Profile Dropdown&lt;/h3&gt;
        &lt;/div&gt;

        &lt;div class="vb-dropdown-nineteen-profile-wrap"&gt;
          &lt;button type="button" class="vb-dropdown-nineteen-trigger" data-vb-dropdown-nineteen-trigger aria-expanded="false" aria-label="Open profile menu"&gt;
            &lt;span&gt;JD&lt;/span&gt;
            &lt;strong&gt;Jordan&lt;/strong&gt;
            &lt;em&gt;⌄&lt;/em&gt;
          &lt;/button&gt;

          &lt;div class="vb-dropdown-nineteen-menu" data-vb-dropdown-nineteen-menu&gt;
            &lt;div class="vb-dropdown-nineteen-user"&gt;
              &lt;span&gt;JD&lt;/span&gt;
              &lt;div&gt;
                &lt;strong&gt;Jordan Davis&lt;/strong&gt;
                &lt;small&gt;jordan@example.com&lt;/small&gt;
              &lt;/div&gt;
            &lt;/div&gt;

            &lt;div class="vb-dropdown-nineteen-plan"&gt;
              &lt;small&gt;Current plan&lt;/small&gt;
              &lt;strong&gt;Pro Workspace&lt;/strong&gt;
            &lt;/div&gt;

            &lt;button type="button" data-profile-action="Open profile settings"&gt;
              &lt;span&gt;👤&lt;/span&gt;
              &lt;strong&gt;Profile settings&lt;/strong&gt;
            &lt;/button&gt;

            &lt;button type="button" data-profile-action="Open billing page"&gt;
              &lt;span&gt;💳&lt;/span&gt;
              &lt;strong&gt;Billing&lt;/strong&gt;
            &lt;/button&gt;

            &lt;button type="button" data-profile-action="Open saved items"&gt;
              &lt;span&gt;⭐&lt;/span&gt;
              &lt;strong&gt;Saved items&lt;/strong&gt;
            &lt;/button&gt;

            &lt;button type="button" data-profile-action="Open notifications"&gt;
              &lt;span&gt;🔔&lt;/span&gt;
              &lt;strong&gt;Notifications&lt;/strong&gt;
            &lt;/button&gt;

            &lt;button type="button" class="vb-dropdown-nineteen-danger" data-profile-action="Logout selected"&gt;
              &lt;span&gt;↪&lt;/span&gt;
              &lt;strong&gt;Logout&lt;/strong&gt;
            &lt;/button&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/header&gt;

      &lt;section class="vb-dropdown-nineteen-content"&gt;
        &lt;p&gt;Open the avatar menu to display account actions inside a compact JavaScript dropdown.&lt;/p&gt;

        &lt;div class="vb-dropdown-nineteen-feedback"&gt;
          &lt;small&gt;Selected action&lt;/small&gt;
          &lt;strong data-vb-dropdown-nineteen-feedback&gt;No action selected yet&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/section&gt;
    &lt;/main&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-nineteen-demo,
.vb-dropdown-nineteen-demo * {
  box-sizing: border-box;
}

.vb-dropdown-nineteen-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(56, 189, 248, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(168, 85, 247, 0.18), transparent 34%),
    linear-gradient(135deg, #020617 0%, #111827 52%, #312e81 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.18);
  box-shadow: 0 24px 70px rgba(2, 6, 23, 0.30);
}

.vb-dropdown-nineteen-dashboard {
  position: relative;
  display: grid;
  grid-template-columns: 210px minmax(0, 1fr);
  gap: 18px;
  max-width: 1080px;
  min-height: 620px;
  margin: 0 auto;
  padding: 18px;
  border-radius: 30px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
  overflow: visible;
}

.vb-dropdown-nineteen-sidebar {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: 18px;
  border-radius: 24px;
  background: rgba(15, 23, 42, 0.78);
  border: 1px solid rgba(255,255,255,0.10);
}

.vb-dropdown-nineteen-sidebar &gt; span {
  width: fit-content;
  margin-bottom: 12px;
  padding: 8px 10px;
  border-radius: 999px;
  background: rgba(56, 189, 248, 0.16);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.1em;
}

.vb-dropdown-nineteen-sidebar a {
  display: flex;
  align-items: center;
  min-height: 42px;
  padding: 10px 12px;
  border-radius: 14px;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 14px;
  font-weight: 850;
  text-decoration: none !important;
}

.vb-dropdown-nineteen-sidebar a:hover {
  background: rgba(255,255,255,0.08);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-nineteen-main {
  position: relative;
  padding: 24px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 80% 15%, rgba(56, 189, 248, 0.12), transparent 34%),
    linear-gradient(135deg, rgba(15, 23, 42, 0.90), rgba(30, 41, 59, 0.68)) !important;
  border: 1px solid rgba(255,255,255,0.10);
  overflow: visible;
}

.vb-dropdown-nineteen-header {
  position: relative;
  z-index: 50;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 20px;
}

.vb-dropdown-nineteen-header &gt; div:first-child &gt; span {
  display: inline-flex;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(168, 85, 247, 0.18);
  color: #e9d5ff !important;
  -webkit-text-fill-color: #e9d5ff !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-nineteen-header h3 {
  max-width: 660px;
  margin: 0 !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-nineteen-profile-wrap {
  position: relative;
  z-index: 70;
}

.vb-dropdown-nineteen-trigger {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: 52px;
  padding: 8px 12px 8px 8px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 999px;
  background: rgba(255,255,255,0.10);
  cursor: pointer;
}

.vb-dropdown-nineteen-trigger span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 999px;
  background: linear-gradient(135deg, #38bdf8, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-dropdown-nineteen-trigger strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-dropdown-nineteen-trigger em {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-nineteen-dashboard.is-open .vb-dropdown-nineteen-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-nineteen-menu {
  position: absolute;
  z-index: 80;
  top: calc(100% + 12px);
  right: 0;
  display: grid;
  gap: 7px;
  width: 300px;
  padding: 12px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.38);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-nineteen-dashboard.is-open .vb-dropdown-nineteen-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-nineteen-user {
  display: grid;
  grid-template-columns: 48px minmax(0, 1fr);
  gap: 12px;
  align-items: center;
  padding: 10px;
  border-radius: 18px;
  background: #f8fafc;
}

.vb-dropdown-nineteen-user &gt; span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 17px;
  background: linear-gradient(135deg, #38bdf8, #a855f7);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-dropdown-nineteen-user strong,
.vb-dropdown-nineteen-plan strong,
.vb-dropdown-nineteen-menu button strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
}

.vb-dropdown-nineteen-user strong {
  display: block;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-nineteen-user small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 700;
}

.vb-dropdown-nineteen-plan {
  padding: 13px;
  border-radius: 18px;
  background: #eef2ff;
}

.vb-dropdown-nineteen-plan small {
  display: block;
  margin-bottom: 5px;
  color: #4338ca !important;
  -webkit-text-fill-color: #4338ca !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-nineteen-plan strong {
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-nineteen-menu button {
  display: grid;
  grid-template-columns: 38px minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  width: 100%;
  min-height: 46px;
  padding: 9px;
  border: 0;
  border-radius: 15px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-nineteen-menu button:hover {
  background: #f8fafc;
  transform: translateX(2px);
}

.vb-dropdown-nineteen-menu button span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  border-radius: 14px;
  background: #eef2ff;
  font-size: 16px;
}

.vb-dropdown-nineteen-menu button strong {
  font-size: 14px;
  font-weight: 900;
}

.vb-dropdown-nineteen-menu .vb-dropdown-nineteen-danger:hover {
  background: #fef2f2;
}

.vb-dropdown-nineteen-menu .vb-dropdown-nineteen-danger span {
  background: #fee2e2;
}

.vb-dropdown-nineteen-menu .vb-dropdown-nineteen-danger strong {
  color: #991b1b !important;
  -webkit-text-fill-color: #991b1b !important;
}

.vb-dropdown-nineteen-content {
  position: absolute;
  left: 24px;
  right: 24px;
  bottom: 24px;
}

.vb-dropdown-nineteen-content p {
  max-width: 560px;
  margin: 0 0 22px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.7;
  font-weight: 650;
}

.vb-dropdown-nineteen-feedback {
  padding: 20px;
  border-radius: 22px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-dropdown-nineteen-feedback small {
  display: block;
  margin-bottom: 6px;
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-nineteen-feedback strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1.2;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-dropdown-nineteen-dashboard {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-nineteen-sidebar {
    display: none;
  }

  .vb-dropdown-nineteen-main {
    min-height: 560px;
  }

  .vb-dropdown-nineteen-header {
    flex-direction: column;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-nineteen-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-nineteen-dashboard {
    min-height: 700px;
    border-radius: 22px;
  }

  .vb-dropdown-nineteen-main {
    padding: 20px;
    border-radius: 20px;
  }

  .vb-dropdown-nineteen-header h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-nineteen-menu {
    left: 0;
    right: auto;
    width: min(100%, 300px);
    transform-origin: top left;
  }

  .vb-dropdown-nineteen-content {
    left: 20px;
    right: 20px;
    bottom: 20px;
  }
}</pre>



<p class="wp-block-paragraph">This user profile dropdown is a practical account menu pattern for logged-in interfaces. You can adapt it for WordPress dashboards, SaaS apps, ecommerce customer accounts, membership websites, learning platforms, and admin panels.</p>



<h2 class="wp-block-heading">20. Date Picker Dropdown</h2>



<p class="wp-block-paragraph"><strong>A date picker dropdown</strong> is useful for booking forms, event pages, appointment systems, hotel websites, travel platforms, dashboards, content scheduling tools, and ecommerce delivery date selectors. It lets users choose a date from a compact calendar panel.</p>



<p class="wp-block-paragraph">This example includes a date dropdown trigger, mini calendar grid, selected date preview, active day styling, clear date button, outside click closing, and Escape key support. The calendar is a simplified static demo, but the same pattern can be extended into a full dynamic date picker.</p>



<ul class="wp-block-list">
<li>Mini date picker dropdown</li>
<li>Clickable calendar day buttons</li>
<li>Selected date preview</li>
<li>Clear date option</li>
<li>Useful for booking forms, appointment tools, dashboards, delivery dates, and scheduling interfaces</li>
</ul>



<div class="vb-dropdown-twenty-demo">
  <div class="vb-dropdown-twenty-booking" data-vb-dropdown-twenty>
    <div class="vb-dropdown-twenty-copy">
      <span>Example 20</span>
      <h3>Date Picker Dropdown</h3>
      <p>Choose a date from a compact dropdown calendar and update the selected booking date instantly.</p>
    </div>

    <div class="vb-dropdown-twenty-card">
      <div class="vb-dropdown-twenty-card-head">
        <small>Booking date</small>
        <strong data-vb-dropdown-twenty-selected>No date selected</strong>
      </div>

      <div class="vb-dropdown-twenty-control">
        <button type="button" class="vb-dropdown-twenty-trigger" data-vb-dropdown-twenty-trigger aria-expanded="false">
          <span data-vb-dropdown-twenty-trigger-text>Select a date</span>
          <em>⌄</em>
        </button>

        <div class="vb-dropdown-twenty-menu" data-vb-dropdown-twenty-menu>
          <div class="vb-dropdown-twenty-month">
            <strong>June 2026</strong>
            <button type="button" data-vb-dropdown-twenty-clear>Clear</button>
          </div>

          <div class="vb-dropdown-twenty-weekdays">
            <span>Mo</span>
            <span>Tu</span>
            <span>We</span>
            <span>Th</span>
            <span>Fr</span>
            <span>Sa</span>
            <span>Su</span>
          </div>

          <div class="vb-dropdown-twenty-days">
            <button type="button" data-date="June 1, 2026">1</button>
            <button type="button" data-date="June 2, 2026">2</button>
            <button type="button" data-date="June 3, 2026">3</button>
            <button type="button" data-date="June 4, 2026">4</button>
            <button type="button" data-date="June 5, 2026">5</button>
            <button type="button" data-date="June 6, 2026">6</button>
            <button type="button" data-date="June 7, 2026">7</button>
            <button type="button" data-date="June 8, 2026">8</button>
            <button type="button" data-date="June 9, 2026">9</button>
            <button type="button" data-date="June 10, 2026">10</button>
            <button type="button" data-date="June 11, 2026">11</button>
            <button type="button" data-date="June 12, 2026">12</button>
            <button type="button" data-date="June 13, 2026">13</button>
            <button type="button" data-date="June 14, 2026">14</button>
            <button type="button" data-date="June 15, 2026">15</button>
            <button type="button" data-date="June 16, 2026">16</button>
            <button type="button" data-date="June 17, 2026">17</button>
            <button type="button" data-date="June 18, 2026">18</button>
            <button type="button" data-date="June 19, 2026">19</button>
            <button type="button" data-date="June 20, 2026">20</button>
            <button type="button" data-date="June 21, 2026">21</button>
          </div>
        </div>
      </div>

      <div class="vb-dropdown-twenty-details">
        <div>
          <small>Service</small>
          <strong>Consultation Call</strong>
        </div>
        <div>
          <small>Duration</small>
          <strong>45 minutes</strong>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-dropdown-twenty-demo,
.vb-dropdown-twenty-demo * {
  box-sizing: border-box;
}

.vb-dropdown-twenty-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(34, 197, 94, 0.20), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(20, 184, 166, 0.18), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #f0fdfa 52%, #ffffff 100%) !important;
  border: 1px solid rgba(187, 247, 208, 0.48);
  box-shadow: 0 24px 70px rgba(21, 128, 61, 0.12);
}

.vb-dropdown-twenty-booking {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(330px, 0.75fr);
  gap: 34px;
  align-items: center;
  max-width: 1040px;
  min-height: 600px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(187, 247, 208, 0.52);
  box-shadow: 0 24px 70px rgba(21, 128, 61, 0.12);
  overflow: visible;
}

.vb-dropdown-twenty-copy > span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-twenty-copy h3 {
  max-width: 680px;
  margin: 0 0 16px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-twenty-copy p {
  max-width: 560px;
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-twenty-card {
  position: relative;
  z-index: 30;
  padding: 22px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 16%, rgba(34, 197, 94, 0.18), transparent 34%),
    linear-gradient(135deg, #064e3b, #0f766e) !important;
  box-shadow: 0 30px 80px rgba(15, 118, 110, 0.28);
  overflow: visible;
}

.vb-dropdown-twenty-card-head {
  margin-bottom: 20px;
  padding: 20px;
  border-radius: 24px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-dropdown-twenty-card-head small {
  display: block;
  margin-bottom: 8px;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twenty-card-head strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 28px;
  line-height: 1.12;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-dropdown-twenty-control {
  position: relative;
  z-index: 50;
  margin-bottom: 18px;
}

.vb-dropdown-twenty-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  min-height: 60px;
  padding: 13px 14px 13px 16px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 20px;
  background: rgba(255,255,255,0.12);
  cursor: pointer;
  text-align: left;
}

.vb-dropdown-twenty-trigger span {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-twenty-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-twenty-booking.is-open .vb-dropdown-twenty-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-twenty-menu {
  position: absolute;
  z-index: 80;
  top: calc(100% + 12px);
  left: 0;
  right: 0;
  padding: 14px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.34);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-twenty-booking.is-open .vb-dropdown-twenty-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-twenty-month {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 12px;
}

.vb-dropdown-twenty-month strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-twenty-month button {
  border: 0;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  padding: 8px 10px;
  font-size: 12px;
  font-weight: 900;
  cursor: pointer;
}

.vb-dropdown-twenty-weekdays,
.vb-dropdown-twenty-days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 6px;
}

.vb-dropdown-twenty-weekdays {
  margin-bottom: 7px;
}

.vb-dropdown-twenty-weekdays span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 28px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 11px;
  font-weight: 950;
  text-transform: uppercase;
}

.vb-dropdown-twenty-days button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 38px;
  border: 0;
  border-radius: 13px;
  background: #f8fafc;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 13px;
  font-weight: 900;
  cursor: pointer;
  transition: background 0.18s ease, color 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-twenty-days button:hover {
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  transform: translateY(-1px);
}

.vb-dropdown-twenty-days button.is-selected {
  background: linear-gradient(135deg, #22c55e, #0f766e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 10px 24px rgba(15, 118, 110, 0.22);
}

.vb-dropdown-twenty-details {
  display: grid;
  gap: 10px;
}

.vb-dropdown-twenty-details div {
  padding: 14px;
  border-radius: 18px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-dropdown-twenty-details small {
  display: block;
  margin-bottom: 5px;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twenty-details strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-dropdown-twenty-booking {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-twenty-card {
    max-width: 440px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-twenty-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twenty-booking {
    min-height: 760px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-twenty-copy h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-twenty-card {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twenty-card-head strong {
    font-size: 23px;
  }

  .vb-dropdown-twenty-days button {
    min-height: 34px;
    border-radius: 10px;
  }
}
</style>

<script>
(function () {
  const picker = document.querySelector("[data-vb-dropdown-twenty]");
  if (!picker) return;

  const trigger = picker.querySelector("[data-vb-dropdown-twenty-trigger]");
  const selectedText = picker.querySelector("[data-vb-dropdown-twenty-selected]");
  const triggerText = picker.querySelector("[data-vb-dropdown-twenty-trigger-text]");
  const dateButtons = picker.querySelectorAll("[data-date]");
  const clearButton = picker.querySelector("[data-vb-dropdown-twenty-clear]");

  function closePicker() {
    picker.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function togglePicker() {
    const isOpen = picker.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    togglePicker();
  });

  dateButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      const date = button.getAttribute("data-date");

      dateButtons.forEach(function (item) {
        item.classList.remove("is-selected");
      });

      button.classList.add("is-selected");
      selectedText.textContent = date;
      triggerText.textContent = date;
      closePicker();
    });
  });

  clearButton.addEventListener("click", function (event) {
    event.stopPropagation();

    dateButtons.forEach(function (item) {
      item.classList.remove("is-selected");
    });

    selectedText.textContent = "No date selected";
    triggerText.textContent = "Select a date";
    closePicker();
  });

  document.addEventListener("click", function (event) {
    if (!picker.contains(event.target)) {
      closePicker();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closePicker();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const picker = document.querySelector("[data-vb-dropdown-twenty]");
  if (!picker) return;

  const trigger = picker.querySelector("[data-vb-dropdown-twenty-trigger]");
  const selectedText = picker.querySelector("[data-vb-dropdown-twenty-selected]");
  const triggerText = picker.querySelector("[data-vb-dropdown-twenty-trigger-text]");
  const dateButtons = picker.querySelectorAll("[data-date]");
  const clearButton = picker.querySelector("[data-vb-dropdown-twenty-clear]");

  function closePicker() {
    picker.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function togglePicker() {
    const isOpen = picker.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    togglePicker();
  });

  dateButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      const date = button.getAttribute("data-date");

      dateButtons.forEach(function (item) {
        item.classList.remove("is-selected");
      });

      button.classList.add("is-selected");
      selectedText.textContent = date;
      triggerText.textContent = date;
      closePicker();
    });
  });

  clearButton.addEventListener("click", function (event) {
    event.stopPropagation();

    dateButtons.forEach(function (item) {
      item.classList.remove("is-selected");
    });

    selectedText.textContent = "No date selected";
    triggerText.textContent = "Select a date";
    closePicker();
  });

  document.addEventListener("click", function (event) {
    if (!picker.contains(event.target)) {
      closePicker();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closePicker();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-twenty-demo"&gt;
  &lt;div class="vb-dropdown-twenty-booking" data-vb-dropdown-twenty&gt;
    &lt;div class="vb-dropdown-twenty-copy"&gt;
      &lt;span&gt;Example 20&lt;/span&gt;
      &lt;h3&gt;Date Picker Dropdown&lt;/h3&gt;
      &lt;p&gt;Choose a date from a compact dropdown calendar and update the selected booking date instantly.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-dropdown-twenty-card"&gt;
      &lt;div class="vb-dropdown-twenty-card-head"&gt;
        &lt;small&gt;Booking date&lt;/small&gt;
        &lt;strong data-vb-dropdown-twenty-selected&gt;No date selected&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-twenty-control"&gt;
        &lt;button type="button" class="vb-dropdown-twenty-trigger" data-vb-dropdown-twenty-trigger aria-expanded="false"&gt;
          &lt;span data-vb-dropdown-twenty-trigger-text&gt;Select a date&lt;/span&gt;
          &lt;em&gt;⌄&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-dropdown-twenty-menu" data-vb-dropdown-twenty-menu&gt;
          &lt;div class="vb-dropdown-twenty-month"&gt;
            &lt;strong&gt;June 2026&lt;/strong&gt;
            &lt;button type="button" data-vb-dropdown-twenty-clear&gt;Clear&lt;/button&gt;
          &lt;/div&gt;

          &lt;div class="vb-dropdown-twenty-weekdays"&gt;
            &lt;span&gt;Mo&lt;/span&gt;
            &lt;span&gt;Tu&lt;/span&gt;
            &lt;span&gt;We&lt;/span&gt;
            &lt;span&gt;Th&lt;/span&gt;
            &lt;span&gt;Fr&lt;/span&gt;
            &lt;span&gt;Sa&lt;/span&gt;
            &lt;span&gt;Su&lt;/span&gt;
          &lt;/div&gt;

          &lt;div class="vb-dropdown-twenty-days"&gt;
            &lt;button type="button" data-date="June 1, 2026"&gt;1&lt;/button&gt;
            &lt;button type="button" data-date="June 2, 2026"&gt;2&lt;/button&gt;
            &lt;button type="button" data-date="June 3, 2026"&gt;3&lt;/button&gt;
            &lt;button type="button" data-date="June 4, 2026"&gt;4&lt;/button&gt;
            &lt;button type="button" data-date="June 5, 2026"&gt;5&lt;/button&gt;
            &lt;button type="button" data-date="June 6, 2026"&gt;6&lt;/button&gt;
            &lt;button type="button" data-date="June 7, 2026"&gt;7&lt;/button&gt;
            &lt;button type="button" data-date="June 8, 2026"&gt;8&lt;/button&gt;
            &lt;button type="button" data-date="June 9, 2026"&gt;9&lt;/button&gt;
            &lt;button type="button" data-date="June 10, 2026"&gt;10&lt;/button&gt;
            &lt;button type="button" data-date="June 11, 2026"&gt;11&lt;/button&gt;
            &lt;button type="button" data-date="June 12, 2026"&gt;12&lt;/button&gt;
            &lt;button type="button" data-date="June 13, 2026"&gt;13&lt;/button&gt;
            &lt;button type="button" data-date="June 14, 2026"&gt;14&lt;/button&gt;
            &lt;button type="button" data-date="June 15, 2026"&gt;15&lt;/button&gt;
            &lt;button type="button" data-date="June 16, 2026"&gt;16&lt;/button&gt;
            &lt;button type="button" data-date="June 17, 2026"&gt;17&lt;/button&gt;
            &lt;button type="button" data-date="June 18, 2026"&gt;18&lt;/button&gt;
            &lt;button type="button" data-date="June 19, 2026"&gt;19&lt;/button&gt;
            &lt;button type="button" data-date="June 20, 2026"&gt;20&lt;/button&gt;
            &lt;button type="button" data-date="June 21, 2026"&gt;21&lt;/button&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-twenty-details"&gt;
        &lt;div&gt;
          &lt;small&gt;Service&lt;/small&gt;
          &lt;strong&gt;Consultation Call&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Duration&lt;/small&gt;
          &lt;strong&gt;45 minutes&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-twenty-demo,
.vb-dropdown-twenty-demo * {
  box-sizing: border-box;
}

.vb-dropdown-twenty-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(34, 197, 94, 0.20), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(20, 184, 166, 0.18), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #f0fdfa 52%, #ffffff 100%) !important;
  border: 1px solid rgba(187, 247, 208, 0.48);
  box-shadow: 0 24px 70px rgba(21, 128, 61, 0.12);
}

.vb-dropdown-twenty-booking {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(330px, 0.75fr);
  gap: 34px;
  align-items: center;
  max-width: 1040px;
  min-height: 600px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(187, 247, 208, 0.52);
  box-shadow: 0 24px 70px rgba(21, 128, 61, 0.12);
  overflow: visible;
}

.vb-dropdown-twenty-copy &gt; span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-twenty-copy h3 {
  max-width: 680px;
  margin: 0 0 16px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-twenty-copy p {
  max-width: 560px;
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-twenty-card {
  position: relative;
  z-index: 30;
  padding: 22px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 18% 16%, rgba(34, 197, 94, 0.18), transparent 34%),
    linear-gradient(135deg, #064e3b, #0f766e) !important;
  box-shadow: 0 30px 80px rgba(15, 118, 110, 0.28);
  overflow: visible;
}

.vb-dropdown-twenty-card-head {
  margin-bottom: 20px;
  padding: 20px;
  border-radius: 24px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-dropdown-twenty-card-head small {
  display: block;
  margin-bottom: 8px;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twenty-card-head strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 28px;
  line-height: 1.12;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-dropdown-twenty-control {
  position: relative;
  z-index: 50;
  margin-bottom: 18px;
}

.vb-dropdown-twenty-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  min-height: 60px;
  padding: 13px 14px 13px 16px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 20px;
  background: rgba(255,255,255,0.12);
  cursor: pointer;
  text-align: left;
}

.vb-dropdown-twenty-trigger span {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-twenty-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-twenty-booking.is-open .vb-dropdown-twenty-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-twenty-menu {
  position: absolute;
  z-index: 80;
  top: calc(100% + 12px);
  left: 0;
  right: 0;
  padding: 14px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.34);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-twenty-booking.is-open .vb-dropdown-twenty-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-twenty-month {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  margin-bottom: 12px;
}

.vb-dropdown-twenty-month strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-twenty-month button {
  border: 0;
  border-radius: 999px;
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  padding: 8px 10px;
  font-size: 12px;
  font-weight: 900;
  cursor: pointer;
}

.vb-dropdown-twenty-weekdays,
.vb-dropdown-twenty-days {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 6px;
}

.vb-dropdown-twenty-weekdays {
  margin-bottom: 7px;
}

.vb-dropdown-twenty-weekdays span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 28px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 11px;
  font-weight: 950;
  text-transform: uppercase;
}

.vb-dropdown-twenty-days button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 38px;
  border: 0;
  border-radius: 13px;
  background: #f8fafc;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 13px;
  font-weight: 900;
  cursor: pointer;
  transition: background 0.18s ease, color 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-twenty-days button:hover {
  background: #dcfce7;
  color: #15803d !important;
  -webkit-text-fill-color: #15803d !important;
  transform: translateY(-1px);
}

.vb-dropdown-twenty-days button.is-selected {
  background: linear-gradient(135deg, #22c55e, #0f766e);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  box-shadow: 0 10px 24px rgba(15, 118, 110, 0.22);
}

.vb-dropdown-twenty-details {
  display: grid;
  gap: 10px;
}

.vb-dropdown-twenty-details div {
  padding: 14px;
  border-radius: 18px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-dropdown-twenty-details small {
  display: block;
  margin-bottom: 5px;
  color: #bbf7d0 !important;
  -webkit-text-fill-color: #bbf7d0 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twenty-details strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-dropdown-twenty-booking {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-twenty-card {
    max-width: 440px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-twenty-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twenty-booking {
    min-height: 760px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-twenty-copy h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-twenty-card {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twenty-card-head strong {
    font-size: 23px;
  }

  .vb-dropdown-twenty-days button {
    min-height: 34px;
    border-radius: 10px;
  }
}</pre>



<p class="wp-block-paragraph">This date picker dropdown is useful for interfaces where users need to select a date without leaving the current form. You can adapt it for booking calendars, appointment forms, delivery selectors, content scheduling tools, hotel booking pages, and dashboard filters.</p>



<h2 class="wp-block-heading">21. Notification Dropdown Menu</h2>



<p class="wp-block-paragraph"><strong>A notification dropdown menu</strong> is useful for dashboards, SaaS apps, ecommerce accounts, admin panels, social platforms, membership websites, and project management tools. It lets users quickly see recent updates without leaving the current page.</p>



<p class="wp-block-paragraph">This example includes a notification bell, unread badge, dropdown panel, notification list, mark all as read button, active unread state, outside click closing, and Escape key support. The JavaScript updates the badge and changes unread notifications into read items.</p>



<ul class="wp-block-list">
<li>Notification bell dropdown</li>
<li>Unread badge counter</li>
<li>Mark all as read action</li>
<li>Outside click and Escape key support</li>
<li>Useful for dashboards, SaaS apps, ecommerce accounts, and admin panels</li>
</ul>



<div class="vb-dropdown-twentyone-demo">
  <div class="vb-dropdown-twentyone-app" data-vb-dropdown-twentyone>
    <header class="vb-dropdown-twentyone-header">
      <a href="#javascript-dropdown-menu-examples" class="vb-dropdown-twentyone-logo">
        <span>N</span>
        <strong>NotifyHub</strong>
      </a>

      <div class="vb-dropdown-twentyone-bell-wrap">
        <button type="button" class="vb-dropdown-twentyone-bell" data-vb-dropdown-twentyone-trigger aria-expanded="false" aria-label="Open notifications">
          <span>🔔</span>
          <em data-vb-dropdown-twentyone-count>3</em>
        </button>

        <div class="vb-dropdown-twentyone-panel" data-vb-dropdown-twentyone-panel>
          <div class="vb-dropdown-twentyone-panel-head">
            <div>
              <strong>Notifications</strong>
              <small data-vb-dropdown-twentyone-summary>3 unread updates</small>
            </div>

            <button type="button" data-vb-dropdown-twentyone-read>Mark all read</button>
          </div>

          <div class="vb-dropdown-twentyone-list" data-vb-dropdown-twentyone-list>
            <article class="is-unread">
              <span>💬</span>
              <div>
                <strong>New comment received</strong>
                <p>A visitor commented on your JavaScript dropdown article.</p>
                <small>2 minutes ago</small>
              </div>
            </article>

            <article class="is-unread">
              <span>🛒</span>
              <div>
                <strong>New product order</strong>
                <p>Your digital UI bundle received a new purchase.</p>
                <small>18 minutes ago</small>
              </div>
            </article>

            <article class="is-unread">
              <span>⚙️</span>
              <div>
                <strong>System update ready</strong>
                <p>A new dashboard component update is available.</p>
                <small>1 hour ago</small>
              </div>
            </article>

            <article>
              <span>📈</span>
              <div>
                <strong>Traffic report generated</strong>
                <p>Your weekly analytics report is ready to review.</p>
                <small>Yesterday</small>
              </div>
            </article>
          </div>
        </div>
      </div>
    </header>

    <section class="vb-dropdown-twentyone-hero">
      <span>Example 21</span>
      <h3>Notification Dropdown Menu</h3>
      <p>Open the notification bell to show recent updates, unread states, and a mark all as read action.</p>

      <div class="vb-dropdown-twentyone-stats">
        <div>
          <small>Unread</small>
          <strong data-vb-dropdown-twentyone-stat>3</strong>
        </div>
        <div>
          <small>Total updates</small>
          <strong>4</strong>
        </div>
      </div>
    </section>
  </div>
</div>

<style>
.vb-dropdown-twentyone-demo,
.vb-dropdown-twentyone-demo * {
  box-sizing: border-box;
}

.vb-dropdown-twentyone-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 16% 18%, rgba(245, 158, 11, 0.20), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(239, 68, 68, 0.18), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fff1f2 52%, #ffffff 100%) !important;
  border: 1px solid rgba(251, 191, 36, 0.34);
  box-shadow: 0 24px 70px rgba(120, 53, 15, 0.12);
}

.vb-dropdown-twentyone-app {
  position: relative;
  max-width: 1080px;
  min-height: 600px;
  margin: 0 auto;
  padding: 24px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 78% 74%, rgba(245, 158, 11, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
  overflow: visible;
}

.vb-dropdown-twentyone-header {
  position: relative;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  padding: 14px;
  border-radius: 24px;
  background: #111827;
  box-shadow: 0 20px 50px rgba(15, 23, 42, 0.22);
}

.vb-dropdown-twentyone-logo {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none !important;
}

.vb-dropdown-twentyone-logo span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: linear-gradient(135deg, #f59e0b, #ef4444);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-twentyone-logo strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-twentyone-bell-wrap {
  position: relative;
}

.vb-dropdown-twentyone-bell {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 17px;
  background: rgba(255,255,255,0.10);
  cursor: pointer;
}

.vb-dropdown-twentyone-bell > span {
  font-size: 20px;
}

.vb-dropdown-twentyone-bell em {
  position: absolute;
  top: -7px;
  right: -7px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 24px;
  padding: 0 7px;
  border-radius: 999px;
  background: #ef4444;
  border: 2px solid #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-style: normal;
  font-weight: 950;
}

.vb-dropdown-twentyone-bell em.is-hidden {
  display: none;
}

.vb-dropdown-twentyone-panel {
  position: absolute;
  z-index: 80;
  top: calc(100% + 14px);
  right: 0;
  width: 390px;
  padding: 14px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.32);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-twentyone-app.is-open .vb-dropdown-twentyone-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-twentyone-panel-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
  padding: 8px 8px 12px;
  border-bottom: 1px solid #e5e7eb;
  margin-bottom: 10px;
}

.vb-dropdown-twentyone-panel-head strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-dropdown-twentyone-panel-head small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 750;
}

.vb-dropdown-twentyone-panel-head button {
  border: 0;
  border-radius: 999px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  padding: 8px 10px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
  white-space: nowrap;
}

.vb-dropdown-twentyone-list {
  display: grid;
  gap: 8px;
  max-height: 350px;
  overflow-y: auto;
  padding-right: 4px;
}

.vb-dropdown-twentyone-list article {
  position: relative;
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr);
  gap: 12px;
  padding: 12px;
  border-radius: 18px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.18);
}

.vb-dropdown-twentyone-list article.is-unread {
  background: #fff7ed;
  border-color: rgba(251, 146, 60, 0.32);
}

.vb-dropdown-twentyone-list article.is-unread::after {
  content: "";
  position: absolute;
  top: 17px;
  right: 15px;
  width: 9px;
  height: 9px;
  border-radius: 999px;
  background: #ef4444;
}

.vb-dropdown-twentyone-list article > span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 16px;
  background: #ffffff;
  font-size: 18px;
  box-shadow: 0 10px 24px rgba(15, 23, 42, 0.08);
}

.vb-dropdown-twentyone-list strong {
  display: block;
  padding-right: 16px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  line-height: 1.25;
  font-weight: 950;
}

.vb-dropdown-twentyone-list p {
  margin: 5px 0 6px !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.45;
  font-weight: 650;
}

.vb-dropdown-twentyone-list small {
  color: #f59e0b !important;
  -webkit-text-fill-color: #f59e0b !important;
  font-size: 11px;
  font-weight: 900;
}

.vb-dropdown-twentyone-hero {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 470px;
  padding: 56px 18px 18px;
}

.vb-dropdown-twentyone-hero > span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-twentyone-hero h3 {
  max-width: 760px;
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(38px, 6vw, 78px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-twentyone-hero p {
  max-width: 640px;
  margin: 0 0 24px !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-twentyone-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 170px));
  gap: 12px;
}

.vb-dropdown-twentyone-stats div {
  padding: 16px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.08);
}

.vb-dropdown-twentyone-stats small {
  display: block;
  margin-bottom: 6px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-dropdown-twentyone-stats strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 32px;
  line-height: 1;
  font-weight: 950;
}

@media (max-width: 640px) {
  .vb-dropdown-twentyone-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twentyone-app {
    min-height: 740px;
    padding: 18px;
    border-radius: 22px;
  }

  .vb-dropdown-twentyone-panel {
    right: -4px;
    width: min(86vw, 390px);
  }

  .vb-dropdown-twentyone-hero h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-twentyone-stats {
    grid-template-columns: 1fr;
    max-width: 260px;
  }
}
</style>

<script>
(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-twentyone]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-twentyone-trigger]");
  const count = dropdown.querySelector("[data-vb-dropdown-twentyone-count]");
  const summary = dropdown.querySelector("[data-vb-dropdown-twentyone-summary]");
  const stat = dropdown.querySelector("[data-vb-dropdown-twentyone-stat]");
  const readButton = dropdown.querySelector("[data-vb-dropdown-twentyone-read]");
  const list = dropdown.querySelector("[data-vb-dropdown-twentyone-list]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function updateUnreadCount() {
    const unreadItems = list.querySelectorAll(".is-unread");
    const unreadCount = unreadItems.length;

    count.textContent = unreadCount;
    stat.textContent = unreadCount;
    summary.textContent = unreadCount === 1 ? "1 unread update" : unreadCount + " unread updates";
    count.classList.toggle("is-hidden", unreadCount === 0);
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  readButton.addEventListener("click", function (event) {
    event.stopPropagation();

    list.querySelectorAll(".is-unread").forEach(function (item) {
      item.classList.remove("is-unread");
    });

    updateUnreadCount();
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });

  updateUnreadCount();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-twentyone]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-twentyone-trigger]");
  const count = dropdown.querySelector("[data-vb-dropdown-twentyone-count]");
  const summary = dropdown.querySelector("[data-vb-dropdown-twentyone-summary]");
  const stat = dropdown.querySelector("[data-vb-dropdown-twentyone-stat]");
  const readButton = dropdown.querySelector("[data-vb-dropdown-twentyone-read]");
  const list = dropdown.querySelector("[data-vb-dropdown-twentyone-list]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function updateUnreadCount() {
    const unreadItems = list.querySelectorAll(".is-unread");
    const unreadCount = unreadItems.length;

    count.textContent = unreadCount;
    stat.textContent = unreadCount;
    summary.textContent = unreadCount === 1 ? "1 unread update" : unreadCount + " unread updates";
    count.classList.toggle("is-hidden", unreadCount === 0);
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  readButton.addEventListener("click", function (event) {
    event.stopPropagation();

    list.querySelectorAll(".is-unread").forEach(function (item) {
      item.classList.remove("is-unread");
    });

    updateUnreadCount();
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });

  updateUnreadCount();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-twentyone-demo"&gt;
  &lt;div class="vb-dropdown-twentyone-app" data-vb-dropdown-twentyone&gt;
    &lt;header class="vb-dropdown-twentyone-header"&gt;
      &lt;a href="#javascript-dropdown-menu-examples" class="vb-dropdown-twentyone-logo"&gt;
        &lt;span&gt;N&lt;/span&gt;
        &lt;strong&gt;NotifyHub&lt;/strong&gt;
      &lt;/a&gt;

      &lt;div class="vb-dropdown-twentyone-bell-wrap"&gt;
        &lt;button type="button" class="vb-dropdown-twentyone-bell" data-vb-dropdown-twentyone-trigger aria-expanded="false" aria-label="Open notifications"&gt;
          &lt;span&gt;🔔&lt;/span&gt;
          &lt;em data-vb-dropdown-twentyone-count&gt;3&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-dropdown-twentyone-panel" data-vb-dropdown-twentyone-panel&gt;
          &lt;div class="vb-dropdown-twentyone-panel-head"&gt;
            &lt;div&gt;
              &lt;strong&gt;Notifications&lt;/strong&gt;
              &lt;small data-vb-dropdown-twentyone-summary&gt;3 unread updates&lt;/small&gt;
            &lt;/div&gt;

            &lt;button type="button" data-vb-dropdown-twentyone-read&gt;Mark all read&lt;/button&gt;
          &lt;/div&gt;

          &lt;div class="vb-dropdown-twentyone-list" data-vb-dropdown-twentyone-list&gt;
            &lt;article class="is-unread"&gt;
              &lt;span&gt;💬&lt;/span&gt;
              &lt;div&gt;
                &lt;strong&gt;New comment received&lt;/strong&gt;
                &lt;p&gt;A visitor commented on your JavaScript dropdown article.&lt;/p&gt;
                &lt;small&gt;2 minutes ago&lt;/small&gt;
              &lt;/div&gt;
            &lt;/article&gt;

            &lt;article class="is-unread"&gt;
              &lt;span&gt;🛒&lt;/span&gt;
              &lt;div&gt;
                &lt;strong&gt;New product order&lt;/strong&gt;
                &lt;p&gt;Your digital UI bundle received a new purchase.&lt;/p&gt;
                &lt;small&gt;18 minutes ago&lt;/small&gt;
              &lt;/div&gt;
            &lt;/article&gt;

            &lt;article class="is-unread"&gt;
              &lt;span&gt;⚙️&lt;/span&gt;
              &lt;div&gt;
                &lt;strong&gt;System update ready&lt;/strong&gt;
                &lt;p&gt;A new dashboard component update is available.&lt;/p&gt;
                &lt;small&gt;1 hour ago&lt;/small&gt;
              &lt;/div&gt;
            &lt;/article&gt;

            &lt;article&gt;
              &lt;span&gt;📈&lt;/span&gt;
              &lt;div&gt;
                &lt;strong&gt;Traffic report generated&lt;/strong&gt;
                &lt;p&gt;Your weekly analytics report is ready to review.&lt;/p&gt;
                &lt;small&gt;Yesterday&lt;/small&gt;
              &lt;/div&gt;
            &lt;/article&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/header&gt;

    &lt;section class="vb-dropdown-twentyone-hero"&gt;
      &lt;span&gt;Example 21&lt;/span&gt;
      &lt;h3&gt;Notification Dropdown Menu&lt;/h3&gt;
      &lt;p&gt;Open the notification bell to show recent updates, unread states, and a mark all as read action.&lt;/p&gt;

      &lt;div class="vb-dropdown-twentyone-stats"&gt;
        &lt;div&gt;
          &lt;small&gt;Unread&lt;/small&gt;
          &lt;strong data-vb-dropdown-twentyone-stat&gt;3&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Total updates&lt;/small&gt;
          &lt;strong&gt;4&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/section&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-twentyone-demo,
.vb-dropdown-twentyone-demo * {
  box-sizing: border-box;
}

.vb-dropdown-twentyone-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 16% 18%, rgba(245, 158, 11, 0.20), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(239, 68, 68, 0.18), transparent 34%),
    linear-gradient(135deg, #fffbeb 0%, #fff1f2 52%, #ffffff 100%) !important;
  border: 1px solid rgba(251, 191, 36, 0.34);
  box-shadow: 0 24px 70px rgba(120, 53, 15, 0.12);
}

.vb-dropdown-twentyone-app {
  position: relative;
  max-width: 1080px;
  min-height: 600px;
  margin: 0 auto;
  padding: 24px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 78% 74%, rgba(245, 158, 11, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
  overflow: visible;
}

.vb-dropdown-twentyone-header {
  position: relative;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  padding: 14px;
  border-radius: 24px;
  background: #111827;
  box-shadow: 0 20px 50px rgba(15, 23, 42, 0.22);
}

.vb-dropdown-twentyone-logo {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none !important;
}

.vb-dropdown-twentyone-logo span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: linear-gradient(135deg, #f59e0b, #ef4444);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-twentyone-logo strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-twentyone-bell-wrap {
  position: relative;
}

.vb-dropdown-twentyone-bell {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 17px;
  background: rgba(255,255,255,0.10);
  cursor: pointer;
}

.vb-dropdown-twentyone-bell &gt; span {
  font-size: 20px;
}

.vb-dropdown-twentyone-bell em {
  position: absolute;
  top: -7px;
  right: -7px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 24px;
  height: 24px;
  padding: 0 7px;
  border-radius: 999px;
  background: #ef4444;
  border: 2px solid #111827;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 12px;
  font-style: normal;
  font-weight: 950;
}

.vb-dropdown-twentyone-bell em.is-hidden {
  display: none;
}

.vb-dropdown-twentyone-panel {
  position: absolute;
  z-index: 80;
  top: calc(100% + 14px);
  right: 0;
  width: 390px;
  padding: 14px;
  border-radius: 26px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.26);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.32);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-twentyone-app.is-open .vb-dropdown-twentyone-panel {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-twentyone-panel-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 14px;
  padding: 8px 8px 12px;
  border-bottom: 1px solid #e5e7eb;
  margin-bottom: 10px;
}

.vb-dropdown-twentyone-panel-head strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-dropdown-twentyone-panel-head small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 13px;
  font-weight: 750;
}

.vb-dropdown-twentyone-panel-head button {
  border: 0;
  border-radius: 999px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  padding: 8px 10px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
  white-space: nowrap;
}

.vb-dropdown-twentyone-list {
  display: grid;
  gap: 8px;
  max-height: 350px;
  overflow-y: auto;
  padding-right: 4px;
}

.vb-dropdown-twentyone-list article {
  position: relative;
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr);
  gap: 12px;
  padding: 12px;
  border-radius: 18px;
  background: #f8fafc;
  border: 1px solid rgba(148, 163, 184, 0.18);
}

.vb-dropdown-twentyone-list article.is-unread {
  background: #fff7ed;
  border-color: rgba(251, 146, 60, 0.32);
}

.vb-dropdown-twentyone-list article.is-unread::after {
  content: "";
  position: absolute;
  top: 17px;
  right: 15px;
  width: 9px;
  height: 9px;
  border-radius: 999px;
  background: #ef4444;
}

.vb-dropdown-twentyone-list article &gt; span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 16px;
  background: #ffffff;
  font-size: 18px;
  box-shadow: 0 10px 24px rgba(15, 23, 42, 0.08);
}

.vb-dropdown-twentyone-list strong {
  display: block;
  padding-right: 16px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  line-height: 1.25;
  font-weight: 950;
}

.vb-dropdown-twentyone-list p {
  margin: 5px 0 6px !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.45;
  font-weight: 650;
}

.vb-dropdown-twentyone-list small {
  color: #f59e0b !important;
  -webkit-text-fill-color: #f59e0b !important;
  font-size: 11px;
  font-weight: 900;
}

.vb-dropdown-twentyone-hero {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 470px;
  padding: 56px 18px 18px;
}

.vb-dropdown-twentyone-hero &gt; span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-twentyone-hero h3 {
  max-width: 760px;
  margin: 0 0 14px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(38px, 6vw, 78px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-twentyone-hero p {
  max-width: 640px;
  margin: 0 0 24px !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-twentyone-stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 170px));
  gap: 12px;
}

.vb-dropdown-twentyone-stats div {
  padding: 16px;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.08);
}

.vb-dropdown-twentyone-stats small {
  display: block;
  margin-bottom: 6px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-dropdown-twentyone-stats strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 32px;
  line-height: 1;
  font-weight: 950;
}

@media (max-width: 640px) {
  .vb-dropdown-twentyone-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twentyone-app {
    min-height: 740px;
    padding: 18px;
    border-radius: 22px;
  }

  .vb-dropdown-twentyone-panel {
    right: -4px;
    width: min(86vw, 390px);
  }

  .vb-dropdown-twentyone-hero h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-twentyone-stats {
    grid-template-columns: 1fr;
    max-width: 260px;
  }
}</pre>



<p class="wp-block-paragraph">This notification dropdown is a strong dashboard pattern because it keeps alerts visible without taking the user away from the current screen. You can adapt it for SaaS apps, ecommerce order updates, admin notifications, membership dashboards, CRM systems, and project management tools.</p>



<h2 class="wp-block-heading">22. Multi-Select Tags Dropdown</h2>



<p class="wp-block-paragraph"><strong>A multi-select tags dropdown</strong> helps users choose several options from one compact control. It is useful for filters, blog tags, product attributes, user interests, project labels, skill selectors, CRM segments, and dashboard search controls.</p>



<p class="wp-block-paragraph">This example includes a dropdown trigger, selectable tag options, selected chips, remove buttons, clear all action, active option states, outside click closing, and Escape key support. The JavaScript keeps selected tags synchronized between the dropdown and the chip preview area.</p>



<ul class="wp-block-list">
<li>Multi-select dropdown with tags</li>
<li>Selected chips with remove buttons</li>
<li>Clear all selected options</li>
<li>Active option styling</li>
<li>Useful for filters, product attributes, blog tags, skills, labels, and dashboard search</li>
</ul>



<div class="vb-dropdown-twentytwo-demo">
  <div class="vb-dropdown-twentytwo-filter" data-vb-dropdown-twentytwo>
    <div class="vb-dropdown-twentytwo-copy">
      <span>Example 22</span>
      <h3>Multi-Select Tags Dropdown</h3>
      <p>Select multiple tags from the dropdown and display them as removable chips below the control.</p>
    </div>

    <div class="vb-dropdown-twentytwo-card">
      <div class="vb-dropdown-twentytwo-card-head">
        <small>Content filters</small>
        <strong>Choose topics</strong>
      </div>

      <div class="vb-dropdown-twentytwo-control">
        <button type="button" class="vb-dropdown-twentytwo-trigger" data-vb-dropdown-twentytwo-trigger aria-expanded="false">
          <span data-vb-dropdown-twentytwo-label>Select tags</span>
          <em>⌄</em>
        </button>

        <div class="vb-dropdown-twentytwo-menu" data-vb-dropdown-twentytwo-menu>
          <div class="vb-dropdown-twentytwo-menu-head">
            <strong>Available tags</strong>
            <button type="button" data-vb-dropdown-twentytwo-clear>Clear all</button>
          </div>

          <button type="button" data-tag="JavaScript">JavaScript</button>
          <button type="button" data-tag="Dropdown UI">Dropdown UI</button>
          <button type="button" data-tag="Ecommerce">Ecommerce</button>
          <button type="button" data-tag="Dashboard">Dashboard</button>
          <button type="button" data-tag="Forms">Forms</button>
          <button type="button" data-tag="Navigation">Navigation</button>
          <button type="button" data-tag="Accessibility">Accessibility</button>
        </div>
      </div>

      <div class="vb-dropdown-twentytwo-selected">
        <small>Selected tags</small>
        <div class="vb-dropdown-twentytwo-chips" data-vb-dropdown-twentytwo-chips>
          <span class="vb-dropdown-twentytwo-empty">No tags selected yet.</span>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-dropdown-twentytwo-demo,
.vb-dropdown-twentytwo-demo * {
  box-sizing: border-box;
}

.vb-dropdown-twentytwo-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(168, 85, 247, 0.20), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(236, 72, 153, 0.18), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #fdf2f8 52%, #ffffff 100%) !important;
  border: 1px solid rgba(216, 180, 254, 0.42);
  box-shadow: 0 24px 70px rgba(107, 33, 168, 0.12);
}

.vb-dropdown-twentytwo-filter {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(330px, 0.75fr);
  gap: 34px;
  align-items: center;
  max-width: 1040px;
  min-height: 600px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(216, 180, 254, 0.42);
  box-shadow: 0 24px 70px rgba(107, 33, 168, 0.12);
  overflow: visible;
}

.vb-dropdown-twentytwo-copy > span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-twentytwo-copy h3 {
  max-width: 680px;
  margin: 0 0 16px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-twentytwo-copy p {
  max-width: 560px;
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-twentytwo-card {
  position: relative;
  z-index: 30;
  padding: 22px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 16% 14%, rgba(236, 72, 153, 0.16), transparent 34%),
    linear-gradient(135deg, #581c87, #be185d) !important;
  box-shadow: 0 30px 80px rgba(107, 33, 168, 0.28);
  overflow: visible;
}

.vb-dropdown-twentytwo-card-head {
  margin-bottom: 20px;
}

.vb-dropdown-twentytwo-card-head small {
  display: block;
  margin-bottom: 8px;
  color: #f5d0fe !important;
  -webkit-text-fill-color: #f5d0fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentytwo-card-head strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-dropdown-twentytwo-control {
  position: relative;
  z-index: 50;
  margin-bottom: 18px;
}

.vb-dropdown-twentytwo-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  min-height: 60px;
  padding: 13px 14px 13px 16px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 20px;
  background: rgba(255,255,255,0.12);
  cursor: pointer;
  text-align: left;
}

.vb-dropdown-twentytwo-trigger span {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-twentytwo-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-twentytwo-filter.is-open .vb-dropdown-twentytwo-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-twentytwo-menu {
  position: absolute;
  z-index: 80;
  top: calc(100% + 12px);
  left: 0;
  right: 0;
  display: grid;
  gap: 7px;
  padding: 12px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.34);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-twentytwo-filter.is-open .vb-dropdown-twentytwo-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-twentytwo-menu-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 4px 4px 8px;
  border-bottom: 1px solid #e5e7eb;
  margin-bottom: 4px;
}

.vb-dropdown-twentytwo-menu-head strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-dropdown-twentytwo-menu-head button {
  border: 0;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  padding: 7px 9px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-dropdown-twentytwo-menu > button[data-tag] {
  width: 100%;
  min-height: 44px;
  padding: 10px 12px;
  border: 0;
  border-radius: 15px;
  background: transparent;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 850;
  text-align: left;
  cursor: pointer;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-twentytwo-menu > button[data-tag]:hover,
.vb-dropdown-twentytwo-menu > button[data-tag].is-selected {
  background: #fdf2f8;
  transform: translateX(2px);
}

.vb-dropdown-twentytwo-menu > button[data-tag].is-selected {
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
}

.vb-dropdown-twentytwo-selected {
  padding: 16px;
  border-radius: 22px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-dropdown-twentytwo-selected > small {
  display: block;
  margin-bottom: 10px;
  color: #f5d0fe !important;
  -webkit-text-fill-color: #f5d0fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentytwo-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  min-height: 42px;
  align-items: center;
}

.vb-dropdown-twentytwo-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 34px;
  padding: 7px 8px 7px 11px;
  border-radius: 999px;
  background: #ffffff;
  color: #581c87 !important;
  -webkit-text-fill-color: #581c87 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-dropdown-twentytwo-chip button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border: 0;
  border-radius: 999px;
  background: #fce7f3;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-dropdown-twentytwo-empty {
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 13px;
  font-weight: 750;
}

@media (max-width: 860px) {
  .vb-dropdown-twentytwo-filter {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-twentytwo-card {
    max-width: 440px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-twentytwo-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twentytwo-filter {
    min-height: 760px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-twentytwo-copy h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-twentytwo-card {
    padding: 18px;
    border-radius: 24px;
  }
}
</style>

<script>
(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-twentytwo]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-twentytwo-trigger]");
  const label = dropdown.querySelector("[data-vb-dropdown-twentytwo-label]");
  const tagButtons = dropdown.querySelectorAll("[data-tag]");
  const chipsWrap = dropdown.querySelector("[data-vb-dropdown-twentytwo-chips]");
  const clearButton = dropdown.querySelector("[data-vb-dropdown-twentytwo-clear]");
  let selectedTags = [];

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function renderTags() {
    chipsWrap.innerHTML = "";

    if (selectedTags.length === 0) {
      const empty = document.createElement("span");
      empty.className = "vb-dropdown-twentytwo-empty";
      empty.textContent = "No tags selected yet.";
      chipsWrap.appendChild(empty);
      label.textContent = "Select tags";
    } else {
      label.textContent = selectedTags.length === 1 ? "1 tag selected" : selectedTags.length + " tags selected";

      selectedTags.forEach(function (tag) {
        const chip = document.createElement("span");
        chip.className = "vb-dropdown-twentytwo-chip";
        chip.textContent = tag;

        const removeButton = document.createElement("button");
        removeButton.type = "button";
        removeButton.textContent = "×";
        removeButton.setAttribute("aria-label", "Remove " + tag);

        removeButton.addEventListener("click", function () {
          selectedTags = selectedTags.filter(function (item) {
            return item !== tag;
          });
          syncButtons();
          renderTags();
        });

        chip.appendChild(removeButton);
        chipsWrap.appendChild(chip);
      });
    }
  }

  function syncButtons() {
    tagButtons.forEach(function (button) {
      const tag = button.getAttribute("data-tag");
      button.classList.toggle("is-selected", selectedTags.includes(tag));
    });
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  tagButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      const tag = button.getAttribute("data-tag");

      if (selectedTags.includes(tag)) {
        selectedTags = selectedTags.filter(function (item) {
          return item !== tag;
        });
      } else {
        selectedTags.push(tag);
      }

      syncButtons();
      renderTags();
    });
  });

  clearButton.addEventListener("click", function (event) {
    event.stopPropagation();
    selectedTags = [];
    syncButtons();
    renderTags();
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });

  renderTags();
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-twentytwo]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-twentytwo-trigger]");
  const label = dropdown.querySelector("[data-vb-dropdown-twentytwo-label]");
  const tagButtons = dropdown.querySelectorAll("[data-tag]");
  const chipsWrap = dropdown.querySelector("[data-vb-dropdown-twentytwo-chips]");
  const clearButton = dropdown.querySelector("[data-vb-dropdown-twentytwo-clear]");
  let selectedTags = [];

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function renderTags() {
    chipsWrap.innerHTML = "";

    if (selectedTags.length === 0) {
      const empty = document.createElement("span");
      empty.className = "vb-dropdown-twentytwo-empty";
      empty.textContent = "No tags selected yet.";
      chipsWrap.appendChild(empty);
      label.textContent = "Select tags";
    } else {
      label.textContent = selectedTags.length === 1 ? "1 tag selected" : selectedTags.length + " tags selected";

      selectedTags.forEach(function (tag) {
        const chip = document.createElement("span");
        chip.className = "vb-dropdown-twentytwo-chip";
        chip.textContent = tag;

        const removeButton = document.createElement("button");
        removeButton.type = "button";
        removeButton.textContent = "×";
        removeButton.setAttribute("aria-label", "Remove " + tag);

        removeButton.addEventListener("click", function () {
          selectedTags = selectedTags.filter(function (item) {
            return item !== tag;
          });
          syncButtons();
          renderTags();
        });

        chip.appendChild(removeButton);
        chipsWrap.appendChild(chip);
      });
    }
  }

  function syncButtons() {
    tagButtons.forEach(function (button) {
      const tag = button.getAttribute("data-tag");
      button.classList.toggle("is-selected", selectedTags.includes(tag));
    });
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  tagButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      const tag = button.getAttribute("data-tag");

      if (selectedTags.includes(tag)) {
        selectedTags = selectedTags.filter(function (item) {
          return item !== tag;
        });
      } else {
        selectedTags.push(tag);
      }

      syncButtons();
      renderTags();
    });
  });

  clearButton.addEventListener("click", function (event) {
    event.stopPropagation();
    selectedTags = [];
    syncButtons();
    renderTags();
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });

  renderTags();
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-twentytwo-demo"&gt;
  &lt;div class="vb-dropdown-twentytwo-filter" data-vb-dropdown-twentytwo&gt;
    &lt;div class="vb-dropdown-twentytwo-copy"&gt;
      &lt;span&gt;Example 22&lt;/span&gt;
      &lt;h3&gt;Multi-Select Tags Dropdown&lt;/h3&gt;
      &lt;p&gt;Select multiple tags from the dropdown and display them as removable chips below the control.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-dropdown-twentytwo-card"&gt;
      &lt;div class="vb-dropdown-twentytwo-card-head"&gt;
        &lt;small&gt;Content filters&lt;/small&gt;
        &lt;strong&gt;Choose topics&lt;/strong&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-twentytwo-control"&gt;
        &lt;button type="button" class="vb-dropdown-twentytwo-trigger" data-vb-dropdown-twentytwo-trigger aria-expanded="false"&gt;
          &lt;span data-vb-dropdown-twentytwo-label&gt;Select tags&lt;/span&gt;
          &lt;em&gt;⌄&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-dropdown-twentytwo-menu" data-vb-dropdown-twentytwo-menu&gt;
          &lt;div class="vb-dropdown-twentytwo-menu-head"&gt;
            &lt;strong&gt;Available tags&lt;/strong&gt;
            &lt;button type="button" data-vb-dropdown-twentytwo-clear&gt;Clear all&lt;/button&gt;
          &lt;/div&gt;

          &lt;button type="button" data-tag="JavaScript"&gt;JavaScript&lt;/button&gt;
          &lt;button type="button" data-tag="Dropdown UI"&gt;Dropdown UI&lt;/button&gt;
          &lt;button type="button" data-tag="Ecommerce"&gt;Ecommerce&lt;/button&gt;
          &lt;button type="button" data-tag="Dashboard"&gt;Dashboard&lt;/button&gt;
          &lt;button type="button" data-tag="Forms"&gt;Forms&lt;/button&gt;
          &lt;button type="button" data-tag="Navigation"&gt;Navigation&lt;/button&gt;
          &lt;button type="button" data-tag="Accessibility"&gt;Accessibility&lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-twentytwo-selected"&gt;
        &lt;small&gt;Selected tags&lt;/small&gt;
        &lt;div class="vb-dropdown-twentytwo-chips" data-vb-dropdown-twentytwo-chips&gt;
          &lt;span class="vb-dropdown-twentytwo-empty"&gt;No tags selected yet.&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-twentytwo-demo,
.vb-dropdown-twentytwo-demo * {
  box-sizing: border-box;
}

.vb-dropdown-twentytwo-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(168, 85, 247, 0.20), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(236, 72, 153, 0.18), transparent 34%),
    linear-gradient(135deg, #faf5ff 0%, #fdf2f8 52%, #ffffff 100%) !important;
  border: 1px solid rgba(216, 180, 254, 0.42);
  box-shadow: 0 24px 70px rgba(107, 33, 168, 0.12);
}

.vb-dropdown-twentytwo-filter {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(330px, 0.75fr);
  gap: 34px;
  align-items: center;
  max-width: 1040px;
  min-height: 600px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(216, 180, 254, 0.42);
  box-shadow: 0 24px 70px rgba(107, 33, 168, 0.12);
  overflow: visible;
}

.vb-dropdown-twentytwo-copy &gt; span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-twentytwo-copy h3 {
  max-width: 680px;
  margin: 0 0 16px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-twentytwo-copy p {
  max-width: 560px;
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-twentytwo-card {
  position: relative;
  z-index: 30;
  padding: 22px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 16% 14%, rgba(236, 72, 153, 0.16), transparent 34%),
    linear-gradient(135deg, #581c87, #be185d) !important;
  box-shadow: 0 30px 80px rgba(107, 33, 168, 0.28);
  overflow: visible;
}

.vb-dropdown-twentytwo-card-head {
  margin-bottom: 20px;
}

.vb-dropdown-twentytwo-card-head small {
  display: block;
  margin-bottom: 8px;
  color: #f5d0fe !important;
  -webkit-text-fill-color: #f5d0fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentytwo-card-head strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.05em;
}

.vb-dropdown-twentytwo-control {
  position: relative;
  z-index: 50;
  margin-bottom: 18px;
}

.vb-dropdown-twentytwo-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  min-height: 60px;
  padding: 13px 14px 13px 16px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 20px;
  background: rgba(255,255,255,0.12);
  cursor: pointer;
  text-align: left;
}

.vb-dropdown-twentytwo-trigger span {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-twentytwo-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-twentytwo-filter.is-open .vb-dropdown-twentytwo-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-twentytwo-menu {
  position: absolute;
  z-index: 80;
  top: calc(100% + 12px);
  left: 0;
  right: 0;
  display: grid;
  gap: 7px;
  padding: 12px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.34);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-twentytwo-filter.is-open .vb-dropdown-twentytwo-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-twentytwo-menu-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 4px 4px 8px;
  border-bottom: 1px solid #e5e7eb;
  margin-bottom: 4px;
}

.vb-dropdown-twentytwo-menu-head strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-dropdown-twentytwo-menu-head button {
  border: 0;
  border-radius: 999px;
  background: #f3e8ff;
  color: #7e22ce !important;
  -webkit-text-fill-color: #7e22ce !important;
  padding: 7px 9px;
  font-size: 12px;
  font-weight: 950;
  cursor: pointer;
}

.vb-dropdown-twentytwo-menu &gt; button[data-tag] {
  width: 100%;
  min-height: 44px;
  padding: 10px 12px;
  border: 0;
  border-radius: 15px;
  background: transparent;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  font-weight: 850;
  text-align: left;
  cursor: pointer;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-twentytwo-menu &gt; button[data-tag]:hover,
.vb-dropdown-twentytwo-menu &gt; button[data-tag].is-selected {
  background: #fdf2f8;
  transform: translateX(2px);
}

.vb-dropdown-twentytwo-menu &gt; button[data-tag].is-selected {
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
}

.vb-dropdown-twentytwo-selected {
  padding: 16px;
  border-radius: 22px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-dropdown-twentytwo-selected &gt; small {
  display: block;
  margin-bottom: 10px;
  color: #f5d0fe !important;
  -webkit-text-fill-color: #f5d0fe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentytwo-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  min-height: 42px;
  align-items: center;
}

.vb-dropdown-twentytwo-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 34px;
  padding: 7px 8px 7px 11px;
  border-radius: 999px;
  background: #ffffff;
  color: #581c87 !important;
  -webkit-text-fill-color: #581c87 !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-dropdown-twentytwo-chip button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  border: 0;
  border-radius: 999px;
  background: #fce7f3;
  color: #be185d !important;
  -webkit-text-fill-color: #be185d !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
}

.vb-dropdown-twentytwo-empty {
  color: #fce7f3 !important;
  -webkit-text-fill-color: #fce7f3 !important;
  font-size: 13px;
  font-weight: 750;
}

@media (max-width: 860px) {
  .vb-dropdown-twentytwo-filter {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-twentytwo-card {
    max-width: 440px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-twentytwo-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twentytwo-filter {
    min-height: 760px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-twentytwo-copy h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-twentytwo-card {
    padding: 18px;
    border-radius: 24px;
  }
}</pre>



<p class="wp-block-paragraph">This multi-select tags dropdown is useful when users need to choose more than one option from a clean control. You can adapt it for product filters, blog tags, topic selectors, user interests, skill filters, CRM labels, project tags, and admin search panels.</p>



<h2 class="wp-block-heading">23. Payment Method Dropdown</h2>



<p class="wp-block-paragraph"><strong>A payment method dropdown</strong> is useful for checkout pages, SaaS billing screens, subscription forms, donation pages, marketplace accounts, and ecommerce payment settings. It lets users choose a payment option from a compact dropdown and instantly updates the selected payment preview.</p>



<p class="wp-block-paragraph">This example includes a payment dropdown trigger, card-style payment options, selected payment preview, active option styling, checkout summary update, outside click closing, and Escape key support. The JavaScript updates the selected method and highlights the active payment option.</p>



<ul class="wp-block-list">
<li>Payment method dropdown</li>
<li>Updates selected payment method with JavaScript</li>
<li>Card, PayPal, Apple Pay, and bank transfer options</li>
<li>Active state and checkout preview</li>
<li>Useful for ecommerce checkout, SaaS billing, subscriptions, donations, and payment settings</li>
</ul>



<div class="vb-dropdown-twentythree-demo">
  <div class="vb-dropdown-twentythree-checkout" data-vb-dropdown-twentythree>
    <div class="vb-dropdown-twentythree-copy">
      <span>Example 23</span>
      <h3>Payment Method Dropdown</h3>
      <p>Choose a payment method from a compact dropdown and update the checkout summary instantly.</p>
    </div>

    <div class="vb-dropdown-twentythree-card">
      <div class="vb-dropdown-twentythree-summary">
        <small>Checkout summary</small>
        <strong>UI Component Bundle</strong>

        <div class="vb-dropdown-twentythree-price">
          <span>Total</span>
          <b>€79.00</b>
        </div>
      </div>

      <div class="vb-dropdown-twentythree-control">
        <label>Payment method</label>

        <button type="button" class="vb-dropdown-twentythree-trigger" data-vb-dropdown-twentythree-trigger aria-expanded="false">
          <span data-vb-dropdown-twentythree-icon>💳</span>
          <strong data-vb-dropdown-twentythree-current>Credit Card</strong>
          <em>⌄</em>
        </button>

        <div class="vb-dropdown-twentythree-menu" data-vb-dropdown-twentythree-menu>
          <button type="button" class="is-active" data-payment="Credit Card" data-icon="💳" data-note="Pay securely with Visa, Mastercard, or debit card.">
            <span>💳</span>
            <strong>Credit Card</strong>
            <small>Visa, Mastercard, debit card</small>
          </button>

          <button type="button" data-payment="PayPal" data-icon="🅿️" data-note="Continue to PayPal and confirm your payment securely.">
            <span>🅿️</span>
            <strong>PayPal</strong>
            <small>Fast wallet checkout</small>
          </button>

          <button type="button" data-payment="Apple Pay" data-icon="" data-note="Use Apple Pay for a quick wallet-based checkout.">
            <span></span>
            <strong>Apple Pay</strong>
            <small>One-tap mobile payment</small>
          </button>

          <button type="button" data-payment="Bank Transfer" data-icon="🏦" data-note="Use manual bank transfer after receiving payment details.">
            <span>🏦</span>
            <strong>Bank Transfer</strong>
            <small>Manual payment option</small>
          </button>
        </div>
      </div>

      <div class="vb-dropdown-twentythree-selected">
        <small>Selected payment</small>
        <strong data-vb-dropdown-twentythree-selected>💳 Credit Card</strong>
        <p data-vb-dropdown-twentythree-note>Pay securely with Visa, Mastercard, or debit card.</p>
      </div>

      <a href="#javascript-dropdown-menu-examples">Continue checkout</a>
    </div>
  </div>
</div>

<style>
.vb-dropdown-twentythree-demo,
.vb-dropdown-twentythree-demo * {
  box-sizing: border-box;
}

.vb-dropdown-twentythree-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(59, 130, 246, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(34, 197, 94, 0.18), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 52%, #ffffff 100%) !important;
  border: 1px solid rgba(147, 197, 253, 0.44);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.12);
}

.vb-dropdown-twentythree-checkout {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(330px, 0.75fr);
  gap: 34px;
  align-items: center;
  max-width: 1040px;
  min-height: 620px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(147, 197, 253, 0.34);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.12);
  overflow: visible;
}

.vb-dropdown-twentythree-copy > span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-twentythree-copy h3 {
  max-width: 680px;
  margin: 0 0 16px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-twentythree-copy p {
  max-width: 560px;
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-twentythree-card {
  position: relative;
  z-index: 30;
  padding: 22px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 16% 14%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #0f172a, #1d4ed8) !important;
  box-shadow: 0 30px 80px rgba(30, 64, 175, 0.28);
  overflow: visible;
}

.vb-dropdown-twentythree-summary {
  margin-bottom: 18px;
  padding: 20px;
  border-radius: 24px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-dropdown-twentythree-summary small,
.vb-dropdown-twentythree-selected small,
.vb-dropdown-twentythree-control label {
  display: block;
  margin-bottom: 8px;
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentythree-summary > strong {
  display: block;
  margin-bottom: 18px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  line-height: 1.15;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-dropdown-twentythree-price {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding-top: 14px;
  border-top: 1px solid rgba(255,255,255,0.12);
}

.vb-dropdown-twentythree-price span {
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-dropdown-twentythree-price b {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 28px;
  line-height: 1;
  font-weight: 950;
}

.vb-dropdown-twentythree-control {
  position: relative;
  z-index: 50;
  margin-bottom: 18px;
}

.vb-dropdown-twentythree-trigger {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr) 34px;
  gap: 11px;
  align-items: center;
  width: 100%;
  min-height: 62px;
  padding: 10px 12px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 20px;
  background: rgba(255,255,255,0.12);
  cursor: pointer;
  text-align: left;
}

.vb-dropdown-twentythree-trigger span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
}

.vb-dropdown-twentythree-trigger strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-twentythree-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-twentythree-checkout.is-open .vb-dropdown-twentythree-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-twentythree-menu {
  position: absolute;
  z-index: 80;
  top: calc(100% + 12px);
  left: 0;
  right: 0;
  display: grid;
  gap: 8px;
  padding: 12px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.34);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-twentythree-checkout.is-open .vb-dropdown-twentythree-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-twentythree-menu button {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  width: 100%;
  padding: 10px;
  border: 0;
  border-radius: 16px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-twentythree-menu button:hover,
.vb-dropdown-twentythree-menu button.is-active {
  background: #eff6ff;
  transform: translateX(2px);
}

.vb-dropdown-twentythree-menu button > span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-dropdown-twentythree-menu button strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-twentythree-menu button small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 700;
}

.vb-dropdown-twentythree-selected {
  margin-bottom: 18px;
  padding: 17px;
  border-radius: 22px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-dropdown-twentythree-selected strong {
  display: block;
  margin-bottom: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 21px;
  font-weight: 950;
}

.vb-dropdown-twentythree-selected p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 13px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-dropdown-twentythree-card > a {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22c55e, #3b82f6);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  text-decoration: none !important;
  box-shadow: 0 18px 40px rgba(59, 130, 246, 0.24);
}

@media (max-width: 860px) {
  .vb-dropdown-twentythree-checkout {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-twentythree-card {
    max-width: 440px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-twentythree-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twentythree-checkout {
    min-height: 780px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-twentythree-copy h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-twentythree-card {
    padding: 18px;
    border-radius: 24px;
  }
}
</style>

<script>
(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-twentythree]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-twentythree-trigger]");
  const triggerIcon = dropdown.querySelector("[data-vb-dropdown-twentythree-icon]");
  const current = dropdown.querySelector("[data-vb-dropdown-twentythree-current]");
  const selected = dropdown.querySelector("[data-vb-dropdown-twentythree-selected]");
  const note = dropdown.querySelector("[data-vb-dropdown-twentythree-note]");
  const options = dropdown.querySelectorAll("[data-payment]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  options.forEach(function (option) {
    option.addEventListener("click", function () {
      const payment = option.getAttribute("data-payment");
      const icon = option.getAttribute("data-icon");
      const paymentNote = option.getAttribute("data-note");

      triggerIcon.textContent = icon;
      current.textContent = payment;
      selected.textContent = icon + " " + payment;
      note.textContent = paymentNote;

      options.forEach(function (item) {
        item.classList.remove("is-active");
      });

      option.classList.add("is-active");
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-twentythree]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-twentythree-trigger]");
  const triggerIcon = dropdown.querySelector("[data-vb-dropdown-twentythree-icon]");
  const current = dropdown.querySelector("[data-vb-dropdown-twentythree-current]");
  const selected = dropdown.querySelector("[data-vb-dropdown-twentythree-selected]");
  const note = dropdown.querySelector("[data-vb-dropdown-twentythree-note]");
  const options = dropdown.querySelectorAll("[data-payment]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  options.forEach(function (option) {
    option.addEventListener("click", function () {
      const payment = option.getAttribute("data-payment");
      const icon = option.getAttribute("data-icon");
      const paymentNote = option.getAttribute("data-note");

      triggerIcon.textContent = icon;
      current.textContent = payment;
      selected.textContent = icon + " " + payment;
      note.textContent = paymentNote;

      options.forEach(function (item) {
        item.classList.remove("is-active");
      });

      option.classList.add("is-active");
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-twentythree-demo"&gt;
  &lt;div class="vb-dropdown-twentythree-checkout" data-vb-dropdown-twentythree&gt;
    &lt;div class="vb-dropdown-twentythree-copy"&gt;
      &lt;span&gt;Example 23&lt;/span&gt;
      &lt;h3&gt;Payment Method Dropdown&lt;/h3&gt;
      &lt;p&gt;Choose a payment method from a compact dropdown and update the checkout summary instantly.&lt;/p&gt;
    &lt;/div&gt;

    &lt;div class="vb-dropdown-twentythree-card"&gt;
      &lt;div class="vb-dropdown-twentythree-summary"&gt;
        &lt;small&gt;Checkout summary&lt;/small&gt;
        &lt;strong&gt;UI Component Bundle&lt;/strong&gt;

        &lt;div class="vb-dropdown-twentythree-price"&gt;
          &lt;span&gt;Total&lt;/span&gt;
          &lt;b&gt;€79.00&lt;/b&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-twentythree-control"&gt;
        &lt;label&gt;Payment method&lt;/label&gt;

        &lt;button type="button" class="vb-dropdown-twentythree-trigger" data-vb-dropdown-twentythree-trigger aria-expanded="false"&gt;
          &lt;span data-vb-dropdown-twentythree-icon&gt;💳&lt;/span&gt;
          &lt;strong data-vb-dropdown-twentythree-current&gt;Credit Card&lt;/strong&gt;
          &lt;em&gt;⌄&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-dropdown-twentythree-menu" data-vb-dropdown-twentythree-menu&gt;
          &lt;button type="button" class="is-active" data-payment="Credit Card" data-icon="💳" data-note="Pay securely with Visa, Mastercard, or debit card."&gt;
            &lt;span&gt;💳&lt;/span&gt;
            &lt;strong&gt;Credit Card&lt;/strong&gt;
            &lt;small&gt;Visa, Mastercard, debit card&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-payment="PayPal" data-icon="🅿️" data-note="Continue to PayPal and confirm your payment securely."&gt;
            &lt;span&gt;🅿️&lt;/span&gt;
            &lt;strong&gt;PayPal&lt;/strong&gt;
            &lt;small&gt;Fast wallet checkout&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-payment="Apple Pay" data-icon="" data-note="Use Apple Pay for a quick wallet-based checkout."&gt;
            &lt;span&gt;&lt;/span&gt;
            &lt;strong&gt;Apple Pay&lt;/strong&gt;
            &lt;small&gt;One-tap mobile payment&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-payment="Bank Transfer" data-icon="🏦" data-note="Use manual bank transfer after receiving payment details."&gt;
            &lt;span&gt;🏦&lt;/span&gt;
            &lt;strong&gt;Bank Transfer&lt;/strong&gt;
            &lt;small&gt;Manual payment option&lt;/small&gt;
          &lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-twentythree-selected"&gt;
        &lt;small&gt;Selected payment&lt;/small&gt;
        &lt;strong data-vb-dropdown-twentythree-selected&gt;💳 Credit Card&lt;/strong&gt;
        &lt;p data-vb-dropdown-twentythree-note&gt;Pay securely with Visa, Mastercard, or debit card.&lt;/p&gt;
      &lt;/div&gt;

      &lt;a href="#javascript-dropdown-menu-examples"&gt;Continue checkout&lt;/a&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-twentythree-demo,
.vb-dropdown-twentythree-demo * {
  box-sizing: border-box;
}

.vb-dropdown-twentythree-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(59, 130, 246, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(34, 197, 94, 0.18), transparent 34%),
    linear-gradient(135deg, #eff6ff 0%, #ecfdf5 52%, #ffffff 100%) !important;
  border: 1px solid rgba(147, 197, 253, 0.44);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.12);
}

.vb-dropdown-twentythree-checkout {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(330px, 0.75fr);
  gap: 34px;
  align-items: center;
  max-width: 1040px;
  min-height: 620px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(147, 197, 253, 0.34);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.12);
  overflow: visible;
}

.vb-dropdown-twentythree-copy &gt; span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-twentythree-copy h3 {
  max-width: 680px;
  margin: 0 0 16px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-twentythree-copy p {
  max-width: 560px;
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-twentythree-card {
  position: relative;
  z-index: 30;
  padding: 22px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 16% 14%, rgba(34, 197, 94, 0.16), transparent 34%),
    linear-gradient(135deg, #0f172a, #1d4ed8) !important;
  box-shadow: 0 30px 80px rgba(30, 64, 175, 0.28);
  overflow: visible;
}

.vb-dropdown-twentythree-summary {
  margin-bottom: 18px;
  padding: 20px;
  border-radius: 24px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-dropdown-twentythree-summary small,
.vb-dropdown-twentythree-selected small,
.vb-dropdown-twentythree-control label {
  display: block;
  margin-bottom: 8px;
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentythree-summary &gt; strong {
  display: block;
  margin-bottom: 18px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 24px;
  line-height: 1.15;
  font-weight: 950;
  letter-spacing: -0.04em;
}

.vb-dropdown-twentythree-price {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding-top: 14px;
  border-top: 1px solid rgba(255,255,255,0.12);
}

.vb-dropdown-twentythree-price span {
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-dropdown-twentythree-price b {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 28px;
  line-height: 1;
  font-weight: 950;
}

.vb-dropdown-twentythree-control {
  position: relative;
  z-index: 50;
  margin-bottom: 18px;
}

.vb-dropdown-twentythree-trigger {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr) 34px;
  gap: 11px;
  align-items: center;
  width: 100%;
  min-height: 62px;
  padding: 10px 12px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 20px;
  background: rgba(255,255,255,0.12);
  cursor: pointer;
  text-align: left;
}

.vb-dropdown-twentythree-trigger span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
}

.vb-dropdown-twentythree-trigger strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-twentythree-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-twentythree-checkout.is-open .vb-dropdown-twentythree-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-twentythree-menu {
  position: absolute;
  z-index: 80;
  top: calc(100% + 12px);
  left: 0;
  right: 0;
  display: grid;
  gap: 8px;
  padding: 12px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.34);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-twentythree-checkout.is-open .vb-dropdown-twentythree-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-twentythree-menu button {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  width: 100%;
  padding: 10px;
  border: 0;
  border-radius: 16px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-twentythree-menu button:hover,
.vb-dropdown-twentythree-menu button.is-active {
  background: #eff6ff;
  transform: translateX(2px);
}

.vb-dropdown-twentythree-menu button &gt; span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-dropdown-twentythree-menu button strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-twentythree-menu button small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 700;
}

.vb-dropdown-twentythree-selected {
  margin-bottom: 18px;
  padding: 17px;
  border-radius: 22px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-dropdown-twentythree-selected strong {
  display: block;
  margin-bottom: 7px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 21px;
  font-weight: 950;
}

.vb-dropdown-twentythree-selected p {
  margin: 0 !important;
  color: #dbeafe !important;
  -webkit-text-fill-color: #dbeafe !important;
  font-size: 13px;
  line-height: 1.55;
  font-weight: 650;
}

.vb-dropdown-twentythree-card &gt; a {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 48px;
  border-radius: 999px;
  background: linear-gradient(135deg, #22c55e, #3b82f6);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  text-decoration: none !important;
  box-shadow: 0 18px 40px rgba(59, 130, 246, 0.24);
}

@media (max-width: 860px) {
  .vb-dropdown-twentythree-checkout {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-twentythree-card {
    max-width: 440px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-twentythree-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twentythree-checkout {
    min-height: 780px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-twentythree-copy h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-twentythree-card {
    padding: 18px;
    border-radius: 24px;
  }
}</pre>



<p class="wp-block-paragraph">This payment method dropdown is a useful checkout pattern because it keeps the payment section compact while still showing clear options. You can adapt it for ecommerce checkout pages, subscription billing, customer account settings, donation forms, SaaS plans, and marketplace payment screens.</p>



<h2 class="wp-block-heading">24. Shipping Option Dropdown</h2>



<p class="wp-block-paragraph"><strong>A shipping option dropdown</strong> helps ecommerce customers choose delivery speed, shipping cost, pickup options, or fulfillment methods without cluttering the checkout page. It is useful for product stores, delivery apps, quote forms, order forms, and WooCommerce-style checkout interfaces.</p>



<p class="wp-block-paragraph">This example includes a shipping dropdown, delivery option cards, price and delivery time preview, selected shipping summary, active state styling, outside click closing, and Escape key support. The JavaScript updates the visible shipping method, delivery estimate, and order total.</p>



<ul class="wp-block-list">
<li>Shipping option dropdown</li>
<li>Updates delivery method, price, and order total</li>
<li>Standard, express, pickup, and freight options</li>
<li>Active option styling</li>
<li>Useful for ecommerce checkout, delivery apps, quote forms, order forms, and WooCommerce interfaces</li>
</ul>



<div class="vb-dropdown-twentyfour-demo">
  <div class="vb-dropdown-twentyfour-order" data-vb-dropdown-twentyfour>
    <div class="vb-dropdown-twentyfour-panel">
      <span>Example 24</span>
      <h3>Shipping Option Dropdown</h3>
      <p>Select a delivery method and update the order total, delivery estimate, and selected shipping summary.</p>

      <div class="vb-dropdown-twentyfour-total">
        <small>Order total</small>
        <strong data-vb-dropdown-twentyfour-total>€128.00</strong>
      </div>
    </div>

    <div class="vb-dropdown-twentyfour-card">
      <div class="vb-dropdown-twentyfour-product">
        <div class="vb-dropdown-twentyfour-art"></div>
        <div>
          <small>Product</small>
          <strong>Premium Website Kit</strong>
          <span>Subtotal: €119.00</span>
        </div>
      </div>

      <div class="vb-dropdown-twentyfour-control">
        <label>Shipping method</label>

        <button type="button" class="vb-dropdown-twentyfour-trigger" data-vb-dropdown-twentyfour-trigger aria-expanded="false">
          <span data-vb-dropdown-twentyfour-current>Standard Delivery</span>
          <em>⌄</em>
        </button>

        <div class="vb-dropdown-twentyfour-menu" data-vb-dropdown-twentyfour-menu>
          <button type="button" class="is-active" data-shipping="Standard Delivery" data-price="9" data-time="3–5 business days">
            <span>🚚</span>
            <strong>Standard Delivery</strong>
            <small>€9.00 · 3–5 business days</small>
          </button>

          <button type="button" data-shipping="Express Delivery" data-price="19" data-time="1–2 business days">
            <span>⚡</span>
            <strong>Express Delivery</strong>
            <small>€19.00 · 1–2 business days</small>
          </button>

          <button type="button" data-shipping="Local Pickup" data-price="0" data-time="Ready today">
            <span>📍</span>
            <strong>Local Pickup</strong>
            <small>Free · Ready today</small>
          </button>

          <button type="button" data-shipping="Freight Delivery" data-price="39" data-time="5–8 business days">
            <span>🏗️</span>
            <strong>Freight Delivery</strong>
            <small>€39.00 · 5–8 business days</small>
          </button>
        </div>
      </div>

      <div class="vb-dropdown-twentyfour-selected">
        <div>
          <small>Selected shipping</small>
          <strong data-vb-dropdown-twentyfour-selected>Standard Delivery</strong>
        </div>
        <div>
          <small>Delivery estimate</small>
          <strong data-vb-dropdown-twentyfour-time>3–5 business days</strong>
        </div>
        <div>
          <small>Shipping cost</small>
          <strong data-vb-dropdown-twentyfour-price>€9.00</strong>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-dropdown-twentyfour-demo,
.vb-dropdown-twentyfour-demo * {
  box-sizing: border-box;
}

.vb-dropdown-twentyfour-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 15% 16%, rgba(249, 115, 22, 0.20), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(234, 179, 8, 0.18), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #fffbeb 52%, #ffffff 100%) !important;
  border: 1px solid rgba(253, 186, 116, 0.44);
  box-shadow: 0 24px 70px rgba(124, 45, 18, 0.12);
}

.vb-dropdown-twentyfour-order {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(330px, 0.78fr);
  gap: 34px;
  align-items: center;
  max-width: 1040px;
  min-height: 620px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(253, 186, 116, 0.34);
  box-shadow: 0 24px 70px rgba(124, 45, 18, 0.12);
  overflow: visible;
}

.vb-dropdown-twentyfour-panel > span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-twentyfour-panel h3 {
  max-width: 680px;
  margin: 0 0 16px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-twentyfour-panel p {
  max-width: 560px;
  margin: 0 0 26px !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-twentyfour-total {
  width: min(100%, 330px);
  padding: 20px;
  border-radius: 24px;
  background: #111827;
  box-shadow: 0 22px 54px rgba(15, 23, 42, 0.20);
}

.vb-dropdown-twentyfour-total small {
  display: block;
  margin-bottom: 8px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentyfour-total strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 38px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vb-dropdown-twentyfour-card {
  position: relative;
  z-index: 30;
  padding: 22px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 16% 14%, rgba(249, 115, 22, 0.18), transparent 34%),
    linear-gradient(135deg, #7c2d12, #ea580c) !important;
  box-shadow: 0 30px 80px rgba(234, 88, 12, 0.25);
  overflow: visible;
}

.vb-dropdown-twentyfour-product {
  display: grid;
  grid-template-columns: 82px minmax(0, 1fr);
  gap: 14px;
  align-items: center;
  margin-bottom: 18px;
  padding: 14px;
  border-radius: 22px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-dropdown-twentyfour-art {
  height: 82px;
  border-radius: 20px;
  background:
    radial-gradient(circle at 35% 30%, rgba(255,255,255,0.26), transparent 32%),
    linear-gradient(135deg, #fbbf24, #f97316) !important;
}

.vb-dropdown-twentyfour-product small,
.vb-dropdown-twentyfour-selected small,
.vb-dropdown-twentyfour-control label {
  display: block;
  margin-bottom: 6px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentyfour-product strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 19px;
  line-height: 1.15;
  font-weight: 950;
}

.vb-dropdown-twentyfour-product span {
  display: block;
  margin-top: 6px;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 13px;
  font-weight: 750;
}

.vb-dropdown-twentyfour-control {
  position: relative;
  z-index: 50;
  margin-bottom: 18px;
}

.vb-dropdown-twentyfour-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  min-height: 60px;
  padding: 13px 14px 13px 16px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 20px;
  background: rgba(255,255,255,0.12);
  cursor: pointer;
  text-align: left;
}

.vb-dropdown-twentyfour-trigger span {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-twentyfour-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-twentyfour-order.is-open .vb-dropdown-twentyfour-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-twentyfour-menu {
  position: absolute;
  z-index: 80;
  top: calc(100% + 12px);
  left: 0;
  right: 0;
  display: grid;
  gap: 8px;
  padding: 12px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.34);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-twentyfour-order.is-open .vb-dropdown-twentyfour-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-twentyfour-menu button {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  width: 100%;
  padding: 10px;
  border: 0;
  border-radius: 16px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-twentyfour-menu button:hover,
.vb-dropdown-twentyfour-menu button.is-active {
  background: #fff7ed;
  transform: translateX(2px);
}

.vb-dropdown-twentyfour-menu button > span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: #ffedd5;
  font-size: 18px;
}

.vb-dropdown-twentyfour-menu button strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-twentyfour-menu button small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 700;
}

.vb-dropdown-twentyfour-selected {
  display: grid;
  gap: 10px;
}

.vb-dropdown-twentyfour-selected div {
  padding: 14px;
  border-radius: 18px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-dropdown-twentyfour-selected strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  line-height: 1.2;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-dropdown-twentyfour-order {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-twentyfour-card {
    max-width: 460px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-twentyfour-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twentyfour-order {
    min-height: 800px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-twentyfour-panel h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-twentyfour-card {
    padding: 18px;
    border-radius: 24px;
  }
}
</style>

<script>
(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-twentyfour]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-twentyfour-trigger]");
  const current = dropdown.querySelector("[data-vb-dropdown-twentyfour-current]");
  const selected = dropdown.querySelector("[data-vb-dropdown-twentyfour-selected]");
  const time = dropdown.querySelector("[data-vb-dropdown-twentyfour-time]");
  const price = dropdown.querySelector("[data-vb-dropdown-twentyfour-price]");
  const total = dropdown.querySelector("[data-vb-dropdown-twentyfour-total]");
  const options = dropdown.querySelectorAll("[data-shipping]");
  const subtotal = 119;

  function formatPrice(value) {
    return "€" + value.toFixed(2);
  }

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  options.forEach(function (option) {
    option.addEventListener("click", function () {
      const shippingName = option.getAttribute("data-shipping");
      const shippingPrice = Number(option.getAttribute("data-price"));
      const shippingTime = option.getAttribute("data-time");

      current.textContent = shippingName;
      selected.textContent = shippingName;
      time.textContent = shippingTime;
      price.textContent = shippingPrice === 0 ? "Free" : formatPrice(shippingPrice);
      total.textContent = formatPrice(subtotal + shippingPrice);

      options.forEach(function (item) {
        item.classList.remove("is-active");
      });

      option.classList.add("is-active");
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-twentyfour]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-twentyfour-trigger]");
  const current = dropdown.querySelector("[data-vb-dropdown-twentyfour-current]");
  const selected = dropdown.querySelector("[data-vb-dropdown-twentyfour-selected]");
  const time = dropdown.querySelector("[data-vb-dropdown-twentyfour-time]");
  const price = dropdown.querySelector("[data-vb-dropdown-twentyfour-price]");
  const total = dropdown.querySelector("[data-vb-dropdown-twentyfour-total]");
  const options = dropdown.querySelectorAll("[data-shipping]");
  const subtotal = 119;

  function formatPrice(value) {
    return "€" + value.toFixed(2);
  }

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  options.forEach(function (option) {
    option.addEventListener("click", function () {
      const shippingName = option.getAttribute("data-shipping");
      const shippingPrice = Number(option.getAttribute("data-price"));
      const shippingTime = option.getAttribute("data-time");

      current.textContent = shippingName;
      selected.textContent = shippingName;
      time.textContent = shippingTime;
      price.textContent = shippingPrice === 0 ? "Free" : formatPrice(shippingPrice);
      total.textContent = formatPrice(subtotal + shippingPrice);

      options.forEach(function (item) {
        item.classList.remove("is-active");
      });

      option.classList.add("is-active");
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-twentyfour-demo"&gt;
  &lt;div class="vb-dropdown-twentyfour-order" data-vb-dropdown-twentyfour&gt;
    &lt;div class="vb-dropdown-twentyfour-panel"&gt;
      &lt;span&gt;Example 24&lt;/span&gt;
      &lt;h3&gt;Shipping Option Dropdown&lt;/h3&gt;
      &lt;p&gt;Select a delivery method and update the order total, delivery estimate, and selected shipping summary.&lt;/p&gt;

      &lt;div class="vb-dropdown-twentyfour-total"&gt;
        &lt;small&gt;Order total&lt;/small&gt;
        &lt;strong data-vb-dropdown-twentyfour-total&gt;€128.00&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-dropdown-twentyfour-card"&gt;
      &lt;div class="vb-dropdown-twentyfour-product"&gt;
        &lt;div class="vb-dropdown-twentyfour-art"&gt;&lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Product&lt;/small&gt;
          &lt;strong&gt;Premium Website Kit&lt;/strong&gt;
          &lt;span&gt;Subtotal: €119.00&lt;/span&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-twentyfour-control"&gt;
        &lt;label&gt;Shipping method&lt;/label&gt;

        &lt;button type="button" class="vb-dropdown-twentyfour-trigger" data-vb-dropdown-twentyfour-trigger aria-expanded="false"&gt;
          &lt;span data-vb-dropdown-twentyfour-current&gt;Standard Delivery&lt;/span&gt;
          &lt;em&gt;⌄&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-dropdown-twentyfour-menu" data-vb-dropdown-twentyfour-menu&gt;
          &lt;button type="button" class="is-active" data-shipping="Standard Delivery" data-price="9" data-time="3–5 business days"&gt;
            &lt;span&gt;🚚&lt;/span&gt;
            &lt;strong&gt;Standard Delivery&lt;/strong&gt;
            &lt;small&gt;€9.00 · 3–5 business days&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-shipping="Express Delivery" data-price="19" data-time="1–2 business days"&gt;
            &lt;span&gt;⚡&lt;/span&gt;
            &lt;strong&gt;Express Delivery&lt;/strong&gt;
            &lt;small&gt;€19.00 · 1–2 business days&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-shipping="Local Pickup" data-price="0" data-time="Ready today"&gt;
            &lt;span&gt;📍&lt;/span&gt;
            &lt;strong&gt;Local Pickup&lt;/strong&gt;
            &lt;small&gt;Free · Ready today&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-shipping="Freight Delivery" data-price="39" data-time="5–8 business days"&gt;
            &lt;span&gt;🏗️&lt;/span&gt;
            &lt;strong&gt;Freight Delivery&lt;/strong&gt;
            &lt;small&gt;€39.00 · 5–8 business days&lt;/small&gt;
          &lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-twentyfour-selected"&gt;
        &lt;div&gt;
          &lt;small&gt;Selected shipping&lt;/small&gt;
          &lt;strong data-vb-dropdown-twentyfour-selected&gt;Standard Delivery&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Delivery estimate&lt;/small&gt;
          &lt;strong data-vb-dropdown-twentyfour-time&gt;3–5 business days&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Shipping cost&lt;/small&gt;
          &lt;strong data-vb-dropdown-twentyfour-price&gt;€9.00&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-twentyfour-demo,
.vb-dropdown-twentyfour-demo * {
  box-sizing: border-box;
}

.vb-dropdown-twentyfour-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 15% 16%, rgba(249, 115, 22, 0.20), transparent 34%),
    radial-gradient(circle at 86% 18%, rgba(234, 179, 8, 0.18), transparent 34%),
    linear-gradient(135deg, #fff7ed 0%, #fffbeb 52%, #ffffff 100%) !important;
  border: 1px solid rgba(253, 186, 116, 0.44);
  box-shadow: 0 24px 70px rgba(124, 45, 18, 0.12);
}

.vb-dropdown-twentyfour-order {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(330px, 0.78fr);
  gap: 34px;
  align-items: center;
  max-width: 1040px;
  min-height: 620px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(253, 186, 116, 0.34);
  box-shadow: 0 24px 70px rgba(124, 45, 18, 0.12);
  overflow: visible;
}

.vb-dropdown-twentyfour-panel &gt; span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffedd5;
  color: #c2410c !important;
  -webkit-text-fill-color: #c2410c !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-twentyfour-panel h3 {
  max-width: 680px;
  margin: 0 0 16px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-twentyfour-panel p {
  max-width: 560px;
  margin: 0 0 26px !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-twentyfour-total {
  width: min(100%, 330px);
  padding: 20px;
  border-radius: 24px;
  background: #111827;
  box-shadow: 0 22px 54px rgba(15, 23, 42, 0.20);
}

.vb-dropdown-twentyfour-total small {
  display: block;
  margin-bottom: 8px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentyfour-total strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 38px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vb-dropdown-twentyfour-card {
  position: relative;
  z-index: 30;
  padding: 22px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 16% 14%, rgba(249, 115, 22, 0.18), transparent 34%),
    linear-gradient(135deg, #7c2d12, #ea580c) !important;
  box-shadow: 0 30px 80px rgba(234, 88, 12, 0.25);
  overflow: visible;
}

.vb-dropdown-twentyfour-product {
  display: grid;
  grid-template-columns: 82px minmax(0, 1fr);
  gap: 14px;
  align-items: center;
  margin-bottom: 18px;
  padding: 14px;
  border-radius: 22px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.14);
}

.vb-dropdown-twentyfour-art {
  height: 82px;
  border-radius: 20px;
  background:
    radial-gradient(circle at 35% 30%, rgba(255,255,255,0.26), transparent 32%),
    linear-gradient(135deg, #fbbf24, #f97316) !important;
}

.vb-dropdown-twentyfour-product small,
.vb-dropdown-twentyfour-selected small,
.vb-dropdown-twentyfour-control label {
  display: block;
  margin-bottom: 6px;
  color: #fed7aa !important;
  -webkit-text-fill-color: #fed7aa !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentyfour-product strong {
  display: block;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 19px;
  line-height: 1.15;
  font-weight: 950;
}

.vb-dropdown-twentyfour-product span {
  display: block;
  margin-top: 6px;
  color: #ffedd5 !important;
  -webkit-text-fill-color: #ffedd5 !important;
  font-size: 13px;
  font-weight: 750;
}

.vb-dropdown-twentyfour-control {
  position: relative;
  z-index: 50;
  margin-bottom: 18px;
}

.vb-dropdown-twentyfour-trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  width: 100%;
  min-height: 60px;
  padding: 13px 14px 13px 16px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 20px;
  background: rgba(255,255,255,0.12);
  cursor: pointer;
  text-align: left;
}

.vb-dropdown-twentyfour-trigger span {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-twentyfour-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-twentyfour-order.is-open .vb-dropdown-twentyfour-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-twentyfour-menu {
  position: absolute;
  z-index: 80;
  top: calc(100% + 12px);
  left: 0;
  right: 0;
  display: grid;
  gap: 8px;
  padding: 12px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.34);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-twentyfour-order.is-open .vb-dropdown-twentyfour-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-twentyfour-menu button {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  width: 100%;
  padding: 10px;
  border: 0;
  border-radius: 16px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-twentyfour-menu button:hover,
.vb-dropdown-twentyfour-menu button.is-active {
  background: #fff7ed;
  transform: translateX(2px);
}

.vb-dropdown-twentyfour-menu button &gt; span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: #ffedd5;
  font-size: 18px;
}

.vb-dropdown-twentyfour-menu button strong {
  display: block;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-twentyfour-menu button small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 700;
}

.vb-dropdown-twentyfour-selected {
  display: grid;
  gap: 10px;
}

.vb-dropdown-twentyfour-selected div {
  padding: 14px;
  border-radius: 18px;
  background: rgba(255,255,255,0.11);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb-dropdown-twentyfour-selected strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  line-height: 1.2;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-dropdown-twentyfour-order {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-twentyfour-card {
    max-width: 460px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-twentyfour-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twentyfour-order {
    min-height: 800px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-twentyfour-panel h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-twentyfour-card {
    padding: 18px;
    border-radius: 24px;
  }
}</pre>



<p class="wp-block-paragraph">This shipping option dropdown is useful for checkout pages where delivery options affect cost and timing. You can adapt it for WooCommerce checkouts, delivery forms, booking requests, order forms, marketplace shipping, local pickup, and freight quote interfaces.</p>



<h2 class="wp-block-heading">25. Language Selector Dropdown</h2>



<p class="wp-block-paragraph"><strong>A language selector dropdown</strong> is useful for multilingual websites, SaaS apps, ecommerce stores, booking platforms, documentation sites, and international landing pages. It lets users switch the visible interface language from a compact dropdown menu.</p>



<p class="wp-block-paragraph">This example includes a language dropdown trigger, flag-style labels, active language state, translated preview text, outside click closing, and Escape key support. The JavaScript updates the selected language, interface heading, description, and active menu item.</p>



<ul class="wp-block-list">
<li>Language selector dropdown</li>
<li>Updates preview text with JavaScript</li>
<li>Active language option styling</li>
<li>Outside click and Escape key support</li>
<li>Useful for multilingual websites, ecommerce stores, SaaS apps, documentation, and international landing pages</li>
</ul>



<div class="vb-dropdown-twentyfive-demo">
  <div class="vb-dropdown-twentyfive-site" data-vb-dropdown-twentyfive>
    <header class="vb-dropdown-twentyfive-header">
      <a href="#javascript-dropdown-menu-examples" class="vb-dropdown-twentyfive-logo">
        <span>G</span>
        <strong>GlobalUI</strong>
      </a>

      <div class="vb-dropdown-twentyfive-wrap">
        <button type="button" class="vb-dropdown-twentyfive-trigger" data-vb-dropdown-twentyfive-trigger aria-expanded="false">
          <span data-vb-dropdown-twentyfive-flag>🇬🇧</span>
          <strong data-vb-dropdown-twentyfive-current>English</strong>
          <em>⌄</em>
        </button>

        <div class="vb-dropdown-twentyfive-menu" data-vb-dropdown-twentyfive-menu>
          <button type="button" class="is-active" data-lang="English" data-flag="🇬🇧" data-title="Build better dropdown menus" data-desc="Create modern JavaScript dropdown components for real websites and applications.">
            <span>🇬🇧</span>
            <strong>English</strong>
            <small>Default language</small>
          </button>

          <button type="button" data-lang="Deutsch" data-flag="🇩🇪" data-title="Bessere Dropdown-Menüs erstellen" data-desc="Erstelle moderne JavaScript-Dropdown-Komponenten für echte Websites und Anwendungen.">
            <span>🇩🇪</span>
            <strong>Deutsch</strong>
            <small>German interface</small>
          </button>

          <button type="button" data-lang="Français" data-flag="🇫🇷" data-title="Créer de meilleurs menus déroulants" data-desc="Créez des composants dropdown JavaScript modernes pour des sites web et applications.">
            <span>🇫🇷</span>
            <strong>Français</strong>
            <small>French interface</small>
          </button>

          <button type="button" data-lang="Eesti" data-flag="🇪🇪" data-title="Ehita paremaid rippmenüüsid" data-desc="Loo moderne JavaScripti dropdown komponente päris veebilehtede ja rakenduste jaoks.">
            <span>🇪🇪</span>
            <strong>Eesti</strong>
            <small>Estonian interface</small>
          </button>
        </div>
      </div>
    </header>

    <section class="vb-dropdown-twentyfive-hero">
      <span>Example 25</span>
      <h3 data-vb-dropdown-twentyfive-title>Build better dropdown menus</h3>
      <p data-vb-dropdown-twentyfive-desc>Create modern JavaScript dropdown components for real websites and applications.</p>

      <div class="vb-dropdown-twentyfive-selected">
        <small>Selected language</small>
        <strong data-vb-dropdown-twentyfive-selected>🇬🇧 English</strong>
      </div>
    </section>
  </div>
</div>

<style>
.vb-dropdown-twentyfive-demo,
.vb-dropdown-twentyfive-demo * {
  box-sizing: border-box;
}

.vb-dropdown-twentyfive-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(14, 165, 233, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(99, 102, 241, 0.18), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(125, 211, 252, 0.38);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.11);
}

.vb-dropdown-twentyfive-site {
  position: relative;
  max-width: 1080px;
  min-height: 600px;
  margin: 0 auto;
  padding: 24px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 80% 76%, rgba(99, 102, 241, 0.12), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
  overflow: visible;
}

.vb-dropdown-twentyfive-header {
  position: relative;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  padding: 14px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 20px 50px rgba(15, 23, 42, 0.12);
}

.vb-dropdown-twentyfive-logo {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none !important;
}

.vb-dropdown-twentyfive-logo span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: linear-gradient(135deg, #0284c7, #4f46e5);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-twentyfive-logo strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-twentyfive-wrap {
  position: relative;
}

.vb-dropdown-twentyfive-trigger {
  display: grid;
  grid-template-columns: 36px minmax(0, 1fr) 30px;
  gap: 9px;
  align-items: center;
  min-width: 170px;
  min-height: 50px;
  padding: 8px 10px;
  border: 1px solid rgba(148, 163, 184, 0.24);
  border-radius: 999px;
  background: #f8fafc;
  cursor: pointer;
  text-align: left;
}

.vb-dropdown-twentyfive-trigger > span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  background: #ffffff;
  font-size: 18px;
  box-shadow: 0 8px 20px rgba(15, 23, 42, 0.08);
}

.vb-dropdown-twentyfive-trigger strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-dropdown-twentyfive-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-twentyfive-site.is-open .vb-dropdown-twentyfive-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-twentyfive-menu {
  position: absolute;
  z-index: 80;
  top: calc(100% + 12px);
  right: 0;
  display: grid;
  gap: 8px;
  width: 300px;
  padding: 12px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.24);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-twentyfive-site.is-open .vb-dropdown-twentyfive-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-twentyfive-menu button {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  width: 100%;
  padding: 10px;
  border: 0;
  border-radius: 16px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-twentyfive-menu button:hover,
.vb-dropdown-twentyfive-menu button.is-active {
  background: #f0f9ff;
  transform: translateX(2px);
}

.vb-dropdown-twentyfive-menu button > span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 16px;
  background: #f8fafc;
  font-size: 20px;
}

.vb-dropdown-twentyfive-menu button strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-twentyfive-menu button small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 700;
}

.vb-dropdown-twentyfive-hero {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 470px;
  padding: 56px 18px 18px;
}

.vb-dropdown-twentyfive-hero > span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-twentyfive-hero h3 {
  max-width: 760px;
  min-height: 150px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(38px, 6vw, 78px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-twentyfive-hero p {
  max-width: 640px;
  margin: 0 0 24px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-twentyfive-selected {
  width: min(100%, 320px);
  padding: 18px;
  border-radius: 22px;
  background: #0f172a;
  box-shadow: 0 22px 54px rgba(15, 23, 42, 0.18);
}

.vb-dropdown-twentyfive-selected small {
  display: block;
  margin-bottom: 7px;
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentyfive-selected strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1.15;
  font-weight: 950;
}

@media (max-width: 640px) {
  .vb-dropdown-twentyfive-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twentyfive-site {
    min-height: 740px;
    padding: 18px;
    border-radius: 22px;
  }

  .vb-dropdown-twentyfive-header {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-dropdown-twentyfive-wrap,
  .vb-dropdown-twentyfive-trigger {
    width: 100%;
  }

  .vb-dropdown-twentyfive-menu {
    left: 0;
    right: auto;
    width: 100%;
    transform-origin: top left;
  }

  .vb-dropdown-twentyfive-hero h3 {
    min-height: auto;
    font-size: 38px !important;
  }
}
</style>

<script>
(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-twentyfive]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-twentyfive-trigger]");
  const current = dropdown.querySelector("[data-vb-dropdown-twentyfive-current]");
  const flag = dropdown.querySelector("[data-vb-dropdown-twentyfive-flag]");
  const title = dropdown.querySelector("[data-vb-dropdown-twentyfive-title]");
  const desc = dropdown.querySelector("[data-vb-dropdown-twentyfive-desc]");
  const selected = dropdown.querySelector("[data-vb-dropdown-twentyfive-selected]");
  const options = dropdown.querySelectorAll("[data-lang]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  options.forEach(function (option) {
    option.addEventListener("click", function () {
      const language = option.getAttribute("data-lang");
      const languageFlag = option.getAttribute("data-flag");

      current.textContent = language;
      flag.textContent = languageFlag;
      selected.textContent = languageFlag + " " + language;
      title.textContent = option.getAttribute("data-title");
      desc.textContent = option.getAttribute("data-desc");

      options.forEach(function (item) {
        item.classList.remove("is-active");
      });

      option.classList.add("is-active");
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-twentyfive]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-twentyfive-trigger]");
  const current = dropdown.querySelector("[data-vb-dropdown-twentyfive-current]");
  const flag = dropdown.querySelector("[data-vb-dropdown-twentyfive-flag]");
  const title = dropdown.querySelector("[data-vb-dropdown-twentyfive-title]");
  const desc = dropdown.querySelector("[data-vb-dropdown-twentyfive-desc]");
  const selected = dropdown.querySelector("[data-vb-dropdown-twentyfive-selected]");
  const options = dropdown.querySelectorAll("[data-lang]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  options.forEach(function (option) {
    option.addEventListener("click", function () {
      const language = option.getAttribute("data-lang");
      const languageFlag = option.getAttribute("data-flag");

      current.textContent = language;
      flag.textContent = languageFlag;
      selected.textContent = languageFlag + " " + language;
      title.textContent = option.getAttribute("data-title");
      desc.textContent = option.getAttribute("data-desc");

      options.forEach(function (item) {
        item.classList.remove("is-active");
      });

      option.classList.add("is-active");
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-twentyfive-demo"&gt;
  &lt;div class="vb-dropdown-twentyfive-site" data-vb-dropdown-twentyfive&gt;
    &lt;header class="vb-dropdown-twentyfive-header"&gt;
      &lt;a href="#javascript-dropdown-menu-examples" class="vb-dropdown-twentyfive-logo"&gt;
        &lt;span&gt;G&lt;/span&gt;
        &lt;strong&gt;GlobalUI&lt;/strong&gt;
      &lt;/a&gt;

      &lt;div class="vb-dropdown-twentyfive-wrap"&gt;
        &lt;button type="button" class="vb-dropdown-twentyfive-trigger" data-vb-dropdown-twentyfive-trigger aria-expanded="false"&gt;
          &lt;span data-vb-dropdown-twentyfive-flag&gt;🇬🇧&lt;/span&gt;
          &lt;strong data-vb-dropdown-twentyfive-current&gt;English&lt;/strong&gt;
          &lt;em&gt;⌄&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-dropdown-twentyfive-menu" data-vb-dropdown-twentyfive-menu&gt;
          &lt;button type="button" class="is-active" data-lang="English" data-flag="🇬🇧" data-title="Build better dropdown menus" data-desc="Create modern JavaScript dropdown components for real websites and applications."&gt;
            &lt;span&gt;🇬🇧&lt;/span&gt;
            &lt;strong&gt;English&lt;/strong&gt;
            &lt;small&gt;Default language&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-lang="Deutsch" data-flag="🇩🇪" data-title="Bessere Dropdown-Menüs erstellen" data-desc="Erstelle moderne JavaScript-Dropdown-Komponenten für echte Websites und Anwendungen."&gt;
            &lt;span&gt;🇩🇪&lt;/span&gt;
            &lt;strong&gt;Deutsch&lt;/strong&gt;
            &lt;small&gt;German interface&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-lang="Français" data-flag="🇫🇷" data-title="Créer de meilleurs menus déroulants" data-desc="Créez des composants dropdown JavaScript modernes pour des sites web et applications."&gt;
            &lt;span&gt;🇫🇷&lt;/span&gt;
            &lt;strong&gt;Français&lt;/strong&gt;
            &lt;small&gt;French interface&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-lang="Eesti" data-flag="🇪🇪" data-title="Ehita paremaid rippmenüüsid" data-desc="Loo moderne JavaScripti dropdown komponente päris veebilehtede ja rakenduste jaoks."&gt;
            &lt;span&gt;🇪🇪&lt;/span&gt;
            &lt;strong&gt;Eesti&lt;/strong&gt;
            &lt;small&gt;Estonian interface&lt;/small&gt;
          &lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/header&gt;

    &lt;section class="vb-dropdown-twentyfive-hero"&gt;
      &lt;span&gt;Example 25&lt;/span&gt;
      &lt;h3 data-vb-dropdown-twentyfive-title&gt;Build better dropdown menus&lt;/h3&gt;
      &lt;p data-vb-dropdown-twentyfive-desc&gt;Create modern JavaScript dropdown components for real websites and applications.&lt;/p&gt;

      &lt;div class="vb-dropdown-twentyfive-selected"&gt;
        &lt;small&gt;Selected language&lt;/small&gt;
        &lt;strong data-vb-dropdown-twentyfive-selected&gt;🇬🇧 English&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/section&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-twentyfive-demo,
.vb-dropdown-twentyfive-demo * {
  box-sizing: border-box;
}

.vb-dropdown-twentyfive-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(14, 165, 233, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(99, 102, 241, 0.18), transparent 34%),
    linear-gradient(135deg, #f0f9ff 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(125, 211, 252, 0.38);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.11);
}

.vb-dropdown-twentyfive-site {
  position: relative;
  max-width: 1080px;
  min-height: 600px;
  margin: 0 auto;
  padding: 24px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 80% 76%, rgba(99, 102, 241, 0.12), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
  overflow: visible;
}

.vb-dropdown-twentyfive-header {
  position: relative;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 18px;
  padding: 14px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 20px 50px rgba(15, 23, 42, 0.12);
}

.vb-dropdown-twentyfive-logo {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none !important;
}

.vb-dropdown-twentyfive-logo span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: linear-gradient(135deg, #0284c7, #4f46e5);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-twentyfive-logo strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-twentyfive-wrap {
  position: relative;
}

.vb-dropdown-twentyfive-trigger {
  display: grid;
  grid-template-columns: 36px minmax(0, 1fr) 30px;
  gap: 9px;
  align-items: center;
  min-width: 170px;
  min-height: 50px;
  padding: 8px 10px;
  border: 1px solid rgba(148, 163, 184, 0.24);
  border-radius: 999px;
  background: #f8fafc;
  cursor: pointer;
  text-align: left;
}

.vb-dropdown-twentyfive-trigger &gt; span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 999px;
  background: #ffffff;
  font-size: 18px;
  box-shadow: 0 8px 20px rgba(15, 23, 42, 0.08);
}

.vb-dropdown-twentyfive-trigger strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  font-weight: 950;
}

.vb-dropdown-twentyfive-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-twentyfive-site.is-open .vb-dropdown-twentyfive-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-twentyfive-menu {
  position: absolute;
  z-index: 80;
  top: calc(100% + 12px);
  right: 0;
  display: grid;
  gap: 8px;
  width: 300px;
  padding: 12px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.24);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-twentyfive-site.is-open .vb-dropdown-twentyfive-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-twentyfive-menu button {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  width: 100%;
  padding: 10px;
  border: 0;
  border-radius: 16px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-twentyfive-menu button:hover,
.vb-dropdown-twentyfive-menu button.is-active {
  background: #f0f9ff;
  transform: translateX(2px);
}

.vb-dropdown-twentyfive-menu button &gt; span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 16px;
  background: #f8fafc;
  font-size: 20px;
}

.vb-dropdown-twentyfive-menu button strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-twentyfive-menu button small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 700;
}

.vb-dropdown-twentyfive-hero {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 470px;
  padding: 56px 18px 18px;
}

.vb-dropdown-twentyfive-hero &gt; span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #dbeafe;
  color: #1d4ed8 !important;
  -webkit-text-fill-color: #1d4ed8 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-twentyfive-hero h3 {
  max-width: 760px;
  min-height: 150px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(38px, 6vw, 78px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-twentyfive-hero p {
  max-width: 640px;
  margin: 0 0 24px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-twentyfive-selected {
  width: min(100%, 320px);
  padding: 18px;
  border-radius: 22px;
  background: #0f172a;
  box-shadow: 0 22px 54px rgba(15, 23, 42, 0.18);
}

.vb-dropdown-twentyfive-selected small {
  display: block;
  margin-bottom: 7px;
  color: #bfdbfe !important;
  -webkit-text-fill-color: #bfdbfe !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentyfive-selected strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px;
  line-height: 1.15;
  font-weight: 950;
}

@media (max-width: 640px) {
  .vb-dropdown-twentyfive-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twentyfive-site {
    min-height: 740px;
    padding: 18px;
    border-radius: 22px;
  }

  .vb-dropdown-twentyfive-header {
    align-items: flex-start;
    flex-direction: column;
  }

  .vb-dropdown-twentyfive-wrap,
  .vb-dropdown-twentyfive-trigger {
    width: 100%;
  }

  .vb-dropdown-twentyfive-menu {
    left: 0;
    right: auto;
    width: 100%;
    transform-origin: top left;
  }

  .vb-dropdown-twentyfive-hero h3 {
    min-height: auto;
    font-size: 38px !important;
  }
}</pre>



<p class="wp-block-paragraph">This language selector dropdown is useful for websites where visitors need to switch between localized versions of the interface. You can adapt it for multilingual WordPress sites, ecommerce stores, SaaS dashboards, documentation hubs, travel websites, booking platforms, and international landing pages.</p>



<h2 class="wp-block-heading">26. Currency Selector Dropdown</h2>



<p class="wp-block-paragraph"><strong>A currency selector dropdown</strong> is useful for ecommerce stores, SaaS pricing pages, marketplaces, booking platforms, international product pages, and subscription checkout screens. It lets users choose their preferred currency and instantly updates the visible prices.</p>



<p class="wp-block-paragraph">This example includes a currency dropdown, active option styling, price conversion preview, selected currency badge, outside click closing, and Escape key support. The JavaScript updates the visible price cards based on simple demo conversion values.</p>



<ul class="wp-block-list">
<li>Currency selector dropdown</li>
<li>Updates pricing cards with JavaScript</li>
<li>Active currency option state</li>
<li>Selected currency preview</li>
<li>Useful for ecommerce stores, pricing pages, marketplaces, booking platforms, and international checkout screens</li>
</ul>



<div class="vb-dropdown-twentysix-demo">
  <div class="vb-dropdown-twentysix-pricing" data-vb-dropdown-twentysix>
    <div class="vb-dropdown-twentysix-top">
      <div>
        <span>Example 26</span>
        <h3>Currency Selector Dropdown</h3>
        <p>Select a currency and update the pricing cards instantly with JavaScript.</p>
      </div>

      <div class="vb-dropdown-twentysix-control">
        <button type="button" class="vb-dropdown-twentysix-trigger" data-vb-dropdown-twentysix-trigger aria-expanded="false">
          <span data-vb-dropdown-twentysix-symbol>€</span>
          <strong data-vb-dropdown-twentysix-current>EUR</strong>
          <em>⌄</em>
        </button>

        <div class="vb-dropdown-twentysix-menu" data-vb-dropdown-twentysix-menu>
          <button type="button" class="is-active" data-currency="EUR" data-symbol="€" data-basic="19" data-pro="49" data-business="99">
            <span>€</span>
            <strong>EUR</strong>
            <small>Euro pricing</small>
          </button>

          <button type="button" data-currency="USD" data-symbol="$" data-basic="21" data-pro="53" data-business="107">
            <span>$</span>
            <strong>USD</strong>
            <small>US dollar pricing</small>
          </button>

          <button type="button" data-currency="GBP" data-symbol="£" data-basic="16" data-pro="42" data-business="84">
            <span>£</span>
            <strong>GBP</strong>
            <small>British pound pricing</small>
          </button>

          <button type="button" data-currency="SEK" data-symbol="kr" data-basic="215" data-pro="555" data-business="1120">
            <span>kr</span>
            <strong>SEK</strong>
            <small>Swedish krona pricing</small>
          </button>
        </div>
      </div>
    </div>

    <div class="vb-dropdown-twentysix-selected">
      <small>Selected currency</small>
      <strong data-vb-dropdown-twentysix-selected>EUR · Euro pricing</strong>
    </div>

    <div class="vb-dropdown-twentysix-cards">
      <article>
        <small>Starter</small>
        <h4>Basic</h4>
        <strong><span data-vb-dropdown-twentysix-basic-symbol>€</span><b data-vb-dropdown-twentysix-basic>19</b></strong>
        <p>Good for small projects and simple UI experiments.</p>
      </article>

      <article class="is-featured">
        <small>Popular</small>
        <h4>Pro</h4>
        <strong><span data-vb-dropdown-twentysix-pro-symbol>€</span><b data-vb-dropdown-twentysix-pro>49</b></strong>
        <p>Best for growing websites, components, and client work.</p>
      </article>

      <article>
        <small>Scale</small>
        <h4>Business</h4>
        <strong><span data-vb-dropdown-twentysix-business-symbol>€</span><b data-vb-dropdown-twentysix-business>99</b></strong>
        <p>Advanced plan for teams, agencies, and dashboards.</p>
      </article>
    </div>
  </div>
</div>

<style>
.vb-dropdown-twentysix-demo,
.vb-dropdown-twentysix-demo * {
  box-sizing: border-box;
}

.vb-dropdown-twentysix-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(16, 185, 129, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(20, 184, 166, 0.18), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #f0fdfa 52%, #ffffff 100%) !important;
  border: 1px solid rgba(167, 243, 208, 0.46);
  box-shadow: 0 24px 70px rgba(6, 95, 70, 0.12);
}

.vb-dropdown-twentysix-pricing {
  position: relative;
  max-width: 1080px;
  min-height: 640px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(167, 243, 208, 0.50);
  box-shadow: 0 24px 70px rgba(6, 95, 70, 0.12);
  overflow: visible;
}

.vb-dropdown-twentysix-top {
  position: relative;
  z-index: 50;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(230px, 280px);
  gap: 28px;
  align-items: end;
  margin-bottom: 18px;
}

.vb-dropdown-twentysix-top > div:first-child > span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #d1fae5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-twentysix-top h3 {
  max-width: 760px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-twentysix-top p {
  max-width: 640px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-twentysix-control {
  position: relative;
  z-index: 60;
}

.vb-dropdown-twentysix-trigger {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr) 34px;
  gap: 11px;
  align-items: center;
  width: 100%;
  min-height: 62px;
  padding: 10px 12px;
  border: 1px solid rgba(5, 150, 105, 0.22);
  border-radius: 20px;
  background: #ecfdf5;
  cursor: pointer;
  text-align: left;
  box-shadow: 0 16px 38px rgba(6, 95, 70, 0.10);
}

.vb-dropdown-twentysix-trigger > span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: #ffffff;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 17px;
  font-weight: 950;
  box-shadow: 0 8px 20px rgba(6, 95, 70, 0.08);
}

.vb-dropdown-twentysix-trigger strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-twentysix-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: #d1fae5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-twentysix-pricing.is-open .vb-dropdown-twentysix-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-twentysix-menu {
  position: absolute;
  z-index: 90;
  top: calc(100% + 12px);
  left: 0;
  right: 0;
  display: grid;
  gap: 8px;
  padding: 12px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.24);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-twentysix-pricing.is-open .vb-dropdown-twentysix-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-twentysix-menu button {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  width: 100%;
  padding: 10px;
  border: 0;
  border-radius: 16px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-twentysix-menu button:hover,
.vb-dropdown-twentysix-menu button.is-active {
  background: #ecfdf5;
  transform: translateX(2px);
}

.vb-dropdown-twentysix-menu button > span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: #d1fae5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-twentysix-menu button strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-twentysix-menu button small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 700;
}

.vb-dropdown-twentysix-selected {
  width: fit-content;
  margin-bottom: 22px;
  padding: 13px 15px;
  border-radius: 999px;
  background: #0f172a;
}

.vb-dropdown-twentysix-selected small {
  display: inline-flex;
  margin-right: 8px;
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-dropdown-twentysix-selected strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-dropdown-twentysix-cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.vb-dropdown-twentysix-cards article {
  min-height: 280px;
  padding: 22px;
  border-radius: 26px;
  background:
    radial-gradient(circle at 20% 16%, rgba(16, 185, 129, 0.12), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb-dropdown-twentysix-cards article.is-featured {
  background:
    radial-gradient(circle at 20% 16%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #064e3b, #047857) !important;
  transform: translateY(-8px);
  box-shadow: 0 30px 70px rgba(6, 95, 70, 0.24);
}

.vb-dropdown-twentysix-cards small {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #d1fae5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 12px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-dropdown-twentysix-cards .is-featured small {
  background: rgba(255,255,255,0.14);
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
}

.vb-dropdown-twentysix-cards h4 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 28px !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.05em;
}

.vb-dropdown-twentysix-cards .is-featured h4 {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-twentysix-cards article > strong {
  display: block;
  margin-bottom: 16px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 42px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vb-dropdown-twentysix-cards .is-featured > strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-twentysix-cards article > strong span {
  margin-right: 2px;
  font-size: 28px;
}

.vb-dropdown-twentysix-cards p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-dropdown-twentysix-cards .is-featured p {
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
}

@media (max-width: 900px) {
  .vb-dropdown-twentysix-top {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-twentysix-control {
    max-width: 280px;
  }

  .vb-dropdown-twentysix-cards {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-twentysix-cards article.is-featured {
    transform: none;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-twentysix-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twentysix-pricing {
    min-height: 900px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-twentysix-top h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-twentysix-control,
  .vb-dropdown-twentysix-trigger {
    width: 100%;
    max-width: none;
  }

  .vb-dropdown-twentysix-selected {
    width: 100%;
    border-radius: 18px;
  }

  .vb-dropdown-twentysix-selected small {
    display: block;
    margin: 0 0 6px;
  }
}
</style>

<script>
(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-twentysix]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-twentysix-trigger]");
  const current = dropdown.querySelector("[data-vb-dropdown-twentysix-current]");
  const triggerSymbol = dropdown.querySelector("[data-vb-dropdown-twentysix-symbol]");
  const selected = dropdown.querySelector("[data-vb-dropdown-twentysix-selected]");
  const basic = dropdown.querySelector("[data-vb-dropdown-twentysix-basic]");
  const pro = dropdown.querySelector("[data-vb-dropdown-twentysix-pro]");
  const business = dropdown.querySelector("[data-vb-dropdown-twentysix-business]");
  const basicSymbol = dropdown.querySelector("[data-vb-dropdown-twentysix-basic-symbol]");
  const proSymbol = dropdown.querySelector("[data-vb-dropdown-twentysix-pro-symbol]");
  const businessSymbol = dropdown.querySelector("[data-vb-dropdown-twentysix-business-symbol]");
  const options = dropdown.querySelectorAll("[data-currency]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function updatePrices(option) {
    const currency = option.getAttribute("data-currency");
    const symbol = option.getAttribute("data-symbol");

    current.textContent = currency;
    triggerSymbol.textContent = symbol;
    selected.textContent = currency + " · " + option.querySelector("small").textContent;

    basic.textContent = option.getAttribute("data-basic");
    pro.textContent = option.getAttribute("data-pro");
    business.textContent = option.getAttribute("data-business");

    basicSymbol.textContent = symbol;
    proSymbol.textContent = symbol;
    businessSymbol.textContent = symbol;

    options.forEach(function (item) {
      item.classList.remove("is-active");
    });

    option.classList.add("is-active");
    closeDropdown();
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  options.forEach(function (option) {
    option.addEventListener("click", function () {
      updatePrices(option);
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const dropdown = document.querySelector("[data-vb-dropdown-twentysix]");
  if (!dropdown) return;

  const trigger = dropdown.querySelector("[data-vb-dropdown-twentysix-trigger]");
  const current = dropdown.querySelector("[data-vb-dropdown-twentysix-current]");
  const triggerSymbol = dropdown.querySelector("[data-vb-dropdown-twentysix-symbol]");
  const selected = dropdown.querySelector("[data-vb-dropdown-twentysix-selected]");
  const basic = dropdown.querySelector("[data-vb-dropdown-twentysix-basic]");
  const pro = dropdown.querySelector("[data-vb-dropdown-twentysix-pro]");
  const business = dropdown.querySelector("[data-vb-dropdown-twentysix-business]");
  const basicSymbol = dropdown.querySelector("[data-vb-dropdown-twentysix-basic-symbol]");
  const proSymbol = dropdown.querySelector("[data-vb-dropdown-twentysix-pro-symbol]");
  const businessSymbol = dropdown.querySelector("[data-vb-dropdown-twentysix-business-symbol]");
  const options = dropdown.querySelectorAll("[data-currency]");

  function closeDropdown() {
    dropdown.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdown.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function updatePrices(option) {
    const currency = option.getAttribute("data-currency");
    const symbol = option.getAttribute("data-symbol");

    current.textContent = currency;
    triggerSymbol.textContent = symbol;
    selected.textContent = currency + " · " + option.querySelector("small").textContent;

    basic.textContent = option.getAttribute("data-basic");
    pro.textContent = option.getAttribute("data-pro");
    business.textContent = option.getAttribute("data-business");

    basicSymbol.textContent = symbol;
    proSymbol.textContent = symbol;
    businessSymbol.textContent = symbol;

    options.forEach(function (item) {
      item.classList.remove("is-active");
    });

    option.classList.add("is-active");
    closeDropdown();
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  options.forEach(function (option) {
    option.addEventListener("click", function () {
      updatePrices(option);
    });
  });

  document.addEventListener("click", function (event) {
    if (!dropdown.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-twentysix-demo"&gt;
  &lt;div class="vb-dropdown-twentysix-pricing" data-vb-dropdown-twentysix&gt;
    &lt;div class="vb-dropdown-twentysix-top"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 26&lt;/span&gt;
        &lt;h3&gt;Currency Selector Dropdown&lt;/h3&gt;
        &lt;p&gt;Select a currency and update the pricing cards instantly with JavaScript.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-twentysix-control"&gt;
        &lt;button type="button" class="vb-dropdown-twentysix-trigger" data-vb-dropdown-twentysix-trigger aria-expanded="false"&gt;
          &lt;span data-vb-dropdown-twentysix-symbol&gt;€&lt;/span&gt;
          &lt;strong data-vb-dropdown-twentysix-current&gt;EUR&lt;/strong&gt;
          &lt;em&gt;⌄&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-dropdown-twentysix-menu" data-vb-dropdown-twentysix-menu&gt;
          &lt;button type="button" class="is-active" data-currency="EUR" data-symbol="€" data-basic="19" data-pro="49" data-business="99"&gt;
            &lt;span&gt;€&lt;/span&gt;
            &lt;strong&gt;EUR&lt;/strong&gt;
            &lt;small&gt;Euro pricing&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-currency="USD" data-symbol="$" data-basic="21" data-pro="53" data-business="107"&gt;
            &lt;span&gt;$&lt;/span&gt;
            &lt;strong&gt;USD&lt;/strong&gt;
            &lt;small&gt;US dollar pricing&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-currency="GBP" data-symbol="£" data-basic="16" data-pro="42" data-business="84"&gt;
            &lt;span&gt;£&lt;/span&gt;
            &lt;strong&gt;GBP&lt;/strong&gt;
            &lt;small&gt;British pound pricing&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-currency="SEK" data-symbol="kr" data-basic="215" data-pro="555" data-business="1120"&gt;
            &lt;span&gt;kr&lt;/span&gt;
            &lt;strong&gt;SEK&lt;/strong&gt;
            &lt;small&gt;Swedish krona pricing&lt;/small&gt;
          &lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-dropdown-twentysix-selected"&gt;
      &lt;small&gt;Selected currency&lt;/small&gt;
      &lt;strong data-vb-dropdown-twentysix-selected&gt;EUR · Euro pricing&lt;/strong&gt;
    &lt;/div&gt;

    &lt;div class="vb-dropdown-twentysix-cards"&gt;
      &lt;article&gt;
        &lt;small&gt;Starter&lt;/small&gt;
        &lt;h4&gt;Basic&lt;/h4&gt;
        &lt;strong&gt;&lt;span data-vb-dropdown-twentysix-basic-symbol&gt;€&lt;/span&gt;&lt;b data-vb-dropdown-twentysix-basic&gt;19&lt;/b&gt;&lt;/strong&gt;
        &lt;p&gt;Good for small projects and simple UI experiments.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article class="is-featured"&gt;
        &lt;small&gt;Popular&lt;/small&gt;
        &lt;h4&gt;Pro&lt;/h4&gt;
        &lt;strong&gt;&lt;span data-vb-dropdown-twentysix-pro-symbol&gt;€&lt;/span&gt;&lt;b data-vb-dropdown-twentysix-pro&gt;49&lt;/b&gt;&lt;/strong&gt;
        &lt;p&gt;Best for growing websites, components, and client work.&lt;/p&gt;
      &lt;/article&gt;

      &lt;article&gt;
        &lt;small&gt;Scale&lt;/small&gt;
        &lt;h4&gt;Business&lt;/h4&gt;
        &lt;strong&gt;&lt;span data-vb-dropdown-twentysix-business-symbol&gt;€&lt;/span&gt;&lt;b data-vb-dropdown-twentysix-business&gt;99&lt;/b&gt;&lt;/strong&gt;
        &lt;p&gt;Advanced plan for teams, agencies, and dashboards.&lt;/p&gt;
      &lt;/article&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-twentysix-demo,
.vb-dropdown-twentysix-demo * {
  box-sizing: border-box;
}

.vb-dropdown-twentysix-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(16, 185, 129, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(20, 184, 166, 0.18), transparent 34%),
    linear-gradient(135deg, #ecfdf5 0%, #f0fdfa 52%, #ffffff 100%) !important;
  border: 1px solid rgba(167, 243, 208, 0.46);
  box-shadow: 0 24px 70px rgba(6, 95, 70, 0.12);
}

.vb-dropdown-twentysix-pricing {
  position: relative;
  max-width: 1080px;
  min-height: 640px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(167, 243, 208, 0.50);
  box-shadow: 0 24px 70px rgba(6, 95, 70, 0.12);
  overflow: visible;
}

.vb-dropdown-twentysix-top {
  position: relative;
  z-index: 50;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(230px, 280px);
  gap: 28px;
  align-items: end;
  margin-bottom: 18px;
}

.vb-dropdown-twentysix-top &gt; div:first-child &gt; span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #d1fae5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-twentysix-top h3 {
  max-width: 760px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-twentysix-top p {
  max-width: 640px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-twentysix-control {
  position: relative;
  z-index: 60;
}

.vb-dropdown-twentysix-trigger {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr) 34px;
  gap: 11px;
  align-items: center;
  width: 100%;
  min-height: 62px;
  padding: 10px 12px;
  border: 1px solid rgba(5, 150, 105, 0.22);
  border-radius: 20px;
  background: #ecfdf5;
  cursor: pointer;
  text-align: left;
  box-shadow: 0 16px 38px rgba(6, 95, 70, 0.10);
}

.vb-dropdown-twentysix-trigger &gt; span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: #ffffff;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 17px;
  font-weight: 950;
  box-shadow: 0 8px 20px rgba(6, 95, 70, 0.08);
}

.vb-dropdown-twentysix-trigger strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-twentysix-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: #d1fae5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-twentysix-pricing.is-open .vb-dropdown-twentysix-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-twentysix-menu {
  position: absolute;
  z-index: 90;
  top: calc(100% + 12px);
  left: 0;
  right: 0;
  display: grid;
  gap: 8px;
  padding: 12px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.24);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-twentysix-pricing.is-open .vb-dropdown-twentysix-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-twentysix-menu button {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  width: 100%;
  padding: 10px;
  border: 0;
  border-radius: 16px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-twentysix-menu button:hover,
.vb-dropdown-twentysix-menu button.is-active {
  background: #ecfdf5;
  transform: translateX(2px);
}

.vb-dropdown-twentysix-menu button &gt; span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: #d1fae5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-twentysix-menu button strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-twentysix-menu button small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 700;
}

.vb-dropdown-twentysix-selected {
  width: fit-content;
  margin-bottom: 22px;
  padding: 13px 15px;
  border-radius: 999px;
  background: #0f172a;
}

.vb-dropdown-twentysix-selected small {
  display: inline-flex;
  margin-right: 8px;
  color: #a7f3d0 !important;
  -webkit-text-fill-color: #a7f3d0 !important;
  font-size: 12px;
  font-weight: 950;
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.vb-dropdown-twentysix-selected strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb-dropdown-twentysix-cards {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 14px;
}

.vb-dropdown-twentysix-cards article {
  min-height: 280px;
  padding: 22px;
  border-radius: 26px;
  background:
    radial-gradient(circle at 20% 16%, rgba(16, 185, 129, 0.12), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb-dropdown-twentysix-cards article.is-featured {
  background:
    radial-gradient(circle at 20% 16%, rgba(255,255,255,0.18), transparent 34%),
    linear-gradient(135deg, #064e3b, #047857) !important;
  transform: translateY(-8px);
  box-shadow: 0 30px 70px rgba(6, 95, 70, 0.24);
}

.vb-dropdown-twentysix-cards small {
  display: inline-flex;
  margin-bottom: 18px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #d1fae5;
  color: #047857 !important;
  -webkit-text-fill-color: #047857 !important;
  font-size: 12px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.vb-dropdown-twentysix-cards .is-featured small {
  background: rgba(255,255,255,0.14);
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
}

.vb-dropdown-twentysix-cards h4 {
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 28px !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.05em;
}

.vb-dropdown-twentysix-cards .is-featured h4 {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-twentysix-cards article &gt; strong {
  display: block;
  margin-bottom: 16px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 42px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vb-dropdown-twentysix-cards .is-featured &gt; strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-twentysix-cards article &gt; strong span {
  margin-right: 2px;
  font-size: 28px;
}

.vb-dropdown-twentysix-cards p {
  margin: 0 !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.6;
  font-weight: 650;
}

.vb-dropdown-twentysix-cards .is-featured p {
  color: #d1fae5 !important;
  -webkit-text-fill-color: #d1fae5 !important;
}

@media (max-width: 900px) {
  .vb-dropdown-twentysix-top {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-twentysix-control {
    max-width: 280px;
  }

  .vb-dropdown-twentysix-cards {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-twentysix-cards article.is-featured {
    transform: none;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-twentysix-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twentysix-pricing {
    min-height: 900px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-twentysix-top h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-twentysix-control,
  .vb-dropdown-twentysix-trigger {
    width: 100%;
    max-width: none;
  }

  .vb-dropdown-twentysix-selected {
    width: 100%;
    border-radius: 18px;
  }

  .vb-dropdown-twentysix-selected small {
    display: block;
    margin: 0 0 6px;
  }
}</pre>



<p class="wp-block-paragraph">This currency selector dropdown is useful for international pricing and checkout experiences. You can adapt it for WooCommerce stores, SaaS pricing tables, marketplaces, booking platforms, product pages, subscription plans, and digital product sales pages.</p>



<h2 class="wp-block-heading">27. Color Theme Dropdown</h2>



<p class="wp-block-paragraph"><strong>A color theme dropdown</strong> is useful for dashboards, SaaS products, admin panels, profile settings, website builders, and design tools. It lets users switch the visible interface style from one compact dropdown control.</p>



<p class="wp-block-paragraph">This example includes a theme dropdown trigger, multiple theme options, active state styling, live theme preview, selected theme text, outside click closing, and Escape key support. JavaScript updates the main demo card by changing the active theme class.</p>



<ul class="wp-block-list">
<li>Color theme selector dropdown</li>
<li>Updates interface theme with JavaScript</li>
<li>Active selected option styling</li>
<li>Live preview card changes instantly</li>
<li>Useful for dashboards, admin panels, SaaS settings, website builders, and profile preferences</li>
</ul>



<div class="vb-dropdown-twentyseven-demo">
  <div class="vb-dropdown-twentyseven-panel theme-ocean" data-vb-dropdown-twentyseven>
    <div class="vb-dropdown-twentyseven-top">
      <div>
        <span>Example 27</span>
        <h3>Color Theme Dropdown</h3>
        <p>Choose a theme from the dropdown and update the interface preview instantly.</p>
      </div>

      <div class="vb-dropdown-twentyseven-control">
        <button type="button" class="vb-dropdown-twentyseven-trigger" data-vb-dropdown-twentyseven-trigger aria-expanded="false">
          <span data-vb-dropdown-twentyseven-dot></span>
          <strong data-vb-dropdown-twentyseven-current>Ocean Theme</strong>
          <em>⌄</em>
        </button>

        <div class="vb-dropdown-twentyseven-menu" data-vb-dropdown-twentyseven-menu>
          <button type="button" class="is-active" data-theme="theme-ocean" data-theme-label="Ocean Theme">
            <span class="vb-dropdown-twentyseven-swatch ocean"></span>
            <strong>Ocean Theme</strong>
            <small>Blue and cyan interface</small>
          </button>

          <button type="button" data-theme="theme-sunset" data-theme-label="Sunset Theme">
            <span class="vb-dropdown-twentyseven-swatch sunset"></span>
            <strong>Sunset Theme</strong>
            <small>Orange and pink interface</small>
          </button>

          <button type="button" data-theme="theme-forest" data-theme-label="Forest Theme">
            <span class="vb-dropdown-twentyseven-swatch forest"></span>
            <strong>Forest Theme</strong>
            <small>Green and emerald interface</small>
          </button>

          <button type="button" data-theme="theme-cosmic" data-theme-label="Cosmic Theme">
            <span class="vb-dropdown-twentyseven-swatch cosmic"></span>
            <strong>Cosmic Theme</strong>
            <small>Purple and indigo interface</small>
          </button>
        </div>
      </div>
    </div>

    <div class="vb-dropdown-twentyseven-preview">
      <div class="vb-dropdown-twentyseven-window">
        <div class="vb-dropdown-twentyseven-window-top">
          <span></span>
          <span></span>
          <span></span>
        </div>

        <div class="vb-dropdown-twentyseven-window-body">
          <small>Selected theme</small>
          <strong data-vb-dropdown-twentyseven-selected>Ocean Theme</strong>
          <p>This preview card changes its accent color when a different dropdown option is selected.</p>

          <div class="vb-dropdown-twentyseven-bars">
            <i></i>
            <i></i>
            <i></i>
          </div>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-dropdown-twentyseven-demo,
.vb-dropdown-twentyseven-demo * {
  box-sizing: border-box;
}

.vb-dropdown-twentyseven-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(59, 130, 246, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(191, 219, 254, 0.44);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.11);
}

.vb-dropdown-twentyseven-panel {
  --theme-a: #0284c7;
  --theme-b: #06b6d4;
  --theme-soft: #e0f2fe;
  --theme-text: #0369a1;
  position: relative;
  max-width: 1080px;
  min-height: 640px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 82% 74%, color-mix(in srgb, var(--theme-a) 18%, transparent), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
  overflow: visible;
}

.vb-dropdown-twentyseven-panel.theme-sunset {
  --theme-a: #f97316;
  --theme-b: #ec4899;
  --theme-soft: #ffedd5;
  --theme-text: #c2410c;
}

.vb-dropdown-twentyseven-panel.theme-forest {
  --theme-a: #16a34a;
  --theme-b: #0f766e;
  --theme-soft: #dcfce7;
  --theme-text: #15803d;
}

.vb-dropdown-twentyseven-panel.theme-cosmic {
  --theme-a: #7c3aed;
  --theme-b: #4f46e5;
  --theme-soft: #ede9fe;
  --theme-text: #6d28d9;
}

.vb-dropdown-twentyseven-top {
  position: relative;
  z-index: 50;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 310px);
  gap: 28px;
  align-items: end;
  margin-bottom: 28px;
}

.vb-dropdown-twentyseven-top > div:first-child > span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: var(--theme-soft);
  color: var(--theme-text) !important;
  -webkit-text-fill-color: var(--theme-text) !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-twentyseven-top h3 {
  max-width: 760px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-twentyseven-top p {
  max-width: 640px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-twentyseven-control {
  position: relative;
  z-index: 60;
}

.vb-dropdown-twentyseven-trigger {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr) 34px;
  gap: 11px;
  align-items: center;
  width: 100%;
  min-height: 62px;
  padding: 10px 12px;
  border: 1px solid rgba(148, 163, 184, 0.24);
  border-radius: 20px;
  background: #ffffff;
  cursor: pointer;
  text-align: left;
  box-shadow: 0 16px 38px rgba(15, 23, 42, 0.08);
}

.vb-dropdown-twentyseven-trigger > span {
  display: inline-flex;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: linear-gradient(135deg, var(--theme-a), var(--theme-b));
  box-shadow: 0 10px 24px color-mix(in srgb, var(--theme-a) 22%, transparent);
}

.vb-dropdown-twentyseven-trigger strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-twentyseven-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: var(--theme-soft);
  color: var(--theme-text) !important;
  -webkit-text-fill-color: var(--theme-text) !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-twentyseven-panel.is-open .vb-dropdown-twentyseven-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-twentyseven-menu {
  position: absolute;
  z-index: 90;
  top: calc(100% + 12px);
  left: 0;
  right: 0;
  display: grid;
  gap: 8px;
  padding: 12px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.24);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-twentyseven-panel.is-open .vb-dropdown-twentyseven-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-twentyseven-menu button {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  width: 100%;
  padding: 10px;
  border: 0;
  border-radius: 16px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-twentyseven-menu button:hover,
.vb-dropdown-twentyseven-menu button.is-active {
  background: #f8fafc;
  transform: translateX(2px);
}

.vb-dropdown-twentyseven-swatch {
  grid-row: span 2;
  display: inline-flex;
  width: 42px;
  height: 42px;
  border-radius: 15px;
}

.vb-dropdown-twentyseven-swatch.ocean {
  background: linear-gradient(135deg, #0284c7, #06b6d4);
}

.vb-dropdown-twentyseven-swatch.sunset {
  background: linear-gradient(135deg, #f97316, #ec4899);
}

.vb-dropdown-twentyseven-swatch.forest {
  background: linear-gradient(135deg, #16a34a, #0f766e);
}

.vb-dropdown-twentyseven-swatch.cosmic {
  background: linear-gradient(135deg, #7c3aed, #4f46e5);
}

.vb-dropdown-twentyseven-menu button strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-twentyseven-menu button small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 700;
}

.vb-dropdown-twentyseven-preview {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 390px;
  border-radius: 28px;
  background:
    radial-gradient(circle at 30% 20%, color-mix(in srgb, var(--theme-a) 22%, transparent), transparent 30%),
    linear-gradient(135deg, #0f172a, #111827) !important;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
}

.vb-dropdown-twentyseven-window {
  width: min(100%, 560px);
  border-radius: 26px;
  overflow: hidden;
  background: #ffffff;
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.28);
}

.vb-dropdown-twentyseven-window-top {
  display: flex;
  gap: 7px;
  padding: 14px;
  background: #f8fafc;
  border-bottom: 1px solid #e5e7eb;
}

.vb-dropdown-twentyseven-window-top span {
  width: 11px;
  height: 11px;
  border-radius: 999px;
  background: var(--theme-a);
}

.vb-dropdown-twentyseven-window-body {
  padding: 28px;
}

.vb-dropdown-twentyseven-window-body small {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 7px 10px;
  border-radius: 999px;
  background: var(--theme-soft);
  color: var(--theme-text) !important;
  -webkit-text-fill-color: var(--theme-text) !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentyseven-window-body strong {
  display: block;
  margin-bottom: 12px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 34px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vb-dropdown-twentyseven-window-body p {
  max-width: 430px;
  margin: 0 0 22px !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-dropdown-twentyseven-bars {
  display: grid;
  gap: 10px;
}

.vb-dropdown-twentyseven-bars i {
  display: block;
  height: 12px;
  border-radius: 999px;
  background: linear-gradient(135deg, var(--theme-a), var(--theme-b));
}

.vb-dropdown-twentyseven-bars i:nth-child(1) {
  width: 76%;
}

.vb-dropdown-twentyseven-bars i:nth-child(2) {
  width: 58%;
  opacity: 0.76;
}

.vb-dropdown-twentyseven-bars i:nth-child(3) {
  width: 86%;
  opacity: 0.52;
}

@media (max-width: 900px) {
  .vb-dropdown-twentyseven-top {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-twentyseven-control {
    max-width: 320px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-twentyseven-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twentyseven-panel {
    min-height: 780px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-twentyseven-top h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-twentyseven-control,
  .vb-dropdown-twentyseven-trigger {
    width: 100%;
    max-width: none;
  }

  .vb-dropdown-twentyseven-preview {
    min-height: 360px;
    padding: 16px;
  }
}
</style>

<script>
(function () {
  const panel = document.querySelector("[data-vb-dropdown-twentyseven]");
  if (!panel) return;

  const trigger = panel.querySelector("[data-vb-dropdown-twentyseven-trigger]");
  const current = panel.querySelector("[data-vb-dropdown-twentyseven-current]");
  const selected = panel.querySelector("[data-vb-dropdown-twentyseven-selected]");
  const options = panel.querySelectorAll("[data-theme]");
  const themeClasses = ["theme-ocean", "theme-sunset", "theme-forest", "theme-cosmic"];

  function closeDropdown() {
    panel.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = panel.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function applyTheme(option) {
    const theme = option.getAttribute("data-theme");
    const label = option.getAttribute("data-theme-label");

    themeClasses.forEach(function (themeClass) {
      panel.classList.remove(themeClass);
    });

    panel.classList.add(theme);
    current.textContent = label;
    selected.textContent = label;

    options.forEach(function (item) {
      item.classList.remove("is-active");
    });

    option.classList.add("is-active");
    closeDropdown();
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  options.forEach(function (option) {
    option.addEventListener("click", function () {
      applyTheme(option);
    });
  });

  document.addEventListener("click", function (event) {
    if (!panel.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const panel = document.querySelector("[data-vb-dropdown-twentyseven]");
  if (!panel) return;

  const trigger = panel.querySelector("[data-vb-dropdown-twentyseven-trigger]");
  const current = panel.querySelector("[data-vb-dropdown-twentyseven-current]");
  const selected = panel.querySelector("[data-vb-dropdown-twentyseven-selected]");
  const options = panel.querySelectorAll("[data-theme]");
  const themeClasses = ["theme-ocean", "theme-sunset", "theme-forest", "theme-cosmic"];

  function closeDropdown() {
    panel.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = panel.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  function applyTheme(option) {
    const theme = option.getAttribute("data-theme");
    const label = option.getAttribute("data-theme-label");

    themeClasses.forEach(function (themeClass) {
      panel.classList.remove(themeClass);
    });

    panel.classList.add(theme);
    current.textContent = label;
    selected.textContent = label;

    options.forEach(function (item) {
      item.classList.remove("is-active");
    });

    option.classList.add("is-active");
    closeDropdown();
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  options.forEach(function (option) {
    option.addEventListener("click", function () {
      applyTheme(option);
    });
  });

  document.addEventListener("click", function (event) {
    if (!panel.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-twentyseven-demo"&gt;
  &lt;div class="vb-dropdown-twentyseven-panel theme-ocean" data-vb-dropdown-twentyseven&gt;
    &lt;div class="vb-dropdown-twentyseven-top"&gt;
      &lt;div&gt;
        &lt;span&gt;Example 27&lt;/span&gt;
        &lt;h3&gt;Color Theme Dropdown&lt;/h3&gt;
        &lt;p&gt;Choose a theme from the dropdown and update the interface preview instantly.&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-twentyseven-control"&gt;
        &lt;button type="button" class="vb-dropdown-twentyseven-trigger" data-vb-dropdown-twentyseven-trigger aria-expanded="false"&gt;
          &lt;span data-vb-dropdown-twentyseven-dot&gt;&lt;/span&gt;
          &lt;strong data-vb-dropdown-twentyseven-current&gt;Ocean Theme&lt;/strong&gt;
          &lt;em&gt;⌄&lt;/em&gt;
        &lt;/button&gt;

        &lt;div class="vb-dropdown-twentyseven-menu" data-vb-dropdown-twentyseven-menu&gt;
          &lt;button type="button" class="is-active" data-theme="theme-ocean" data-theme-label="Ocean Theme"&gt;
            &lt;span class="vb-dropdown-twentyseven-swatch ocean"&gt;&lt;/span&gt;
            &lt;strong&gt;Ocean Theme&lt;/strong&gt;
            &lt;small&gt;Blue and cyan interface&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-theme="theme-sunset" data-theme-label="Sunset Theme"&gt;
            &lt;span class="vb-dropdown-twentyseven-swatch sunset"&gt;&lt;/span&gt;
            &lt;strong&gt;Sunset Theme&lt;/strong&gt;
            &lt;small&gt;Orange and pink interface&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-theme="theme-forest" data-theme-label="Forest Theme"&gt;
            &lt;span class="vb-dropdown-twentyseven-swatch forest"&gt;&lt;/span&gt;
            &lt;strong&gt;Forest Theme&lt;/strong&gt;
            &lt;small&gt;Green and emerald interface&lt;/small&gt;
          &lt;/button&gt;

          &lt;button type="button" data-theme="theme-cosmic" data-theme-label="Cosmic Theme"&gt;
            &lt;span class="vb-dropdown-twentyseven-swatch cosmic"&gt;&lt;/span&gt;
            &lt;strong&gt;Cosmic Theme&lt;/strong&gt;
            &lt;small&gt;Purple and indigo interface&lt;/small&gt;
          &lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-dropdown-twentyseven-preview"&gt;
      &lt;div class="vb-dropdown-twentyseven-window"&gt;
        &lt;div class="vb-dropdown-twentyseven-window-top"&gt;
          &lt;span&gt;&lt;/span&gt;
          &lt;span&gt;&lt;/span&gt;
          &lt;span&gt;&lt;/span&gt;
        &lt;/div&gt;

        &lt;div class="vb-dropdown-twentyseven-window-body"&gt;
          &lt;small&gt;Selected theme&lt;/small&gt;
          &lt;strong data-vb-dropdown-twentyseven-selected&gt;Ocean Theme&lt;/strong&gt;
          &lt;p&gt;This preview card changes its accent color when a different dropdown option is selected.&lt;/p&gt;

          &lt;div class="vb-dropdown-twentyseven-bars"&gt;
            &lt;i&gt;&lt;/i&gt;
            &lt;i&gt;&lt;/i&gt;
            &lt;i&gt;&lt;/i&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-twentyseven-demo,
.vb-dropdown-twentyseven-demo * {
  box-sizing: border-box;
}

.vb-dropdown-twentyseven-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(59, 130, 246, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(168, 85, 247, 0.16), transparent 34%),
    linear-gradient(135deg, #f8fafc 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(191, 219, 254, 0.44);
  box-shadow: 0 24px 70px rgba(30, 64, 175, 0.11);
}

.vb-dropdown-twentyseven-panel {
  --theme-a: #0284c7;
  --theme-b: #06b6d4;
  --theme-soft: #e0f2fe;
  --theme-text: #0369a1;
  position: relative;
  max-width: 1080px;
  min-height: 640px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 82% 74%, color-mix(in srgb, var(--theme-a) 18%, transparent), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
  overflow: visible;
}

.vb-dropdown-twentyseven-panel.theme-sunset {
  --theme-a: #f97316;
  --theme-b: #ec4899;
  --theme-soft: #ffedd5;
  --theme-text: #c2410c;
}

.vb-dropdown-twentyseven-panel.theme-forest {
  --theme-a: #16a34a;
  --theme-b: #0f766e;
  --theme-soft: #dcfce7;
  --theme-text: #15803d;
}

.vb-dropdown-twentyseven-panel.theme-cosmic {
  --theme-a: #7c3aed;
  --theme-b: #4f46e5;
  --theme-soft: #ede9fe;
  --theme-text: #6d28d9;
}

.vb-dropdown-twentyseven-top {
  position: relative;
  z-index: 50;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(260px, 310px);
  gap: 28px;
  align-items: end;
  margin-bottom: 28px;
}

.vb-dropdown-twentyseven-top &gt; div:first-child &gt; span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: var(--theme-soft);
  color: var(--theme-text) !important;
  -webkit-text-fill-color: var(--theme-text) !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-twentyseven-top h3 {
  max-width: 760px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-twentyseven-top p {
  max-width: 640px;
  margin: 0 !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-twentyseven-control {
  position: relative;
  z-index: 60;
}

.vb-dropdown-twentyseven-trigger {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr) 34px;
  gap: 11px;
  align-items: center;
  width: 100%;
  min-height: 62px;
  padding: 10px 12px;
  border: 1px solid rgba(148, 163, 184, 0.24);
  border-radius: 20px;
  background: #ffffff;
  cursor: pointer;
  text-align: left;
  box-shadow: 0 16px 38px rgba(15, 23, 42, 0.08);
}

.vb-dropdown-twentyseven-trigger &gt; span {
  display: inline-flex;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: linear-gradient(135deg, var(--theme-a), var(--theme-b));
  box-shadow: 0 10px 24px color-mix(in srgb, var(--theme-a) 22%, transparent);
}

.vb-dropdown-twentyseven-trigger strong {
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-twentyseven-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  border-radius: 999px;
  background: var(--theme-soft);
  color: var(--theme-text) !important;
  -webkit-text-fill-color: var(--theme-text) !important;
  font-style: normal;
  transition: transform 0.2s ease;
}

.vb-dropdown-twentyseven-panel.is-open .vb-dropdown-twentyseven-trigger em {
  transform: rotate(180deg);
}

.vb-dropdown-twentyseven-menu {
  position: absolute;
  z-index: 90;
  top: calc(100% + 12px);
  left: 0;
  right: 0;
  display: grid;
  gap: 8px;
  padding: 12px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.24);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-twentyseven-panel.is-open .vb-dropdown-twentyseven-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-twentyseven-menu button {
  display: grid;
  grid-template-columns: 42px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  width: 100%;
  padding: 10px;
  border: 0;
  border-radius: 16px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-twentyseven-menu button:hover,
.vb-dropdown-twentyseven-menu button.is-active {
  background: #f8fafc;
  transform: translateX(2px);
}

.vb-dropdown-twentyseven-swatch {
  grid-row: span 2;
  display: inline-flex;
  width: 42px;
  height: 42px;
  border-radius: 15px;
}

.vb-dropdown-twentyseven-swatch.ocean {
  background: linear-gradient(135deg, #0284c7, #06b6d4);
}

.vb-dropdown-twentyseven-swatch.sunset {
  background: linear-gradient(135deg, #f97316, #ec4899);
}

.vb-dropdown-twentyseven-swatch.forest {
  background: linear-gradient(135deg, #16a34a, #0f766e);
}

.vb-dropdown-twentyseven-swatch.cosmic {
  background: linear-gradient(135deg, #7c3aed, #4f46e5);
}

.vb-dropdown-twentyseven-menu button strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-twentyseven-menu button small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 700;
}

.vb-dropdown-twentyseven-preview {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 390px;
  border-radius: 28px;
  background:
    radial-gradient(circle at 30% 20%, color-mix(in srgb, var(--theme-a) 22%, transparent), transparent 30%),
    linear-gradient(135deg, #0f172a, #111827) !important;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
}

.vb-dropdown-twentyseven-window {
  width: min(100%, 560px);
  border-radius: 26px;
  overflow: hidden;
  background: #ffffff;
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.28);
}

.vb-dropdown-twentyseven-window-top {
  display: flex;
  gap: 7px;
  padding: 14px;
  background: #f8fafc;
  border-bottom: 1px solid #e5e7eb;
}

.vb-dropdown-twentyseven-window-top span {
  width: 11px;
  height: 11px;
  border-radius: 999px;
  background: var(--theme-a);
}

.vb-dropdown-twentyseven-window-body {
  padding: 28px;
}

.vb-dropdown-twentyseven-window-body small {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 7px 10px;
  border-radius: 999px;
  background: var(--theme-soft);
  color: var(--theme-text) !important;
  -webkit-text-fill-color: var(--theme-text) !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentyseven-window-body strong {
  display: block;
  margin-bottom: 12px;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 34px;
  line-height: 1;
  font-weight: 950;
  letter-spacing: -0.06em;
}

.vb-dropdown-twentyseven-window-body p {
  max-width: 430px;
  margin: 0 0 22px !important;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 14px;
  line-height: 1.65;
  font-weight: 650;
}

.vb-dropdown-twentyseven-bars {
  display: grid;
  gap: 10px;
}

.vb-dropdown-twentyseven-bars i {
  display: block;
  height: 12px;
  border-radius: 999px;
  background: linear-gradient(135deg, var(--theme-a), var(--theme-b));
}

.vb-dropdown-twentyseven-bars i:nth-child(1) {
  width: 76%;
}

.vb-dropdown-twentyseven-bars i:nth-child(2) {
  width: 58%;
  opacity: 0.76;
}

.vb-dropdown-twentyseven-bars i:nth-child(3) {
  width: 86%;
  opacity: 0.52;
}

@media (max-width: 900px) {
  .vb-dropdown-twentyseven-top {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-twentyseven-control {
    max-width: 320px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-twentyseven-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twentyseven-panel {
    min-height: 780px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-twentyseven-top h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-twentyseven-control,
  .vb-dropdown-twentyseven-trigger {
    width: 100%;
    max-width: none;
  }

  .vb-dropdown-twentyseven-preview {
    min-height: 360px;
    padding: 16px;
  }
}</pre>



<p class="wp-block-paragraph">This color theme dropdown is useful for user preference settings and customizable interfaces. You can adapt it for SaaS dashboards, admin panels, website builders, profile settings, white-label tools, design systems, and WordPress plugin interfaces.</p>



<h2 class="wp-block-heading">28. File Action Dropdown Menu</h2>



<p class="wp-block-paragraph"><strong>A file action dropdown menu</strong> is useful for dashboards, cloud storage interfaces, document managers, media libraries, admin panels, project tools, and file upload systems. It keeps common actions hidden until the user needs them.</p>



<p class="wp-block-paragraph">This example includes a file card, action dropdown button, menu actions, selected action feedback, danger action styling, outside click closing, and Escape key support. JavaScript updates the visible activity message when a file action is selected.</p>



<ul class="wp-block-list">
<li>File actions dropdown menu</li>
<li>Download, rename, duplicate, share, and delete actions</li>
<li>Selected action feedback with JavaScript</li>
<li>Danger action styling</li>
<li>Useful for dashboards, media libraries, document managers, file upload tools, and admin panels</li>
</ul>



<div class="vb-dropdown-twentyeight-demo">
  <div class="vb-dropdown-twentyeight-manager" data-vb-dropdown-twentyeight>
    <div class="vb-dropdown-twentyeight-copy">
      <span>Example 28</span>
      <h3>File Action Dropdown Menu</h3>
      <p>Open the action menu on the file card and choose a file operation from the dropdown.</p>

      <div class="vb-dropdown-twentyeight-log">
        <small>Latest action</small>
        <strong data-vb-dropdown-twentyeight-log>No action selected yet</strong>
      </div>
    </div>

    <div class="vb-dropdown-twentyeight-file">
      <div class="vb-dropdown-twentyeight-file-top">
        <div class="vb-dropdown-twentyeight-icon">PDF</div>

        <div class="vb-dropdown-twentyeight-action-wrap">
          <button type="button" class="vb-dropdown-twentyeight-trigger" data-vb-dropdown-twentyeight-trigger aria-expanded="false" aria-label="Open file actions">
            ⋯
          </button>

          <div class="vb-dropdown-twentyeight-menu" data-vb-dropdown-twentyeight-menu>
            <button type="button" data-file-action="Downloaded project-brief.pdf">
              <span>⬇</span>
              <strong>Download</strong>
            </button>

            <button type="button" data-file-action="Renamed project-brief.pdf">
              <span>✎</span>
              <strong>Rename</strong>
            </button>

            <button type="button" data-file-action="Duplicated project-brief.pdf">
              <span>⧉</span>
              <strong>Duplicate</strong>
            </button>

            <button type="button" data-file-action="Created share link for project-brief.pdf">
              <span>↗</span>
              <strong>Share link</strong>
            </button>

            <button type="button" class="is-danger" data-file-action="Moved project-brief.pdf to trash">
              <span>×</span>
              <strong>Delete file</strong>
            </button>
          </div>
        </div>
      </div>

      <div class="vb-dropdown-twentyeight-file-body">
        <small>Design document</small>
        <h4>project-brief.pdf</h4>
        <p>Updated 12 minutes ago · 2.4 MB</p>
      </div>

      <div class="vb-dropdown-twentyeight-meta">
        <div>
          <small>Status</small>
          <strong>Ready</strong>
        </div>
        <div>
          <small>Shared</small>
          <strong>Team</strong>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-dropdown-twentyeight-demo,
.vb-dropdown-twentyeight-demo * {
  box-sizing: border-box;
}

.vb-dropdown-twentyeight-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(239, 68, 68, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(99, 102, 241, 0.18), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(254, 205, 211, 0.46);
  box-shadow: 0 24px 70px rgba(136, 19, 55, 0.11);
}

.vb-dropdown-twentyeight-manager {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(330px, 0.7fr);
  gap: 34px;
  align-items: center;
  max-width: 1040px;
  min-height: 620px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(254, 205, 211, 0.40);
  box-shadow: 0 24px 70px rgba(136, 19, 55, 0.10);
  overflow: visible;
}

.vb-dropdown-twentyeight-copy > span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-twentyeight-copy h3 {
  max-width: 700px;
  margin: 0 0 16px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-twentyeight-copy p {
  max-width: 560px;
  margin: 0 0 26px !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-twentyeight-log {
  width: min(100%, 390px);
  padding: 18px;
  border-radius: 22px;
  background: #111827;
  box-shadow: 0 22px 54px rgba(15, 23, 42, 0.18);
}

.vb-dropdown-twentyeight-log small {
  display: block;
  margin-bottom: 7px;
  color: #fecdd3 !important;
  -webkit-text-fill-color: #fecdd3 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentyeight-log strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 19px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-twentyeight-file {
  position: relative;
  z-index: 30;
  padding: 22px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 18% 16%, rgba(255,255,255,0.14), transparent 34%),
    linear-gradient(135deg, #be123c, #4f46e5) !important;
  box-shadow: 0 30px 80px rgba(79, 70, 229, 0.25);
  overflow: visible;
}

.vb-dropdown-twentyeight-file-top {
  position: relative;
  z-index: 50;
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: flex-start;
  margin-bottom: 64px;
}

.vb-dropdown-twentyeight-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 82px;
  height: 104px;
  border-radius: 24px;
  background: #ffffff;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 20px;
  font-weight: 950;
  box-shadow: 0 22px 50px rgba(2, 6, 23, 0.22);
}

.vb-dropdown-twentyeight-action-wrap {
  position: relative;
  z-index: 70;
}

.vb-dropdown-twentyeight-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 17px;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 30px;
  line-height: 1;
  font-weight: 950;
  cursor: pointer;
}

.vb-dropdown-twentyeight-menu {
  position: absolute;
  z-index: 90;
  top: calc(100% + 12px);
  right: 0;
  display: grid;
  gap: 7px;
  width: 230px;
  padding: 10px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.32);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-twentyeight-manager.is-open .vb-dropdown-twentyeight-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-twentyeight-menu button {
  display: grid;
  grid-template-columns: 36px minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  width: 100%;
  min-height: 42px;
  padding: 8px;
  border: 0;
  border-radius: 14px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-twentyeight-menu button:hover {
  background: #f8fafc;
  transform: translateX(2px);
}

.vb-dropdown-twentyeight-menu button span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 13px;
  background: #eef2ff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-twentyeight-menu button strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 900;
}

.vb-dropdown-twentyeight-menu button.is-danger:hover {
  background: #fff1f2;
}

.vb-dropdown-twentyeight-menu button.is-danger span {
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
}

.vb-dropdown-twentyeight-menu button.is-danger strong {
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
}

.vb-dropdown-twentyeight-file-body {
  margin-bottom: 18px;
}

.vb-dropdown-twentyeight-file-body small {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fecdd3 !important;
  -webkit-text-fill-color: #fecdd3 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentyeight-file-body h4 {
  margin: 0 0 10px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-dropdown-twentyeight-file-body p {
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 700;
}

.vb-dropdown-twentyeight-meta {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.vb-dropdown-twentyeight-meta div {
  padding: 14px;
  border-radius: 18px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-dropdown-twentyeight-meta small {
  display: block;
  margin-bottom: 5px;
  color: #fecdd3 !important;
  -webkit-text-fill-color: #fecdd3 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentyeight-meta strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-dropdown-twentyeight-manager {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-twentyeight-file {
    max-width: 440px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-twentyeight-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twentyeight-manager {
    min-height: 760px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-twentyeight-copy h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-twentyeight-file {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twentyeight-file-body h4 {
    font-size: 28px !important;
  }
}
</style>

<script>
(function () {
  const manager = document.querySelector("[data-vb-dropdown-twentyeight]");
  if (!manager) return;

  const trigger = manager.querySelector("[data-vb-dropdown-twentyeight-trigger]");
  const actions = manager.querySelectorAll("[data-file-action]");
  const log = manager.querySelector("[data-vb-dropdown-twentyeight-log]");

  function closeDropdown() {
    manager.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = manager.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  actions.forEach(function (action) {
    action.addEventListener("click", function () {
      log.textContent = action.getAttribute("data-file-action");
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!manager.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const manager = document.querySelector("[data-vb-dropdown-twentyeight]");
  if (!manager) return;

  const trigger = manager.querySelector("[data-vb-dropdown-twentyeight-trigger]");
  const actions = manager.querySelectorAll("[data-file-action]");
  const log = manager.querySelector("[data-vb-dropdown-twentyeight-log]");

  function closeDropdown() {
    manager.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = manager.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  actions.forEach(function (action) {
    action.addEventListener("click", function () {
      log.textContent = action.getAttribute("data-file-action");
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!manager.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-twentyeight-demo"&gt;
  &lt;div class="vb-dropdown-twentyeight-manager" data-vb-dropdown-twentyeight&gt;
    &lt;div class="vb-dropdown-twentyeight-copy"&gt;
      &lt;span&gt;Example 28&lt;/span&gt;
      &lt;h3&gt;File Action Dropdown Menu&lt;/h3&gt;
      &lt;p&gt;Open the action menu on the file card and choose a file operation from the dropdown.&lt;/p&gt;

      &lt;div class="vb-dropdown-twentyeight-log"&gt;
        &lt;small&gt;Latest action&lt;/small&gt;
        &lt;strong data-vb-dropdown-twentyeight-log&gt;No action selected yet&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;div class="vb-dropdown-twentyeight-file"&gt;
      &lt;div class="vb-dropdown-twentyeight-file-top"&gt;
        &lt;div class="vb-dropdown-twentyeight-icon"&gt;PDF&lt;/div&gt;

        &lt;div class="vb-dropdown-twentyeight-action-wrap"&gt;
          &lt;button type="button" class="vb-dropdown-twentyeight-trigger" data-vb-dropdown-twentyeight-trigger aria-expanded="false" aria-label="Open file actions"&gt;
            ⋯
          &lt;/button&gt;

          &lt;div class="vb-dropdown-twentyeight-menu" data-vb-dropdown-twentyeight-menu&gt;
            &lt;button type="button" data-file-action="Downloaded project-brief.pdf"&gt;
              &lt;span&gt;⬇&lt;/span&gt;
              &lt;strong&gt;Download&lt;/strong&gt;
            &lt;/button&gt;

            &lt;button type="button" data-file-action="Renamed project-brief.pdf"&gt;
              &lt;span&gt;✎&lt;/span&gt;
              &lt;strong&gt;Rename&lt;/strong&gt;
            &lt;/button&gt;

            &lt;button type="button" data-file-action="Duplicated project-brief.pdf"&gt;
              &lt;span&gt;⧉&lt;/span&gt;
              &lt;strong&gt;Duplicate&lt;/strong&gt;
            &lt;/button&gt;

            &lt;button type="button" data-file-action="Created share link for project-brief.pdf"&gt;
              &lt;span&gt;↗&lt;/span&gt;
              &lt;strong&gt;Share link&lt;/strong&gt;
            &lt;/button&gt;

            &lt;button type="button" class="is-danger" data-file-action="Moved project-brief.pdf to trash"&gt;
              &lt;span&gt;×&lt;/span&gt;
              &lt;strong&gt;Delete file&lt;/strong&gt;
            &lt;/button&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-twentyeight-file-body"&gt;
        &lt;small&gt;Design document&lt;/small&gt;
        &lt;h4&gt;project-brief.pdf&lt;/h4&gt;
        &lt;p&gt;Updated 12 minutes ago · 2.4 MB&lt;/p&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-twentyeight-meta"&gt;
        &lt;div&gt;
          &lt;small&gt;Status&lt;/small&gt;
          &lt;strong&gt;Ready&lt;/strong&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;small&gt;Shared&lt;/small&gt;
          &lt;strong&gt;Team&lt;/strong&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-twentyeight-demo,
.vb-dropdown-twentyeight-demo * {
  box-sizing: border-box;
}

.vb-dropdown-twentyeight-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(239, 68, 68, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(99, 102, 241, 0.18), transparent 34%),
    linear-gradient(135deg, #fff1f2 0%, #eef2ff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(254, 205, 211, 0.46);
  box-shadow: 0 24px 70px rgba(136, 19, 55, 0.11);
}

.vb-dropdown-twentyeight-manager {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(330px, 0.7fr);
  gap: 34px;
  align-items: center;
  max-width: 1040px;
  min-height: 620px;
  margin: 0 auto;
  padding: 38px;
  border-radius: 30px;
  background: #ffffff;
  border: 1px solid rgba(254, 205, 211, 0.40);
  box-shadow: 0 24px 70px rgba(136, 19, 55, 0.10);
  overflow: visible;
}

.vb-dropdown-twentyeight-copy &gt; span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-twentyeight-copy h3 {
  max-width: 700px;
  margin: 0 0 16px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-twentyeight-copy p {
  max-width: 560px;
  margin: 0 0 26px !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-twentyeight-log {
  width: min(100%, 390px);
  padding: 18px;
  border-radius: 22px;
  background: #111827;
  box-shadow: 0 22px 54px rgba(15, 23, 42, 0.18);
}

.vb-dropdown-twentyeight-log small {
  display: block;
  margin-bottom: 7px;
  color: #fecdd3 !important;
  -webkit-text-fill-color: #fecdd3 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentyeight-log strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 19px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-twentyeight-file {
  position: relative;
  z-index: 30;
  padding: 22px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 18% 16%, rgba(255,255,255,0.14), transparent 34%),
    linear-gradient(135deg, #be123c, #4f46e5) !important;
  box-shadow: 0 30px 80px rgba(79, 70, 229, 0.25);
  overflow: visible;
}

.vb-dropdown-twentyeight-file-top {
  position: relative;
  z-index: 50;
  display: flex;
  justify-content: space-between;
  gap: 16px;
  align-items: flex-start;
  margin-bottom: 64px;
}

.vb-dropdown-twentyeight-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 82px;
  height: 104px;
  border-radius: 24px;
  background: #ffffff;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
  font-size: 20px;
  font-weight: 950;
  box-shadow: 0 22px 50px rgba(2, 6, 23, 0.22);
}

.vb-dropdown-twentyeight-action-wrap {
  position: relative;
  z-index: 70;
}

.vb-dropdown-twentyeight-trigger {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 17px;
  background: rgba(255,255,255,0.14);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 30px;
  line-height: 1;
  font-weight: 950;
  cursor: pointer;
}

.vb-dropdown-twentyeight-menu {
  position: absolute;
  z-index: 90;
  top: calc(100% + 12px);
  right: 0;
  display: grid;
  gap: 7px;
  width: 230px;
  padding: 10px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.32);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-twentyeight-manager.is-open .vb-dropdown-twentyeight-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-twentyeight-menu button {
  display: grid;
  grid-template-columns: 36px minmax(0, 1fr);
  gap: 10px;
  align-items: center;
  width: 100%;
  min-height: 42px;
  padding: 8px;
  border: 0;
  border-radius: 14px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-twentyeight-menu button:hover {
  background: #f8fafc;
  transform: translateX(2px);
}

.vb-dropdown-twentyeight-menu button span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: 13px;
  background: #eef2ff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 15px;
  font-weight: 950;
}

.vb-dropdown-twentyeight-menu button strong {
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 900;
}

.vb-dropdown-twentyeight-menu button.is-danger:hover {
  background: #fff1f2;
}

.vb-dropdown-twentyeight-menu button.is-danger span {
  background: #ffe4e6;
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
}

.vb-dropdown-twentyeight-menu button.is-danger strong {
  color: #be123c !important;
  -webkit-text-fill-color: #be123c !important;
}

.vb-dropdown-twentyeight-file-body {
  margin-bottom: 18px;
}

.vb-dropdown-twentyeight-file-body small {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(255,255,255,0.14);
  color: #fecdd3 !important;
  -webkit-text-fill-color: #fecdd3 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentyeight-file-body h4 {
  margin: 0 0 10px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 34px !important;
  line-height: 1 !important;
  font-weight: 950 !important;
  letter-spacing: -0.06em;
}

.vb-dropdown-twentyeight-file-body p {
  margin: 0 !important;
  color: #e0e7ff !important;
  -webkit-text-fill-color: #e0e7ff !important;
  font-size: 14px;
  line-height: 1.5;
  font-weight: 700;
}

.vb-dropdown-twentyeight-meta {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.vb-dropdown-twentyeight-meta div {
  padding: 14px;
  border-radius: 18px;
  background: rgba(255,255,255,0.12);
  border: 1px solid rgba(255,255,255,0.13);
}

.vb-dropdown-twentyeight-meta small {
  display: block;
  margin-bottom: 5px;
  color: #fecdd3 !important;
  -webkit-text-fill-color: #fecdd3 !important;
  font-size: 11px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentyeight-meta strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 15px;
  font-weight: 950;
}

@media (max-width: 860px) {
  .vb-dropdown-twentyeight-manager {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-twentyeight-file {
    max-width: 440px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-twentyeight-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twentyeight-manager {
    min-height: 760px;
    padding: 22px;
    border-radius: 22px;
  }

  .vb-dropdown-twentyeight-copy h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-twentyeight-file {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twentyeight-file-body h4 {
    font-size: 28px !important;
  }
}</pre>



<p class="wp-block-paragraph">This file action dropdown is a practical pattern for interfaces where each item has several secondary actions. You can adapt it for media libraries, document managers, cloud storage dashboards, file upload tools, project boards, admin tables, and WordPress-style content lists.</p>



<h2 class="wp-block-heading">29. Keyboard Shortcuts Dropdown</h2>



<p class="wp-block-paragraph"><strong>A keyboard shortcuts dropdown</strong> is useful for SaaS dashboards, admin panels, developer tools, productivity apps, content editors, design tools, and advanced web applications. It gives users a quick overview of available shortcuts without opening a separate help page.</p>



<p class="wp-block-paragraph">This example includes a shortcut help button, dropdown panel, grouped shortcut rows, selected shortcut feedback, outside click closing, and Escape key support. JavaScript opens and closes the shortcut dropdown and updates the activity message when a shortcut row is clicked.</p>



<ul class="wp-block-list">
<li>Keyboard shortcuts dropdown</li>
<li>Grouped shortcut list</li>
<li>Clickable shortcut rows</li>
<li>Selected action feedback</li>
<li>Useful for SaaS apps, dashboards, editors, productivity tools, and admin panels</li>
</ul>



<div class="vb-dropdown-twentynine-demo">
  <div class="vb-dropdown-twentynine-app" data-vb-dropdown-twentynine>
    <div class="vb-dropdown-twentynine-main">
      <div class="vb-dropdown-twentynine-top">
        <div>
          <span>Example 29</span>
          <h3>Keyboard Shortcuts Dropdown</h3>
          <p>Open the shortcuts menu to show helpful keyboard commands inside a compact dropdown panel.</p>
        </div>

        <div class="vb-dropdown-twentynine-wrap">
          <button type="button" class="vb-dropdown-twentynine-trigger" data-vb-dropdown-twentynine-trigger aria-expanded="false">
            <span>⌘</span>
            Shortcuts
            <em>?</em>
          </button>

          <div class="vb-dropdown-twentynine-menu" data-vb-dropdown-twentynine-menu>
            <div class="vb-dropdown-twentynine-head">
              <strong>Keyboard shortcuts</strong>
              <small>Click a command to preview the action.</small>
            </div>

            <div class="vb-dropdown-twentynine-group">
              <h4>Navigation</h4>

              <button type="button" data-shortcut-action="Opened dashboard overview">
                <span>Open dashboard</span>
                <kbd>G</kbd><kbd>D</kbd>
              </button>

              <button type="button" data-shortcut-action="Opened project search">
                <span>Search projects</span>
                <kbd>⌘</kbd><kbd>K</kbd>
              </button>

              <button type="button" data-shortcut-action="Opened notifications">
                <span>View notifications</span>
                <kbd>N</kbd>
              </button>
            </div>

            <div class="vb-dropdown-twentynine-group">
              <h4>Actions</h4>

              <button type="button" data-shortcut-action="Created a new document">
                <span>New document</span>
                <kbd>⌘</kbd><kbd>N</kbd>
              </button>

              <button type="button" data-shortcut-action="Saved current changes">
                <span>Save changes</span>
                <kbd>⌘</kbd><kbd>S</kbd>
              </button>

              <button type="button" data-shortcut-action="Opened settings panel">
                <span>Open settings</span>
                <kbd>⌘</kbd><kbd>,</kbd>
              </button>
            </div>
          </div>
        </div>
      </div>

      <div class="vb-dropdown-twentynine-terminal">
        <div class="vb-dropdown-twentynine-terminal-top">
          <i></i>
          <i></i>
          <i></i>
        </div>

        <div class="vb-dropdown-twentynine-terminal-body">
          <small>Latest shortcut action</small>
          <strong data-vb-dropdown-twentynine-status>No shortcut selected yet</strong>
          <p>Shortcut dropdowns are helpful when an application has many fast actions, panels, and navigation commands.</p>
        </div>
      </div>
    </div>
  </div>
</div>

<style>
.vb-dropdown-twentynine-demo,
.vb-dropdown-twentynine-demo * {
  box-sizing: border-box;
}

.vb-dropdown-twentynine-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 16% 18%, rgba(34, 211, 238, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(99, 102, 241, 0.20), transparent 34%),
    linear-gradient(135deg, #020617 0%, #111827 52%, #1e1b4b 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.18);
  box-shadow: 0 24px 70px rgba(2, 6, 23, 0.30);
}

.vb-dropdown-twentynine-app {
  max-width: 1080px;
  min-height: 640px;
  margin: 0 auto;
  padding: 18px;
  border-radius: 30px;
  background: rgba(255,255,255,0.07);
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
  overflow: visible;
}

.vb-dropdown-twentynine-main {
  position: relative;
  min-height: 604px;
  padding: 34px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 80% 16%, rgba(34, 211, 238, 0.14), transparent 34%),
    linear-gradient(135deg, rgba(15, 23, 42, 0.94), rgba(30, 41, 59, 0.72)) !important;
  border: 1px solid rgba(255,255,255,0.10);
  overflow: visible;
}

.vb-dropdown-twentynine-top {
  position: relative;
  z-index: 60;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(230px, 270px);
  gap: 28px;
  align-items: start;
}

.vb-dropdown-twentynine-top > div:first-child > span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(34, 211, 238, 0.16);
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-twentynine-top h3 {
  max-width: 760px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-twentynine-top p {
  max-width: 620px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-twentynine-wrap {
  position: relative;
  z-index: 70;
}

.vb-dropdown-twentynine-trigger {
  display: grid;
  grid-template-columns: 38px minmax(0, 1fr) 34px;
  gap: 10px;
  align-items: center;
  width: 100%;
  min-height: 58px;
  padding: 10px 12px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 20px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
  text-align: left;
}

.vb-dropdown-twentynine-trigger span,
.vb-dropdown-twentynine-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 34px;
  border-radius: 13px;
  background: rgba(255,255,255,0.13);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  font-weight: 950;
}

.vb-dropdown-twentynine-trigger span {
  width: 38px;
}

.vb-dropdown-twentynine-trigger em {
  width: 34px;
}

.vb-dropdown-twentynine-menu {
  position: absolute;
  z-index: 90;
  top: calc(100% + 12px);
  right: 0;
  width: 360px;
  padding: 14px;
  border-radius: 26px;
  background: #0f172a;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 40px 100px rgba(2, 6, 23, 0.56);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.22s ease, visibility 0.22s ease, transform 0.22s ease;
}

.vb-dropdown-twentynine-app.is-open .vb-dropdown-twentynine-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-twentynine-head {
  padding: 8px 8px 14px;
  border-bottom: 1px solid rgba(255,255,255,0.10);
  margin-bottom: 12px;
}

.vb-dropdown-twentynine-head strong {
  display: block;
  margin-bottom: 5px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-dropdown-twentynine-head small {
  display: block;
  color: #94a3b8 !important;
  -webkit-text-fill-color: #94a3b8 !important;
  font-size: 13px;
  font-weight: 700;
}

.vb-dropdown-twentynine-group {
  display: grid;
  gap: 7px;
  margin-bottom: 12px;
}

.vb-dropdown-twentynine-group:last-child {
  margin-bottom: 0;
}

.vb-dropdown-twentynine-group h4 {
  margin: 0 0 4px !important;
  padding: 0 8px;
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px !important;
  font-weight: 950 !important;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentynine-group button {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: 7px;
  align-items: center;
  width: 100%;
  min-height: 46px;
  padding: 8px 9px 8px 11px;
  border: 0;
  border-radius: 15px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-twentynine-group button:hover {
  background: rgba(255,255,255,0.08);
  transform: translateX(2px);
}

.vb-dropdown-twentynine-group button span {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-dropdown-twentynine-group kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 30px;
  height: 30px;
  padding: 0 8px;
  border-radius: 10px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.12);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-family: inherit;
  font-size: 12px;
  font-weight: 950;
}

.vb-dropdown-twentynine-terminal {
  position: absolute;
  left: 34px;
  right: 34px;
  bottom: 34px;
  border-radius: 26px;
  overflow: hidden;
  background: #020617;
  border: 1px solid rgba(255,255,255,0.10);
  box-shadow: 0 30px 80px rgba(2, 6, 23, 0.40);
}

.vb-dropdown-twentynine-terminal-top {
  display: flex;
  gap: 8px;
  padding: 14px;
  background: rgba(255,255,255,0.06);
  border-bottom: 1px solid rgba(255,255,255,0.10);
}

.vb-dropdown-twentynine-terminal-top i {
  width: 11px;
  height: 11px;
  border-radius: 999px;
  background: #22d3ee;
}

.vb-dropdown-twentynine-terminal-top i:nth-child(2) {
  background: #818cf8;
}

.vb-dropdown-twentynine-terminal-top i:nth-child(3) {
  background: #a78bfa;
}

.vb-dropdown-twentynine-terminal-body {
  padding: 24px;
}

.vb-dropdown-twentynine-terminal-body small {
  display: inline-flex;
  margin-bottom: 10px;
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentynine-terminal-body strong {
  display: block;
  margin-bottom: 10px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 26px;
  line-height: 1.1;
  font-weight: 950;
}

.vb-dropdown-twentynine-terminal-body p {
  max-width: 620px;
  margin: 0 !important;
  color: #94a3b8 !important;
  -webkit-text-fill-color: #94a3b8 !important;
  font-size: 14px;
  line-height: 1.65;
  font-weight: 650;
}

@media (max-width: 860px) {
  .vb-dropdown-twentynine-top {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-twentynine-wrap {
    max-width: 320px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-twentynine-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twentynine-app {
    min-height: 780px;
    border-radius: 22px;
  }

  .vb-dropdown-twentynine-main {
    min-height: 744px;
    padding: 22px;
    border-radius: 20px;
  }

  .vb-dropdown-twentynine-top h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-twentynine-wrap,
  .vb-dropdown-twentynine-trigger {
    width: 100%;
    max-width: none;
  }

  .vb-dropdown-twentynine-menu {
    left: 0;
    right: auto;
    width: 100%;
    transform-origin: top left;
  }

  .vb-dropdown-twentynine-terminal {
    left: 22px;
    right: 22px;
    bottom: 22px;
  }
}
</style>

<script>
(function () {
  const app = document.querySelector("[data-vb-dropdown-twentynine]");
  if (!app) return;

  const trigger = app.querySelector("[data-vb-dropdown-twentynine-trigger]");
  const shortcutButtons = app.querySelectorAll("[data-shortcut-action]");
  const status = app.querySelector("[data-vb-dropdown-twentynine-status]");

  function closeDropdown() {
    app.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = app.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  shortcutButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      status.textContent = button.getAttribute("data-shortcut-action");
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!app.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const app = document.querySelector("[data-vb-dropdown-twentynine]");
  if (!app) return;

  const trigger = app.querySelector("[data-vb-dropdown-twentynine-trigger]");
  const shortcutButtons = app.querySelectorAll("[data-shortcut-action]");
  const status = app.querySelector("[data-vb-dropdown-twentynine-status]");

  function closeDropdown() {
    app.classList.remove("is-open");
    trigger.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = app.classList.toggle("is-open");
    trigger.setAttribute("aria-expanded", String(isOpen));
  }

  trigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  shortcutButtons.forEach(function (button) {
    button.addEventListener("click", function () {
      status.textContent = button.getAttribute("data-shortcut-action");
      closeDropdown();
    });
  });

  document.addEventListener("click", function (event) {
    if (!app.contains(event.target)) {
      closeDropdown();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-twentynine-demo"&gt;
  &lt;div class="vb-dropdown-twentynine-app" data-vb-dropdown-twentynine&gt;
    &lt;div class="vb-dropdown-twentynine-main"&gt;
      &lt;div class="vb-dropdown-twentynine-top"&gt;
        &lt;div&gt;
          &lt;span&gt;Example 29&lt;/span&gt;
          &lt;h3&gt;Keyboard Shortcuts Dropdown&lt;/h3&gt;
          &lt;p&gt;Open the shortcuts menu to show helpful keyboard commands inside a compact dropdown panel.&lt;/p&gt;
        &lt;/div&gt;

        &lt;div class="vb-dropdown-twentynine-wrap"&gt;
          &lt;button type="button" class="vb-dropdown-twentynine-trigger" data-vb-dropdown-twentynine-trigger aria-expanded="false"&gt;
            &lt;span&gt;⌘&lt;/span&gt;
            Shortcuts
            &lt;em&gt;?&lt;/em&gt;
          &lt;/button&gt;

          &lt;div class="vb-dropdown-twentynine-menu" data-vb-dropdown-twentynine-menu&gt;
            &lt;div class="vb-dropdown-twentynine-head"&gt;
              &lt;strong&gt;Keyboard shortcuts&lt;/strong&gt;
              &lt;small&gt;Click a command to preview the action.&lt;/small&gt;
            &lt;/div&gt;

            &lt;div class="vb-dropdown-twentynine-group"&gt;
              &lt;h4&gt;Navigation&lt;/h4&gt;

              &lt;button type="button" data-shortcut-action="Opened dashboard overview"&gt;
                &lt;span&gt;Open dashboard&lt;/span&gt;
                &lt;kbd&gt;G&lt;/kbd&gt;&lt;kbd&gt;D&lt;/kbd&gt;
              &lt;/button&gt;

              &lt;button type="button" data-shortcut-action="Opened project search"&gt;
                &lt;span&gt;Search projects&lt;/span&gt;
                &lt;kbd&gt;⌘&lt;/kbd&gt;&lt;kbd&gt;K&lt;/kbd&gt;
              &lt;/button&gt;

              &lt;button type="button" data-shortcut-action="Opened notifications"&gt;
                &lt;span&gt;View notifications&lt;/span&gt;
                &lt;kbd&gt;N&lt;/kbd&gt;
              &lt;/button&gt;
            &lt;/div&gt;

            &lt;div class="vb-dropdown-twentynine-group"&gt;
              &lt;h4&gt;Actions&lt;/h4&gt;

              &lt;button type="button" data-shortcut-action="Created a new document"&gt;
                &lt;span&gt;New document&lt;/span&gt;
                &lt;kbd&gt;⌘&lt;/kbd&gt;&lt;kbd&gt;N&lt;/kbd&gt;
              &lt;/button&gt;

              &lt;button type="button" data-shortcut-action="Saved current changes"&gt;
                &lt;span&gt;Save changes&lt;/span&gt;
                &lt;kbd&gt;⌘&lt;/kbd&gt;&lt;kbd&gt;S&lt;/kbd&gt;
              &lt;/button&gt;

              &lt;button type="button" data-shortcut-action="Opened settings panel"&gt;
                &lt;span&gt;Open settings&lt;/span&gt;
                &lt;kbd&gt;⌘&lt;/kbd&gt;&lt;kbd&gt;,&lt;/kbd&gt;
              &lt;/button&gt;
            &lt;/div&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;

      &lt;div class="vb-dropdown-twentynine-terminal"&gt;
        &lt;div class="vb-dropdown-twentynine-terminal-top"&gt;
          &lt;i&gt;&lt;/i&gt;
          &lt;i&gt;&lt;/i&gt;
          &lt;i&gt;&lt;/i&gt;
        &lt;/div&gt;

        &lt;div class="vb-dropdown-twentynine-terminal-body"&gt;
          &lt;small&gt;Latest shortcut action&lt;/small&gt;
          &lt;strong data-vb-dropdown-twentynine-status&gt;No shortcut selected yet&lt;/strong&gt;
          &lt;p&gt;Shortcut dropdowns are helpful when an application has many fast actions, panels, and navigation commands.&lt;/p&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-twentynine-demo,
.vb-dropdown-twentynine-demo * {
  box-sizing: border-box;
}

.vb-dropdown-twentynine-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 16% 18%, rgba(34, 211, 238, 0.18), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(99, 102, 241, 0.20), transparent 34%),
    linear-gradient(135deg, #020617 0%, #111827 52%, #1e1b4b 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.18);
  box-shadow: 0 24px 70px rgba(2, 6, 23, 0.30);
}

.vb-dropdown-twentynine-app {
  max-width: 1080px;
  min-height: 640px;
  margin: 0 auto;
  padding: 18px;
  border-radius: 30px;
  background: rgba(255,255,255,0.07);
  border: 1px solid rgba(255,255,255,0.12);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.08);
  overflow: visible;
}

.vb-dropdown-twentynine-main {
  position: relative;
  min-height: 604px;
  padding: 34px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 80% 16%, rgba(34, 211, 238, 0.14), transparent 34%),
    linear-gradient(135deg, rgba(15, 23, 42, 0.94), rgba(30, 41, 59, 0.72)) !important;
  border: 1px solid rgba(255,255,255,0.10);
  overflow: visible;
}

.vb-dropdown-twentynine-top {
  position: relative;
  z-index: 60;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(230px, 270px);
  gap: 28px;
  align-items: start;
}

.vb-dropdown-twentynine-top &gt; div:first-child &gt; span {
  display: inline-flex;
  margin-bottom: 16px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(34, 211, 238, 0.16);
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-twentynine-top h3 {
  max-width: 760px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(36px, 5vw, 70px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-twentynine-top p {
  max-width: 620px;
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-twentynine-wrap {
  position: relative;
  z-index: 70;
}

.vb-dropdown-twentynine-trigger {
  display: grid;
  grid-template-columns: 38px minmax(0, 1fr) 34px;
  gap: 10px;
  align-items: center;
  width: 100%;
  min-height: 58px;
  padding: 10px 12px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 20px;
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 950;
  cursor: pointer;
  text-align: left;
}

.vb-dropdown-twentynine-trigger span,
.vb-dropdown-twentynine-trigger em {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 34px;
  border-radius: 13px;
  background: rgba(255,255,255,0.13);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-style: normal;
  font-weight: 950;
}

.vb-dropdown-twentynine-trigger span {
  width: 38px;
}

.vb-dropdown-twentynine-trigger em {
  width: 34px;
}

.vb-dropdown-twentynine-menu {
  position: absolute;
  z-index: 90;
  top: calc(100% + 12px);
  right: 0;
  width: 360px;
  padding: 14px;
  border-radius: 26px;
  background: #0f172a;
  border: 1px solid rgba(255,255,255,0.14);
  box-shadow: 0 40px 100px rgba(2, 6, 23, 0.56);
  opacity: 0;
  visibility: hidden;
  transform: translateY(12px) scale(0.98);
  transform-origin: top right;
  transition: opacity 0.22s ease, visibility 0.22s ease, transform 0.22s ease;
}

.vb-dropdown-twentynine-app.is-open .vb-dropdown-twentynine-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0) scale(1);
}

.vb-dropdown-twentynine-head {
  padding: 8px 8px 14px;
  border-bottom: 1px solid rgba(255,255,255,0.10);
  margin-bottom: 12px;
}

.vb-dropdown-twentynine-head strong {
  display: block;
  margin-bottom: 5px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 18px;
  font-weight: 950;
}

.vb-dropdown-twentynine-head small {
  display: block;
  color: #94a3b8 !important;
  -webkit-text-fill-color: #94a3b8 !important;
  font-size: 13px;
  font-weight: 700;
}

.vb-dropdown-twentynine-group {
  display: grid;
  gap: 7px;
  margin-bottom: 12px;
}

.vb-dropdown-twentynine-group:last-child {
  margin-bottom: 0;
}

.vb-dropdown-twentynine-group h4 {
  margin: 0 0 4px !important;
  padding: 0 8px;
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px !important;
  font-weight: 950 !important;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentynine-group button {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  gap: 7px;
  align-items: center;
  width: 100%;
  min-height: 46px;
  padding: 8px 9px 8px 11px;
  border: 0;
  border-radius: 15px;
  background: transparent;
  cursor: pointer;
  text-align: left;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-twentynine-group button:hover {
  background: rgba(255,255,255,0.08);
  transform: translateX(2px);
}

.vb-dropdown-twentynine-group button span {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 850;
}

.vb-dropdown-twentynine-group kbd {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 30px;
  height: 30px;
  padding: 0 8px;
  border-radius: 10px;
  background: rgba(255,255,255,0.10);
  border: 1px solid rgba(255,255,255,0.12);
  color: #e0f2fe !important;
  -webkit-text-fill-color: #e0f2fe !important;
  font-family: inherit;
  font-size: 12px;
  font-weight: 950;
}

.vb-dropdown-twentynine-terminal {
  position: absolute;
  left: 34px;
  right: 34px;
  bottom: 34px;
  border-radius: 26px;
  overflow: hidden;
  background: #020617;
  border: 1px solid rgba(255,255,255,0.10);
  box-shadow: 0 30px 80px rgba(2, 6, 23, 0.40);
}

.vb-dropdown-twentynine-terminal-top {
  display: flex;
  gap: 8px;
  padding: 14px;
  background: rgba(255,255,255,0.06);
  border-bottom: 1px solid rgba(255,255,255,0.10);
}

.vb-dropdown-twentynine-terminal-top i {
  width: 11px;
  height: 11px;
  border-radius: 999px;
  background: #22d3ee;
}

.vb-dropdown-twentynine-terminal-top i:nth-child(2) {
  background: #818cf8;
}

.vb-dropdown-twentynine-terminal-top i:nth-child(3) {
  background: #a78bfa;
}

.vb-dropdown-twentynine-terminal-body {
  padding: 24px;
}

.vb-dropdown-twentynine-terminal-body small {
  display: inline-flex;
  margin-bottom: 10px;
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-twentynine-terminal-body strong {
  display: block;
  margin-bottom: 10px;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 26px;
  line-height: 1.1;
  font-weight: 950;
}

.vb-dropdown-twentynine-terminal-body p {
  max-width: 620px;
  margin: 0 !important;
  color: #94a3b8 !important;
  -webkit-text-fill-color: #94a3b8 !important;
  font-size: 14px;
  line-height: 1.65;
  font-weight: 650;
}

@media (max-width: 860px) {
  .vb-dropdown-twentynine-top {
    grid-template-columns: 1fr;
  }

  .vb-dropdown-twentynine-wrap {
    max-width: 320px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-twentynine-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-twentynine-app {
    min-height: 780px;
    border-radius: 22px;
  }

  .vb-dropdown-twentynine-main {
    min-height: 744px;
    padding: 22px;
    border-radius: 20px;
  }

  .vb-dropdown-twentynine-top h3 {
    font-size: 38px !important;
  }

  .vb-dropdown-twentynine-wrap,
  .vb-dropdown-twentynine-trigger {
    width: 100%;
    max-width: none;
  }

  .vb-dropdown-twentynine-menu {
    left: 0;
    right: auto;
    width: 100%;
    transform-origin: top left;
  }

  .vb-dropdown-twentynine-terminal {
    left: 22px;
    right: 22px;
    bottom: 22px;
  }
}</pre>



<p class="wp-block-paragraph">This keyboard shortcuts dropdown is a useful help pattern for advanced interfaces. You can adapt it for SaaS dashboards, editors, project tools, admin panels, developer apps, CRM systems, and productivity platforms where users need quick access to commands.</p>



<h2 class="wp-block-heading">30. Complete Responsive Dropdown Navigation</h2>



<p class="wp-block-paragraph"><strong>A complete responsive dropdown navigation</strong> combines desktop dropdown behavior with a mobile menu pattern. This is one of the most practical JavaScript dropdown examples because real websites often need desktop navigation, dropdown submenus, mobile hamburger controls, and clear call-to-action links in one component.</p>



<p class="wp-block-paragraph">This final example includes a desktop dropdown, mobile hamburger menu, service links, active states, responsive layout, outside click closing, Escape key support, and a selected navigation feedback message. It is a complete pattern for business websites, agencies, SaaS landing pages, ecommerce stores, and WordPress themes.</p>



<ul class="wp-block-list">
<li>Complete responsive dropdown navigation</li>
<li>Desktop dropdown and mobile hamburger menu</li>
<li>Service submenu with CTA link</li>
<li>Selected navigation feedback</li>
<li>Useful for business websites, SaaS sites, agencies, ecommerce stores, and WordPress themes</li>
</ul>



<div class="vb-dropdown-thirty-demo">
  <div class="vb-dropdown-thirty-site" data-vb-dropdown-thirty>
    <header class="vb-dropdown-thirty-header">
      <a href="#javascript-dropdown-menu-examples" class="vb-dropdown-thirty-logo">
        <span>D</span>
        <strong>DropStudio</strong>
      </a>

      <button type="button" class="vb-dropdown-thirty-mobile" data-vb-dropdown-thirty-mobile aria-expanded="false" aria-label="Open mobile navigation">
        <i></i>
        <i></i>
        <i></i>
      </button>

      <nav class="vb-dropdown-thirty-nav" data-vb-dropdown-thirty-nav aria-label="Complete responsive dropdown navigation">
        <a href="#what-is-a-javascript-dropdown-menu" data-nav-action="Opened Home section">Home</a>

        <div class="vb-dropdown-thirty-item">
          <button type="button" data-vb-dropdown-thirty-trigger aria-expanded="false">
            Services
            <span>⌄</span>
          </button>

          <div class="vb-dropdown-thirty-menu" data-vb-dropdown-thirty-menu>
            <a href="#javascript-dropdown-menu-examples" data-nav-action="Opened UI Components service">
              <span>⚙</span>
              <strong>UI Components</strong>
              <small>Dropdowns, modals, sliders, and app widgets</small>
            </a>

            <a href="#javascript-dropdown-best-practices" data-nav-action="Opened Website Systems service">
              <span>🌐</span>
              <strong>Website Systems</strong>
              <small>Responsive layouts and conversion-focused pages</small>
            </a>

            <a href="#responsive-dropdown-design-tips" data-nav-action="Opened Mobile UX service">
              <span>📱</span>
              <strong>Mobile UX</strong>
              <small>Touch-friendly navigation and interface patterns</small>
            </a>

            <a href="#javascript-dropdown-faq" class="vb-dropdown-thirty-feature" data-nav-action="Opened JavaScript Dropdown FAQ">
              <strong>Need a complete dropdown guide?</strong>
              <small>Jump to the FAQ section</small>
            </a>
          </div>
        </div>

        <a href="#common-javascript-dropdown-mistakes" data-nav-action="Opened Mistakes section">Mistakes</a>
        <a href="#javascript-dropdown-faq" data-nav-action="Opened FAQ section">FAQ</a>
      </nav>

      <a class="vb-dropdown-thirty-cta" href="#javascript-dropdown-menu-examples" data-nav-action="Opened Examples section">View Examples</a>
    </header>

    <section class="vb-dropdown-thirty-hero">
      <span>Example 30</span>
      <h3>Complete Responsive Dropdown Navigation</h3>
      <p>This final example combines a desktop dropdown, mobile hamburger navigation, service submenu, CTA link, and JavaScript-powered state management.</p>

      <div class="vb-dropdown-thirty-status">
        <small>Navigation action</small>
        <strong data-vb-dropdown-thirty-status>No navigation item selected yet</strong>
      </div>
    </section>
  </div>
</div>

<style>
.vb-dropdown-thirty-demo,
.vb-dropdown-thirty-demo * {
  box-sizing: border-box;
}

.vb-dropdown-thirty-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(79, 70, 229, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(14, 165, 233, 0.18), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #ecfeff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(199, 210, 254, 0.46);
  box-shadow: 0 24px 70px rgba(67, 56, 202, 0.12);
}

.vb-dropdown-thirty-site {
  position: relative;
  max-width: 1120px;
  min-height: 660px;
  margin: 0 auto;
  padding: 24px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 80% 75%, rgba(14, 165, 233, 0.12), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
  overflow: visible;
}

.vb-dropdown-thirty-header {
  position: relative;
  z-index: 80;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 18px;
  align-items: center;
  padding: 14px;
  border-radius: 24px;
  background: #111827;
  box-shadow: 0 22px 60px rgba(15, 23, 42, 0.24);
}

.vb-dropdown-thirty-logo {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none !important;
}

.vb-dropdown-thirty-logo span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: linear-gradient(135deg, #4f46e5, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-thirty-logo strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-thirty-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.vb-dropdown-thirty-nav > a,
.vb-dropdown-thirty-item > button {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 42px;
  padding: 10px 13px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 14px;
  line-height: 1;
  font-weight: 850;
  text-decoration: none !important;
  cursor: pointer;
  transition: background 0.18s ease, color 0.18s ease;
}

.vb-dropdown-thirty-nav > a:hover,
.vb-dropdown-thirty-item > button:hover,
.vb-dropdown-thirty-item.is-open > button {
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-thirty-item {
  position: relative;
}

.vb-dropdown-thirty-item > button span {
  transition: transform 0.2s ease;
}

.vb-dropdown-thirty-item.is-open > button span {
  transform: rotate(180deg);
}

.vb-dropdown-thirty-menu {
  position: absolute;
  z-index: 100;
  top: calc(100% + 14px);
  left: 50%;
  display: grid;
  gap: 8px;
  width: 380px;
  padding: 12px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.32);
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, 12px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-thirty-item.is-open .vb-dropdown-thirty-menu {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0) scale(1);
}

.vb-dropdown-thirty-menu a {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  padding: 11px;
  border-radius: 17px;
  text-decoration: none !important;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-thirty-menu a:hover {
  background: #f8fafc;
  transform: translateX(2px);
}

.vb-dropdown-thirty-menu a > span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 16px;
  background: #eef2ff;
  font-size: 18px;
}

.vb-dropdown-thirty-menu a strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-thirty-menu a small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 700;
}

.vb-dropdown-thirty-menu .vb-dropdown-thirty-feature {
  display: block;
  padding: 16px;
  background: linear-gradient(135deg, #4f46e5, #06b6d4) !important;
}

.vb-dropdown-thirty-menu .vb-dropdown-thirty-feature strong,
.vb-dropdown-thirty-menu .vb-dropdown-thirty-feature small {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-thirty-menu .vb-dropdown-thirty-feature small {
  opacity: 0.86;
}

.vb-dropdown-thirty-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 42px;
  padding: 10px 15px;
  border-radius: 999px;
  background: linear-gradient(135deg, #4f46e5, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
  white-space: nowrap;
  box-shadow: 0 16px 34px rgba(79, 70, 229, 0.24);
}

.vb-dropdown-thirty-mobile {
  display: none;
  width: 46px;
  height: 46px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 16px;
  background: rgba(255,255,255,0.10);
  cursor: pointer;
}

.vb-dropdown-thirty-mobile i {
  display: block;
  width: 20px;
  height: 2px;
  margin: 4px auto;
  border-radius: 999px;
  background: #ffffff;
  transition: transform 0.2s ease, opacity 0.2s ease;
}

.vb-dropdown-thirty-site.is-mobile-open .vb-dropdown-thirty-mobile i:nth-child(1) {
  transform: translateY(6px) rotate(45deg);
}

.vb-dropdown-thirty-site.is-mobile-open .vb-dropdown-thirty-mobile i:nth-child(2) {
  opacity: 0;
}

.vb-dropdown-thirty-site.is-mobile-open .vb-dropdown-thirty-mobile i:nth-child(3) {
  transform: translateY(-6px) rotate(-45deg);
}

.vb-dropdown-thirty-hero {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 520px;
  padding: 62px 18px 18px;
}

.vb-dropdown-thirty-hero > span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #eef2ff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-thirty-hero h3 {
  max-width: 860px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(38px, 6vw, 78px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-thirty-hero p {
  max-width: 680px;
  margin: 0 0 24px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-thirty-status {
  width: min(100%, 430px);
  padding: 18px;
  border-radius: 22px;
  background: #0f172a;
  box-shadow: 0 22px 54px rgba(15, 23, 42, 0.18);
}

.vb-dropdown-thirty-status small {
  display: block;
  margin-bottom: 7px;
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-thirty-status strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 19px;
  line-height: 1.2;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vb-dropdown-thirty-header {
    grid-template-columns: auto auto;
  }

  .vb-dropdown-thirty-mobile {
    display: inline-block;
    justify-self: end;
  }

  .vb-dropdown-thirty-nav {
    position: absolute;
    top: calc(100% + 12px);
    left: 14px;
    right: 14px;
    display: grid;
    justify-content: stretch;
    gap: 8px;
    padding: 12px;
    border-radius: 22px;
    background: #ffffff;
    border: 1px solid rgba(148, 163, 184, 0.24);
    box-shadow: 0 34px 90px rgba(2, 6, 23, 0.26);
    opacity: 0;
    visibility: hidden;
    transform: translateY(12px) scale(0.98);
    transform-origin: top;
    transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
  }

  .vb-dropdown-thirty-site.is-mobile-open .vb-dropdown-thirty-nav {
    opacity: 1;
    visibility: visible;
    transform: translateY(0) scale(1);
  }

  .vb-dropdown-thirty-nav > a,
  .vb-dropdown-thirty-item > button {
    justify-content: space-between;
    width: 100%;
    border-radius: 16px;
    color: #0f172a !important;
    -webkit-text-fill-color: #0f172a !important;
  }

  .vb-dropdown-thirty-nav > a:hover,
  .vb-dropdown-thirty-item > button:hover,
  .vb-dropdown-thirty-item.is-open > button {
    background: #f8fafc;
    color: #0f172a !important;
    -webkit-text-fill-color: #0f172a !important;
  }

  .vb-dropdown-thirty-item {
    width: 100%;
  }

  .vb-dropdown-thirty-menu {
    position: static;
    width: 100%;
    box-shadow: none;
    border-radius: 18px;
    margin-top: 8px;
    opacity: 1;
    visibility: visible;
    display: none;
    transform: none;
    border-color: rgba(148, 163, 184, 0.18);
  }

  .vb-dropdown-thirty-item.is-open .vb-dropdown-thirty-menu {
    display: grid;
    transform: none;
  }

  .vb-dropdown-thirty-cta {
    grid-column: 1 / -1;
    justify-self: stretch;
    margin-top: 8px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-thirty-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-thirty-site {
    min-height: 780px;
    padding: 18px;
    border-radius: 22px;
  }

  .vb-dropdown-thirty-header {
    border-radius: 20px;
  }

  .vb-dropdown-thirty-hero {
    min-height: 610px;
    padding-top: 72px;
  }

  .vb-dropdown-thirty-hero h3 {
    font-size: 38px !important;
  }
}
</style>

<script>
(function () {
  const site = document.querySelector("[data-vb-dropdown-thirty]");
  if (!site) return;

  const mobileButton = site.querySelector("[data-vb-dropdown-thirty-mobile]");
  const dropdownTrigger = site.querySelector("[data-vb-dropdown-thirty-trigger]");
  const dropdownItem = dropdownTrigger.closest(".vb-dropdown-thirty-item");
  const navActions = site.querySelectorAll("[data-nav-action]");
  const status = site.querySelector("[data-vb-dropdown-thirty-status]");

  function closeDropdown() {
    dropdownItem.classList.remove("is-open");
    dropdownTrigger.setAttribute("aria-expanded", "false");
  }

  function closeMobileNav() {
    site.classList.remove("is-mobile-open");
    mobileButton.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdownItem.classList.toggle("is-open");
    dropdownTrigger.setAttribute("aria-expanded", String(isOpen));
  }

  function toggleMobileNav() {
    const isOpen = site.classList.toggle("is-mobile-open");
    mobileButton.setAttribute("aria-expanded", String(isOpen));
  }

  mobileButton.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleMobileNav();
  });

  dropdownTrigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  navActions.forEach(function (link) {
    link.addEventListener("click", function () {
      status.textContent = link.getAttribute("data-nav-action");
      closeDropdown();
      closeMobileNav();
    });
  });

  document.addEventListener("click", function (event) {
    if (!site.contains(event.target)) {
      closeDropdown();
      closeMobileNav();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
      closeMobileNav();
    }
  });
})();
</script>



<h4 class="wp-block-heading">JavaScript</h4>



<pre class="wp-block-preformatted">(function () {
  const site = document.querySelector("[data-vb-dropdown-thirty]");
  if (!site) return;

  const mobileButton = site.querySelector("[data-vb-dropdown-thirty-mobile]");
  const dropdownTrigger = site.querySelector("[data-vb-dropdown-thirty-trigger]");
  const dropdownItem = dropdownTrigger.closest(".vb-dropdown-thirty-item");
  const navActions = site.querySelectorAll("[data-nav-action]");
  const status = site.querySelector("[data-vb-dropdown-thirty-status]");

  function closeDropdown() {
    dropdownItem.classList.remove("is-open");
    dropdownTrigger.setAttribute("aria-expanded", "false");
  }

  function closeMobileNav() {
    site.classList.remove("is-mobile-open");
    mobileButton.setAttribute("aria-expanded", "false");
  }

  function toggleDropdown() {
    const isOpen = dropdownItem.classList.toggle("is-open");
    dropdownTrigger.setAttribute("aria-expanded", String(isOpen));
  }

  function toggleMobileNav() {
    const isOpen = site.classList.toggle("is-mobile-open");
    mobileButton.setAttribute("aria-expanded", String(isOpen));
  }

  mobileButton.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleMobileNav();
  });

  dropdownTrigger.addEventListener("click", function (event) {
    event.stopPropagation();
    toggleDropdown();
  });

  navActions.forEach(function (link) {
    link.addEventListener("click", function () {
      status.textContent = link.getAttribute("data-nav-action");
      closeDropdown();
      closeMobileNav();
    });
  });

  document.addEventListener("click", function (event) {
    if (!site.contains(event.target)) {
      closeDropdown();
      closeMobileNav();
    }
  });

  document.addEventListener("keydown", function (event) {
    if (event.key === "Escape") {
      closeDropdown();
      closeMobileNav();
    }
  });
})();</pre>



<h4 class="wp-block-heading">HTML</h4>



<pre class="wp-block-preformatted">&lt;div class="vb-dropdown-thirty-demo"&gt;
  &lt;div class="vb-dropdown-thirty-site" data-vb-dropdown-thirty&gt;
    &lt;header class="vb-dropdown-thirty-header"&gt;
      &lt;a href="#javascript-dropdown-menu-examples" class="vb-dropdown-thirty-logo"&gt;
        &lt;span&gt;D&lt;/span&gt;
        &lt;strong&gt;DropStudio&lt;/strong&gt;
      &lt;/a&gt;

      &lt;button type="button" class="vb-dropdown-thirty-mobile" data-vb-dropdown-thirty-mobile aria-expanded="false" aria-label="Open mobile navigation"&gt;
        &lt;i&gt;&lt;/i&gt;
        &lt;i&gt;&lt;/i&gt;
        &lt;i&gt;&lt;/i&gt;
      &lt;/button&gt;

      &lt;nav class="vb-dropdown-thirty-nav" data-vb-dropdown-thirty-nav aria-label="Complete responsive dropdown navigation"&gt;
        &lt;a href="#what-is-a-javascript-dropdown-menu" data-nav-action="Opened Home section"&gt;Home&lt;/a&gt;

        &lt;div class="vb-dropdown-thirty-item"&gt;
          &lt;button type="button" data-vb-dropdown-thirty-trigger aria-expanded="false"&gt;
            Services
            &lt;span&gt;⌄&lt;/span&gt;
          &lt;/button&gt;

          &lt;div class="vb-dropdown-thirty-menu" data-vb-dropdown-thirty-menu&gt;
            &lt;a href="#javascript-dropdown-menu-examples" data-nav-action="Opened UI Components service"&gt;
              &lt;span&gt;⚙&lt;/span&gt;
              &lt;strong&gt;UI Components&lt;/strong&gt;
              &lt;small&gt;Dropdowns, modals, sliders, and app widgets&lt;/small&gt;
            &lt;/a&gt;

            &lt;a href="#javascript-dropdown-best-practices" data-nav-action="Opened Website Systems service"&gt;
              &lt;span&gt;🌐&lt;/span&gt;
              &lt;strong&gt;Website Systems&lt;/strong&gt;
              &lt;small&gt;Responsive layouts and conversion-focused pages&lt;/small&gt;
            &lt;/a&gt;

            &lt;a href="#responsive-dropdown-design-tips" data-nav-action="Opened Mobile UX service"&gt;
              &lt;span&gt;📱&lt;/span&gt;
              &lt;strong&gt;Mobile UX&lt;/strong&gt;
              &lt;small&gt;Touch-friendly navigation and interface patterns&lt;/small&gt;
            &lt;/a&gt;

            &lt;a href="#javascript-dropdown-faq" class="vb-dropdown-thirty-feature" data-nav-action="Opened JavaScript Dropdown FAQ"&gt;
              &lt;strong&gt;Need a complete dropdown guide?&lt;/strong&gt;
              &lt;small&gt;Jump to the FAQ section&lt;/small&gt;
            &lt;/a&gt;
          &lt;/div&gt;
        &lt;/div&gt;

        &lt;a href="#common-javascript-dropdown-mistakes" data-nav-action="Opened Mistakes section"&gt;Mistakes&lt;/a&gt;
        &lt;a href="#javascript-dropdown-faq" data-nav-action="Opened FAQ section"&gt;FAQ&lt;/a&gt;
      &lt;/nav&gt;

      &lt;a class="vb-dropdown-thirty-cta" href="#javascript-dropdown-menu-examples" data-nav-action="Opened Examples section"&gt;View Examples&lt;/a&gt;
    &lt;/header&gt;

    &lt;section class="vb-dropdown-thirty-hero"&gt;
      &lt;span&gt;Example 30&lt;/span&gt;
      &lt;h3&gt;Complete Responsive Dropdown Navigation&lt;/h3&gt;
      &lt;p&gt;This final example combines a desktop dropdown, mobile hamburger navigation, service submenu, CTA link, and JavaScript-powered state management.&lt;/p&gt;

      &lt;div class="vb-dropdown-thirty-status"&gt;
        &lt;small&gt;Navigation action&lt;/small&gt;
        &lt;strong data-vb-dropdown-thirty-status&gt;No navigation item selected yet&lt;/strong&gt;
      &lt;/div&gt;
    &lt;/section&gt;
  &lt;/div&gt;
&lt;/div&gt;</pre>



<h4 class="wp-block-heading">CSS</h4>



<pre class="wp-block-preformatted">.vb-dropdown-thirty-demo,
.vb-dropdown-thirty-demo * {
  box-sizing: border-box;
}

.vb-dropdown-thirty-demo {
  margin: 28px 0;
  padding: 34px;
  border-radius: 32px;
  background:
    radial-gradient(circle at 14% 18%, rgba(79, 70, 229, 0.20), transparent 34%),
    radial-gradient(circle at 86% 16%, rgba(14, 165, 233, 0.18), transparent 34%),
    linear-gradient(135deg, #eef2ff 0%, #ecfeff 52%, #ffffff 100%) !important;
  border: 1px solid rgba(199, 210, 254, 0.46);
  box-shadow: 0 24px 70px rgba(67, 56, 202, 0.12);
}

.vb-dropdown-thirty-site {
  position: relative;
  max-width: 1120px;
  min-height: 660px;
  margin: 0 auto;
  padding: 24px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 80% 75%, rgba(14, 165, 233, 0.12), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 24px 70px rgba(15, 23, 42, 0.10);
  overflow: visible;
}

.vb-dropdown-thirty-header {
  position: relative;
  z-index: 80;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  gap: 18px;
  align-items: center;
  padding: 14px;
  border-radius: 24px;
  background: #111827;
  box-shadow: 0 22px 60px rgba(15, 23, 42, 0.24);
}

.vb-dropdown-thirty-logo {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  text-decoration: none !important;
}

.vb-dropdown-thirty-logo span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: 15px;
  background: linear-gradient(135deg, #4f46e5, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-thirty-logo strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 16px;
  font-weight: 950;
}

.vb-dropdown-thirty-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
}

.vb-dropdown-thirty-nav &gt; a,
.vb-dropdown-thirty-item &gt; button {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  min-height: 42px;
  padding: 10px 13px;
  border: 0;
  border-radius: 999px;
  background: transparent;
  color: #e5e7eb !important;
  -webkit-text-fill-color: #e5e7eb !important;
  font-size: 14px;
  line-height: 1;
  font-weight: 850;
  text-decoration: none !important;
  cursor: pointer;
  transition: background 0.18s ease, color 0.18s ease;
}

.vb-dropdown-thirty-nav &gt; a:hover,
.vb-dropdown-thirty-item &gt; button:hover,
.vb-dropdown-thirty-item.is-open &gt; button {
  background: rgba(255,255,255,0.10);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-thirty-item {
  position: relative;
}

.vb-dropdown-thirty-item &gt; button span {
  transition: transform 0.2s ease;
}

.vb-dropdown-thirty-item.is-open &gt; button span {
  transform: rotate(180deg);
}

.vb-dropdown-thirty-menu {
  position: absolute;
  z-index: 100;
  top: calc(100% + 14px);
  left: 50%;
  display: grid;
  gap: 8px;
  width: 380px;
  padding: 12px;
  border-radius: 24px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.24);
  box-shadow: 0 34px 90px rgba(2, 6, 23, 0.32);
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, 12px) scale(0.98);
  transform-origin: top;
  transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
}

.vb-dropdown-thirty-item.is-open .vb-dropdown-thirty-menu {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0) scale(1);
}

.vb-dropdown-thirty-menu a {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr);
  gap: 11px;
  align-items: center;
  padding: 11px;
  border-radius: 17px;
  text-decoration: none !important;
  transition: background 0.18s ease, transform 0.18s ease;
}

.vb-dropdown-thirty-menu a:hover {
  background: #f8fafc;
  transform: translateX(2px);
}

.vb-dropdown-thirty-menu a &gt; span {
  grid-row: span 2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 16px;
  background: #eef2ff;
  font-size: 18px;
}

.vb-dropdown-thirty-menu a strong {
  display: block;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: 14px;
  line-height: 1.2;
  font-weight: 950;
}

.vb-dropdown-thirty-menu a small {
  display: block;
  margin-top: 4px;
  color: #64748b !important;
  -webkit-text-fill-color: #64748b !important;
  font-size: 12px;
  line-height: 1.35;
  font-weight: 700;
}

.vb-dropdown-thirty-menu .vb-dropdown-thirty-feature {
  display: block;
  padding: 16px;
  background: linear-gradient(135deg, #4f46e5, #06b6d4) !important;
}

.vb-dropdown-thirty-menu .vb-dropdown-thirty-feature strong,
.vb-dropdown-thirty-menu .vb-dropdown-thirty-feature small {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
}

.vb-dropdown-thirty-menu .vb-dropdown-thirty-feature small {
  opacity: 0.86;
}

.vb-dropdown-thirty-cta {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 42px;
  padding: 10px 15px;
  border-radius: 999px;
  background: linear-gradient(135deg, #4f46e5, #06b6d4);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
  text-decoration: none !important;
  white-space: nowrap;
  box-shadow: 0 16px 34px rgba(79, 70, 229, 0.24);
}

.vb-dropdown-thirty-mobile {
  display: none;
  width: 46px;
  height: 46px;
  border: 1px solid rgba(255,255,255,0.16);
  border-radius: 16px;
  background: rgba(255,255,255,0.10);
  cursor: pointer;
}

.vb-dropdown-thirty-mobile i {
  display: block;
  width: 20px;
  height: 2px;
  margin: 4px auto;
  border-radius: 999px;
  background: #ffffff;
  transition: transform 0.2s ease, opacity 0.2s ease;
}

.vb-dropdown-thirty-site.is-mobile-open .vb-dropdown-thirty-mobile i:nth-child(1) {
  transform: translateY(6px) rotate(45deg);
}

.vb-dropdown-thirty-site.is-mobile-open .vb-dropdown-thirty-mobile i:nth-child(2) {
  opacity: 0;
}

.vb-dropdown-thirty-site.is-mobile-open .vb-dropdown-thirty-mobile i:nth-child(3) {
  transform: translateY(-6px) rotate(-45deg);
}

.vb-dropdown-thirty-hero {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 520px;
  padding: 62px 18px 18px;
}

.vb-dropdown-thirty-hero &gt; span {
  display: inline-flex;
  width: fit-content;
  margin-bottom: 14px;
  padding: 8px 12px;
  border-radius: 999px;
  background: #eef2ff;
  color: #4f46e5 !important;
  -webkit-text-fill-color: #4f46e5 !important;
  font-size: 13px;
  font-weight: 950;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb-dropdown-thirty-hero h3 {
  max-width: 860px;
  margin: 0 0 14px !important;
  color: #0f172a !important;
  -webkit-text-fill-color: #0f172a !important;
  font-size: clamp(38px, 6vw, 78px) !important;
  line-height: 0.96 !important;
  font-weight: 950 !important;
  letter-spacing: -0.08em;
}

.vb-dropdown-thirty-hero p {
  max-width: 680px;
  margin: 0 0 24px !important;
  color: #475569 !important;
  -webkit-text-fill-color: #475569 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb-dropdown-thirty-status {
  width: min(100%, 430px);
  padding: 18px;
  border-radius: 22px;
  background: #0f172a;
  box-shadow: 0 22px 54px rgba(15, 23, 42, 0.18);
}

.vb-dropdown-thirty-status small {
  display: block;
  margin-bottom: 7px;
  color: #a5f3fc !important;
  -webkit-text-fill-color: #a5f3fc !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb-dropdown-thirty-status strong {
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 19px;
  line-height: 1.2;
  font-weight: 950;
}

@media (max-width: 900px) {
  .vb-dropdown-thirty-header {
    grid-template-columns: auto auto;
  }

  .vb-dropdown-thirty-mobile {
    display: inline-block;
    justify-self: end;
  }

  .vb-dropdown-thirty-nav {
    position: absolute;
    top: calc(100% + 12px);
    left: 14px;
    right: 14px;
    display: grid;
    justify-content: stretch;
    gap: 8px;
    padding: 12px;
    border-radius: 22px;
    background: #ffffff;
    border: 1px solid rgba(148, 163, 184, 0.24);
    box-shadow: 0 34px 90px rgba(2, 6, 23, 0.26);
    opacity: 0;
    visibility: hidden;
    transform: translateY(12px) scale(0.98);
    transform-origin: top;
    transition: opacity 0.2s ease, visibility 0.2s ease, transform 0.2s ease;
  }

  .vb-dropdown-thirty-site.is-mobile-open .vb-dropdown-thirty-nav {
    opacity: 1;
    visibility: visible;
    transform: translateY(0) scale(1);
  }

  .vb-dropdown-thirty-nav &gt; a,
  .vb-dropdown-thirty-item &gt; button {
    justify-content: space-between;
    width: 100%;
    border-radius: 16px;
    color: #0f172a !important;
    -webkit-text-fill-color: #0f172a !important;
  }

  .vb-dropdown-thirty-nav &gt; a:hover,
  .vb-dropdown-thirty-item &gt; button:hover,
  .vb-dropdown-thirty-item.is-open &gt; button {
    background: #f8fafc;
    color: #0f172a !important;
    -webkit-text-fill-color: #0f172a !important;
  }

  .vb-dropdown-thirty-item {
    width: 100%;
  }

  .vb-dropdown-thirty-menu {
    position: static;
    width: 100%;
    box-shadow: none;
    border-radius: 18px;
    margin-top: 8px;
    opacity: 1;
    visibility: visible;
    display: none;
    transform: none;
    border-color: rgba(148, 163, 184, 0.18);
  }

  .vb-dropdown-thirty-item.is-open .vb-dropdown-thirty-menu {
    display: grid;
    transform: none;
  }

  .vb-dropdown-thirty-cta {
    grid-column: 1 / -1;
    justify-self: stretch;
    margin-top: 8px;
  }
}

@media (max-width: 640px) {
  .vb-dropdown-thirty-demo {
    padding: 18px;
    border-radius: 24px;
  }

  .vb-dropdown-thirty-site {
    min-height: 780px;
    padding: 18px;
    border-radius: 22px;
  }

  .vb-dropdown-thirty-header {
    border-radius: 20px;
  }

  .vb-dropdown-thirty-hero {
    min-height: 610px;
    padding-top: 72px;
  }

  .vb-dropdown-thirty-hero h3 {
    font-size: 38px !important;
  }
}</pre>



<p class="wp-block-paragraph">This complete responsive dropdown navigation is a strong final pattern because it combines multiple real website needs in one example. You can adapt it for business websites, SaaS landing pages, agency websites, ecommerce stores, documentation hubs, portfolio sites, and WordPress themes.</p>



<div class="vb24-js-dropdown-mid-ad" id="javascript-dropdown-bottom-ad">
  <div class="vb24-js-dropdown-mid-ad-content">
    <span>Recommended WordPress Hosting</span>
    <h2>Need faster hosting for JavaScript-heavy websites?</h2>
    <p>Interactive UI components like dropdown menus, mega menus, filters, modals, sliders, animations, and responsive navigation patterns work best on fast and reliable hosting. A performance-focused WordPress setup can improve page speed, user experience, Core Web Vitals, and SEO.</p>
    <a href="https://kinsta.com?kaid=XTNLJLKTCJHP" target="_blank" rel="sponsored nofollow noopener">Explore Kinsta Hosting</a>
  </div>

  <div class="vb24-js-dropdown-mid-ad-image">
    <a href="https://kinsta.com?kaid=XTNLJLKTCJHP" target="_blank" rel="sponsored nofollow noopener">
      <img decoding="async" src="https://veebilehed24.ee/wp-content/uploads/2026/03/300x250-wp-dark-2-months-free-hosting.webp" width="300" height="250" alt="Kinsta managed WordPress hosting for fast JavaScript dropdown websites" loading="lazy">
    </a>
  </div>
</div>

<style>
.vb24-js-dropdown-mid-ad,
.vb24-js-dropdown-mid-ad * {
  box-sizing: border-box;
}

.vb24-js-dropdown-mid-ad {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: 28px;
  align-items: center;
  margin: 46px 0;
  padding: 30px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 14% 18%, rgba(14, 165, 233, 0.22), transparent 30%),
    radial-gradient(circle at 86% 20%, rgba(124, 58, 237, 0.22), transparent 32%),
    linear-gradient(135deg, #0f172a 0%, #020617 100%) !important;
  border: 1px solid rgba(148, 163, 184, 0.20);
  box-shadow: 0 26px 80px rgba(15, 23, 42, 0.22);
  overflow: hidden;
}

.vb24-js-dropdown-mid-ad-content span {
  display: inline-flex;
  margin-bottom: 13px;
  padding: 8px 12px;
  border-radius: 999px;
  background: rgba(14, 165, 233, 0.16);
  border: 1px solid rgba(125, 211, 252, 0.24);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 900;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.vb24-js-dropdown-mid-ad-content h2 {
  max-width: 820px;
  margin: 0 0 14px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: clamp(30px, 4vw, 54px) !important;
  line-height: 1.05 !important;
  font-weight: 950 !important;
  letter-spacing: -0.065em;
}

.vb24-js-dropdown-mid-ad-content p {
  max-width: 760px;
  margin: 0 0 24px !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 16px;
  line-height: 1.75;
  font-weight: 650;
}

.vb24-js-dropdown-mid-ad-content a {
  display: inline-flex;
  min-height: 48px;
  align-items: center;
  justify-content: center;
  padding: 13px 18px;
  border-radius: 999px;
  background: linear-gradient(135deg, #06b6d4, #2563eb, #7c3aed);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 900;
  text-decoration: none !important;
  box-shadow: 0 16px 36px rgba(37, 99, 235, 0.28);
}

.vb24-js-dropdown-mid-ad-image {
  display: flex;
  justify-content: center;
}

.vb24-js-dropdown-mid-ad-image a {
  display: block;
  line-height: 0;
}

.vb24-js-dropdown-mid-ad-image img {
  display: block;
  width: 300px;
  max-width: 100%;
  height: auto;
  border-radius: 20px;
  box-shadow: 0 22px 60px rgba(0, 0, 0, 0.28);
}

@media (max-width: 900px) {
  .vb24-js-dropdown-mid-ad {
    grid-template-columns: 1fr;
  }

  .vb24-js-dropdown-mid-ad-image {
    justify-content: flex-start;
  }
}

@media (max-width: 640px) {
  .vb24-js-dropdown-mid-ad {
    padding: 22px;
    border-radius: 24px;
  }

  .vb24-js-dropdown-mid-ad-content a {
    width: 100%;
  }
}
</style>



<h2 class="wp-block-heading" id="javascript-dropdown-best-practices">JavaScript Dropdown Best Practices</h2>



<p class="wp-block-paragraph">JavaScript dropdown menus are simple in theory, but they need careful structure to feel professional. A good dropdown should open quickly, close predictably, work on mobile, support keyboard interaction, show active states, and keep the user focused on the next action. Whether you are building a navigation dropdown, custom select menu, profile menu, notification panel, ecommerce filter, or responsive mobile dropdown, usability should always come before decoration.</p>



<p class="wp-block-paragraph">The most important rule is to make dropdown behavior obvious. Users should understand what opens the menu, where the menu appears, which option is selected, and how to close it. This is especially important for mobile dropdown menus, custom select fields, multi-select filters, and mega menus because they often contain many interactive items in a small space.</p>



<div class="vb24-js-dropdown-practice-grid">
  <article>
    <span>01</span>
    <h3>Use real buttons for triggers</h3>
    <p>A dropdown trigger should usually be a button, not a plain div. Buttons are easier to access, focus, label, and control with JavaScript.</p>
  </article>

  <article>
    <span>02</span>
    <h3>Show clear open states</h3>
    <p>Change the trigger background, rotate the arrow, or highlight the active option so users know the dropdown is open.</p>
  </article>

  <article>
    <span>03</span>
    <h3>Close on outside click</h3>
    <p>Dropdowns should close when visitors click outside the component. This prevents panels from staying open unnecessarily.</p>
  </article>

  <article>
    <span>04</span>
    <h3>Support Escape key closing</h3>
    <p>Keyboard users expect Escape to close overlays, menus, dialogs, dropdowns, and temporary interface panels.</p>
  </article>

  <article>
    <span>05</span>
    <h3>Keep tap targets large</h3>
    <p>Mobile dropdown items should be comfortable to tap. Avoid tiny links, cramped spacing, and menus that sit too close to the screen edge.</p>
  </article>

  <article>
    <span>06</span>
    <h3>Use reusable JavaScript</h3>
    <p>When possible, write dropdown code that can work with multiple components instead of hardcoding one specific menu.</p>
  </article>
</div>

<style>
.vb24-js-dropdown-practice-grid,
.vb24-js-dropdown-practice-grid * {
  box-sizing: border-box;
}

.vb24-js-dropdown-practice-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  margin: 26px 0 34px;
}

.vb24-js-dropdown-practice-grid article {
  padding: 22px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 18% 14%, rgba(14, 165, 233, 0.12), transparent 32%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.08);
}

.vb24-js-dropdown-practice-grid span {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  margin-bottom: 14px;
  border-radius: 14px;
  background: linear-gradient(135deg, #06b6d4, #2563eb);
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 13px;
  font-weight: 950;
}

.vb24-js-dropdown-practice-grid h3 {
  margin: 0 0 10px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 20px !important;
  line-height: 1.2 !important;
  font-weight: 900 !important;
  letter-spacing: -0.03em;
}

.vb24-js-dropdown-practice-grid p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 900px) {
  .vb24-js-dropdown-practice-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 640px) {
  .vb24-js-dropdown-practice-grid {
    grid-template-columns: 1fr;
  }

  .vb24-js-dropdown-practice-grid article {
    padding: 20px;
    border-radius: 20px;
  }
}
</style>



<p class="wp-block-paragraph">For SEO and user experience, dropdowns should support the page goal instead of hiding important content. A dropdown navigation can organize service links, but the most important landing pages should still be easy to find. A product filter dropdown can improve browsing, but users should still understand what filters are active. A custom select dropdown can improve design, but it should not be harder to use than a normal select field.</p>



<ul class="wp-block-list">
  <li><strong>Use descriptive labels</strong> so visitors know what the dropdown controls before opening it.</li>
  <li><strong>Keep dropdown content focused</strong> instead of placing unrelated links, actions, and form controls together.</li>
  <li><strong>Use one active state</strong> so the selected option or open menu is easy to identify.</li>
  <li><strong>Do not rely only on hover</strong> because touch devices do not work like desktop mouse interfaces.</li>
  <li><strong>Keep JavaScript lightweight</strong> when the component only needs simple open, close, and selected-state logic.</li>
  <li><strong>Test multiple dropdowns on one page</strong> to make sure one open menu does not break another menu.</li>
  <li><strong>Use unique class names</strong> when adding examples to WordPress posts or Gutenberg blocks.</li>
  <li><strong>Check keyboard behavior</strong> for Escape, Tab, focus states, and screen reader labels.</li>
</ul>



<h2 class="wp-block-heading" id="responsive-dropdown-design-tips">Responsive Dropdown Design Tips</h2>



<p class="wp-block-paragraph">Responsive dropdown design is important because the same menu may need to work as a compact desktop dropdown, a full-width mobile panel, a hamburger menu, a filter drawer, or a tap-friendly custom select field. A dropdown that looks good on a large desktop screen can easily become difficult to use on a phone if the panel is too wide, too close to the edge, or filled with tiny links.</p>



<p class="wp-block-paragraph">On mobile screens, dropdown menus should prioritize spacing, touch targets, readable labels, and clear close behavior. If the menu contains many links, a full-width dropdown panel or mobile drawer often works better than a small floating menu. If the dropdown is part of a navigation header, the desktop dropdown may need to become a stacked mobile menu with collapsible sections.</p>



<div class="vb24-js-dropdown-responsive-box">
  <div>
    <span>Desktop</span>
    <h3>Use floating dropdown panels</h3>
    <p>Desktop menus can use compact floating panels, mega dropdowns, account menus, category menus, and hover-assisted visual states as long as click and keyboard support still work.</p>
  </div>

  <div>
    <span>Tablet</span>
    <h3>Avoid edge overflow</h3>
    <p>Tablet layouts need enough space around dropdown panels. Use max-width values, left/right alignment checks, and flexible wrapping for larger dropdown content.</p>
  </div>

  <div>
    <span>Mobile</span>
    <h3>Use full-width controls</h3>
    <p>Mobile dropdowns should often become full-width panels with larger links, better spacing, and clear touch-friendly buttons.</p>
  </div>
</div>

<style>
.vb24-js-dropdown-responsive-box,
.vb24-js-dropdown-responsive-box * {
  box-sizing: border-box;
}

.vb24-js-dropdown-responsive-box {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 16px;
  margin: 26px 0 34px;
  padding: 24px;
  border-radius: 30px;
  background:
    radial-gradient(circle at 15% 18%, rgba(14, 165, 233, 0.16), transparent 34%),
    radial-gradient(circle at 85% 20%, rgba(124, 58, 237, 0.16), transparent 34%),
    linear-gradient(135deg, #0f172a, #111827) !important;
  border: 1px solid rgba(148, 163, 184, 0.18);
  box-shadow: 0 22px 64px rgba(15, 23, 42, 0.18);
}

.vb24-js-dropdown-responsive-box div {
  padding: 22px;
  border-radius: 22px;
  background: rgba(255,255,255,0.08);
  border: 1px solid rgba(255,255,255,0.12);
}

.vb24-js-dropdown-responsive-box span {
  display: inline-flex;
  margin-bottom: 13px;
  padding: 7px 10px;
  border-radius: 999px;
  background: rgba(14, 165, 233, 0.18);
  color: #bae6fd !important;
  -webkit-text-fill-color: #bae6fd !important;
  font-size: 12px;
  font-weight: 900;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.vb24-js-dropdown-responsive-box h3 {
  margin: 0 0 10px !important;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 22px !important;
  line-height: 1.15 !important;
  font-weight: 900 !important;
  letter-spacing: -0.04em;
}

.vb24-js-dropdown-responsive-box p {
  margin: 0 !important;
  color: #cbd5e1 !important;
  -webkit-text-fill-color: #cbd5e1 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 900px) {
  .vb24-js-dropdown-responsive-box {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .vb24-js-dropdown-responsive-box {
    padding: 18px;
    border-radius: 24px;
  }

  .vb24-js-dropdown-responsive-box div {
    padding: 18px;
    border-radius: 18px;
  }
}
</style>



<ul class="wp-block-list">
  <li><strong>Use full-width dropdowns on mobile</strong> when the content has several links or long labels.</li>
  <li><strong>Keep dropdown panels inside the viewport</strong> by testing left, right, top, and bottom alignment.</li>
  <li><strong>Increase item height on touch screens</strong> so every option is easy to tap.</li>
  <li><strong>Stack menu content on smaller screens</strong> instead of forcing multi-column dropdowns into narrow layouts.</li>
  <li><strong>Use media queries for navigation dropdowns</strong> so desktop menus can become mobile hamburger menus.</li>
  <li><strong>Test dropdowns inside WordPress content</strong> because themes can add extra spacing, z-index layers, or inherited styles.</li>
</ul>



<h2 class="wp-block-heading" id="common-javascript-dropdown-mistakes">Common JavaScript Dropdown Mistakes</h2>



<p class="wp-block-paragraph">Many dropdown problems come from small details: the menu does not close, the z-index is too low, the mobile panel overflows, the selected state is unclear, or the JavaScript only works for one dropdown instance. These issues can make a polished design feel broken, especially on ecommerce pages, navigation headers, dashboards, and mobile interfaces.</p>



<p class="wp-block-paragraph">The easiest way to avoid dropdown mistakes is to test the component as a real user would use it. Open it, close it, click outside it, press Escape, select several options, resize the browser, test it on mobile, and place more than one dropdown on the same page. A dropdown should remain predictable in all of those situations.</p>



<div class="vb24-js-dropdown-mistakes">
  <article>
    <h3>Only building for desktop hover</h3>
    <p>Hover-only dropdowns can fail on touch devices. Use click or tap behavior for important menus.</p>
  </article>

  <article>
    <h3>Forgetting outside click closing</h3>
    <p>If users cannot close the dropdown naturally, the menu can block content and make the interface feel unfinished.</p>
  </article>

  <article>
    <h3>Using weak z-index values</h3>
    <p>Dropdowns often sit inside headers, cards, sliders, forms, and Gutenberg blocks. Make sure the panel appears above nearby content.</p>
  </article>

  <article>
    <h3>Making mobile menus too small</h3>
    <p>A tiny floating dropdown can look good on desktop but feel cramped on phones. Mobile menus need more space.</p>
  </article>

  <article>
    <h3>Hiding important links</h3>
    <p>Do not hide critical conversion links inside dropdowns that users may not notice or open.</p>
  </article>

  <article>
    <h3>Hardcoding one dropdown only</h3>
    <p>If the same page needs several dropdowns, reusable JavaScript and scoped selectors prevent conflicts.</p>
  </article>
</div>

<style>
.vb24-js-dropdown-mistakes,
.vb24-js-dropdown-mistakes * {
  box-sizing: border-box;
}

.vb24-js-dropdown-mistakes {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  margin: 26px 0 34px;
}

.vb24-js-dropdown-mistakes article {
  position: relative;
  padding: 22px 22px 22px 58px;
  border-radius: 22px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 40px rgba(15, 23, 42, 0.08);
}

.vb24-js-dropdown-mistakes article::before {
  content: "!";
  position: absolute;
  top: 22px;
  left: 20px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border-radius: 999px;
  background: #fee2e2;
  color: #b91c1c !important;
  -webkit-text-fill-color: #b91c1c !important;
  font-size: 14px;
  font-weight: 950;
}

.vb24-js-dropdown-mistakes h3 {
  margin: 0 0 8px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 19px !important;
  line-height: 1.25 !important;
  font-weight: 900 !important;
}

.vb24-js-dropdown-mistakes p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 760px) {
  .vb24-js-dropdown-mistakes {
    grid-template-columns: 1fr;
  }
}
</style>



<h2 class="wp-block-heading" id="javascript-dropdown-faq">JavaScript Dropdown FAQ</h2>



<p class="wp-block-paragraph">Here are common questions about JavaScript dropdown menus, custom select menus, mega dropdowns, mobile dropdown navigation, and reusable dropdown UI patterns.</p>



<div class="vb24-js-dropdown-faq">
  <details>
    <summary>What is a JavaScript dropdown menu?</summary>
    <div>
      <p>A JavaScript dropdown menu is an interactive UI component that opens hidden links, actions, filters, settings, or selectable options when a user clicks, taps, focuses, or triggers a control. It is commonly used in navigation menus, custom selects, profile menus, ecommerce filters, account actions, and dashboard controls.</p>
    </div>
  </details>

  <details>
    <summary>Should a dropdown open on click or hover?</summary>
    <div>
      <p>For most modern websites, click or tap behavior is safer than hover-only behavior because it works better on mobile and touch screens. Hover can still be used as a visual enhancement on desktop, but important dropdown functionality should not rely only on hover.</p>
    </div>
  </details>

  <details>
    <summary>How do I close a JavaScript dropdown when clicking outside?</summary>
    <div>
      <p>You can add a document-level click listener and check whether the click target is outside the dropdown container. If the click happens outside, remove the open class and update the trigger attribute, such as aria-expanded=&#8221;false&#8221;.</p>
    </div>
  </details>

  <details>
    <summary>What is the difference between a dropdown menu and a select menu?</summary>
    <div>
      <p>A dropdown menu usually reveals links or actions, while a select menu is used to choose one or more values from a list. A custom select dropdown often uses JavaScript to update the selected value, active state, and visible label.</p>
    </div>
  </details>

  <details>
    <summary>Are custom JavaScript dropdowns bad for accessibility?</summary>
    <div>
      <p>They are not automatically bad, but they need careful markup. Use button triggers, clear labels, visible focus states, keyboard support, Escape key closing, readable menu items, and ARIA attributes where needed. If a native select field is enough, it may be the better choice for simple forms.</p>
    </div>
  </details>

  <details>
    <summary>Can I use these JavaScript dropdown examples in WordPress?</summary>
    <div>
      <p>Yes. These examples are written with visible HTML, CSS, and vanilla JavaScript, so they can be adapted for Gutenberg blocks, custom WordPress themes, landing pages, plugin admin screens, WooCommerce filters, and frontend UI sections. Use unique class names to avoid conflicts with your theme styles.</p>
    </div>
  </details>

  <details>
    <summary>How can I make a dropdown menu responsive?</summary>
    <div>
      <p>Use media queries to change the dropdown layout on smaller screens. A desktop dropdown can become a full-width mobile panel, a stacked menu, a hamburger navigation, or a drawer-style control. Make links larger, keep spacing comfortable, and prevent the menu from overflowing the viewport.</p>
    </div>
  </details>

  <details>
    <summary>Do dropdown menus affect SEO?</summary>
    <div>
      <p>Dropdowns do not automatically hurt SEO, but important internal links should remain crawlable and accessible in the HTML. Avoid hiding essential page links only behind complex JavaScript. A clear navigation structure and useful internal linking can support both users and search engines.</p>
    </div>
  </details>
</div>

<style>
.vb24-js-dropdown-faq,
.vb24-js-dropdown-faq * {
  box-sizing: border-box;
}

.vb24-js-dropdown-faq {
  display: grid;
  gap: 12px;
  margin: 26px 0 42px;
}

.vb24-js-dropdown-faq details {
  overflow: hidden;
  border-radius: 20px;
  background: #ffffff;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 14px 34px rgba(15, 23, 42, 0.07);
}

.vb24-js-dropdown-faq summary {
  position: relative;
  display: block;
  padding: 19px 58px 19px 20px;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 17px;
  line-height: 1.35;
  font-weight: 900;
  cursor: pointer;
  list-style: none;
}

.vb24-js-dropdown-faq summary::-webkit-details-marker {
  display: none;
}

.vb24-js-dropdown-faq summary::after {
  content: "+";
  position: absolute;
  top: 50%;
  right: 18px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 30px;
  height: 30px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 20px;
  line-height: 1;
  font-weight: 900;
  transform: translateY(-50%);
}

.vb24-js-dropdown-faq details[open] summary::after {
  content: "−";
}

.vb24-js-dropdown-faq details > div {
  padding: 0 20px 20px;
}

.vb24-js-dropdown-faq p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.7;
}
</style>



<h2 class="wp-block-heading" id="javascript-dropdown-conclusion">Conclusion</h2>



<p class="wp-block-paragraph">JavaScript dropdown menus are one of the most flexible UI patterns for modern websites. They can power navigation menus, custom select fields, profile menus, notification panels, searchable filters, ecommerce controls, mega menus, settings panels, language selectors, currency switchers, and complete responsive header layouts.</p>



<p class="wp-block-paragraph">The key is to use dropdowns where they improve clarity. A strong JavaScript dropdown should be easy to open, easy to close, readable, responsive, keyboard-friendly, visually polished, and simple to customize. It should help users find the right option faster instead of hiding important content or making the interface harder to understand.</p>



<p class="wp-block-paragraph">If you are building a WordPress website, SaaS dashboard, ecommerce store, service website, portfolio, landing page, admin panel, or custom frontend component, you can start with one of these 30 JavaScript dropdown examples and adapt the markup, CSS, and JavaScript for your own project.</p>



<div class="vb24-js-dropdown-back-links">
  <a href="#javascript-dropdown-menu-examples">Back to JavaScript Dropdown Examples</a>
  <a href="#what-is-a-javascript-dropdown-menu">Back to Dropdown Basics</a>
  <a href="#javascript-dropdown-faq">Back to FAQ</a>
</div>

<style>
.vb24-js-dropdown-back-links {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin: 26px 0 42px;
}

.vb24-js-dropdown-back-links a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 46px;
  padding: 12px 17px;
  border-radius: 999px;
  background: #0f172a;
  color: #ffffff !important;
  -webkit-text-fill-color: #ffffff !important;
  font-size: 14px;
  font-weight: 850;
  text-decoration: none !important;
}

.vb24-js-dropdown-back-links a::after {
  content: "↑";
  margin-left: 8px;
}

@media (max-width: 640px) {
  .vb24-js-dropdown-back-links a {
    width: 100%;
  }
}
</style>



<h2 class="wp-block-heading" id="related-javascript-and-css-guides">Related JavaScript and CSS Guides</h2>



<p class="wp-block-paragraph">Continue with these related JavaScript and CSS guides. These internal links help connect dropdown menus with other modern UI patterns, including sliders, modals, form validation, navigation menus, cards, accordions, tabs, pricing sections, banners, footers, testimonials, hero sections, and responsive layouts.</p>



<div class="vb24-js-dropdown-related">
  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-slider-examples/">
    <span>JavaScript</span>
    <h3>30 JavaScript Slider Examples</h3>
    <p>Image sliders, content carousels, product sliders, hero sliders, and responsive UI slider examples.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-form-validation-examples/">
    <span>JavaScript</span>
    <h3>30 JavaScript Form Validation Examples</h3>
    <p>Input validation, signup forms, checkout forms, error states, password checks, and form UI examples.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/javascript/javascript-modal-examples/">
    <span>JavaScript</span>
    <h3>30 JavaScript Modal Examples</h3>
    <p>Responsive modal windows, dialogs, popups, overlays, confirmation boxes, and interaction patterns.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-navigation-menus/">
    <span>CSS</span>
    <h3>25 Modern CSS Navigation Menus</h3>
    <p>Responsive navbars, dropdown menus, mega menus, hamburger menus, and complete website headers.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-forms/">
    <span>CSS</span>
    <h3>30 Modern CSS Forms</h3>
    <p>Contact forms, login forms, checkout forms, booking forms, lead forms, and modern input layouts.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-tabs/">
    <span>CSS</span>
    <h3>30 Modern CSS Tabs</h3>
    <p>Responsive tab UI, product tabs, dashboard tabs, content tabs, and accessible tab examples.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-accordions/">
    <span>CSS</span>
    <h3>30 Modern CSS Accordions</h3>
    <p>FAQ accordions, product toggles, content expanders, mobile sections, and collapsible UI patterns.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-banners/">
    <span>CSS</span>
    <h3>30 Modern CSS Banners</h3>
    <p>Promo banners, alert bars, CTA banners, announcement bars, sale banners, and notification sections.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-footers/">
    <span>CSS</span>
    <h3>30 Modern CSS Footers</h3>
    <p>Responsive footer layouts, newsletter footers, SaaS footers, ecommerce footers, and link sections.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-testimonials/">
    <span>CSS</span>
    <h3>30 Modern CSS Testimonials</h3>
    <p>Review cards, quote sections, social proof blocks, customer stories, and trust-building UI examples.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-pricing-tables/">
    <span>CSS</span>
    <h3>30 Modern CSS Pricing Tables</h3>
    <p>Responsive pricing sections, SaaS pricing cards, comparison tables, featured plans, and plan selectors.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-website-hero-sections/">
    <span>CSS</span>
    <h3>30 Modern Website Hero Sections</h3>
    <p>Responsive hero layouts, landing page headers, SaaS heroes, ecommerce heroes, and CTA sections.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/25-modern-css-cards-for-websites-html-css-examples/">
    <span>CSS</span>
    <h3>25 Modern CSS Cards</h3>
    <p>Product cards, blog cards, feature cards, pricing cards, profile cards, and responsive card layouts.</p>
  </a>

  <a href="https://veebilehed24.ee/en/blog/css-effects/modern-css-layouts/">
    <span>CSS</span>
    <h3>25 Modern CSS Layouts</h3>
    <p>Grid layouts, flexbox layouts, dashboard layouts, bento grids, responsive sections, and container queries.</p>
  </a>
</div>

<style>
.vb24-js-dropdown-related,
.vb24-js-dropdown-related * {
  box-sizing: border-box;
}

.vb24-js-dropdown-related {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 16px;
  margin: 26px 0 46px;
}

.vb24-js-dropdown-related a {
  display: block;
  padding: 22px;
  border-radius: 24px;
  background:
    radial-gradient(circle at 16% 14%, rgba(14, 165, 233, 0.10), transparent 34%),
    linear-gradient(135deg, #ffffff, #f8fafc) !important;
  border: 1px solid rgba(148, 163, 184, 0.22);
  box-shadow: 0 16px 42px rgba(15, 23, 42, 0.08);
  text-decoration: none !important;
  transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}

.vb24-js-dropdown-related a:hover {
  transform: translateY(-3px);
  border-color: rgba(14, 165, 233, 0.52);
  box-shadow: 0 22px 54px rgba(15, 23, 42, 0.12);
}

.vb24-js-dropdown-related span {
  display: inline-flex;
  margin-bottom: 12px;
  padding: 7px 10px;
  border-radius: 999px;
  background: #e0f2fe;
  color: #0369a1 !important;
  -webkit-text-fill-color: #0369a1 !important;
  font-size: 12px;
  font-weight: 950;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vb24-js-dropdown-related h3 {
  margin: 0 0 10px !important;
  color: #111827 !important;
  -webkit-text-fill-color: #111827 !important;
  font-size: 22px !important;
  line-height: 1.18 !important;
  font-weight: 950 !important;
  letter-spacing: -0.04em;
}

.vb24-js-dropdown-related p {
  margin: 0 !important;
  color: #4b5563 !important;
  -webkit-text-fill-color: #4b5563 !important;
  font-size: 15px;
  line-height: 1.65;
}

@media (max-width: 760px) {
  .vb24-js-dropdown-related {
    grid-template-columns: 1fr;
  }

  .vb24-js-dropdown-related a {
    padding: 20px;
    border-radius: 20px;
  }
}
</style>
]]></content:encoded>
					
					<wfw:commentRss>https://veebilehed24.ee/en/blog/javascript/javascript-dropdown-menu-examples/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
