Navigation Bars
MediumResponsive navigation bars with mobile menu and dropdown support
Live Demo
Basic Navbar
Simple navigation bar with logo and menu items
📖 Basic Navbar Overview
Simple navigation bar with logo and menu items
💡 Key Features
- • Basic Navbar functionality with Stimulus controller
- • Navigation bars, sidebars, breadcrumbs, and layout components
- • Responsive design optimized for all screen sizes
- • Accessible markup with proper semantic HTML
- • Modern CSS transitions and interactive effects
- • Enhanced with navbar capabilities
- • Enhanced with navigation capabilities
- • Enhanced with responsive capabilities
- • Enhanced with mobile capabilities
- • Enhanced with menu capabilities
- • Enhanced with dropdown capabilities
🏗️ Basic Navbar HTML Structure
This basic navbar component uses semantic HTML structure with Stimulus data attributes to connect HTML elements to JavaScript functionality.
📋 Stimulus Data Attributes
data-controller="navigation-navbars-basic"
Connects this HTML element to the Basic Navbar Stimulus controller
data-action="click->navigation-navbars-basic#method"
Defines click events that trigger basic navbar controller methods
data-navigation-navbars-basic-target="element"
Identifies elements that the Basic Navbar controller can reference and manipulate
♿ Accessibility Features
- • Semantic HTML elements provide screen reader context
- • ARIA attributes enhance basic navbar accessibility
- • Keyboard navigation fully supported
- • Focus management for interactive elements
🎨 Basic Navbar Tailwind Classes
This basic navbar component uses Tailwind CSS utility classes with the forest theme color palette for styling and responsive design.
🎨 Navigation & Layout Colors
bg-moss-600
Primary
bg-moss-100
Light
bg-honey-400
Accent
📐 Layout & Spacing
p-4
- Padding for basic navbar contentmb-4
- Margin bottom between elementsspace-y-2
- Vertical spacing in listsrounded-lg
- Rounded corners for modern look📱 Responsive Basic Navbar Design
- •
sm:
- Small screens (640px+) optimized for basic navbar - •
md:
- Medium screens (768px+) enhanced layout - •
lg:
- Large screens (1024px+) full functionality - • Mobile-first approach ensures basic navbar works on all devices
⚡ Basic Navbar JavaScript Logic
The Basic Navbar component uses a dedicated Stimulus controller (navigation-navbars-basic
) to handle basic navbar interactions and manage component state.
🎯 Basic Navbar Controller Features
Targets
DOM elements the basic navbar controller can reference and manipulate
Values
Configuration data for basic navbar behavior passed from HTML
Actions
Methods triggered by basic navbar user events and interactions
Lifecycle
Setup and cleanup methods for basic navbar initialization
🔄 Basic Navbar Event Flow
- 1. User interacts with basic navbar element (click, hover, input, etc.)
- 2. Stimulus detects event through
data-action
attribute - 3. Basic Navbar controller method executes with access to targets and values
- 4. Controller updates DOM with new basic navbar state or visual changes
- 5. CSS transitions provide smooth visual feedback for basic navbar interactions
<nav class="bg-white border-b border-green-200" data-controller="navbars-basic">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<!-- Logo -->
<div class="flex items-center">
<div class="flex-shrink-0">
<span class="text-xl font-bold text-green-900">Stimulush</span>
</div>
</div>
<!-- Desktop Navigation -->
<div class="hidden md:flex items-center space-x-8">
<a href="#" class="text-green-600 hover:text-green-900 px-3 py-2 text-sm font-medium transition-colors duration-200">
Home
</a>
<a href="#" class="text-green-600 hover:text-green-900 px-3 py-2 text-sm font-medium transition-colors duration-200">
Components
</a>
<a href="#" class="text-green-600 hover:text-green-900 px-3 py-2 text-sm font-medium transition-colors duration-200">
Documentation
</a>
<a href="#" class="text-green-600 hover:text-green-900 px-3 py-2 text-sm font-medium transition-colors duration-200">
About
</a>
</div>
<!-- Actions -->
<div class="hidden md:flex items-center space-x-4">
<button class="text-green-600 hover:text-green-900 p-2 transition-colors duration-200">
<svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
</svg>
</button>
<button class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg text-sm font-medium transition-colors duration-200">
Get Started
</button>
</div>
</div>
</div>
</nav>
import { Controller } from "@hotwired/stimulus"
// Basic Navbar Controller
// Handles simple navigation bar interactions and link highlighting
export default class extends Controller {
connect() {
console.log("Basic navbar connected!")
this.highlightCurrentPage()
}
highlightCurrentPage() {
// Find all navigation links
const links = this.element.querySelectorAll('a[href]')
// Add active state to current page (demo purposes - highlights first link)
if (links.length > 0) {
links[0].classList.add('text-green-900', 'font-semibold')
links[0].classList.remove('text-green-600')
}
}
// Handle navigation click events
navigate(event) {
event.preventDefault()
// Remove active state from all links
const links = this.element.querySelectorAll('a[href]')
links.forEach(link => {
link.classList.add('text-green-600')
link.classList.remove('text-green-900', 'font-semibold')
})
// Add active state to clicked link
const clickedLink = event.currentTarget
clickedLink.classList.add('text-green-900', 'font-semibold')
clickedLink.classList.remove('text-green-600')
console.log(`Navigating to: ${clickedLink.textContent.trim()}`)
}
}
Responsive Navbar
Mobile-responsive navbar with hamburger menu
📖 Responsive Navbar Overview
Mobile-responsive navbar with hamburger menu
💡 Key Features
- • Responsive Navbar functionality with Stimulus controller
- • Navigation bars, sidebars, breadcrumbs, and layout components
- • Responsive design optimized for all screen sizes
- • Accessible markup with proper semantic HTML
- • Modern CSS transitions and interactive effects
- • Enhanced with navbar capabilities
- • Enhanced with navigation capabilities
- • Enhanced with responsive capabilities
- • Enhanced with mobile capabilities
- • Enhanced with menu capabilities
- • Enhanced with dropdown capabilities
🏗️ Responsive Navbar HTML Structure
This responsive navbar component uses semantic HTML structure with Stimulus data attributes to connect HTML elements to JavaScript functionality.
📋 Stimulus Data Attributes
data-controller="navigation-navbars-responsive"
Connects this HTML element to the Responsive Navbar Stimulus controller
data-action="click->navigation-navbars-responsive#method"
Defines click events that trigger responsive navbar controller methods
data-navigation-navbars-responsive-target="element"
Identifies elements that the Responsive Navbar controller can reference and manipulate
♿ Accessibility Features
- • Semantic HTML elements provide screen reader context
- • ARIA attributes enhance responsive navbar accessibility
- • Keyboard navigation fully supported
- • Focus management for interactive elements
🎨 Responsive Navbar Tailwind Classes
This responsive navbar component uses Tailwind CSS utility classes with the forest theme color palette for styling and responsive design.
🎨 Navigation & Layout Colors
bg-moss-600
Primary
bg-moss-100
Light
bg-honey-400
Accent
📐 Layout & Spacing
p-4
- Padding for responsive navbar contentmb-4
- Margin bottom between elementsspace-y-2
- Vertical spacing in listsrounded-lg
- Rounded corners for modern look📱 Responsive Responsive Navbar Design
- •
sm:
- Small screens (640px+) optimized for responsive navbar - •
md:
- Medium screens (768px+) enhanced layout - •
lg:
- Large screens (1024px+) full functionality - • Mobile-first approach ensures responsive navbar works on all devices
⚡ Responsive Navbar JavaScript Logic
The Responsive Navbar component uses a dedicated Stimulus controller (navigation-navbars-responsive
) to handle responsive navbar interactions and manage component state.
🎯 Responsive Navbar Controller Features
Targets
DOM elements the responsive navbar controller can reference and manipulate
Values
Configuration data for responsive navbar behavior passed from HTML
Actions
Methods triggered by responsive navbar user events and interactions
Lifecycle
Setup and cleanup methods for responsive navbar initialization
🔄 Responsive Navbar Event Flow
- 1. User interacts with responsive navbar element (click, hover, input, etc.)
- 2. Stimulus detects event through
data-action
attribute - 3. Responsive Navbar controller method executes with access to targets and values
- 4. Controller updates DOM with new responsive navbar state or visual changes
- 5. CSS transitions provide smooth visual feedback for responsive navbar interactions
<nav class="bg-white border-b border-green-200" data-controller="navbars-responsive">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<!-- Logo -->
<div class="flex items-center">
<div class="flex-shrink-0">
<span class="text-xl font-bold text-green-900">Stimulush</span>
</div>
</div>
<!-- Desktop Navigation -->
<div class="hidden md:flex items-center space-x-8">
<a href="#" class="text-green-600 hover:text-green-900 px-3 py-2 text-sm font-medium transition-colors duration-200">
Home
</a>
<a href="#" class="text-green-600 hover:text-green-900 px-3 py-2 text-sm font-medium transition-colors duration-200">
Components
</a>
<a href="#" class="text-green-600 hover:text-green-900 px-3 py-2 text-sm font-medium transition-colors duration-200">
Documentation
</a>
<a href="#" class="text-green-600 hover:text-green-900 px-3 py-2 text-sm font-medium transition-colors duration-200">
About
</a>
</div>
<!-- Mobile menu button -->
<div class="md:hidden flex items-center">
<button
class="inline-flex items-center justify-center p-2 rounded-md text-green-600 hover:text-green-900 hover:bg-green-100 transition-colors duration-200"
data-action="click->navbars-responsive#toggle"
data-navbars-responsive-target="menuButton"
>
<svg class="block h-6 w-6" data-navbars-responsive-target="hamburgerIcon" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M3.75 6.75h16.5M3.75 12h16.5m-16.5 5.25h16.5" />
</svg>
<svg class="hidden h-6 w-6" data-navbars-responsive-target="closeIcon" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18L18 6M6 6l12 12" />
</svg>
</button>
</div>
<!-- Actions (Desktop) -->
<div class="hidden md:flex items-center space-x-4">
<button class="text-green-600 hover:text-green-900 p-2 transition-colors duration-200">
<svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
</svg>
</button>
<button class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg text-sm font-medium transition-colors duration-200">
Get Started
</button>
</div>
</div>
</div>
<!-- Mobile menu -->
<div class="md:hidden hidden" data-navbars-responsive-target="mobileMenu">
<div class="px-2 pt-2 pb-3 space-y-1 bg-white border-t border-green-200">
<a href="#" class="block px-3 py-2 text-base font-medium text-green-600 hover:text-green-900 hover:bg-green-50 rounded-md transition-colors duration-200">
Home
</a>
<a href="#" class="block px-3 py-2 text-base font-medium text-green-600 hover:text-green-900 hover:bg-green-50 rounded-md transition-colors duration-200">
Components
</a>
<a href="#" class="block px-3 py-2 text-base font-medium text-green-600 hover:text-green-900 hover:bg-green-50 rounded-md transition-colors duration-200">
Documentation
</a>
<a href="#" class="block px-3 py-2 text-base font-medium text-green-600 hover:text-green-900 hover:bg-green-50 rounded-md transition-colors duration-200">
About
</a>
<div class="px-3 py-2 border-t border-green-200 mt-3 pt-3">
<button class="w-full bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg text-sm font-medium transition-colors duration-200">
Get Started
</button>
</div>
</div>
</div>
</nav>
import { Controller } from "@hotwired/stimulus"
// Responsive Navbar Controller
// Handles mobile menu toggle and responsive navigation behavior
export default class extends Controller {
static targets = ["mobileMenu", "menuButton", "hamburgerIcon", "closeIcon"]
connect() {
console.log("Responsive navbar connected!")
this.isOpen = false
this.setupEventListeners()
}
disconnect() {
this.removeEventListeners()
}
setupEventListeners() {
// Close mobile menu when clicking outside
this.handleOutsideClick = this.handleOutsideClick.bind(this)
// Close mobile menu on escape key
this.handleEscapeKey = this.handleEscapeKey.bind(this)
}
removeEventListeners() {
document.removeEventListener('click', this.handleOutsideClick)
document.removeEventListener('keydown', this.handleEscapeKey)
}
toggle(event) {
event.preventDefault()
this.isOpen ? this.close() : this.open()
}
open() {
this.isOpen = true
this.mobileMenuTarget.classList.remove('hidden')
this.hamburgerIconTarget.classList.add('hidden')
this.closeIconTarget.classList.remove('hidden')
// Add event listeners when menu opens
setTimeout(() => {
document.addEventListener('click', this.handleOutsideClick)
document.addEventListener('keydown', this.handleEscapeKey)
}, 0)
console.log("Mobile menu opened")
}
close() {
this.isOpen = false
this.mobileMenuTarget.classList.add('hidden')
this.hamburgerIconTarget.classList.remove('hidden')
this.closeIconTarget.classList.add('hidden')
// Remove event listeners when menu closes
document.removeEventListener('click', this.handleOutsideClick)
document.removeEventListener('keydown', this.handleEscapeKey)
console.log("Mobile menu closed")
}
handleOutsideClick(event) {
if (!this.element.contains(event.target)) {
this.close()
}
}
handleEscapeKey(event) {
if (event.key === 'Escape') {
this.close()
}
}
// Handle mobile menu link clicks
navigateMobile(event) {
event.preventDefault()
const linkText = event.currentTarget.textContent.trim()
console.log(`Mobile navigation: ${linkText}`)
// Close mobile menu after navigation
this.close()
}
}
Navbar with Dropdowns
Navigation with dropdown menu items
📖 Navbar with Dropdowns Overview
Navigation with dropdown menu items
💡 Key Features
- • Navbar with Dropdowns functionality with Stimulus controller
- • Navigation bars, sidebars, breadcrumbs, and layout components
- • Responsive design optimized for all screen sizes
- • Accessible markup with proper semantic HTML
- • Modern CSS transitions and interactive effects
- • Enhanced with navbar capabilities
- • Enhanced with navigation capabilities
- • Enhanced with responsive capabilities
- • Enhanced with mobile capabilities
- • Enhanced with menu capabilities
- • Enhanced with dropdown capabilities
🏗️ Navbar with Dropdowns HTML Structure
This navbar with dropdowns component uses semantic HTML structure with Stimulus data attributes to connect HTML elements to JavaScript functionality.
📋 Stimulus Data Attributes
data-controller="navigation-navbars-dropdown"
Connects this HTML element to the Navbar with Dropdowns Stimulus controller
data-action="click->navigation-navbars-dropdown#method"
Defines click events that trigger navbar with dropdowns controller methods
data-navigation-navbars-dropdown-target="element"
Identifies elements that the Navbar with Dropdowns controller can reference and manipulate
♿ Accessibility Features
- • Semantic HTML elements provide screen reader context
- • ARIA attributes enhance navbar with dropdowns accessibility
- • Keyboard navigation fully supported
- • Focus management for interactive elements
🎨 Navbar with Dropdowns Tailwind Classes
This navbar with dropdowns component uses Tailwind CSS utility classes with the forest theme color palette for styling and responsive design.
🎨 Navigation & Layout Colors
bg-moss-600
Primary
bg-moss-100
Light
bg-honey-400
Accent
📐 Layout & Spacing
p-4
- Padding for navbar with dropdowns contentmb-4
- Margin bottom between elementsspace-y-2
- Vertical spacing in listsrounded-lg
- Rounded corners for modern look📱 Responsive Navbar with Dropdowns Design
- •
sm:
- Small screens (640px+) optimized for navbar with dropdowns - •
md:
- Medium screens (768px+) enhanced layout - •
lg:
- Large screens (1024px+) full functionality - • Mobile-first approach ensures navbar with dropdowns works on all devices
⚡ Navbar with Dropdowns JavaScript Logic
The Navbar with Dropdowns component uses a dedicated Stimulus controller (navigation-navbars-dropdown
) to handle navbar with dropdowns interactions and manage component state.
🎯 Navbar with Dropdowns Controller Features
Targets
DOM elements the navbar with dropdowns controller can reference and manipulate
Values
Configuration data for navbar with dropdowns behavior passed from HTML
Actions
Methods triggered by navbar with dropdowns user events and interactions
Lifecycle
Setup and cleanup methods for navbar with dropdowns initialization
🔄 Navbar with Dropdowns Event Flow
- 1. User interacts with navbar with dropdowns element (click, hover, input, etc.)
- 2. Stimulus detects event through
data-action
attribute - 3. Navbar with Dropdowns controller method executes with access to targets and values
- 4. Controller updates DOM with new navbar with dropdowns state or visual changes
- 5. CSS transitions provide smooth visual feedback for navbar with dropdowns interactions
<nav class="bg-white border-b border-green-200" data-controller="navbars-dropdown">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<!-- Logo -->
<div class="flex items-center">
<div class="flex-shrink-0">
<span class="text-xl font-bold text-green-900">Stimulush</span>
</div>
</div>
<!-- Desktop Navigation -->
<div class="hidden md:flex items-center space-x-8">
<a href="#" class="text-green-600 hover:text-green-900 px-3 py-2 text-sm font-medium transition-colors duration-200">
Home
</a>
<!-- Components Dropdown -->
<div class="relative" data-navbars-dropdown-target="dropdown">
<button
class="flex items-center text-green-600 hover:text-green-900 px-3 py-2 text-sm font-medium transition-colors duration-200"
data-action="click->navbars-dropdown#toggleDropdown"
data-navbars-dropdown-target="trigger"
>
Components
<svg class="ml-1 h-4 w-4 transform transition-transform duration-200" data-navbars-dropdown-target="chevron" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="m19.5 8.25-7.5 7.5-7.5-7.5" />
</svg>
</button>
<!-- Dropdown Menu -->
<div class="absolute left-0 mt-2 w-56 rounded-md shadow-lg bg-white border border-green-200 opacity-0 invisible transform -translate-y-1 transition-all duration-200"
data-navbars-dropdown-target="menu">
<div class="py-1">
<a href="#" class="block px-4 py-2 text-sm text-green-600 hover:text-green-900 hover:bg-green-50 transition-colors duration-200">
<div class="flex items-center">
<svg class="w-4 h-4 mr-3 text-green-400" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M15.042 21.672 13.684 16.6m0 0-2.51 2.225.569-9.47 5.227 7.917-3.286-.672ZM12 2.25V4.5m5.834.166-1.591 1.591M20.25 10.5H18M7.757 14.743l-1.59 1.59M6 10.5H3.75m4.007-4.243-1.59-1.59" />
</svg>
Interactive Elements
</div>
</a>
<a href="#" class="block px-4 py-2 text-sm text-green-600 hover:text-green-900 hover:bg-green-50 transition-colors duration-200">
<div class="flex items-center">
<svg class="w-4 h-4 mr-3 text-green-400" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M19.5 14.25v-2.625a3.375 3.375 0 0 0-3.375-3.375h-4.5B7.125 8.25 5.25 10.125 5.25 13.5v2.625m14.25-2.625v2.625A2.625 2.625 0 0 1 17.25 18H6.75A2.625 2.625 0 0 1 4.125 15.375V12.75" />
</svg>
Form Components
</div>
</a>
<a href="#" class="block px-4 py-2 text-sm text-green-600 hover:text-green-900 hover:bg-green-50 transition-colors duration-200">
<div class="flex items-center">
<svg class="w-4 h-4 mr-3 text-green-400" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M9 17V7m0 10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V7a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2m0 10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2H9m0 0V5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2v2M9 7h6" />
</svg>
Navigation
</div>
</a>
<div class="border-t border-green-200 my-1"></div>
<a href="#" class="block px-4 py-2 text-sm text-green-600 hover:text-green-900 hover:bg-green-50 transition-colors duration-200">
<div class="flex items-center">
<svg class="w-4 h-4 mr-3 text-green-400" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M2.036 12.322a1.012 1.012 0 0 1 0-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.963-7.178Z" />
<path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 1 1-6 0 3 3 0 0 1 6 0Z" />
</svg>
View All Components
</div>
</a>
</div>
</div>
</div>
<a href="#" class="text-green-600 hover:text-green-900 px-3 py-2 text-sm font-medium transition-colors duration-200">
Documentation
</a>
<a href="#" class="text-green-600 hover:text-green-900 px-3 py-2 text-sm font-medium transition-colors duration-200">
About
</a>
</div>
<!-- Actions -->
<div class="hidden md:flex items-center space-x-4">
<button class="text-green-600 hover:text-green-900 p-2 transition-colors duration-200">
<svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
</svg>
</button>
<button class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg text-sm font-medium transition-colors duration-200">
Get Started
</button>
</div>
</div>
</div>
</nav>
import { Controller } from "@hotwired/stimulus"
// Dropdown Navbar Controller
// Handles dropdown menu interactions with keyboard navigation and accessibility
export default class extends Controller {
static targets = ["dropdown", "trigger", "menu", "chevron"]
connect() {
console.log("Dropdown navbar connected!")
this.isOpen = false
this.setupEventListeners()
}
disconnect() {
this.removeEventListeners()
}
setupEventListeners() {
// Close dropdown when clicking outside
this.handleOutsideClick = this.handleOutsideClick.bind(this)
// Handle escape key
this.handleEscapeKey = this.handleEscapeKey.bind(this)
}
removeEventListeners() {
document.removeEventListener('click', this.handleOutsideClick)
document.removeEventListener('keydown', this.handleEscapeKey)
}
toggleDropdown(event) {
event.preventDefault()
this.isOpen ? this.closeDropdown() : this.openDropdown()
}
openDropdown() {
this.isOpen = true
// Show menu with animation
this.menuTarget.classList.remove('opacity-0', 'invisible', '-translate-y-1')
this.menuTarget.classList.add('opacity-100', 'visible', 'translate-y-0')
// Rotate chevron
this.chevronTarget.classList.add('rotate-180')
// Add active state to trigger
this.triggerTarget.classList.add('text-green-900')
this.triggerTarget.classList.remove('text-green-600')
// Add event listeners
setTimeout(() => {
document.addEventListener('click', this.handleOutsideClick)
document.addEventListener('keydown', this.handleEscapeKey)
}, 0)
console.log("Dropdown opened")
}
closeDropdown() {
this.isOpen = false
// Hide menu with animation
this.menuTarget.classList.add('opacity-0', 'invisible', '-translate-y-1')
this.menuTarget.classList.remove('opacity-100', 'visible', 'translate-y-0')
// Reset chevron
this.chevronTarget.classList.remove('rotate-180')
// Remove active state from trigger
this.triggerTarget.classList.add('text-green-600')
this.triggerTarget.classList.remove('text-green-900')
// Remove event listeners
document.removeEventListener('click', this.handleOutsideClick)
document.removeEventListener('keydown', this.handleEscapeKey)
console.log("Dropdown closed")
}
handleOutsideClick(event) {
if (!this.dropdownTarget.contains(event.target)) {
this.closeDropdown()
}
}
handleEscapeKey(event) {
if (event.key === 'Escape') {
this.closeDropdown()
this.triggerTarget.focus()
}
}
// Handle dropdown item clicks
selectItem(event) {
event.preventDefault()
const itemText = event.currentTarget.textContent.trim()
console.log(`Selected: ${itemText}`)
// Close dropdown after selection
this.closeDropdown()
}
// Handle hover events for better UX
handleMouseEnter() {
if (!this.isOpen) {
this.openDropdown()
}
}
handleMouseLeave() {
// Small delay before closing to allow mouse movement
setTimeout(() => {
if (this.isOpen) {
this.closeDropdown()
}
}, 150)
}
}
Navbar with Search
Navigation bar with integrated search functionality
📖 Navbar with Search Overview
Navigation bar with integrated search functionality
💡 Key Features
- • Navbar with Search functionality with Stimulus controller
- • Navigation bars, sidebars, breadcrumbs, and layout components
- • Responsive design optimized for all screen sizes
- • Accessible markup with proper semantic HTML
- • Modern CSS transitions and interactive effects
- • Enhanced with navbar capabilities
- • Enhanced with navigation capabilities
- • Enhanced with responsive capabilities
- • Enhanced with mobile capabilities
- • Enhanced with menu capabilities
- • Enhanced with dropdown capabilities
🏗️ Navbar with Search HTML Structure
This navbar with search component uses semantic HTML structure with Stimulus data attributes to connect HTML elements to JavaScript functionality.
📋 Stimulus Data Attributes
data-controller="navigation-navbars-search"
Connects this HTML element to the Navbar with Search Stimulus controller
data-action="click->navigation-navbars-search#method"
Defines click events that trigger navbar with search controller methods
data-navigation-navbars-search-target="element"
Identifies elements that the Navbar with Search controller can reference and manipulate
♿ Accessibility Features
- • Semantic HTML elements provide screen reader context
- • ARIA attributes enhance navbar with search accessibility
- • Keyboard navigation fully supported
- • Focus management for interactive elements
🎨 Navbar with Search Tailwind Classes
This navbar with search component uses Tailwind CSS utility classes with the forest theme color palette for styling and responsive design.
🎨 Navigation & Layout Colors
bg-moss-600
Primary
bg-moss-100
Light
bg-honey-400
Accent
📐 Layout & Spacing
p-4
- Padding for navbar with search contentmb-4
- Margin bottom between elementsspace-y-2
- Vertical spacing in listsrounded-lg
- Rounded corners for modern look📱 Responsive Navbar with Search Design
- •
sm:
- Small screens (640px+) optimized for navbar with search - •
md:
- Medium screens (768px+) enhanced layout - •
lg:
- Large screens (1024px+) full functionality - • Mobile-first approach ensures navbar with search works on all devices
⚡ Navbar with Search JavaScript Logic
The Navbar with Search component uses a dedicated Stimulus controller (navigation-navbars-search
) to handle navbar with search interactions and manage component state.
🎯 Navbar with Search Controller Features
Targets
DOM elements the navbar with search controller can reference and manipulate
Values
Configuration data for navbar with search behavior passed from HTML
Actions
Methods triggered by navbar with search user events and interactions
Lifecycle
Setup and cleanup methods for navbar with search initialization
🔄 Navbar with Search Event Flow
- 1. User interacts with navbar with search element (click, hover, input, etc.)
- 2. Stimulus detects event through
data-action
attribute - 3. Navbar with Search controller method executes with access to targets and values
- 4. Controller updates DOM with new navbar with search state or visual changes
- 5. CSS transitions provide smooth visual feedback for navbar with search interactions
<nav class="bg-white border-b border-green-200" data-controller="navbars-search">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<!-- Logo -->
<div class="flex items-center">
<div class="flex-shrink-0">
<span class="text-xl font-bold text-green-900">Stimulush</span>
</div>
</div>
<!-- Desktop Navigation with Search -->
<div class="hidden md:flex items-center space-x-8">
<a href="#" class="text-green-600 hover:text-green-900 px-3 py-2 text-sm font-medium transition-colors duration-200">
Home
</a>
<a href="#" class="text-green-600 hover:text-green-900 px-3 py-2 text-sm font-medium transition-colors duration-200">
Components
</a>
<!-- Search Bar -->
<div class="relative flex-1 max-w-lg">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg class="h-5 w-5 text-green-400" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
</svg>
</div>
<input
type="text"
placeholder="Search components..."
class="block w-full pl-10 pr-4 py-2 border border-green-300 rounded-lg text-sm placeholder-green-400 focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent transition-all duration-200"
data-navbars-search-target="searchInput"
data-action="input->navbars-search#handleSearch keydown->navbars-search#handleKeydown"
>
<!-- Search Results Dropdown -->
<div class="absolute top-full left-0 right-0 mt-2 bg-white border border-green-200 rounded-lg shadow-lg max-h-96 overflow-y-auto hidden"
data-navbars-search-target="searchResults">
<div class="p-4">
<p class="text-sm text-green-600">Start typing to search components...</p>
</div>
</div>
</div>
<a href="#" class="text-green-600 hover:text-green-900 px-3 py-2 text-sm font-medium transition-colors duration-200">
Documentation
</a>
</div>
<!-- Actions -->
<div class="hidden md:flex items-center space-x-4">
<button class="text-green-600 hover:text-green-900 p-2 transition-colors duration-200"
data-action="click->navbars-search#toggleSearch">
<svg class="w-5 h-5" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
</svg>
</button>
<button class="bg-green-600 hover:bg-green-700 text-white px-4 py-2 rounded-lg text-sm font-medium transition-colors duration-200">
Get Started
</button>
</div>
<!-- Mobile Search Toggle -->
<div class="md:hidden flex items-center">
<button
class="p-2 text-green-600 hover:text-green-900 hover:bg-green-100 rounded-md transition-colors duration-200"
data-action="click->navbars-search#toggleMobileSearch"
>
<svg class="w-6 h-6" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
</svg>
</button>
</div>
</div>
<!-- Mobile Search Bar -->
<div class="md:hidden px-4 pb-4 hidden" data-navbars-search-target="mobileSearch">
<div class="relative">
<div class="absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none">
<svg class="h-5 w-5 text-green-400" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="m21 21-5.197-5.197m0 0A7.5 7.5 0 1 0 5.196 5.196a7.5 7.5 0 0 0 10.607 10.607Z" />
</svg>
</div>
<input
type="text"
placeholder="Search components..."
class="block w-full pl-10 pr-4 py-2 border border-green-300 rounded-lg text-sm placeholder-green-400 focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent transition-all duration-200"
data-navbars-search-target="mobileSearchInput"
data-action="input->navbars-search#handleMobileSearch"
>
</div>
</div>
</div>
</nav>
import { Controller } from "@hotwired/stimulus"
// Search Navbar Controller
// Handles search functionality with live results and keyboard navigation
export default class extends Controller {
static targets = ["searchInput", "searchResults", "mobileSearch", "mobileSearchInput"]
connect() {
console.log("Search navbar connected!")
this.debounceTimer = null
this.searchResults = []
this.currentIndex = -1
this.setupEventListeners()
this.loadSampleData()
}
disconnect() {
this.removeEventListeners()
}
setupEventListeners() {
// Close search results when clicking outside
this.handleOutsideClick = this.handleOutsideClick.bind(this)
}
removeEventListeners() {
document.removeEventListener('click', this.handleOutsideClick)
}
loadSampleData() {
// Sample component data for demo
this.components = [
{ name: "Button", category: "Interactive", description: "Clickable button elements" },
{ name: "Modal", category: "Interactive", description: "Overlay dialogs" },
{ name: "Input Field", category: "Forms", description: "Text input components" },
{ name: "Dropdown", category: "Interactive", description: "Select and context menus" },
{ name: "Navigation", category: "Navigation", description: "Navigation bars" },
{ name: "Breadcrumbs", category: "Navigation", description: "Path navigation" },
{ name: "Card", category: "Data Display", description: "Content containers" },
{ name: "Alert", category: "Feedback", description: "Status messages" }
]
}
handleSearch(event) {
const query = event.target.value.trim()
// Clear previous timer
if (this.debounceTimer) {
clearTimeout(this.debounceTimer)
}
// Debounce search to avoid excessive calls
this.debounceTimer = setTimeout(() => {
this.performSearch(query, this.searchResultsTarget)
}, 300)
}
handleMobileSearch(event) {
const query = event.target.value.trim()
if (this.debounceTimer) {
clearTimeout(this.debounceTimer)
}
this.debounceTimer = setTimeout(() => {
this.performSearch(query, null, true)
}, 300)
}
performSearch(query, resultsContainer = null, isMobile = false) {
if (!query) {
if (resultsContainer) {
resultsContainer.classList.add('hidden')
}
return
}
// Filter components based on query
const filteredResults = this.components.filter(component =>
component.name.toLowerCase().includes(query.toLowerCase()) ||
component.category.toLowerCase().includes(query.toLowerCase()) ||
component.description.toLowerCase().includes(query.toLowerCase())
)
if (isMobile) {
console.log(`Mobile search for "${query}": ${filteredResults.length} results`)
return
}
this.displayResults(filteredResults, resultsContainer || this.searchResultsTarget)
}
displayResults(results, container) {
if (results.length === 0) {
container.innerHTML = `
<div class="p-4">
<p class="text-sm text-green-600">No components found.</p>
</div>
`
} else {
const resultsHtml = results.map((result, index) => `
<div class="px-4 py-2 hover:bg-green-50 cursor-pointer border-b border-green-100 last:border-b-0 transition-colors duration-200"
data-search-index="${index}"
data-action="click->navbars-search#selectResult">
<div class="flex items-start justify-between">
<div>
<p class="text-sm font-medium text-green-900">${result.name}</p>
<p class="text-xs text-green-600">${result.description}</p>
</div>
<span class="text-xs bg-green-100 text-green-700 px-2 py-1 rounded-full">${result.category}</span>
</div>
</div>
`).join('')
container.innerHTML = resultsHtml
}
container.classList.remove('hidden')
this.currentIndex = -1
// Add outside click listener
setTimeout(() => {
document.addEventListener('click', this.handleOutsideClick)
}, 0)
}
handleKeydown(event) {
const isSearchOpen = !this.searchResultsTarget.classList.contains('hidden')
if (!isSearchOpen) return
switch (event.key) {
case 'Escape':
this.closeSearch()
event.preventDefault()
break
case 'ArrowDown':
this.navigateResults(1)
event.preventDefault()
break
case 'ArrowUp':
this.navigateResults(-1)
event.preventDefault()
break
case 'Enter':
this.selectCurrentResult()
event.preventDefault()
break
}
}
navigateResults(direction) {
const results = this.searchResultsTarget.querySelectorAll('[data-search-index]')
if (results.length === 0) return
// Remove current highlight
results.forEach(result => result.classList.remove('bg-green-100'))
// Update index
if (direction === 1) {
this.currentIndex = Math.min(this.currentIndex + 1, results.length - 1)
} else {
this.currentIndex = Math.max(this.currentIndex - 1, 0)
}
// Highlight new result
results[this.currentIndex]?.classList.add('bg-green-100')
}
selectCurrentResult() {
if (this.currentIndex >= 0) {
const results = this.searchResultsTarget.querySelectorAll('[data-search-index]')
const currentResult = results[this.currentIndex]
if (currentResult) {
this.selectResult({ currentTarget: currentResult })
}
}
}
selectResult(event) {
const resultElement = event.currentTarget
const componentName = resultElement.querySelector('p').textContent
console.log(`Selected component: ${componentName}`)
// Clear search and close results
this.searchInputTarget.value = ''
this.closeSearch()
}
toggleSearch() {
// Focus search input
this.searchInputTarget.focus()
}
toggleMobileSearch() {
this.mobileSearchTarget.classList.toggle('hidden')
if (!this.mobileSearchTarget.classList.contains('hidden')) {
setTimeout(() => {
this.mobileSearchInputTarget.focus()
}, 100)
}
}
closeSearch() {
this.searchResultsTarget.classList.add('hidden')
document.removeEventListener('click', this.handleOutsideClick)
}
handleOutsideClick(event) {
if (!this.element.contains(event.target)) {
this.closeSearch()
}
}
}
Installation & Usage
Copy the ERB template
Copy the ERB code from the template tab above and paste it into your Rails view file.
Add the Stimulus controller
Create the Stimulus controller file in your JavaScript controllers directory.